8016696: PPC64 (part 4): add relocation for trampoline stubs
Summary: A trampoline allows to encode a small branch in the code, even if there is the chance that this branch can not reach all possible code locations. If the relocation finds that a branch is too far for the instruction in the code, it can patch it to jump to the trampoline where is sufficient space for a far branch. Needed on PPC.
Reviewed-by: kvn, bdelsart, jrose
--- a/hotspot/src/share/vm/code/relocInfo.cpp Wed Jul 03 11:50:29 2013 -0700
+++ b/hotspot/src/share/vm/code/relocInfo.cpp Thu Jul 04 10:51:31 2013 +0200
@@ -582,6 +582,18 @@
_static_call = address_from_scaled_offset(unpack_1_int(), base);
}
+void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) {
+ short* p = (short*) dest->locs_end();
+ CodeSection* insts = dest->outer()->insts();
+ normalize_address(_owner, insts);
+ p = pack_1_int_to(p, scaled_offset(_owner, insts->start()));
+ dest->set_locs_end((relocInfo*) p);
+}
+
+void trampoline_stub_Relocation::unpack_data() {
+ address base = binding()->section_start(CodeBuffer::SECT_INSTS);
+ _owner = address_from_scaled_offset(unpack_1_int(), base);
+}
void external_word_Relocation::pack_data_to(CodeSection* dest) {
short* p = (short*) dest->locs_end();
@@ -811,6 +823,25 @@
return NULL;
}
+// Finds the trampoline address for a call. If no trampoline stub is
+// found NULL is returned which can be handled by the caller.
+address trampoline_stub_Relocation::get_trampoline_for(address call, nmethod* code) {
+ // There are no relocations available when the code gets relocated
+ // because of CodeBuffer expansion.
+ if (code->relocation_size() == 0)
+ return NULL;
+
+ RelocIterator iter(code, call);
+ while (iter.next()) {
+ if (iter.type() == relocInfo::trampoline_stub_type) {
+ if (iter.trampoline_stub_reloc()->owner() == call) {
+ return iter.addr();
+ }
+ }
+ }
+
+ return NULL;
+}
void static_stub_Relocation::clear_inline_cache() {
// Call stub is only used when calling the interpreted code.
@@ -975,6 +1006,12 @@
tty->print(" | [static_call=" INTPTR_FORMAT "]", r->static_call());
break;
}
+ case relocInfo::trampoline_stub_type:
+ {
+ trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc();
+ tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", r->owner());
+ break;
+ }
}
tty->cr();
}
--- a/hotspot/src/share/vm/code/relocInfo.hpp Wed Jul 03 11:50:29 2013 -0700
+++ b/hotspot/src/share/vm/code/relocInfo.hpp Thu Jul 04 10:51:31 2013 +0200
@@ -260,8 +260,8 @@
poll_type = 10, // polling instruction for safepoints
poll_return_type = 11, // polling instruction for safepoints at return
metadata_type = 12, // metadata that used to be oops
- yet_unused_type_1 = 13, // Still unused
- yet_unused_type_2 = 14, // Still unused
+ trampoline_stub_type = 13, // stub-entry for trampoline
+ yet_unused_type_1 = 14, // Still unused
data_prefix_tag = 15, // tag for a prefix (carries data arguments)
type_mask = 15 // A mask which selects only the above values
};
@@ -301,6 +301,7 @@
visitor(poll) \
visitor(poll_return) \
visitor(section_word) \
+ visitor(trampoline_stub) \
public:
@@ -1150,6 +1151,43 @@
public:
};
+// Trampoline Relocations.
+// A trampoline allows to encode a small branch in the code, even if there
+// is the chance that this branch can not reach all possible code locations.
+// If the relocation finds that a branch is too far for the instruction
+// in the code, it can patch it to jump to the trampoline where is
+// sufficient space for a far branch. Needed on PPC.
+class trampoline_stub_Relocation : public Relocation {
+ relocInfo::relocType type() { return relocInfo::trampoline_stub_type; }
+
+ public:
+ static RelocationHolder spec(address static_call) {
+ RelocationHolder rh = newHolder();
+ return (new (rh) trampoline_stub_Relocation(static_call));
+ }
+
+ private:
+ address _owner; // Address of the NativeCall that owns the trampoline.
+
+ trampoline_stub_Relocation(address owner) {
+ _owner = owner;
+ }
+
+ friend class RelocIterator;
+ trampoline_stub_Relocation() { }
+
+ public:
+
+ // Return the address of the NativeCall that owns the trampoline.
+ address owner() { return _owner; }
+
+ void pack_data_to(CodeSection * dest);
+ void unpack_data();
+
+ // Find the trampoline stub for a call.
+ static address get_trampoline_for(address call, nmethod* code);
+};
+
class external_word_Relocation : public DataRelocation {
relocInfo::relocType type() { return relocInfo::external_word_type; }