/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
if (nm == NULL && begin != NULL) { // allow nmethod to be deduced from beginning address
CodeBlob* cb = CodeCache::find_blob(begin);
nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
}
guarantee(nm != NULL, "must be able to deduce nmethod from other arguments");
// the limit affects this next stuff: if (begin != NULL) {
relocInfo* backup;
address backup_addr; while (true) {
backup = _current;
backup_addr = _addr; if (!next() || addr() >= begin) break;
} // At this point, either we are at the first matching record, // or else there is no such record, and !has_current(). // In either case, revert to the immediately preceding state.
_current = backup;
_addr = backup_addr;
set_has_current(false);
}
}
// All the strange bit-encodings are in here. // The idea is to encode relocation data which are small integers // very efficiently (a single extra halfword). Larger chunks of // relocation data need a halfword header to hold their size. void RelocIterator::advance_over_prefix() { if (_current->is_datalen()) {
_data = (short*) _current->data();
_datalen = _current->datalen();
_current += _datalen + 1; // skip the embedded data & header
} else {
_databuf = _current->immediate();
_data = &_databuf;
_datalen = 1;
_current++; // skip the header
} // The client will see the following relocInfo, whatever that is. // It is the reloc to which the preceding data applies.
}
void RelocIterator::initialize_misc() {
set_has_current(false); for (int i = (int) CodeBuffer::SECT_FIRST; i < (int) CodeBuffer::SECT_LIMIT; i++) {
_section_start[i] = NULL; // these will be lazily computed, if needed
_section_end [i] = NULL;
}
}
Relocation* RelocIterator::reloc() { // (take the "switch" out-of-line)
relocInfo::relocType t = type(); if (false) {} #define EACH_TYPE(name) \ elseif (t == relocInfo::name##_type) { \ return name##_reloc(); \
}
APPLY_TO_RELOCATIONS(EACH_TYPE); #undef EACH_TYPE
assert(t == relocInfo::none, "must be padding"); returnnew(_rh) Relocation(t);
}
//////// Methods for flyweight Relocation types
RelocationHolder RelocationHolder::plus(int offset) const { if (offset != 0) { switch (type()) { case relocInfo::none: break; case relocInfo::oop_type:
{
oop_Relocation* r = (oop_Relocation*)reloc(); return oop_Relocation::spec(r->oop_index(), r->offset() + offset);
} case relocInfo::metadata_type:
{
metadata_Relocation* r = (metadata_Relocation*)reloc(); return metadata_Relocation::spec(r->metadata_index(), r->offset() + offset);
} default:
ShouldNotReachHere();
}
} return (*this);
}
// some relocations can compute their own values
address Relocation::value() {
ShouldNotReachHere(); return NULL;
}
void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { // Usually a self-relative reference to an external routine. // On some platforms, the reference is absolute (not self-relative). // The enhanced use of pd_call_destination sorts this all out.
address orig_addr = old_addr_for(addr(), src, dest);
address callee = pd_call_destination(orig_addr); // Reassert the callee address, this time in the new copy of the code.
pd_set_call_destination(callee);
}
//// pack/unpack methods
void oop_Relocation::pack_data_to(CodeSection* dest) { short* p = (short*) dest->locs_end();
p = pack_2_ints_to(p, _oop_index, _offset);
dest->set_locs_end((relocInfo*) p);
}
// Check whether my target address is valid within this section. // If not, strengthen the relocation type to point to another section. int sindex = _section; if (sindex == CodeBuffer::SECT_NONE && _target != NULL
&& (!dest->allocates(_target) || _target == dest->locs_point())) {
sindex = dest->outer()->section_index_of(_target);
guarantee(sindex != CodeBuffer::SECT_NONE, "must belong somewhere");
relocInfo* base = dest->locs_end() - 1;
assert(base->type() == this->type(), "sanity"); // Change the written type, to be section_word_type instead.
base->set_type(relocInfo::section_word_type);
}
// Note: An internal_word relocation cannot refer to its own instruction, // because we reserve "0" to mean that the pointer itself is embedded // in the code stream. We use a section_word relocation for such cases.
if (sindex == CodeBuffer::SECT_NONE) {
assert(type() == relocInfo::internal_word_type, "must be base class");
guarantee(_target == NULL || dest->allocates2(_target), "must be within the given code section");
jint x0 = scaled_offset_null_special(_target, dest->locs_point());
assert(!(x0 == 0 && _target != NULL), "correct encoding of null target");
p = pack_1_int_to(p, x0);
} else {
assert(_target != NULL, "sanity");
CodeSection* sect = dest->outer()->code_section(sindex);
guarantee(sect->allocates2(_target), "must be in correct section");
address base = sect->start();
jint offset = scaled_offset(_target, base);
assert((uint)sindex < (uint)CodeBuffer::SECT_LIMIT, "sanity");
assert(CodeBuffer::SECT_LIMIT <= (1 << section_width), "section_width++");
p = pack_1_int_to(p, (offset << section_width) | sindex);
}
//// miscellaneous methods
oop* oop_Relocation::oop_addr() { int n = _oop_index; if (n == 0) { // oop is stored in the code stream return (oop*) pd_address_in_code();
} else { // oop is stored in table at nmethod::oops_begin return code()->oop_addr_at(n);
}
}
oop oop_Relocation::oop_value() { // clean inline caches store a special pseudo-null if (Universe::contains_non_oop_word(oop_addr())) { return NULL;
} return *oop_addr();
}
void oop_Relocation::fix_oop_relocation() { if (!oop_is_immediate()) { // get the oop from the pool, and re-insert it into the instruction:
set_value(value());
}
}
void oop_Relocation::verify_oop_relocation() { if (!oop_is_immediate()) { // get the oop from the pool, and re-insert it into the instruction:
verify_value(value());
}
}
// meta data versions
Metadata** metadata_Relocation::metadata_addr() { int n = _metadata_index; if (n == 0) { // metadata is stored in the code stream return (Metadata**) pd_address_in_code();
} else { // metadata is stored in table at nmethod::metadatas_begin return code()->metadata_addr_at(n);
}
}
Metadata* metadata_Relocation::metadata_value() {
Metadata* v = *metadata_addr(); // clean inline caches store a special pseudo-null if (v == (Metadata*)Universe::non_oop_word()) v = NULL; return v;
}
void metadata_Relocation::fix_metadata_relocation() { if (!metadata_is_immediate()) { // get the metadata from the pool, and re-insert it into the instruction:
pd_fix_value(value());
}
}
bool static_call_Relocation::clear_inline_cache() { // Safe call site info
CompiledStaticCall* handler = this->code()->compiledStaticCall_at(this); return set_to_clean_no_ic_refill(handler);
}
address static_call_Relocation::static_stub() { // search for the static stub who points back to this static call
address static_call_addr = addr();
RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) {
static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); if (stub_reloc->static_call() == static_call_addr) { return iter.addr();
}
}
} 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;
}
bool static_stub_Relocation::clear_inline_cache() { // Call stub is only used when calling the interpreted code. // It does not really need to be cleared, except that we want to clean out the methodoop.
CompiledDirectStaticCall::set_stub_to_clean(this); returntrue;
}
void external_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { if (_target != NULL) { // Probably this reference is absolute, not relative, so the following is // probably a no-op.
set_value(_target);
} // If target is NULL, this is an absolute embedded reference to an external // location, which means there is nothing to fix here. In either case, the // resulting target should be an "external" address.
postcond(src->section_index_of(target()) == CodeBuffer::SECT_NONE);
postcond(dest->section_index_of(target()) == CodeBuffer::SECT_NONE);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.