| File: | jdk/src/hotspot/share/code/relocInfo.hpp |
| Warning: | line 512, column 7 Value assigned to field '_databuf' in implicit constructor is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. | |||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
| 4 | * | |||
| 5 | * This code is free software; you can redistribute it and/or modify it | |||
| 6 | * under the terms of the GNU General Public License version 2 only, as | |||
| 7 | * published by the Free Software Foundation. | |||
| 8 | * | |||
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT | |||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
| 12 | * version 2 for more details (a copy is included in the LICENSE file that | |||
| 13 | * accompanied this code). | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU General Public License version | |||
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, | |||
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| 18 | * | |||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include "precompiled.hpp" | |||
| 26 | #include "code/codeCache.hpp" | |||
| 27 | #include "code/compiledIC.hpp" | |||
| 28 | #include "code/nmethod.hpp" | |||
| 29 | #include "code/relocInfo.hpp" | |||
| 30 | #include "memory/resourceArea.hpp" | |||
| 31 | #include "memory/universe.hpp" | |||
| 32 | #include "oops/compressedOops.inline.hpp" | |||
| 33 | #include "oops/oop.inline.hpp" | |||
| 34 | #include "runtime/flags/flagSetting.hpp" | |||
| 35 | #include "runtime/stubCodeGenerator.hpp" | |||
| 36 | #include "utilities/align.hpp" | |||
| 37 | #include "utilities/copy.hpp" | |||
| 38 | ||||
| 39 | const RelocationHolder RelocationHolder::none; // its type is relocInfo::none | |||
| 40 | ||||
| 41 | ||||
| 42 | // Implementation of relocInfo | |||
| 43 | ||||
| 44 | #ifdef ASSERT1 | |||
| 45 | relocInfo::relocType relocInfo::check_relocType(relocType type) { | |||
| 46 | assert(type != data_prefix_tag, "cannot build a prefix this way")do { if (!(type != data_prefix_tag)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 46, "assert(" "type != data_prefix_tag" ") failed", "cannot build a prefix this way" ); ::breakpoint(); } } while (0); | |||
| 47 | assert((type & type_mask) == type, "wrong type")do { if (!((type & type_mask) == type)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 47, "assert(" "(type & type_mask) == type" ") failed", "wrong type" ); ::breakpoint(); } } while (0); | |||
| 48 | return type; | |||
| 49 | } | |||
| 50 | ||||
| 51 | void relocInfo::check_offset_and_format(int offset, int format) { | |||
| 52 | assert(offset >= 0 && offset < offset_limit(), "offset out off bounds")do { if (!(offset >= 0 && offset < offset_limit ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 52, "assert(" "offset >= 0 && offset < offset_limit()" ") failed", "offset out off bounds"); ::breakpoint(); } } while (0); | |||
| 53 | assert(is_aligned(offset, offset_unit), "misaligned offset")do { if (!(is_aligned(offset, offset_unit))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 53, "assert(" "is_aligned(offset, offset_unit)" ") failed", "misaligned offset"); ::breakpoint(); } } while (0); | |||
| 54 | assert((format & format_mask) == format, "wrong format")do { if (!((format & format_mask) == format)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 54, "assert(" "(format & format_mask) == format" ") failed" , "wrong format"); ::breakpoint(); } } while (0); | |||
| 55 | } | |||
| 56 | #endif // ASSERT | |||
| 57 | ||||
| 58 | void relocInfo::initialize(CodeSection* dest, Relocation* reloc) { | |||
| 59 | relocInfo* data = this+1; // here's where the data might go | |||
| 60 | dest->set_locs_end(data); // sync end: the next call may read dest.locs_end | |||
| 61 | reloc->pack_data_to(dest); // maybe write data into locs, advancing locs_end | |||
| 62 | relocInfo* data_limit = dest->locs_end(); | |||
| 63 | if (data_limit > data) { | |||
| 64 | relocInfo suffix = (*this); | |||
| 65 | data_limit = this->finish_prefix((short*) data_limit); | |||
| 66 | // Finish up with the suffix. (Hack note: pack_data_to might edit this.) | |||
| 67 | *data_limit = suffix; | |||
| 68 | dest->set_locs_end(data_limit+1); | |||
| 69 | } | |||
| 70 | } | |||
| 71 | ||||
| 72 | relocInfo* relocInfo::finish_prefix(short* prefix_limit) { | |||
| 73 | assert(sizeof(relocInfo) == sizeof(short), "change this code")do { if (!(sizeof(relocInfo) == sizeof(short))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 73, "assert(" "sizeof(relocInfo) == sizeof(short)" ") failed" , "change this code"); ::breakpoint(); } } while (0); | |||
| 74 | short* p = (short*)(this+1); | |||
| 75 | assert(prefix_limit >= p, "must be a valid span of data")do { if (!(prefix_limit >= p)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 75, "assert(" "prefix_limit >= p" ") failed", "must be a valid span of data" ); ::breakpoint(); } } while (0); | |||
| 76 | int plen = prefix_limit - p; | |||
| 77 | if (plen == 0) { | |||
| 78 | debug_only(_value = 0xFFFF)_value = 0xFFFF; | |||
| 79 | return this; // no data: remove self completely | |||
| 80 | } | |||
| 81 | if (plen == 1 && fits_into_immediate(p[0])) { | |||
| 82 | (*this) = immediate_relocInfo(p[0]); // move data inside self | |||
| 83 | return this+1; | |||
| 84 | } | |||
| 85 | // cannot compact, so just update the count and return the limit pointer | |||
| 86 | (*this) = prefix_relocInfo(plen); // write new datalen | |||
| 87 | assert(data() + datalen() == prefix_limit, "pointers must line up")do { if (!(data() + datalen() == prefix_limit)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 87, "assert(" "data() + datalen() == prefix_limit" ") failed" , "pointers must line up"); ::breakpoint(); } } while (0); | |||
| 88 | return (relocInfo*)prefix_limit; | |||
| 89 | } | |||
| 90 | ||||
| 91 | void relocInfo::set_type(relocType t) { | |||
| 92 | int old_offset = addr_offset(); | |||
| 93 | int old_format = format(); | |||
| 94 | (*this) = relocInfo(t, old_offset, old_format); | |||
| 95 | assert(type()==(int)t, "sanity check")do { if (!(type()==(int)t)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 95, "assert(" "type()==(int)t" ") failed", "sanity check"); ::breakpoint(); } } while (0); | |||
| 96 | assert(addr_offset()==old_offset, "sanity check")do { if (!(addr_offset()==old_offset)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 96, "assert(" "addr_offset()==old_offset" ") failed", "sanity check" ); ::breakpoint(); } } while (0); | |||
| 97 | assert(format()==old_format, "sanity check")do { if (!(format()==old_format)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 97, "assert(" "format()==old_format" ") failed", "sanity check" ); ::breakpoint(); } } while (0); | |||
| 98 | } | |||
| 99 | ||||
| 100 | void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type, relocType new_type) { | |||
| 101 | bool found = false; | |||
| 102 | while (itr->next() && !found) { | |||
| 103 | if (itr->addr() == pc) { | |||
| 104 | assert(itr->type()==old_type, "wrong relocInfo type found")do { if (!(itr->type()==old_type)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 104, "assert(" "itr->type()==old_type" ") failed", "wrong relocInfo type found" ); ::breakpoint(); } } while (0); | |||
| 105 | itr->current()->set_type(new_type); | |||
| 106 | found=true; | |||
| 107 | } | |||
| 108 | } | |||
| 109 | assert(found, "no relocInfo found for pc")do { if (!(found)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 109, "assert(" "found" ") failed", "no relocInfo found for pc" ); ::breakpoint(); } } while (0); | |||
| 110 | } | |||
| 111 | ||||
| 112 | ||||
| 113 | // ---------------------------------------------------------------------------------------------------- | |||
| 114 | // Implementation of RelocIterator | |||
| 115 | ||||
| 116 | void RelocIterator::initialize(CompiledMethod* nm, address begin, address limit) { | |||
| 117 | initialize_misc(); | |||
| 118 | ||||
| 119 | if (nm == NULL__null && begin != NULL__null) { | |||
| 120 | // allow nmethod to be deduced from beginning address | |||
| 121 | CodeBlob* cb = CodeCache::find_blob(begin); | |||
| 122 | nm = (cb != NULL__null) ? cb->as_compiled_method_or_null() : NULL__null; | |||
| 123 | } | |||
| 124 | guarantee(nm != NULL, "must be able to deduce nmethod from other arguments")do { if (!(nm != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 124, "guarantee(" "nm != NULL" ") failed", "must be able to deduce nmethod from other arguments" ); ::breakpoint(); } } while (0); | |||
| 125 | ||||
| 126 | _code = nm; | |||
| 127 | _current = nm->relocation_begin() - 1; | |||
| 128 | _end = nm->relocation_end(); | |||
| 129 | _addr = nm->content_begin(); | |||
| 130 | ||||
| 131 | // Initialize code sections. | |||
| 132 | _section_start[CodeBuffer::SECT_CONSTS] = nm->consts_begin(); | |||
| 133 | _section_start[CodeBuffer::SECT_INSTS ] = nm->insts_begin() ; | |||
| 134 | _section_start[CodeBuffer::SECT_STUBS ] = nm->stub_begin() ; | |||
| 135 | ||||
| 136 | _section_end [CodeBuffer::SECT_CONSTS] = nm->consts_end() ; | |||
| 137 | _section_end [CodeBuffer::SECT_INSTS ] = nm->insts_end() ; | |||
| 138 | _section_end [CodeBuffer::SECT_STUBS ] = nm->stub_end() ; | |||
| 139 | ||||
| 140 | assert(!has_current(), "just checking")do { if (!(!has_current())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 140, "assert(" "!has_current()" ") failed", "just checking" ); ::breakpoint(); } } while (0); | |||
| 141 | assert(begin == NULL || begin >= nm->code_begin(), "in bounds")do { if (!(begin == __null || begin >= nm->code_begin() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 141, "assert(" "begin == __null || begin >= nm->code_begin()" ") failed", "in bounds"); ::breakpoint(); } } while (0); | |||
| 142 | assert(limit == NULL || limit <= nm->code_end(), "in bounds")do { if (!(limit == __null || limit <= nm->code_end())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 142, "assert(" "limit == __null || limit <= nm->code_end()" ") failed", "in bounds"); ::breakpoint(); } } while (0); | |||
| 143 | set_limits(begin, limit); | |||
| 144 | } | |||
| 145 | ||||
| 146 | ||||
| 147 | RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { | |||
| 148 | initialize_misc(); | |||
| 149 | ||||
| 150 | _current = cs->locs_start()-1; | |||
| 151 | _end = cs->locs_end(); | |||
| 152 | _addr = cs->start(); | |||
| 153 | _code = NULL__null; // Not cb->blob(); | |||
| 154 | ||||
| 155 | CodeBuffer* cb = cs->outer(); | |||
| 156 | assert((int) SECT_LIMIT == CodeBuffer::SECT_LIMIT, "my copy must be equal")do { if (!((int) SECT_LIMIT == CodeBuffer::SECT_LIMIT)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 156, "assert(" "(int) SECT_LIMIT == CodeBuffer::SECT_LIMIT" ") failed", "my copy must be equal"); ::breakpoint(); } } while (0); | |||
| 157 | for (int n = (int) CodeBuffer::SECT_FIRST; n < (int) CodeBuffer::SECT_LIMIT; n++) { | |||
| 158 | CodeSection* cs = cb->code_section(n); | |||
| 159 | _section_start[n] = cs->start(); | |||
| 160 | _section_end [n] = cs->end(); | |||
| 161 | } | |||
| 162 | ||||
| 163 | assert(!has_current(), "just checking")do { if (!(!has_current())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 163, "assert(" "!has_current()" ") failed", "just checking" ); ::breakpoint(); } } while (0); | |||
| 164 | ||||
| 165 | assert(begin == NULL || begin >= cs->start(), "in bounds")do { if (!(begin == __null || begin >= cs->start())) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 165, "assert(" "begin == __null || begin >= cs->start()" ") failed", "in bounds"); ::breakpoint(); } } while (0); | |||
| 166 | assert(limit == NULL || limit <= cs->end(), "in bounds")do { if (!(limit == __null || limit <= cs->end())) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 166, "assert(" "limit == __null || limit <= cs->end()" ") failed", "in bounds"); ::breakpoint(); } } while (0); | |||
| 167 | set_limits(begin, limit); | |||
| 168 | } | |||
| 169 | ||||
| 170 | bool RelocIterator::addr_in_const() const { | |||
| 171 | const int n = CodeBuffer::SECT_CONSTS; | |||
| 172 | return section_start(n) <= addr() && addr() < section_end(n); | |||
| 173 | } | |||
| 174 | ||||
| 175 | ||||
| 176 | void RelocIterator::set_limits(address begin, address limit) { | |||
| 177 | _limit = limit; | |||
| 178 | ||||
| 179 | // the limit affects this next stuff: | |||
| 180 | if (begin != NULL__null) { | |||
| 181 | relocInfo* backup; | |||
| 182 | address backup_addr; | |||
| 183 | while (true) { | |||
| 184 | backup = _current; | |||
| 185 | backup_addr = _addr; | |||
| 186 | if (!next() || addr() >= begin) break; | |||
| 187 | } | |||
| 188 | // At this point, either we are at the first matching record, | |||
| 189 | // or else there is no such record, and !has_current(). | |||
| 190 | // In either case, revert to the immediatly preceding state. | |||
| 191 | _current = backup; | |||
| 192 | _addr = backup_addr; | |||
| 193 | set_has_current(false); | |||
| 194 | } | |||
| 195 | } | |||
| 196 | ||||
| 197 | ||||
| 198 | // All the strange bit-encodings are in here. | |||
| 199 | // The idea is to encode relocation data which are small integers | |||
| 200 | // very efficiently (a single extra halfword). Larger chunks of | |||
| 201 | // relocation data need a halfword header to hold their size. | |||
| 202 | void RelocIterator::advance_over_prefix() { | |||
| 203 | if (_current->is_datalen()) { | |||
| 204 | _data = (short*) _current->data(); | |||
| 205 | _datalen = _current->datalen(); | |||
| 206 | _current += _datalen + 1; // skip the embedded data & header | |||
| 207 | } else { | |||
| 208 | _databuf = _current->immediate(); | |||
| 209 | _data = &_databuf; | |||
| 210 | _datalen = 1; | |||
| 211 | _current++; // skip the header | |||
| 212 | } | |||
| 213 | // The client will see the following relocInfo, whatever that is. | |||
| 214 | // It is the reloc to which the preceding data applies. | |||
| 215 | } | |||
| 216 | ||||
| 217 | ||||
| 218 | void RelocIterator::initialize_misc() { | |||
| 219 | set_has_current(false); | |||
| 220 | for (int i = (int) CodeBuffer::SECT_FIRST; i < (int) CodeBuffer::SECT_LIMIT; i++) { | |||
| 221 | _section_start[i] = NULL__null; // these will be lazily computed, if needed | |||
| 222 | _section_end [i] = NULL__null; | |||
| 223 | } | |||
| 224 | } | |||
| 225 | ||||
| 226 | ||||
| 227 | Relocation* RelocIterator::reloc() { | |||
| 228 | // (take the "switch" out-of-line) | |||
| 229 | relocInfo::relocType t = type(); | |||
| 230 | if (false) {} | |||
| 231 | #define EACH_TYPE(name) \ | |||
| 232 | else if (t == relocInfo::name##_type) { \ | |||
| 233 | return name##_reloc(); \ | |||
| 234 | } | |||
| 235 | APPLY_TO_RELOCATIONS(EACH_TYPE)EACH_TYPE(oop) EACH_TYPE(metadata) EACH_TYPE(virtual_call) EACH_TYPE (opt_virtual_call) EACH_TYPE(static_call) EACH_TYPE(static_stub ) EACH_TYPE(runtime_call) EACH_TYPE(runtime_call_w_cp) EACH_TYPE (external_word) EACH_TYPE(internal_word) EACH_TYPE(poll) EACH_TYPE (poll_return) EACH_TYPE(section_word) EACH_TYPE(trampoline_stub ); | |||
| 236 | #undef EACH_TYPE | |||
| 237 | assert(t == relocInfo::none, "must be padding")do { if (!(t == relocInfo::none)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 237, "assert(" "t == relocInfo::none" ") failed", "must be padding" ); ::breakpoint(); } } while (0); | |||
| 238 | return new(_rh) Relocation(t); | |||
| 239 | } | |||
| 240 | ||||
| 241 | ||||
| 242 | //////// Methods for flyweight Relocation types | |||
| 243 | ||||
| 244 | ||||
| 245 | RelocationHolder RelocationHolder::plus(int offset) const { | |||
| 246 | if (offset != 0) { | |||
| 247 | switch (type()) { | |||
| 248 | case relocInfo::none: | |||
| 249 | break; | |||
| 250 | case relocInfo::oop_type: | |||
| 251 | { | |||
| 252 | oop_Relocation* r = (oop_Relocation*)reloc(); | |||
| 253 | return oop_Relocation::spec(r->oop_index(), r->offset() + offset); | |||
| 254 | } | |||
| 255 | case relocInfo::metadata_type: | |||
| 256 | { | |||
| 257 | metadata_Relocation* r = (metadata_Relocation*)reloc(); | |||
| 258 | return metadata_Relocation::spec(r->metadata_index(), r->offset() + offset); | |||
| 259 | } | |||
| 260 | default: | |||
| 261 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 261); ::breakpoint(); } while (0); | |||
| 262 | } | |||
| 263 | } | |||
| 264 | return (*this); | |||
| 265 | } | |||
| 266 | ||||
| 267 | // some relocations can compute their own values | |||
| 268 | address Relocation::value() { | |||
| 269 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 269); ::breakpoint(); } while (0); | |||
| 270 | return NULL__null; | |||
| 271 | } | |||
| 272 | ||||
| 273 | ||||
| 274 | void Relocation::set_value(address x) { | |||
| 275 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 275); ::breakpoint(); } while (0); | |||
| 276 | } | |||
| 277 | ||||
| 278 | void Relocation::const_set_data_value(address x) { | |||
| 279 | #ifdef _LP641 | |||
| 280 | if (format() == relocInfo::narrow_oop_in_const) { | |||
| 281 | *(narrowOop*)addr() = CompressedOops::encode(cast_to_oop(x)); | |||
| 282 | } else { | |||
| 283 | #endif | |||
| 284 | *(address*)addr() = x; | |||
| 285 | #ifdef _LP641 | |||
| 286 | } | |||
| 287 | #endif | |||
| 288 | } | |||
| 289 | ||||
| 290 | void Relocation::const_verify_data_value(address x) { | |||
| 291 | #ifdef _LP641 | |||
| 292 | if (format() == relocInfo::narrow_oop_in_const) { | |||
| 293 | guarantee(*(narrowOop*)addr() == CompressedOops::encode(cast_to_oop(x)), "must agree")do { if (!(*(narrowOop*)addr() == CompressedOops::encode(cast_to_oop (x)))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 293, "guarantee(" "*(narrowOop*)addr() == CompressedOops::encode(cast_to_oop(x))" ") failed", "must agree"); ::breakpoint(); } } while (0); | |||
| 294 | } else { | |||
| 295 | #endif | |||
| 296 | guarantee(*(address*)addr() == x, "must agree")do { if (!(*(address*)addr() == x)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 296, "guarantee(" "*(address*)addr() == x" ") failed", "must agree" ); ::breakpoint(); } } while (0); | |||
| 297 | #ifdef _LP641 | |||
| 298 | } | |||
| 299 | #endif | |||
| 300 | } | |||
| 301 | ||||
| 302 | ||||
| 303 | RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { | |||
| 304 | if (rtype == relocInfo::none) return RelocationHolder::none; | |||
| 305 | relocInfo ri = relocInfo(rtype, 0); | |||
| 306 | RelocIterator itr; | |||
| 307 | itr.set_current(ri); | |||
| 308 | itr.reloc(); | |||
| 309 | return itr._rh; | |||
| 310 | } | |||
| 311 | ||||
| 312 | address Relocation::old_addr_for(address newa, | |||
| 313 | const CodeBuffer* src, CodeBuffer* dest) { | |||
| 314 | int sect = dest->section_index_of(newa); | |||
| 315 | guarantee(sect != CodeBuffer::SECT_NONE, "lost track of this address")do { if (!(sect != CodeBuffer::SECT_NONE)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 315, "guarantee(" "sect != CodeBuffer::SECT_NONE" ") failed" , "lost track of this address"); ::breakpoint(); } } while (0 ); | |||
| 316 | address ostart = src->code_section(sect)->start(); | |||
| 317 | address nstart = dest->code_section(sect)->start(); | |||
| 318 | return ostart + (newa - nstart); | |||
| 319 | } | |||
| 320 | ||||
| 321 | address Relocation::new_addr_for(address olda, | |||
| 322 | const CodeBuffer* src, CodeBuffer* dest) { | |||
| 323 | debug_only(const CodeBuffer* src0 = src)const CodeBuffer* src0 = src; | |||
| 324 | int sect = CodeBuffer::SECT_NONE; | |||
| 325 | // Look for olda in the source buffer, and all previous incarnations | |||
| 326 | // if the source buffer has been expanded. | |||
| 327 | for (; src != NULL__null; src = src->before_expand()) { | |||
| 328 | sect = src->section_index_of(olda); | |||
| 329 | if (sect != CodeBuffer::SECT_NONE) break; | |||
| 330 | } | |||
| 331 | guarantee(sect != CodeBuffer::SECT_NONE, "lost track of this address")do { if (!(sect != CodeBuffer::SECT_NONE)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 331, "guarantee(" "sect != CodeBuffer::SECT_NONE" ") failed" , "lost track of this address"); ::breakpoint(); } } while (0 ); | |||
| 332 | address ostart = src->code_section(sect)->start(); | |||
| 333 | address nstart = dest->code_section(sect)->start(); | |||
| 334 | return nstart + (olda - ostart); | |||
| 335 | } | |||
| 336 | ||||
| 337 | void Relocation::normalize_address(address& addr, const CodeSection* dest, bool allow_other_sections) { | |||
| 338 | address addr0 = addr; | |||
| 339 | if (addr0 == NULL__null || dest->allocates2(addr0)) return; | |||
| 340 | CodeBuffer* cb = dest->outer(); | |||
| 341 | addr = new_addr_for(addr0, cb, cb); | |||
| 342 | assert(allow_other_sections || dest->contains2(addr),do { if (!(allow_other_sections || dest->contains2(addr))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 343, "assert(" "allow_other_sections || dest->contains2(addr)" ") failed", "addr must be in required section"); ::breakpoint (); } } while (0) | |||
| 343 | "addr must be in required section")do { if (!(allow_other_sections || dest->contains2(addr))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 343, "assert(" "allow_other_sections || dest->contains2(addr)" ") failed", "addr must be in required section"); ::breakpoint (); } } while (0); | |||
| 344 | } | |||
| 345 | ||||
| 346 | ||||
| 347 | void CallRelocation::set_destination(address x) { | |||
| 348 | pd_set_call_destination(x); | |||
| 349 | } | |||
| 350 | ||||
| 351 | void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { | |||
| 352 | // Usually a self-relative reference to an external routine. | |||
| 353 | // On some platforms, the reference is absolute (not self-relative). | |||
| 354 | // The enhanced use of pd_call_destination sorts this all out. | |||
| 355 | address orig_addr = old_addr_for(addr(), src, dest); | |||
| 356 | address callee = pd_call_destination(orig_addr); | |||
| 357 | // Reassert the callee address, this time in the new copy of the code. | |||
| 358 | pd_set_call_destination(callee); | |||
| 359 | } | |||
| 360 | ||||
| 361 | ||||
| 362 | //// pack/unpack methods | |||
| 363 | ||||
| 364 | void oop_Relocation::pack_data_to(CodeSection* dest) { | |||
| 365 | short* p = (short*) dest->locs_end(); | |||
| 366 | p = pack_2_ints_to(p, _oop_index, _offset); | |||
| 367 | dest->set_locs_end((relocInfo*) p); | |||
| 368 | } | |||
| 369 | ||||
| 370 | ||||
| 371 | void oop_Relocation::unpack_data() { | |||
| 372 | unpack_2_ints(_oop_index, _offset); | |||
| 373 | } | |||
| 374 | ||||
| 375 | void metadata_Relocation::pack_data_to(CodeSection* dest) { | |||
| 376 | short* p = (short*) dest->locs_end(); | |||
| 377 | p = pack_2_ints_to(p, _metadata_index, _offset); | |||
| 378 | dest->set_locs_end((relocInfo*) p); | |||
| 379 | } | |||
| 380 | ||||
| 381 | ||||
| 382 | void metadata_Relocation::unpack_data() { | |||
| 383 | unpack_2_ints(_metadata_index, _offset); | |||
| 384 | } | |||
| 385 | ||||
| 386 | ||||
| 387 | void virtual_call_Relocation::pack_data_to(CodeSection* dest) { | |||
| 388 | short* p = (short*) dest->locs_end(); | |||
| 389 | address point = dest->locs_point(); | |||
| 390 | ||||
| 391 | normalize_address(_cached_value, dest); | |||
| 392 | jint x0 = scaled_offset_null_special(_cached_value, point); | |||
| 393 | p = pack_2_ints_to(p, x0, _method_index); | |||
| 394 | dest->set_locs_end((relocInfo*) p); | |||
| 395 | } | |||
| 396 | ||||
| 397 | ||||
| 398 | void virtual_call_Relocation::unpack_data() { | |||
| 399 | jint x0 = 0; | |||
| 400 | unpack_2_ints(x0, _method_index); | |||
| 401 | address point = addr(); | |||
| 402 | _cached_value = x0==0? NULL__null: address_from_scaled_offset(x0, point); | |||
| 403 | } | |||
| 404 | ||||
| 405 | void runtime_call_w_cp_Relocation::pack_data_to(CodeSection * dest) { | |||
| 406 | short* p = pack_1_int_to((short *)dest->locs_end(), (jint)(_offset >> 2)); | |||
| 407 | dest->set_locs_end((relocInfo*) p); | |||
| 408 | } | |||
| 409 | ||||
| 410 | void runtime_call_w_cp_Relocation::unpack_data() { | |||
| 411 | _offset = unpack_1_int() << 2; | |||
| 412 | } | |||
| 413 | ||||
| 414 | void static_stub_Relocation::pack_data_to(CodeSection* dest) { | |||
| 415 | short* p = (short*) dest->locs_end(); | |||
| 416 | CodeSection* insts = dest->outer()->insts(); | |||
| 417 | normalize_address(_static_call, insts); | |||
| 418 | p = pack_1_int_to(p, scaled_offset(_static_call, insts->start())); | |||
| 419 | dest->set_locs_end((relocInfo*) p); | |||
| 420 | } | |||
| 421 | ||||
| 422 | void static_stub_Relocation::unpack_data() { | |||
| 423 | address base = binding()->section_start(CodeBuffer::SECT_INSTS); | |||
| 424 | jint offset = unpack_1_int(); | |||
| 425 | _static_call = address_from_scaled_offset(offset, base); | |||
| 426 | } | |||
| 427 | ||||
| 428 | void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) { | |||
| 429 | short* p = (short*) dest->locs_end(); | |||
| 430 | CodeSection* insts = dest->outer()->insts(); | |||
| 431 | normalize_address(_owner, insts); | |||
| 432 | p = pack_1_int_to(p, scaled_offset(_owner, insts->start())); | |||
| 433 | dest->set_locs_end((relocInfo*) p); | |||
| 434 | } | |||
| 435 | ||||
| 436 | void trampoline_stub_Relocation::unpack_data() { | |||
| 437 | address base = binding()->section_start(CodeBuffer::SECT_INSTS); | |||
| 438 | _owner = address_from_scaled_offset(unpack_1_int(), base); | |||
| 439 | } | |||
| 440 | ||||
| 441 | void external_word_Relocation::pack_data_to(CodeSection* dest) { | |||
| 442 | short* p = (short*) dest->locs_end(); | |||
| 443 | #ifndef _LP641 | |||
| 444 | p = pack_1_int_to(p, (int32_t) (intptr_t)_target); | |||
| 445 | #else | |||
| 446 | jlong t = (jlong) _target; | |||
| 447 | int32_t lo = low(t); | |||
| 448 | int32_t hi = high(t); | |||
| 449 | p = pack_2_ints_to(p, lo, hi); | |||
| 450 | #endif /* _LP64 */ | |||
| 451 | dest->set_locs_end((relocInfo*) p); | |||
| 452 | } | |||
| 453 | ||||
| 454 | ||||
| 455 | void external_word_Relocation::unpack_data() { | |||
| 456 | #ifndef _LP641 | |||
| 457 | _target = (address) (intptr_t)unpack_1_int(); | |||
| 458 | #else | |||
| 459 | jint lo, hi; | |||
| 460 | unpack_2_ints(lo, hi); | |||
| 461 | jlong t = jlong_from(hi, lo);; | |||
| 462 | _target = (address) t; | |||
| 463 | #endif /* _LP64 */ | |||
| 464 | } | |||
| 465 | ||||
| 466 | ||||
| 467 | void internal_word_Relocation::pack_data_to(CodeSection* dest) { | |||
| 468 | short* p = (short*) dest->locs_end(); | |||
| 469 | normalize_address(_target, dest, true); | |||
| 470 | ||||
| 471 | // Check whether my target address is valid within this section. | |||
| 472 | // If not, strengthen the relocation type to point to another section. | |||
| 473 | int sindex = _section; | |||
| 474 | if (sindex == CodeBuffer::SECT_NONE && _target != NULL__null | |||
| 475 | && (!dest->allocates(_target) || _target == dest->locs_point())) { | |||
| 476 | sindex = dest->outer()->section_index_of(_target); | |||
| 477 | guarantee(sindex != CodeBuffer::SECT_NONE, "must belong somewhere")do { if (!(sindex != CodeBuffer::SECT_NONE)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 477, "guarantee(" "sindex != CodeBuffer::SECT_NONE" ") failed" , "must belong somewhere"); ::breakpoint(); } } while (0); | |||
| 478 | relocInfo* base = dest->locs_end() - 1; | |||
| 479 | assert(base->type() == this->type(), "sanity")do { if (!(base->type() == this->type())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 479, "assert(" "base->type() == this->type()" ") failed" , "sanity"); ::breakpoint(); } } while (0); | |||
| 480 | // Change the written type, to be section_word_type instead. | |||
| 481 | base->set_type(relocInfo::section_word_type); | |||
| 482 | } | |||
| 483 | ||||
| 484 | // Note: An internal_word relocation cannot refer to its own instruction, | |||
| 485 | // because we reserve "0" to mean that the pointer itself is embedded | |||
| 486 | // in the code stream. We use a section_word relocation for such cases. | |||
| 487 | ||||
| 488 | if (sindex == CodeBuffer::SECT_NONE) { | |||
| 489 | assert(type() == relocInfo::internal_word_type, "must be base class")do { if (!(type() == relocInfo::internal_word_type)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 489, "assert(" "type() == relocInfo::internal_word_type" ") failed" , "must be base class"); ::breakpoint(); } } while (0); | |||
| 490 | guarantee(_target == NULL || dest->allocates2(_target), "must be within the given code section")do { if (!(_target == __null || dest->allocates2(_target)) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 490, "guarantee(" "_target == NULL || dest->allocates2(_target)" ") failed", "must be within the given code section"); ::breakpoint (); } } while (0); | |||
| 491 | jint x0 = scaled_offset_null_special(_target, dest->locs_point()); | |||
| 492 | assert(!(x0 == 0 && _target != NULL), "correct encoding of null target")do { if (!(!(x0 == 0 && _target != __null))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 492, "assert(" "!(x0 == 0 && _target != __null)" ") failed" , "correct encoding of null target"); ::breakpoint(); } } while (0); | |||
| 493 | p = pack_1_int_to(p, x0); | |||
| 494 | } else { | |||
| 495 | assert(_target != NULL, "sanity")do { if (!(_target != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 495, "assert(" "_target != __null" ") failed", "sanity"); :: breakpoint(); } } while (0); | |||
| 496 | CodeSection* sect = dest->outer()->code_section(sindex); | |||
| 497 | guarantee(sect->allocates2(_target), "must be in correct section")do { if (!(sect->allocates2(_target))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 497, "guarantee(" "sect->allocates2(_target)" ") failed" , "must be in correct section"); ::breakpoint(); } } while (0 ); | |||
| 498 | address base = sect->start(); | |||
| 499 | jint offset = scaled_offset(_target, base); | |||
| 500 | assert((uint)sindex < (uint)CodeBuffer::SECT_LIMIT, "sanity")do { if (!((uint)sindex < (uint)CodeBuffer::SECT_LIMIT)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 500, "assert(" "(uint)sindex < (uint)CodeBuffer::SECT_LIMIT" ") failed", "sanity"); ::breakpoint(); } } while (0); | |||
| 501 | assert(CodeBuffer::SECT_LIMIT <= (1 << section_width), "section_width++")do { if (!(CodeBuffer::SECT_LIMIT <= (1 << section_width ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 501, "assert(" "CodeBuffer::SECT_LIMIT <= (1 << section_width)" ") failed", "section_width++"); ::breakpoint(); } } while (0 ); | |||
| 502 | p = pack_1_int_to(p, (offset << section_width) | sindex); | |||
| 503 | } | |||
| 504 | ||||
| 505 | dest->set_locs_end((relocInfo*) p); | |||
| 506 | } | |||
| 507 | ||||
| 508 | ||||
| 509 | void internal_word_Relocation::unpack_data() { | |||
| 510 | jint x0 = unpack_1_int(); | |||
| 511 | _target = x0==0? NULL__null: address_from_scaled_offset(x0, addr()); | |||
| 512 | _section = CodeBuffer::SECT_NONE; | |||
| 513 | } | |||
| 514 | ||||
| 515 | ||||
| 516 | void section_word_Relocation::unpack_data() { | |||
| 517 | jint x = unpack_1_int(); | |||
| 518 | jint offset = (x >> section_width); | |||
| 519 | int sindex = (x & ((1<<section_width)-1)); | |||
| 520 | address base = binding()->section_start(sindex); | |||
| 521 | ||||
| 522 | _section = sindex; | |||
| 523 | _target = address_from_scaled_offset(offset, base); | |||
| 524 | } | |||
| 525 | ||||
| 526 | //// miscellaneous methods | |||
| 527 | oop* oop_Relocation::oop_addr() { | |||
| 528 | int n = _oop_index; | |||
| 529 | if (n == 0) { | |||
| 530 | // oop is stored in the code stream | |||
| 531 | return (oop*) pd_address_in_code(); | |||
| 532 | } else { | |||
| 533 | // oop is stored in table at nmethod::oops_begin | |||
| 534 | return code()->oop_addr_at(n); | |||
| 535 | } | |||
| 536 | } | |||
| 537 | ||||
| 538 | ||||
| 539 | oop oop_Relocation::oop_value() { | |||
| 540 | // clean inline caches store a special pseudo-null | |||
| 541 | if (Universe::contains_non_oop_word(oop_addr())) { | |||
| 542 | return NULL__null; | |||
| 543 | } | |||
| 544 | return *oop_addr(); | |||
| 545 | } | |||
| 546 | ||||
| 547 | ||||
| 548 | void oop_Relocation::fix_oop_relocation() { | |||
| 549 | if (!oop_is_immediate()) { | |||
| 550 | // get the oop from the pool, and re-insert it into the instruction: | |||
| 551 | set_value(value()); | |||
| 552 | } | |||
| 553 | } | |||
| 554 | ||||
| 555 | ||||
| 556 | void oop_Relocation::verify_oop_relocation() { | |||
| 557 | if (!oop_is_immediate()) { | |||
| 558 | // get the oop from the pool, and re-insert it into the instruction: | |||
| 559 | verify_value(value()); | |||
| 560 | } | |||
| 561 | } | |||
| 562 | ||||
| 563 | // meta data versions | |||
| 564 | Metadata** metadata_Relocation::metadata_addr() { | |||
| 565 | int n = _metadata_index; | |||
| 566 | if (n == 0) { | |||
| 567 | // metadata is stored in the code stream | |||
| 568 | return (Metadata**) pd_address_in_code(); | |||
| 569 | } else { | |||
| 570 | // metadata is stored in table at nmethod::metadatas_begin | |||
| 571 | return code()->metadata_addr_at(n); | |||
| 572 | } | |||
| 573 | } | |||
| 574 | ||||
| 575 | ||||
| 576 | Metadata* metadata_Relocation::metadata_value() { | |||
| 577 | Metadata* v = *metadata_addr(); | |||
| 578 | // clean inline caches store a special pseudo-null | |||
| 579 | if (v == (Metadata*)Universe::non_oop_word()) v = NULL__null; | |||
| 580 | return v; | |||
| 581 | } | |||
| 582 | ||||
| 583 | ||||
| 584 | void metadata_Relocation::fix_metadata_relocation() { | |||
| 585 | if (!metadata_is_immediate()) { | |||
| 586 | // get the metadata from the pool, and re-insert it into the instruction: | |||
| 587 | pd_fix_value(value()); | |||
| 588 | } | |||
| 589 | } | |||
| 590 | ||||
| 591 | address virtual_call_Relocation::cached_value() { | |||
| 592 | assert(_cached_value != NULL && _cached_value < addr(), "must precede ic_call")do { if (!(_cached_value != __null && _cached_value < addr())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 592, "assert(" "_cached_value != __null && _cached_value < addr()" ") failed", "must precede ic_call"); ::breakpoint(); } } while (0); | |||
| 593 | return _cached_value; | |||
| 594 | } | |||
| 595 | ||||
| 596 | Method* virtual_call_Relocation::method_value() { | |||
| 597 | CompiledMethod* cm = code(); | |||
| 598 | if (cm == NULL__null) return (Method*)NULL__null; | |||
| 599 | Metadata* m = cm->metadata_at(_method_index); | |||
| 600 | assert(m != NULL || _method_index == 0, "should be non-null for non-zero index")do { if (!(m != __null || _method_index == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 600, "assert(" "m != __null || _method_index == 0" ") failed" , "should be non-null for non-zero index"); ::breakpoint(); } } while (0); | |||
| 601 | assert(m == NULL || m->is_method(), "not a method")do { if (!(m == __null || m->is_method())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 601, "assert(" "m == __null || m->is_method()" ") failed" , "not a method"); ::breakpoint(); } } while (0); | |||
| 602 | return (Method*)m; | |||
| 603 | } | |||
| 604 | ||||
| 605 | bool virtual_call_Relocation::clear_inline_cache() { | |||
| 606 | // No stubs for ICs | |||
| 607 | // Clean IC | |||
| 608 | ResourceMark rm; | |||
| 609 | CompiledIC* icache = CompiledIC_at(this); | |||
| 610 | return icache->set_to_clean(); | |||
| 611 | } | |||
| 612 | ||||
| 613 | ||||
| 614 | void opt_virtual_call_Relocation::pack_data_to(CodeSection* dest) { | |||
| 615 | short* p = (short*) dest->locs_end(); | |||
| 616 | p = pack_1_int_to(p, _method_index); | |||
| 617 | dest->set_locs_end((relocInfo*) p); | |||
| 618 | } | |||
| 619 | ||||
| 620 | void opt_virtual_call_Relocation::unpack_data() { | |||
| 621 | _method_index = unpack_1_int(); | |||
| 622 | } | |||
| 623 | ||||
| 624 | Method* opt_virtual_call_Relocation::method_value() { | |||
| 625 | CompiledMethod* cm = code(); | |||
| 626 | if (cm == NULL__null) return (Method*)NULL__null; | |||
| 627 | Metadata* m = cm->metadata_at(_method_index); | |||
| 628 | assert(m != NULL || _method_index == 0, "should be non-null for non-zero index")do { if (!(m != __null || _method_index == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 628, "assert(" "m != __null || _method_index == 0" ") failed" , "should be non-null for non-zero index"); ::breakpoint(); } } while (0); | |||
| 629 | assert(m == NULL || m->is_method(), "not a method")do { if (!(m == __null || m->is_method())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 629, "assert(" "m == __null || m->is_method()" ") failed" , "not a method"); ::breakpoint(); } } while (0); | |||
| 630 | return (Method*)m; | |||
| 631 | } | |||
| 632 | ||||
| 633 | template<typename CompiledICorStaticCall> | |||
| 634 | static bool set_to_clean_no_ic_refill(CompiledICorStaticCall* ic) { | |||
| 635 | guarantee(ic->set_to_clean(), "Should not need transition stubs")do { if (!(ic->set_to_clean())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 635, "guarantee(" "ic->set_to_clean()" ") failed", "Should not need transition stubs" ); ::breakpoint(); } } while (0); | |||
| 636 | return true; | |||
| 637 | } | |||
| 638 | ||||
| 639 | bool opt_virtual_call_Relocation::clear_inline_cache() { | |||
| 640 | // No stubs for ICs | |||
| 641 | // Clean IC | |||
| 642 | ResourceMark rm; | |||
| 643 | CompiledIC* icache = CompiledIC_at(this); | |||
| 644 | return set_to_clean_no_ic_refill(icache); | |||
| 645 | } | |||
| 646 | ||||
| 647 | address opt_virtual_call_Relocation::static_stub() { | |||
| 648 | // search for the static stub who points back to this static call | |||
| 649 | address static_call_addr = addr(); | |||
| 650 | RelocIterator iter(code()); | |||
| 651 | while (iter.next()) { | |||
| 652 | if (iter.type() == relocInfo::static_stub_type) { | |||
| 653 | static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); | |||
| 654 | if (stub_reloc->static_call() == static_call_addr) { | |||
| 655 | return iter.addr(); | |||
| 656 | } | |||
| 657 | } | |||
| 658 | } | |||
| 659 | return NULL__null; | |||
| 660 | } | |||
| 661 | ||||
| 662 | Method* static_call_Relocation::method_value() { | |||
| 663 | CompiledMethod* cm = code(); | |||
| 664 | if (cm == NULL__null) return (Method*)NULL__null; | |||
| 665 | Metadata* m = cm->metadata_at(_method_index); | |||
| 666 | assert(m != NULL || _method_index == 0, "should be non-null for non-zero index")do { if (!(m != __null || _method_index == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 666, "assert(" "m != __null || _method_index == 0" ") failed" , "should be non-null for non-zero index"); ::breakpoint(); } } while (0); | |||
| 667 | assert(m == NULL || m->is_method(), "not a method")do { if (!(m == __null || m->is_method())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 667, "assert(" "m == __null || m->is_method()" ") failed" , "not a method"); ::breakpoint(); } } while (0); | |||
| 668 | return (Method*)m; | |||
| 669 | } | |||
| 670 | ||||
| 671 | void static_call_Relocation::pack_data_to(CodeSection* dest) { | |||
| 672 | short* p = (short*) dest->locs_end(); | |||
| 673 | p = pack_1_int_to(p, _method_index); | |||
| 674 | dest->set_locs_end((relocInfo*) p); | |||
| 675 | } | |||
| 676 | ||||
| 677 | void static_call_Relocation::unpack_data() { | |||
| 678 | _method_index = unpack_1_int(); | |||
| 679 | } | |||
| 680 | ||||
| 681 | bool static_call_Relocation::clear_inline_cache() { | |||
| 682 | // Safe call site info | |||
| 683 | CompiledStaticCall* handler = this->code()->compiledStaticCall_at(this); | |||
| 684 | return set_to_clean_no_ic_refill(handler); | |||
| 685 | } | |||
| 686 | ||||
| 687 | ||||
| 688 | address static_call_Relocation::static_stub() { | |||
| 689 | // search for the static stub who points back to this static call | |||
| 690 | address static_call_addr = addr(); | |||
| 691 | RelocIterator iter(code()); | |||
| 692 | while (iter.next()) { | |||
| 693 | if (iter.type() == relocInfo::static_stub_type) { | |||
| 694 | static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); | |||
| 695 | if (stub_reloc->static_call() == static_call_addr) { | |||
| 696 | return iter.addr(); | |||
| 697 | } | |||
| 698 | } | |||
| 699 | } | |||
| 700 | return NULL__null; | |||
| 701 | } | |||
| 702 | ||||
| 703 | // Finds the trampoline address for a call. If no trampoline stub is | |||
| 704 | // found NULL is returned which can be handled by the caller. | |||
| 705 | address trampoline_stub_Relocation::get_trampoline_for(address call, nmethod* code) { | |||
| 706 | // There are no relocations available when the code gets relocated | |||
| 707 | // because of CodeBuffer expansion. | |||
| 708 | if (code->relocation_size() == 0) | |||
| 709 | return NULL__null; | |||
| 710 | ||||
| 711 | RelocIterator iter(code, call); | |||
| 712 | while (iter.next()) { | |||
| 713 | if (iter.type() == relocInfo::trampoline_stub_type) { | |||
| 714 | if (iter.trampoline_stub_reloc()->owner() == call) { | |||
| 715 | return iter.addr(); | |||
| 716 | } | |||
| 717 | } | |||
| 718 | } | |||
| 719 | ||||
| 720 | return NULL__null; | |||
| 721 | } | |||
| 722 | ||||
| 723 | bool static_stub_Relocation::clear_inline_cache() { | |||
| 724 | // Call stub is only used when calling the interpreted code. | |||
| 725 | // It does not really need to be cleared, except that we want to clean out the methodoop. | |||
| 726 | CompiledDirectStaticCall::set_stub_to_clean(this); | |||
| 727 | return true; | |||
| 728 | } | |||
| 729 | ||||
| 730 | ||||
| 731 | void external_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { | |||
| 732 | if (_target != NULL__null) { | |||
| 733 | // Probably this reference is absolute, not relative, so the following is | |||
| 734 | // probably a no-op. | |||
| 735 | set_value(_target); | |||
| 736 | } | |||
| 737 | // If target is NULL, this is an absolute embedded reference to an external | |||
| 738 | // location, which means there is nothing to fix here. In either case, the | |||
| 739 | // resulting target should be an "external" address. | |||
| 740 | postcond(src->section_index_of(target()) == CodeBuffer::SECT_NONE)do { if (!(src->section_index_of(target()) == CodeBuffer:: SECT_NONE)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 740, "assert(" "src->section_index_of(target()) == CodeBuffer::SECT_NONE" ") failed", "postcond"); ::breakpoint(); } } while (0); | |||
| 741 | postcond(dest->section_index_of(target()) == CodeBuffer::SECT_NONE)do { if (!(dest->section_index_of(target()) == CodeBuffer:: SECT_NONE)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.cpp" , 741, "assert(" "dest->section_index_of(target()) == CodeBuffer::SECT_NONE" ") failed", "postcond"); ::breakpoint(); } } while (0); | |||
| 742 | } | |||
| 743 | ||||
| 744 | ||||
| 745 | address external_word_Relocation::target() { | |||
| 746 | address target = _target; | |||
| 747 | if (target == NULL__null) { | |||
| 748 | target = pd_get_address_from_code(); | |||
| 749 | } | |||
| 750 | return target; | |||
| 751 | } | |||
| 752 | ||||
| 753 | ||||
| 754 | void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { | |||
| 755 | address target = _target; | |||
| 756 | if (target == NULL__null) { | |||
| 757 | target = new_addr_for(this->target(), src, dest); | |||
| 758 | } | |||
| 759 | set_value(target); | |||
| 760 | } | |||
| 761 | ||||
| 762 | ||||
| 763 | address internal_word_Relocation::target() { | |||
| 764 | address target = _target; | |||
| 765 | if (target == NULL__null) { | |||
| 766 | if (addr_in_const()) { | |||
| 767 | target = *(address*)addr(); | |||
| 768 | } else { | |||
| 769 | target = pd_get_address_from_code(); | |||
| 770 | } | |||
| 771 | } | |||
| 772 | return target; | |||
| 773 | } | |||
| 774 | ||||
| 775 | //--------------------------------------------------------------------------------- | |||
| 776 | // Non-product code | |||
| 777 | ||||
| 778 | #ifndef PRODUCT | |||
| 779 | ||||
| 780 | static const char* reloc_type_string(relocInfo::relocType t) { | |||
| 781 | switch (t) { | |||
| 782 | #define EACH_CASE(name) \ | |||
| 783 | case relocInfo::name##_type: \ | |||
| 784 | return #name; | |||
| 785 | ||||
| 786 | APPLY_TO_RELOCATIONS(EACH_CASE)EACH_CASE(oop) EACH_CASE(metadata) EACH_CASE(virtual_call) EACH_CASE (opt_virtual_call) EACH_CASE(static_call) EACH_CASE(static_stub ) EACH_CASE(runtime_call) EACH_CASE(runtime_call_w_cp) EACH_CASE (external_word) EACH_CASE(internal_word) EACH_CASE(poll) EACH_CASE (poll_return) EACH_CASE(section_word) EACH_CASE(trampoline_stub ); | |||
| 787 | #undef EACH_CASE | |||
| 788 | ||||
| 789 | case relocInfo::none: | |||
| 790 | return "none"; | |||
| 791 | case relocInfo::data_prefix_tag: | |||
| 792 | return "prefix"; | |||
| 793 | default: | |||
| 794 | return "UNKNOWN RELOC TYPE"; | |||
| 795 | } | |||
| 796 | } | |||
| 797 | ||||
| 798 | ||||
| 799 | void RelocIterator::print_current() { | |||
| 800 | if (!has_current()) { | |||
| 801 | tty->print_cr("(no relocs)"); | |||
| 802 | return; | |||
| 803 | } | |||
| 804 | tty->print("relocInfo@" INTPTR_FORMAT"0x%016" "l" "x" " [type=%d(%s) addr=" INTPTR_FORMAT"0x%016" "l" "x" " offset=%d", | |||
| 805 | p2i(_current), type(), reloc_type_string((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); | |||
| 806 | if (current()->format() != 0) | |||
| 807 | tty->print(" format=%d", current()->format()); | |||
| 808 | if (datalen() == 1) { | |||
| 809 | tty->print(" data=%d", data()[0]); | |||
| 810 | } else if (datalen() > 0) { | |||
| 811 | tty->print(" data={"); | |||
| 812 | for (int i = 0; i < datalen(); i++) { | |||
| 813 | tty->print("%04x", data()[i] & 0xFFFF); | |||
| 814 | } | |||
| 815 | tty->print("}"); | |||
| 816 | } | |||
| 817 | tty->print("]"); | |||
| 818 | switch (type()) { | |||
| 819 | case relocInfo::oop_type: | |||
| 820 | { | |||
| 821 | oop_Relocation* r = oop_reloc(); | |||
| 822 | oop* oop_addr = NULL__null; | |||
| 823 | oop raw_oop = NULL__null; | |||
| 824 | oop oop_value = NULL__null; | |||
| 825 | if (code() != NULL__null || r->oop_is_immediate()) { | |||
| 826 | oop_addr = r->oop_addr(); | |||
| 827 | raw_oop = *oop_addr; | |||
| 828 | oop_value = r->oop_value(); | |||
| 829 | } | |||
| 830 | tty->print(" | [oop_addr=" INTPTR_FORMAT"0x%016" "l" "x" " *=" INTPTR_FORMAT"0x%016" "l" "x" " offset=%d]", | |||
| 831 | p2i(oop_addr), p2i(raw_oop), r->offset()); | |||
| 832 | // Do not print the oop by default--we want this routine to | |||
| 833 | // work even during GC or other inconvenient times. | |||
| 834 | if (WizardMode && oop_value != NULL__null) { | |||
| 835 | tty->print("oop_value=" INTPTR_FORMAT"0x%016" "l" "x" ": ", p2i(oop_value)); | |||
| 836 | if (oopDesc::is_oop(oop_value)) { | |||
| 837 | oop_value->print_value_on(tty); | |||
| 838 | } | |||
| 839 | } | |||
| 840 | break; | |||
| 841 | } | |||
| 842 | case relocInfo::metadata_type: | |||
| 843 | { | |||
| 844 | metadata_Relocation* r = metadata_reloc(); | |||
| 845 | Metadata** metadata_addr = NULL__null; | |||
| 846 | Metadata* raw_metadata = NULL__null; | |||
| 847 | Metadata* metadata_value = NULL__null; | |||
| 848 | if (code() != NULL__null || r->metadata_is_immediate()) { | |||
| 849 | metadata_addr = r->metadata_addr(); | |||
| 850 | raw_metadata = *metadata_addr; | |||
| 851 | metadata_value = r->metadata_value(); | |||
| 852 | } | |||
| 853 | tty->print(" | [metadata_addr=" INTPTR_FORMAT"0x%016" "l" "x" " *=" INTPTR_FORMAT"0x%016" "l" "x" " offset=%d]", | |||
| 854 | p2i(metadata_addr), p2i(raw_metadata), r->offset()); | |||
| 855 | if (metadata_value != NULL__null) { | |||
| 856 | tty->print("metadata_value=" INTPTR_FORMAT"0x%016" "l" "x" ": ", p2i(metadata_value)); | |||
| 857 | metadata_value->print_value_on(tty); | |||
| 858 | } | |||
| 859 | break; | |||
| 860 | } | |||
| 861 | case relocInfo::external_word_type: | |||
| 862 | case relocInfo::internal_word_type: | |||
| 863 | case relocInfo::section_word_type: | |||
| 864 | { | |||
| 865 | DataRelocation* r = (DataRelocation*) reloc(); | |||
| 866 | tty->print(" | [target=" INTPTR_FORMAT"0x%016" "l" "x" "]", p2i(r->value())); //value==target | |||
| 867 | break; | |||
| 868 | } | |||
| 869 | case relocInfo::static_call_type: | |||
| 870 | { | |||
| 871 | static_call_Relocation* r = (static_call_Relocation*) reloc(); | |||
| 872 | tty->print(" | [destination=" INTPTR_FORMAT"0x%016" "l" "x" " metadata=" INTPTR_FORMAT"0x%016" "l" "x" "]", | |||
| 873 | p2i(r->destination()), p2i(r->method_value())); | |||
| 874 | break; | |||
| 875 | } | |||
| 876 | case relocInfo::runtime_call_type: | |||
| 877 | case relocInfo::runtime_call_w_cp_type: | |||
| 878 | { | |||
| 879 | CallRelocation* r = (CallRelocation*) reloc(); | |||
| 880 | tty->print(" | [destination=" INTPTR_FORMAT"0x%016" "l" "x" "]", p2i(r->destination())); | |||
| 881 | break; | |||
| 882 | } | |||
| 883 | case relocInfo::virtual_call_type: | |||
| 884 | { | |||
| 885 | virtual_call_Relocation* r = (virtual_call_Relocation*) reloc(); | |||
| 886 | tty->print(" | [destination=" INTPTR_FORMAT"0x%016" "l" "x" " cached_value=" INTPTR_FORMAT"0x%016" "l" "x" " metadata=" INTPTR_FORMAT"0x%016" "l" "x" "]", | |||
| 887 | p2i(r->destination()), p2i(r->cached_value()), p2i(r->method_value())); | |||
| 888 | break; | |||
| 889 | } | |||
| 890 | case relocInfo::static_stub_type: | |||
| 891 | { | |||
| 892 | static_stub_Relocation* r = (static_stub_Relocation*) reloc(); | |||
| 893 | tty->print(" | [static_call=" INTPTR_FORMAT"0x%016" "l" "x" "]", p2i(r->static_call())); | |||
| 894 | break; | |||
| 895 | } | |||
| 896 | case relocInfo::trampoline_stub_type: | |||
| 897 | { | |||
| 898 | trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc(); | |||
| 899 | tty->print(" | [trampoline owner=" INTPTR_FORMAT"0x%016" "l" "x" "]", p2i(r->owner())); | |||
| 900 | break; | |||
| 901 | } | |||
| 902 | case relocInfo::opt_virtual_call_type: | |||
| 903 | { | |||
| 904 | opt_virtual_call_Relocation* r = (opt_virtual_call_Relocation*) reloc(); | |||
| 905 | tty->print(" | [destination=" INTPTR_FORMAT"0x%016" "l" "x" " metadata=" INTPTR_FORMAT"0x%016" "l" "x" "]", | |||
| 906 | p2i(r->destination()), p2i(r->method_value())); | |||
| 907 | break; | |||
| 908 | } | |||
| 909 | default: | |||
| 910 | break; | |||
| 911 | } | |||
| 912 | tty->cr(); | |||
| 913 | } | |||
| 914 | ||||
| 915 | ||||
| 916 | void RelocIterator::print() { | |||
| 917 | RelocIterator save_this = (*this); | |||
| 918 | relocInfo* scan = _current; | |||
| 919 | if (!has_current()) scan += 1; // nothing to scan here! | |||
| 920 | ||||
| 921 | bool skip_next = has_current(); | |||
| 922 | bool got_next; | |||
| 923 | while (true) { | |||
| 924 | got_next = (skip_next || next()); | |||
| 925 | skip_next = false; | |||
| 926 | ||||
| 927 | tty->print(" @" INTPTR_FORMAT"0x%016" "l" "x" ": ", p2i(scan)); | |||
| 928 | relocInfo* newscan = _current+1; | |||
| 929 | if (!has_current()) newscan -= 1; // nothing to scan here! | |||
| 930 | while (scan < newscan) { | |||
| 931 | tty->print("%04x", *(short*)scan & 0xFFFF); | |||
| 932 | scan++; | |||
| 933 | } | |||
| 934 | tty->cr(); | |||
| 935 | ||||
| 936 | if (!got_next) break; | |||
| 937 | print_current(); | |||
| 938 | } | |||
| 939 | ||||
| 940 | (*this) = save_this; | |||
| 941 | } | |||
| 942 | ||||
| 943 | // For the debugger: | |||
| 944 | extern "C" | |||
| 945 | void print_blob_locs(nmethod* nm) { | |||
| 946 | nm->print(); | |||
| 947 | RelocIterator iter(nm); | |||
| 948 | iter.print(); | |||
| ||||
| 949 | } | |||
| 950 | extern "C" | |||
| 951 | void print_buf_locs(CodeBuffer* cb) { | |||
| 952 | FlagSetting fs(PrintRelocations, true); | |||
| 953 | cb->print(); | |||
| 954 | } | |||
| 955 | #endif // !PRODUCT |
| 1 | /* | |||
| 2 | * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. | |||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
| 4 | * | |||
| 5 | * This code is free software; you can redistribute it and/or modify it | |||
| 6 | * under the terms of the GNU General Public License version 2 only, as | |||
| 7 | * published by the Free Software Foundation. | |||
| 8 | * | |||
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT | |||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
| 12 | * version 2 for more details (a copy is included in the LICENSE file that | |||
| 13 | * accompanied this code). | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU General Public License version | |||
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, | |||
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| 18 | * | |||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #ifndef SHARE_CODE_RELOCINFO_HPP | |||
| 26 | #define SHARE_CODE_RELOCINFO_HPP | |||
| 27 | ||||
| 28 | #include "runtime/os.hpp" | |||
| 29 | #include "utilities/macros.hpp" | |||
| 30 | ||||
| 31 | class nmethod; | |||
| 32 | class CodeBlob; | |||
| 33 | class CompiledMethod; | |||
| 34 | class Metadata; | |||
| 35 | class NativeMovConstReg; | |||
| 36 | ||||
| 37 | // Types in this file: | |||
| 38 | // relocInfo | |||
| 39 | // One element of an array of halfwords encoding compressed relocations. | |||
| 40 | // Also, the source of relocation types (relocInfo::oop_type, ...). | |||
| 41 | // Relocation | |||
| 42 | // A flyweight object representing a single relocation. | |||
| 43 | // It is fully unpacked from the compressed relocation array. | |||
| 44 | // metadata_Relocation, ... (subclasses of Relocation) | |||
| 45 | // The location of some type-specific operations (metadata_addr, ...). | |||
| 46 | // Also, the source of relocation specs (metadata_Relocation::spec, ...). | |||
| 47 | // oop_Relocation, ... (subclasses of Relocation) | |||
| 48 | // oops in the code stream (strings, class loaders) | |||
| 49 | // Also, the source of relocation specs (oop_Relocation::spec, ...). | |||
| 50 | // RelocationHolder | |||
| 51 | // A value type which acts as a union holding a Relocation object. | |||
| 52 | // Represents a relocation spec passed into a CodeBuffer during assembly. | |||
| 53 | // RelocIterator | |||
| 54 | // A StackObj which iterates over the relocations associated with | |||
| 55 | // a range of code addresses. Can be used to operate a copy of code. | |||
| 56 | ||||
| 57 | ||||
| 58 | // Notes on relocType: | |||
| 59 | // | |||
| 60 | // These hold enough information to read or write a value embedded in | |||
| 61 | // the instructions of an CodeBlob. They're used to update: | |||
| 62 | // | |||
| 63 | // 1) embedded oops (isOop() == true) | |||
| 64 | // 2) inline caches (isIC() == true) | |||
| 65 | // 3) runtime calls (isRuntimeCall() == true) | |||
| 66 | // 4) internal word ref (isInternalWord() == true) | |||
| 67 | // 5) external word ref (isExternalWord() == true) | |||
| 68 | // | |||
| 69 | // when objects move (GC) or if code moves (compacting the code heap). | |||
| 70 | // They are also used to patch the code (if a call site must change) | |||
| 71 | // | |||
| 72 | // A relocInfo is represented in 16 bits: | |||
| 73 | // 4 bits indicating the relocation type | |||
| 74 | // 12 bits indicating the offset from the previous relocInfo address | |||
| 75 | // | |||
| 76 | // The offsets accumulate along the relocInfo stream to encode the | |||
| 77 | // address within the CodeBlob, which is named RelocIterator::addr(). | |||
| 78 | // The address of a particular relocInfo always points to the first | |||
| 79 | // byte of the relevant instruction (and not to any of its subfields | |||
| 80 | // or embedded immediate constants). | |||
| 81 | // | |||
| 82 | // The offset value is scaled appropriately for the target machine. | |||
| 83 | // (See relocInfo_<arch>.hpp for the offset scaling.) | |||
| 84 | // | |||
| 85 | // On some machines, there may also be a "format" field which may provide | |||
| 86 | // additional information about the format of the instruction stream | |||
| 87 | // at the corresponding code address. The format value is usually zero. | |||
| 88 | // Any machine (such as Intel) whose instructions can sometimes contain | |||
| 89 | // more than one relocatable constant needs format codes to distinguish | |||
| 90 | // which operand goes with a given relocation. | |||
| 91 | // | |||
| 92 | // If the target machine needs N format bits, the offset has 12-N bits, | |||
| 93 | // the format is encoded between the offset and the type, and the | |||
| 94 | // relocInfo_<arch>.hpp file has manifest constants for the format codes. | |||
| 95 | // | |||
| 96 | // If the type is "data_prefix_tag" then the offset bits are further encoded, | |||
| 97 | // and in fact represent not a code-stream offset but some inline data. | |||
| 98 | // The data takes the form of a counted sequence of halfwords, which | |||
| 99 | // precedes the actual relocation record. (Clients never see it directly.) | |||
| 100 | // The interpetation of this extra data depends on the relocation type. | |||
| 101 | // | |||
| 102 | // On machines that have 32-bit immediate fields, there is usually | |||
| 103 | // little need for relocation "prefix" data, because the instruction stream | |||
| 104 | // is a perfectly reasonable place to store the value. On machines in | |||
| 105 | // which 32-bit values must be "split" across instructions, the relocation | |||
| 106 | // data is the "true" specification of the value, which is then applied | |||
| 107 | // to some field of the instruction (22 or 13 bits, on SPARC). | |||
| 108 | // | |||
| 109 | // Whenever the location of the CodeBlob changes, any PC-relative | |||
| 110 | // relocations, and any internal_word_type relocations, must be reapplied. | |||
| 111 | // After the GC runs, oop_type relocations must be reapplied. | |||
| 112 | // | |||
| 113 | // | |||
| 114 | // Here are meanings of the types: | |||
| 115 | // | |||
| 116 | // relocInfo::none -- a filler record | |||
| 117 | // Value: none | |||
| 118 | // Instruction: The corresponding code address is ignored | |||
| 119 | // Data: Any data prefix and format code are ignored | |||
| 120 | // (This means that any relocInfo can be disabled by setting | |||
| 121 | // its type to none. See relocInfo::remove.) | |||
| 122 | // | |||
| 123 | // relocInfo::oop_type, relocInfo::metadata_type -- a reference to an oop or meta data | |||
| 124 | // Value: an oop, or else the address (handle) of an oop | |||
| 125 | // Instruction types: memory (load), set (load address) | |||
| 126 | // Data: [] an oop stored in 4 bytes of instruction | |||
| 127 | // [n] n is the index of an oop in the CodeBlob's oop pool | |||
| 128 | // [[N]n l] and l is a byte offset to be applied to the oop | |||
| 129 | // [Nn Ll] both index and offset may be 32 bits if necessary | |||
| 130 | // Here is a special hack, used only by the old compiler: | |||
| 131 | // [[N]n 00] the value is the __address__ of the nth oop in the pool | |||
| 132 | // (Note that the offset allows optimal references to class variables.) | |||
| 133 | // | |||
| 134 | // relocInfo::internal_word_type -- an address within the same CodeBlob | |||
| 135 | // relocInfo::section_word_type -- same, but can refer to another section | |||
| 136 | // Value: an address in the CodeBlob's code or constants section | |||
| 137 | // Instruction types: memory (load), set (load address) | |||
| 138 | // Data: [] stored in 4 bytes of instruction | |||
| 139 | // [[L]l] a relative offset (see [About Offsets] below) | |||
| 140 | // In the case of section_word_type, the offset is relative to a section | |||
| 141 | // base address, and the section number (e.g., SECT_INSTS) is encoded | |||
| 142 | // into the low two bits of the offset L. | |||
| 143 | // | |||
| 144 | // relocInfo::external_word_type -- a fixed address in the runtime system | |||
| 145 | // Value: an address | |||
| 146 | // Instruction types: memory (load), set (load address) | |||
| 147 | // Data: [] stored in 4 bytes of instruction | |||
| 148 | // [n] the index of a "well-known" stub (usual case on RISC) | |||
| 149 | // [Ll] a 32-bit address | |||
| 150 | // | |||
| 151 | // relocInfo::runtime_call_type -- a fixed subroutine in the runtime system | |||
| 152 | // Value: an address | |||
| 153 | // Instruction types: PC-relative call (or a PC-relative branch) | |||
| 154 | // Data: [] stored in 4 bytes of instruction | |||
| 155 | // | |||
| 156 | // relocInfo::static_call_type -- a static call | |||
| 157 | // Value: an CodeBlob, a stub, or a fixup routine | |||
| 158 | // Instruction types: a call | |||
| 159 | // Data: [] | |||
| 160 | // The identity of the callee is extracted from debugging information. | |||
| 161 | // //%note reloc_3 | |||
| 162 | // | |||
| 163 | // relocInfo::virtual_call_type -- a virtual call site (which includes an inline | |||
| 164 | // cache) | |||
| 165 | // Value: an CodeBlob, a stub, the interpreter, or a fixup routine | |||
| 166 | // Instruction types: a call, plus some associated set-oop instructions | |||
| 167 | // Data: [] the associated set-oops are adjacent to the call | |||
| 168 | // [n] n is a relative offset to the first set-oop | |||
| 169 | // [[N]n l] and l is a limit within which the set-oops occur | |||
| 170 | // [Nn Ll] both n and l may be 32 bits if necessary | |||
| 171 | // The identity of the callee is extracted from debugging information. | |||
| 172 | // | |||
| 173 | // relocInfo::opt_virtual_call_type -- a virtual call site that is statically bound | |||
| 174 | // | |||
| 175 | // Same info as a static_call_type. We use a special type, so the handling of | |||
| 176 | // virtuals and statics are separated. | |||
| 177 | // | |||
| 178 | // | |||
| 179 | // The offset n points to the first set-oop. (See [About Offsets] below.) | |||
| 180 | // In turn, the set-oop instruction specifies or contains an oop cell devoted | |||
| 181 | // exclusively to the IC call, which can be patched along with the call. | |||
| 182 | // | |||
| 183 | // The locations of any other set-oops are found by searching the relocation | |||
| 184 | // information starting at the first set-oop, and continuing until all | |||
| 185 | // relocations up through l have been inspected. The value l is another | |||
| 186 | // relative offset. (Both n and l are relative to the call's first byte.) | |||
| 187 | // | |||
| 188 | // The limit l of the search is exclusive. However, if it points within | |||
| 189 | // the call (e.g., offset zero), it is adjusted to point after the call and | |||
| 190 | // any associated machine-specific delay slot. | |||
| 191 | // | |||
| 192 | // Since the offsets could be as wide as 32-bits, these conventions | |||
| 193 | // put no restrictions whatever upon code reorganization. | |||
| 194 | // | |||
| 195 | // The compiler is responsible for ensuring that transition from a clean | |||
| 196 | // state to a monomorphic compiled state is MP-safe. This implies that | |||
| 197 | // the system must respond well to intermediate states where a random | |||
| 198 | // subset of the set-oops has been correctly from the clean state | |||
| 199 | // upon entry to the VEP of the compiled method. In the case of a | |||
| 200 | // machine (Intel) with a single set-oop instruction, the 32-bit | |||
| 201 | // immediate field must not straddle a unit of memory coherence. | |||
| 202 | // //%note reloc_3 | |||
| 203 | // | |||
| 204 | // relocInfo::static_stub_type -- an extra stub for each static_call_type | |||
| 205 | // Value: none | |||
| 206 | // Instruction types: a virtual call: { set_oop; jump; } | |||
| 207 | // Data: [[N]n] the offset of the associated static_call reloc | |||
| 208 | // This stub becomes the target of a static call which must be upgraded | |||
| 209 | // to a virtual call (because the callee is interpreted). | |||
| 210 | // See [About Offsets] below. | |||
| 211 | // //%note reloc_2 | |||
| 212 | // | |||
| 213 | // relocInfo::poll_[return_]type -- a safepoint poll | |||
| 214 | // Value: none | |||
| 215 | // Instruction types: memory load or test | |||
| 216 | // Data: none | |||
| 217 | // | |||
| 218 | // For example: | |||
| 219 | // | |||
| 220 | // INSTRUCTIONS RELOC: TYPE PREFIX DATA | |||
| 221 | // ------------ ---- ----------- | |||
| 222 | // sethi %hi(myObject), R oop_type [n(myObject)] | |||
| 223 | // ld [R+%lo(myObject)+fldOffset], R2 oop_type [n(myObject) fldOffset] | |||
| 224 | // add R2, 1, R2 | |||
| 225 | // st R2, [R+%lo(myObject)+fldOffset] oop_type [n(myObject) fldOffset] | |||
| 226 | //%note reloc_1 | |||
| 227 | // | |||
| 228 | // This uses 4 instruction words, 8 relocation halfwords, | |||
| 229 | // and an entry (which is sharable) in the CodeBlob's oop pool, | |||
| 230 | // for a total of 36 bytes. | |||
| 231 | // | |||
| 232 | // Note that the compiler is responsible for ensuring the "fldOffset" when | |||
| 233 | // added to "%lo(myObject)" does not overflow the immediate fields of the | |||
| 234 | // memory instructions. | |||
| 235 | // | |||
| 236 | // | |||
| 237 | // [About Offsets] Relative offsets are supplied to this module as | |||
| 238 | // positive byte offsets, but they may be internally stored scaled | |||
| 239 | // and/or negated, depending on what is most compact for the target | |||
| 240 | // system. Since the object pointed to by the offset typically | |||
| 241 | // precedes the relocation address, it is profitable to store | |||
| 242 | // these negative offsets as positive numbers, but this decision | |||
| 243 | // is internal to the relocation information abstractions. | |||
| 244 | // | |||
| 245 | ||||
| 246 | class Relocation; | |||
| 247 | class CodeBuffer; | |||
| 248 | class CodeSection; | |||
| 249 | class RelocIterator; | |||
| 250 | ||||
| 251 | class relocInfo { | |||
| 252 | friend class RelocIterator; | |||
| 253 | public: | |||
| 254 | enum relocType { | |||
| 255 | none = 0, // Used when no relocation should be generated | |||
| 256 | oop_type = 1, // embedded oop | |||
| 257 | virtual_call_type = 2, // a standard inline cache call for a virtual send | |||
| 258 | opt_virtual_call_type = 3, // a virtual call that has been statically bound (i.e., no IC cache) | |||
| 259 | static_call_type = 4, // a static send | |||
| 260 | static_stub_type = 5, // stub-entry for static send (takes care of interpreter case) | |||
| 261 | runtime_call_type = 6, // call to fixed external routine | |||
| 262 | external_word_type = 7, // reference to fixed external address | |||
| 263 | internal_word_type = 8, // reference within the current code blob | |||
| 264 | section_word_type = 9, // internal, but a cross-section reference | |||
| 265 | poll_type = 10, // polling instruction for safepoints | |||
| 266 | poll_return_type = 11, // polling instruction for safepoints at return | |||
| 267 | metadata_type = 12, // metadata that used to be oops | |||
| 268 | trampoline_stub_type = 13, // stub-entry for trampoline | |||
| 269 | runtime_call_w_cp_type = 14, // Runtime call which may load its target from the constant pool | |||
| 270 | data_prefix_tag = 15, // tag for a prefix (carries data arguments) | |||
| 271 | type_mask = 15 // A mask which selects only the above values | |||
| 272 | }; | |||
| 273 | ||||
| 274 | private: | |||
| 275 | unsigned short _value; | |||
| 276 | ||||
| 277 | static const enum class RawBitsToken {} RAW_BITS{}; | |||
| 278 | ||||
| 279 | relocInfo(relocType type, RawBitsToken, int bits) | |||
| 280 | : _value((type << nontype_width) + bits) { } | |||
| 281 | ||||
| 282 | static relocType check_relocType(relocType type) NOT_DEBUG({ return type; }); | |||
| 283 | ||||
| 284 | static void check_offset_and_format(int offset, int format) NOT_DEBUG_RETURN; | |||
| 285 | ||||
| 286 | static int compute_bits(int offset, int format) { | |||
| 287 | check_offset_and_format(offset, format); | |||
| 288 | return (offset / offset_unit) + (format << offset_width); | |||
| 289 | } | |||
| 290 | ||||
| 291 | public: | |||
| 292 | relocInfo(relocType type, int offset, int format = 0) | |||
| 293 | : relocInfo(check_relocType(type), RAW_BITS, compute_bits(offset, format)) {} | |||
| 294 | ||||
| 295 | #define APPLY_TO_RELOCATIONS(visitor)visitor(oop) visitor(metadata) visitor(virtual_call) visitor( opt_virtual_call) visitor(static_call) visitor(static_stub) visitor (runtime_call) visitor(runtime_call_w_cp) visitor(external_word ) visitor(internal_word) visitor(poll) visitor(poll_return) visitor (section_word) visitor(trampoline_stub) \ | |||
| 296 | visitor(oop) \ | |||
| 297 | visitor(metadata) \ | |||
| 298 | visitor(virtual_call) \ | |||
| 299 | visitor(opt_virtual_call) \ | |||
| 300 | visitor(static_call) \ | |||
| 301 | visitor(static_stub) \ | |||
| 302 | visitor(runtime_call) \ | |||
| 303 | visitor(runtime_call_w_cp) \ | |||
| 304 | visitor(external_word) \ | |||
| 305 | visitor(internal_word) \ | |||
| 306 | visitor(poll) \ | |||
| 307 | visitor(poll_return) \ | |||
| 308 | visitor(section_word) \ | |||
| 309 | visitor(trampoline_stub) \ | |||
| 310 | ||||
| 311 | ||||
| 312 | public: | |||
| 313 | enum { | |||
| 314 | value_width = sizeof(unsigned short) * BitsPerByte, | |||
| 315 | type_width = 4, // == log2(type_mask+1) | |||
| 316 | nontype_width = value_width - type_width, | |||
| 317 | datalen_width = nontype_width-1, | |||
| 318 | datalen_tag = 1 << datalen_width, // or-ed into _value | |||
| 319 | datalen_limit = 1 << datalen_width, | |||
| 320 | datalen_mask = (1 << datalen_width)-1 | |||
| 321 | }; | |||
| 322 | ||||
| 323 | // accessors | |||
| 324 | public: | |||
| 325 | relocType type() const { return (relocType)((unsigned)_value >> nontype_width); } | |||
| 326 | int format() const { return format_mask==0? 0: format_mask & | |||
| 327 | ((unsigned)_value >> offset_width); } | |||
| 328 | int addr_offset() const { assert(!is_prefix(), "must have offset")do { if (!(!is_prefix())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 328, "assert(" "!is_prefix()" ") failed", "must have offset" ); ::breakpoint(); } } while (0); | |||
| 329 | return (_value & offset_mask)*offset_unit; } | |||
| 330 | ||||
| 331 | protected: | |||
| 332 | const short* data() const { assert(is_datalen(), "must have data")do { if (!(is_datalen())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 332, "assert(" "is_datalen()" ") failed", "must have data") ; ::breakpoint(); } } while (0); | |||
| 333 | return (const short*)(this + 1); } | |||
| 334 | int datalen() const { assert(is_datalen(), "must have data")do { if (!(is_datalen())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 334, "assert(" "is_datalen()" ") failed", "must have data") ; ::breakpoint(); } } while (0); | |||
| 335 | return (_value & datalen_mask); } | |||
| 336 | int immediate() const { assert(is_immediate(), "must have immed")do { if (!(is_immediate())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 336, "assert(" "is_immediate()" ") failed", "must have immed" ); ::breakpoint(); } } while (0); | |||
| 337 | return (_value & datalen_mask); } | |||
| 338 | public: | |||
| 339 | static int addr_unit() { return offset_unit; } | |||
| 340 | static int offset_limit() { return (1 << offset_width) * offset_unit; } | |||
| 341 | ||||
| 342 | void set_type(relocType type); | |||
| 343 | ||||
| 344 | void remove() { set_type(none); } | |||
| 345 | ||||
| 346 | protected: | |||
| 347 | bool is_none() const { return type() == none; } | |||
| 348 | bool is_prefix() const { return type() == data_prefix_tag; } | |||
| 349 | bool is_datalen() const { assert(is_prefix(), "must be prefix")do { if (!(is_prefix())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 349, "assert(" "is_prefix()" ") failed", "must be prefix"); ::breakpoint(); } } while (0); | |||
| 350 | return (_value & datalen_tag) != 0; } | |||
| 351 | bool is_immediate() const { assert(is_prefix(), "must be prefix")do { if (!(is_prefix())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 351, "assert(" "is_prefix()" ") failed", "must be prefix"); ::breakpoint(); } } while (0); | |||
| 352 | return (_value & datalen_tag) == 0; } | |||
| 353 | ||||
| 354 | public: | |||
| 355 | // Occasionally records of type relocInfo::none will appear in the stream. | |||
| 356 | // We do not bother to filter these out, but clients should ignore them. | |||
| 357 | // These records serve as "filler" in three ways: | |||
| 358 | // - to skip large spans of unrelocated code (this is rare) | |||
| 359 | // - to pad out the relocInfo array to the required oop alignment | |||
| 360 | // - to disable old relocation information which is no longer applicable | |||
| 361 | ||||
| 362 | inline friend relocInfo filler_relocInfo(); | |||
| 363 | ||||
| 364 | // Every non-prefix relocation may be preceded by at most one prefix, | |||
| 365 | // which supplies 1 or more halfwords of associated data. Conventionally, | |||
| 366 | // an int is represented by 0, 1, or 2 halfwords, depending on how | |||
| 367 | // many bits are required to represent the value. (In addition, | |||
| 368 | // if the sole halfword is a 10-bit unsigned number, it is made | |||
| 369 | // "immediate" in the prefix header word itself. This optimization | |||
| 370 | // is invisible outside this module.) | |||
| 371 | ||||
| 372 | inline friend relocInfo prefix_relocInfo(int datalen); | |||
| 373 | ||||
| 374 | private: | |||
| 375 | // an immediate relocInfo optimizes a prefix with one 10-bit unsigned value | |||
| 376 | static relocInfo immediate_relocInfo(int data0) { | |||
| 377 | assert(fits_into_immediate(data0), "data0 in limits")do { if (!(fits_into_immediate(data0))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 377, "assert(" "fits_into_immediate(data0)" ") failed", "data0 in limits" ); ::breakpoint(); } } while (0); | |||
| 378 | return relocInfo(relocInfo::data_prefix_tag, RAW_BITS, data0); | |||
| 379 | } | |||
| 380 | static bool fits_into_immediate(int data0) { | |||
| 381 | return (data0 >= 0 && data0 < datalen_limit); | |||
| 382 | } | |||
| 383 | ||||
| 384 | public: | |||
| 385 | // Support routines for compilers. | |||
| 386 | ||||
| 387 | // This routine takes an infant relocInfo (unprefixed) and | |||
| 388 | // edits in its prefix, if any. It also updates dest.locs_end. | |||
| 389 | void initialize(CodeSection* dest, Relocation* reloc); | |||
| 390 | ||||
| 391 | // This routine updates a prefix and returns the limit pointer. | |||
| 392 | // It tries to compress the prefix from 32 to 16 bits, and if | |||
| 393 | // successful returns a reduced "prefix_limit" pointer. | |||
| 394 | relocInfo* finish_prefix(short* prefix_limit); | |||
| 395 | ||||
| 396 | // bit-packers for the data array: | |||
| 397 | ||||
| 398 | // As it happens, the bytes within the shorts are ordered natively, | |||
| 399 | // but the shorts within the word are ordered big-endian. | |||
| 400 | // This is an arbitrary choice, made this way mainly to ease debugging. | |||
| 401 | static int data0_from_int(jint x) { return x >> value_width; } | |||
| 402 | static int data1_from_int(jint x) { return (short)x; } | |||
| 403 | static jint jint_from_data(short* data) { | |||
| 404 | return (data[0] << value_width) + (unsigned short)data[1]; | |||
| 405 | } | |||
| 406 | ||||
| 407 | static jint short_data_at(int n, short* data, int datalen) { | |||
| 408 | return datalen > n ? data[n] : 0; | |||
| 409 | } | |||
| 410 | ||||
| 411 | static jint jint_data_at(int n, short* data, int datalen) { | |||
| 412 | return datalen > n+1 ? jint_from_data(&data[n]) : short_data_at(n, data, datalen); | |||
| 413 | } | |||
| 414 | ||||
| 415 | // Update methods for relocation information | |||
| 416 | // (since code is dynamically patched, we also need to dynamically update the relocation info) | |||
| 417 | // Both methods takes old_type, so it is able to performe sanity checks on the information removed. | |||
| 418 | static void change_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type, relocType new_type); | |||
| 419 | ||||
| 420 | // Machine dependent stuff | |||
| 421 | #include CPU_HEADER(relocInfo)"relocInfo_x86.hpp" | |||
| 422 | ||||
| 423 | protected: | |||
| 424 | // Derived constant, based on format_width which is PD: | |||
| 425 | enum { | |||
| 426 | offset_width = nontype_width - format_width, | |||
| 427 | offset_mask = (1<<offset_width) - 1, | |||
| 428 | format_mask = (1<<format_width) - 1 | |||
| 429 | }; | |||
| 430 | public: | |||
| 431 | enum { | |||
| 432 | #ifdef _LP641 | |||
| 433 | // for use in format | |||
| 434 | // format_width must be at least 1 on _LP64 | |||
| 435 | narrow_oop_in_const = 1, | |||
| 436 | #endif | |||
| 437 | // Conservatively large estimate of maximum length (in shorts) | |||
| 438 | // of any relocation record. | |||
| 439 | // Extended format is length prefix, data words, and tag/offset suffix. | |||
| 440 | length_limit = 1 + 1 + (3*BytesPerWord/BytesPerShort) + 1, | |||
| 441 | have_format = format_width > 0 | |||
| 442 | }; | |||
| 443 | }; | |||
| 444 | ||||
| 445 | #define FORWARD_DECLARE_EACH_CLASS(name) \ | |||
| 446 | class name##_Relocation; | |||
| 447 | APPLY_TO_RELOCATIONS(FORWARD_DECLARE_EACH_CLASS)FORWARD_DECLARE_EACH_CLASS(oop) FORWARD_DECLARE_EACH_CLASS(metadata ) FORWARD_DECLARE_EACH_CLASS(virtual_call) FORWARD_DECLARE_EACH_CLASS (opt_virtual_call) FORWARD_DECLARE_EACH_CLASS(static_call) FORWARD_DECLARE_EACH_CLASS (static_stub) FORWARD_DECLARE_EACH_CLASS(runtime_call) FORWARD_DECLARE_EACH_CLASS (runtime_call_w_cp) FORWARD_DECLARE_EACH_CLASS(external_word) FORWARD_DECLARE_EACH_CLASS(internal_word) FORWARD_DECLARE_EACH_CLASS (poll) FORWARD_DECLARE_EACH_CLASS(poll_return) FORWARD_DECLARE_EACH_CLASS (section_word) FORWARD_DECLARE_EACH_CLASS(trampoline_stub) | |||
| 448 | #undef FORWARD_DECLARE_EACH_CLASS | |||
| 449 | ||||
| 450 | ||||
| 451 | ||||
| 452 | inline relocInfo filler_relocInfo() { | |||
| 453 | return relocInfo(relocInfo::none, relocInfo::offset_limit() - relocInfo::offset_unit); | |||
| 454 | } | |||
| 455 | ||||
| 456 | inline relocInfo prefix_relocInfo(int datalen = 0) { | |||
| 457 | assert(relocInfo::fits_into_immediate(datalen), "datalen in limits")do { if (!(relocInfo::fits_into_immediate(datalen))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 457, "assert(" "relocInfo::fits_into_immediate(datalen)" ") failed" , "datalen in limits"); ::breakpoint(); } } while (0); | |||
| 458 | return relocInfo(relocInfo::data_prefix_tag, relocInfo::RAW_BITS, relocInfo::datalen_tag | datalen); | |||
| 459 | } | |||
| 460 | ||||
| 461 | ||||
| 462 | // Holder for flyweight relocation objects. | |||
| 463 | // Although the flyweight subclasses are of varying sizes, | |||
| 464 | // the holder is "one size fits all". | |||
| 465 | class RelocationHolder { | |||
| 466 | friend class Relocation; | |||
| 467 | friend class CodeSection; | |||
| 468 | ||||
| 469 | private: | |||
| 470 | // this preallocated memory must accommodate all subclasses of Relocation | |||
| 471 | // (this number is assertion-checked in Relocation::operator new) | |||
| 472 | enum { _relocbuf_size = 5 }; | |||
| 473 | void* _relocbuf[ _relocbuf_size ]; | |||
| 474 | ||||
| 475 | public: | |||
| 476 | Relocation* reloc() const { return (Relocation*) &_relocbuf[0]; } | |||
| 477 | inline relocInfo::relocType type() const; | |||
| 478 | ||||
| 479 | // Add a constant offset to a relocation. Helper for class Address. | |||
| 480 | RelocationHolder plus(int offset) const; | |||
| 481 | ||||
| 482 | inline RelocationHolder(); // initializes type to none | |||
| 483 | ||||
| 484 | inline RelocationHolder(Relocation* r); // make a copy | |||
| 485 | ||||
| 486 | static const RelocationHolder none; | |||
| 487 | }; | |||
| 488 | ||||
| 489 | // A RelocIterator iterates through the relocation information of a CodeBlob. | |||
| 490 | // It provides access to successive relocations as it is advanced through a | |||
| 491 | // code stream. | |||
| 492 | // Usage: | |||
| 493 | // RelocIterator iter(nm); | |||
| 494 | // while (iter.next()) { | |||
| 495 | // iter.reloc()->some_operation(); | |||
| 496 | // } | |||
| 497 | // or: | |||
| 498 | // RelocIterator iter(nm); | |||
| 499 | // while (iter.next()) { | |||
| 500 | // switch (iter.type()) { | |||
| 501 | // case relocInfo::oop_type : | |||
| 502 | // case relocInfo::ic_type : | |||
| 503 | // case relocInfo::prim_type : | |||
| 504 | // case relocInfo::uncommon_type : | |||
| 505 | // case relocInfo::runtime_call_type : | |||
| 506 | // case relocInfo::internal_word_type: | |||
| 507 | // case relocInfo::external_word_type: | |||
| 508 | // ... | |||
| 509 | // } | |||
| 510 | // } | |||
| 511 | ||||
| 512 | class RelocIterator : public StackObj { | |||
| ||||
| 513 | friend class section_word_Relocation; // for section verification | |||
| 514 | enum { SECT_LIMIT = 3 }; // must be equal to CodeBuffer::SECT_LIMIT, checked in ctor | |||
| 515 | friend class Relocation; | |||
| 516 | friend class relocInfo; // for change_reloc_info_for_address only | |||
| 517 | typedef relocInfo::relocType relocType; | |||
| 518 | ||||
| 519 | private: | |||
| 520 | address _limit; // stop producing relocations after this _addr | |||
| 521 | relocInfo* _current; // the current relocation information | |||
| 522 | relocInfo* _end; // end marker; we're done iterating when _current == _end | |||
| 523 | CompiledMethod* _code; // compiled method containing _addr | |||
| 524 | address _addr; // instruction to which the relocation applies | |||
| 525 | short _databuf; // spare buffer for compressed data | |||
| 526 | short* _data; // pointer to the relocation's data | |||
| 527 | short _datalen; // number of halfwords in _data | |||
| 528 | ||||
| 529 | // Base addresses needed to compute targets of section_word_type relocs. | |||
| 530 | address _section_start[SECT_LIMIT]; | |||
| 531 | address _section_end [SECT_LIMIT]; | |||
| 532 | ||||
| 533 | void set_has_current(bool b) { | |||
| 534 | _datalen = !b ? -1 : 0; | |||
| 535 | debug_only(_data = NULL)_data = __null; | |||
| 536 | } | |||
| 537 | void set_current(relocInfo& ri) { | |||
| 538 | _current = &ri; | |||
| 539 | set_has_current(true); | |||
| 540 | } | |||
| 541 | ||||
| 542 | RelocationHolder _rh; // where the current relocation is allocated | |||
| 543 | ||||
| 544 | relocInfo* current() const { assert(has_current(), "must have current")do { if (!(has_current())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 544, "assert(" "has_current()" ") failed", "must have current" ); ::breakpoint(); } } while (0); | |||
| 545 | return _current; } | |||
| 546 | ||||
| 547 | void set_limits(address begin, address limit); | |||
| 548 | ||||
| 549 | void advance_over_prefix(); // helper method | |||
| 550 | ||||
| 551 | void initialize_misc(); | |||
| 552 | ||||
| 553 | void initialize(CompiledMethod* nm, address begin, address limit); | |||
| 554 | ||||
| 555 | RelocIterator() { initialize_misc(); } | |||
| 556 | ||||
| 557 | public: | |||
| 558 | // constructor | |||
| 559 | RelocIterator(CompiledMethod* nm, address begin = NULL__null, address limit = NULL__null); | |||
| 560 | RelocIterator(CodeSection* cb, address begin = NULL__null, address limit = NULL__null); | |||
| 561 | ||||
| 562 | // get next reloc info, return !eos | |||
| 563 | bool next() { | |||
| 564 | _current++; | |||
| 565 | assert(_current <= _end, "must not overrun relocInfo")do { if (!(_current <= _end)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 565, "assert(" "_current <= _end" ") failed", "must not overrun relocInfo" ); ::breakpoint(); } } while (0); | |||
| 566 | if (_current == _end) { | |||
| 567 | set_has_current(false); | |||
| 568 | return false; | |||
| 569 | } | |||
| 570 | set_has_current(true); | |||
| 571 | ||||
| 572 | if (_current->is_prefix()) { | |||
| 573 | advance_over_prefix(); | |||
| 574 | assert(!current()->is_prefix(), "only one prefix at a time")do { if (!(!current()->is_prefix())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 574, "assert(" "!current()->is_prefix()" ") failed", "only one prefix at a time" ); ::breakpoint(); } } while (0); | |||
| 575 | } | |||
| 576 | ||||
| 577 | _addr += _current->addr_offset(); | |||
| 578 | ||||
| 579 | if (_limit != NULL__null && _addr >= _limit) { | |||
| 580 | set_has_current(false); | |||
| 581 | return false; | |||
| 582 | } | |||
| 583 | ||||
| 584 | return true; | |||
| 585 | } | |||
| 586 | ||||
| 587 | // accessors | |||
| 588 | address limit() const { return _limit; } | |||
| 589 | relocType type() const { return current()->type(); } | |||
| 590 | int format() const { return (relocInfo::have_format) ? current()->format() : 0; } | |||
| 591 | address addr() const { return _addr; } | |||
| 592 | CompiledMethod* code() const { return _code; } | |||
| 593 | short* data() const { return _data; } | |||
| 594 | int datalen() const { return _datalen; } | |||
| 595 | bool has_current() const { return _datalen >= 0; } | |||
| 596 | bool addr_in_const() const; | |||
| 597 | ||||
| 598 | address section_start(int n) const { | |||
| 599 | assert(_section_start[n], "must be initialized")do { if (!(_section_start[n])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 599, "assert(" "_section_start[n]" ") failed", "must be initialized" ); ::breakpoint(); } } while (0); | |||
| 600 | return _section_start[n]; | |||
| 601 | } | |||
| 602 | address section_end(int n) const { | |||
| 603 | assert(_section_end[n], "must be initialized")do { if (!(_section_end[n])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 603, "assert(" "_section_end[n]" ") failed", "must be initialized" ); ::breakpoint(); } } while (0); | |||
| 604 | return _section_end[n]; | |||
| 605 | } | |||
| 606 | ||||
| 607 | // The address points to the affected displacement part of the instruction. | |||
| 608 | // For RISC, this is just the whole instruction. | |||
| 609 | // For Intel, this is an unaligned 32-bit word. | |||
| 610 | ||||
| 611 | // type-specific relocation accessors: oop_Relocation* oop_reloc(), etc. | |||
| 612 | #define EACH_TYPE(name) \ | |||
| 613 | inline name##_Relocation* name##_reloc(); | |||
| 614 | APPLY_TO_RELOCATIONS(EACH_TYPE)EACH_TYPE(oop) EACH_TYPE(metadata) EACH_TYPE(virtual_call) EACH_TYPE (opt_virtual_call) EACH_TYPE(static_call) EACH_TYPE(static_stub ) EACH_TYPE(runtime_call) EACH_TYPE(runtime_call_w_cp) EACH_TYPE (external_word) EACH_TYPE(internal_word) EACH_TYPE(poll) EACH_TYPE (poll_return) EACH_TYPE(section_word) EACH_TYPE(trampoline_stub ) | |||
| 615 | #undef EACH_TYPE | |||
| 616 | // generic relocation accessor; switches on type to call the above | |||
| 617 | Relocation* reloc(); | |||
| 618 | ||||
| 619 | #ifndef PRODUCT | |||
| 620 | public: | |||
| 621 | void print(); | |||
| 622 | void print_current(); | |||
| 623 | #endif | |||
| 624 | }; | |||
| 625 | ||||
| 626 | ||||
| 627 | // A Relocation is a flyweight object allocated within a RelocationHolder. | |||
| 628 | // It represents the relocation data of relocation record. | |||
| 629 | // So, the RelocIterator unpacks relocInfos into Relocations. | |||
| 630 | ||||
| 631 | class Relocation { | |||
| 632 | friend class RelocationHolder; | |||
| 633 | friend class RelocIterator; | |||
| 634 | ||||
| 635 | private: | |||
| 636 | // When a relocation has been created by a RelocIterator, | |||
| 637 | // this field is non-null. It allows the relocation to know | |||
| 638 | // its context, such as the address to which it applies. | |||
| 639 | RelocIterator* _binding; | |||
| 640 | ||||
| 641 | relocInfo::relocType _rtype; | |||
| 642 | ||||
| 643 | protected: | |||
| 644 | RelocIterator* binding() const { | |||
| 645 | assert(_binding != NULL, "must be bound")do { if (!(_binding != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 645, "assert(" "_binding != __null" ") failed", "must be bound" ); ::breakpoint(); } } while (0); | |||
| 646 | return _binding; | |||
| 647 | } | |||
| 648 | void set_binding(RelocIterator* b) { | |||
| 649 | assert(_binding == NULL, "must be unbound")do { if (!(_binding == __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 649, "assert(" "_binding == __null" ") failed", "must be unbound" ); ::breakpoint(); } } while (0); | |||
| 650 | _binding = b; | |||
| 651 | assert(_binding != NULL, "must now be bound")do { if (!(_binding != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 651, "assert(" "_binding != __null" ") failed", "must now be bound" ); ::breakpoint(); } } while (0); | |||
| 652 | } | |||
| 653 | ||||
| 654 | Relocation(relocInfo::relocType rtype) : _binding(NULL__null), _rtype(rtype) { } | |||
| 655 | ||||
| 656 | static RelocationHolder newHolder() { | |||
| 657 | return RelocationHolder(); | |||
| 658 | } | |||
| 659 | ||||
| 660 | public: | |||
| 661 | void* operator new(size_t size, const RelocationHolder& holder) throw() { | |||
| 662 | assert(size <= sizeof(holder._relocbuf), "Make _relocbuf bigger!")do { if (!(size <= sizeof(holder._relocbuf))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 662, "assert(" "size <= sizeof(holder._relocbuf)" ") failed" , "Make _relocbuf bigger!"); ::breakpoint(); } } while (0); | |||
| 663 | assert((void* const *)holder.reloc() == &holder._relocbuf[0], "ptrs must agree")do { if (!((void* const *)holder.reloc() == &holder._relocbuf [0])) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 663, "assert(" "(void* const *)holder.reloc() == &holder._relocbuf[0]" ") failed", "ptrs must agree"); ::breakpoint(); } } while (0 ); | |||
| 664 | return holder.reloc(); | |||
| 665 | } | |||
| 666 | ||||
| 667 | // make a generic relocation for a given type (if possible) | |||
| 668 | static RelocationHolder spec_simple(relocInfo::relocType rtype); | |||
| 669 | ||||
| 670 | // here is the type-specific hook which writes relocation data: | |||
| 671 | virtual void pack_data_to(CodeSection* dest) { } | |||
| 672 | ||||
| 673 | // here is the type-specific hook which reads (unpacks) relocation data: | |||
| 674 | virtual void unpack_data() { | |||
| 675 | assert(datalen()==0 || type()==relocInfo::none, "no data here")do { if (!(datalen()==0 || type()==relocInfo::none)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 675, "assert(" "datalen()==0 || type()==relocInfo::none" ") failed" , "no data here"); ::breakpoint(); } } while (0); | |||
| 676 | } | |||
| 677 | ||||
| 678 | protected: | |||
| 679 | // Helper functions for pack_data_to() and unpack_data(). | |||
| 680 | ||||
| 681 | // Most of the compression logic is confined here. | |||
| 682 | // (The "immediate data" mechanism of relocInfo works independently | |||
| 683 | // of this stuff, and acts to further compress most 1-word data prefixes.) | |||
| 684 | ||||
| 685 | // A variable-width int is encoded as a short if it will fit in 16 bits. | |||
| 686 | // The decoder looks at datalen to decide whether to unpack short or jint. | |||
| 687 | // Most relocation records are quite simple, containing at most two ints. | |||
| 688 | ||||
| 689 | static bool is_short(jint x) { return x == (short)x; } | |||
| 690 | static short* add_short(short* p, int x) { *p++ = x; return p; } | |||
| 691 | static short* add_jint (short* p, jint x) { | |||
| 692 | *p++ = relocInfo::data0_from_int(x); *p++ = relocInfo::data1_from_int(x); | |||
| 693 | return p; | |||
| 694 | } | |||
| 695 | static short* add_var_int(short* p, jint x) { // add a variable-width int | |||
| 696 | if (is_short(x)) p = add_short(p, x); | |||
| 697 | else p = add_jint (p, x); | |||
| 698 | return p; | |||
| 699 | } | |||
| 700 | ||||
| 701 | static short* pack_1_int_to(short* p, jint x0) { | |||
| 702 | // Format is one of: [] [x] [Xx] | |||
| 703 | if (x0 != 0) p = add_var_int(p, x0); | |||
| 704 | return p; | |||
| 705 | } | |||
| 706 | int unpack_1_int() { | |||
| 707 | assert(datalen() <= 2, "too much data")do { if (!(datalen() <= 2)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 707, "assert(" "datalen() <= 2" ") failed", "too much data" ); ::breakpoint(); } } while (0); | |||
| 708 | return relocInfo::jint_data_at(0, data(), datalen()); | |||
| 709 | } | |||
| 710 | ||||
| 711 | // With two ints, the short form is used only if both ints are short. | |||
| 712 | short* pack_2_ints_to(short* p, jint x0, jint x1) { | |||
| 713 | // Format is one of: [] [x y?] [Xx Y?y] | |||
| 714 | if (x0 == 0 && x1 == 0) { | |||
| 715 | // no halfwords needed to store zeroes | |||
| 716 | } else if (is_short(x0) && is_short(x1)) { | |||
| 717 | // 1-2 halfwords needed to store shorts | |||
| 718 | p = add_short(p, x0); if (x1!=0) p = add_short(p, x1); | |||
| 719 | } else { | |||
| 720 | // 3-4 halfwords needed to store jints | |||
| 721 | p = add_jint(p, x0); p = add_var_int(p, x1); | |||
| 722 | } | |||
| 723 | return p; | |||
| 724 | } | |||
| 725 | void unpack_2_ints(jint& x0, jint& x1) { | |||
| 726 | int dlen = datalen(); | |||
| 727 | short* dp = data(); | |||
| 728 | if (dlen <= 2) { | |||
| 729 | x0 = relocInfo::short_data_at(0, dp, dlen); | |||
| 730 | x1 = relocInfo::short_data_at(1, dp, dlen); | |||
| 731 | } else { | |||
| 732 | assert(dlen <= 4, "too much data")do { if (!(dlen <= 4)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 732, "assert(" "dlen <= 4" ") failed", "too much data"); ::breakpoint(); } } while (0); | |||
| 733 | x0 = relocInfo::jint_data_at(0, dp, dlen); | |||
| 734 | x1 = relocInfo::jint_data_at(2, dp, dlen); | |||
| 735 | } | |||
| 736 | } | |||
| 737 | ||||
| 738 | protected: | |||
| 739 | // platform-independent utility for patching constant section | |||
| 740 | void const_set_data_value (address x); | |||
| 741 | void const_verify_data_value (address x); | |||
| 742 | // platform-dependent utilities for decoding and patching instructions | |||
| 743 | void pd_set_data_value (address x, intptr_t off, bool verify_only = false); // a set or mem-ref | |||
| 744 | void pd_verify_data_value (address x, intptr_t off) { pd_set_data_value(x, off, true); } | |||
| 745 | address pd_call_destination (address orig_addr = NULL__null); | |||
| 746 | void pd_set_call_destination (address x); | |||
| 747 | ||||
| 748 | // this extracts the address of an address in the code stream instead of the reloc data | |||
| 749 | address* pd_address_in_code (); | |||
| 750 | ||||
| 751 | // this extracts an address from the code stream instead of the reloc data | |||
| 752 | address pd_get_address_from_code (); | |||
| 753 | ||||
| 754 | // these convert from byte offsets, to scaled offsets, to addresses | |||
| 755 | static jint scaled_offset(address x, address base) { | |||
| 756 | int byte_offset = x - base; | |||
| 757 | int offset = -byte_offset / relocInfo::addr_unit(); | |||
| 758 | assert(address_from_scaled_offset(offset, base) == x, "just checkin'")do { if (!(address_from_scaled_offset(offset, base) == x)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 758, "assert(" "address_from_scaled_offset(offset, base) == x" ") failed", "just checkin'"); ::breakpoint(); } } while (0); | |||
| 759 | return offset; | |||
| 760 | } | |||
| 761 | static jint scaled_offset_null_special(address x, address base) { | |||
| 762 | // Some relocations treat offset=0 as meaning NULL. | |||
| 763 | // Handle this extra convention carefully. | |||
| 764 | if (x == NULL__null) return 0; | |||
| 765 | assert(x != base, "offset must not be zero")do { if (!(x != base)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 765, "assert(" "x != base" ") failed", "offset must not be zero" ); ::breakpoint(); } } while (0); | |||
| 766 | return scaled_offset(x, base); | |||
| 767 | } | |||
| 768 | static address address_from_scaled_offset(jint offset, address base) { | |||
| 769 | int byte_offset = -( offset * relocInfo::addr_unit() ); | |||
| 770 | return base + byte_offset; | |||
| 771 | } | |||
| 772 | ||||
| 773 | // helpers for mapping between old and new addresses after a move or resize | |||
| 774 | address old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest); | |||
| 775 | address new_addr_for(address olda, const CodeBuffer* src, CodeBuffer* dest); | |||
| 776 | void normalize_address(address& addr, const CodeSection* dest, bool allow_other_sections = false); | |||
| 777 | ||||
| 778 | public: | |||
| 779 | // accessors which only make sense for a bound Relocation | |||
| 780 | address addr() const { return binding()->addr(); } | |||
| 781 | CompiledMethod* code() const { return binding()->code(); } | |||
| 782 | bool addr_in_const() const { return binding()->addr_in_const(); } | |||
| 783 | protected: | |||
| 784 | short* data() const { return binding()->data(); } | |||
| 785 | int datalen() const { return binding()->datalen(); } | |||
| 786 | int format() const { return binding()->format(); } | |||
| 787 | ||||
| 788 | public: | |||
| 789 | relocInfo::relocType type() const { return _rtype; } | |||
| 790 | ||||
| 791 | // is it a call instruction? | |||
| 792 | virtual bool is_call() { return false; } | |||
| 793 | ||||
| 794 | // is it a data movement instruction? | |||
| 795 | virtual bool is_data() { return false; } | |||
| 796 | ||||
| 797 | // some relocations can compute their own values | |||
| 798 | virtual address value(); | |||
| 799 | ||||
| 800 | // all relocations are able to reassert their values | |||
| 801 | virtual void set_value(address x); | |||
| 802 | ||||
| 803 | virtual bool clear_inline_cache() { return true; } | |||
| 804 | ||||
| 805 | // This method assumes that all virtual/static (inline) caches are cleared (since for static_call_type and | |||
| 806 | // ic_call_type is not always posisition dependent (depending on the state of the cache)). However, this is | |||
| 807 | // probably a reasonable assumption, since empty caches simplifies code reloacation. | |||
| 808 | virtual void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } | |||
| 809 | }; | |||
| 810 | ||||
| 811 | ||||
| 812 | // certain inlines must be deferred until class Relocation is defined: | |||
| 813 | ||||
| 814 | inline RelocationHolder::RelocationHolder() { | |||
| 815 | // initialize the vtbl, just to keep things type-safe | |||
| 816 | new(*this) Relocation(relocInfo::none); | |||
| 817 | } | |||
| 818 | ||||
| 819 | ||||
| 820 | inline RelocationHolder::RelocationHolder(Relocation* r) { | |||
| 821 | // wordwise copy from r (ok if it copies garbage after r) | |||
| 822 | for (int i = 0; i < _relocbuf_size; i++) { | |||
| 823 | _relocbuf[i] = ((void**)r)[i]; | |||
| 824 | } | |||
| 825 | } | |||
| 826 | ||||
| 827 | relocInfo::relocType RelocationHolder::type() const { | |||
| 828 | return reloc()->type(); | |||
| 829 | } | |||
| 830 | ||||
| 831 | // A DataRelocation always points at a memory or load-constant instruction.. | |||
| 832 | // It is absolute on most machines, and the constant is split on RISCs. | |||
| 833 | // The specific subtypes are oop, external_word, and internal_word. | |||
| 834 | // By convention, the "value" does not include a separately reckoned "offset". | |||
| 835 | class DataRelocation : public Relocation { | |||
| 836 | public: | |||
| 837 | DataRelocation(relocInfo::relocType type) : Relocation(type) {} | |||
| 838 | ||||
| 839 | bool is_data() { return true; } | |||
| 840 | ||||
| 841 | // both target and offset must be computed somehow from relocation data | |||
| 842 | virtual int offset() { return 0; } | |||
| 843 | address value() = 0; | |||
| 844 | void set_value(address x) { set_value(x, offset()); } | |||
| 845 | void set_value(address x, intptr_t o) { | |||
| 846 | if (addr_in_const()) | |||
| 847 | const_set_data_value(x); | |||
| 848 | else | |||
| 849 | pd_set_data_value(x, o); | |||
| 850 | } | |||
| 851 | void verify_value(address x) { | |||
| 852 | if (addr_in_const()) | |||
| 853 | const_verify_data_value(x); | |||
| 854 | else | |||
| 855 | pd_verify_data_value(x, offset()); | |||
| 856 | } | |||
| 857 | ||||
| 858 | // The "o" (displacement) argument is relevant only to split relocations | |||
| 859 | // on RISC machines. In some CPUs (SPARC), the set-hi and set-lo ins'ns | |||
| 860 | // can encode more than 32 bits between them. This allows compilers to | |||
| 861 | // share set-hi instructions between addresses that differ by a small | |||
| 862 | // offset (e.g., different static variables in the same class). | |||
| 863 | // On such machines, the "x" argument to set_value on all set-lo | |||
| 864 | // instructions must be the same as the "x" argument for the | |||
| 865 | // corresponding set-hi instructions. The "o" arguments for the | |||
| 866 | // set-hi instructions are ignored, and must not affect the high-half | |||
| 867 | // immediate constant. The "o" arguments for the set-lo instructions are | |||
| 868 | // added into the low-half immediate constant, and must not overflow it. | |||
| 869 | }; | |||
| 870 | ||||
| 871 | // A CallRelocation always points at a call instruction. | |||
| 872 | // It is PC-relative on most machines. | |||
| 873 | class CallRelocation : public Relocation { | |||
| 874 | public: | |||
| 875 | CallRelocation(relocInfo::relocType type) : Relocation(type) { } | |||
| 876 | ||||
| 877 | bool is_call() { return true; } | |||
| 878 | ||||
| 879 | address destination() { return pd_call_destination(); } | |||
| 880 | void set_destination(address x); // pd_set_call_destination | |||
| 881 | ||||
| 882 | void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); | |||
| 883 | address value() { return destination(); } | |||
| 884 | void set_value(address x) { set_destination(x); } | |||
| 885 | }; | |||
| 886 | ||||
| 887 | class oop_Relocation : public DataRelocation { | |||
| 888 | public: | |||
| 889 | // encode in one of these formats: [] [n] [n l] [Nn l] [Nn Ll] | |||
| 890 | // an oop in the CodeBlob's oop pool | |||
| 891 | static RelocationHolder spec(int oop_index, int offset = 0) { | |||
| 892 | assert(oop_index > 0, "must be a pool-resident oop")do { if (!(oop_index > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 892, "assert(" "oop_index > 0" ") failed", "must be a pool-resident oop" ); ::breakpoint(); } } while (0); | |||
| 893 | RelocationHolder rh = newHolder(); | |||
| 894 | new(rh) oop_Relocation(oop_index, offset); | |||
| 895 | return rh; | |||
| 896 | } | |||
| 897 | // an oop in the instruction stream | |||
| 898 | static RelocationHolder spec_for_immediate() { | |||
| 899 | // If no immediate oops are generated, we can skip some walks over nmethods. | |||
| 900 | // Assert that they don't get generated accidently! | |||
| 901 | assert(relocInfo::mustIterateImmediateOopsInCode(),do { if (!(relocInfo::mustIterateImmediateOopsInCode())) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 902, "assert(" "relocInfo::mustIterateImmediateOopsInCode()" ") failed", "Must return true so we will search for oops as roots etc. in the code." ); ::breakpoint(); } } while (0) | |||
| 902 | "Must return true so we will search for oops as roots etc. in the code.")do { if (!(relocInfo::mustIterateImmediateOopsInCode())) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 902, "assert(" "relocInfo::mustIterateImmediateOopsInCode()" ") failed", "Must return true so we will search for oops as roots etc. in the code." ); ::breakpoint(); } } while (0); | |||
| 903 | const int oop_index = 0; | |||
| 904 | const int offset = 0; // if you want an offset, use the oop pool | |||
| 905 | RelocationHolder rh = newHolder(); | |||
| 906 | new(rh) oop_Relocation(oop_index, offset); | |||
| 907 | return rh; | |||
| 908 | } | |||
| 909 | ||||
| 910 | private: | |||
| 911 | jint _oop_index; // if > 0, index into CodeBlob::oop_at | |||
| 912 | jint _offset; // byte offset to apply to the oop itself | |||
| 913 | ||||
| 914 | oop_Relocation(int oop_index, int offset) | |||
| 915 | : DataRelocation(relocInfo::oop_type), _oop_index(oop_index), _offset(offset) { } | |||
| 916 | ||||
| 917 | friend class RelocIterator; | |||
| 918 | oop_Relocation() : DataRelocation(relocInfo::oop_type) {} | |||
| 919 | ||||
| 920 | public: | |||
| 921 | int oop_index() { return _oop_index; } | |||
| 922 | int offset() { return _offset; } | |||
| 923 | ||||
| 924 | // data is packed in "2_ints" format: [i o] or [Ii Oo] | |||
| 925 | void pack_data_to(CodeSection* dest); | |||
| 926 | void unpack_data(); | |||
| 927 | ||||
| 928 | void fix_oop_relocation(); // reasserts oop value | |||
| 929 | ||||
| 930 | void verify_oop_relocation(); | |||
| 931 | ||||
| 932 | address value() { return cast_from_oop<address>(*oop_addr()); } | |||
| 933 | ||||
| 934 | bool oop_is_immediate() { return oop_index() == 0; } | |||
| 935 | ||||
| 936 | oop* oop_addr(); // addr or &pool[jint_data] | |||
| 937 | oop oop_value(); // *oop_addr | |||
| 938 | // Note: oop_value transparently converts Universe::non_oop_word to NULL. | |||
| 939 | }; | |||
| 940 | ||||
| 941 | ||||
| 942 | // copy of oop_Relocation for now but may delete stuff in both/either | |||
| 943 | class metadata_Relocation : public DataRelocation { | |||
| 944 | ||||
| 945 | public: | |||
| 946 | // encode in one of these formats: [] [n] [n l] [Nn l] [Nn Ll] | |||
| 947 | // an metadata in the CodeBlob's metadata pool | |||
| 948 | static RelocationHolder spec(int metadata_index, int offset = 0) { | |||
| 949 | assert(metadata_index > 0, "must be a pool-resident metadata")do { if (!(metadata_index > 0)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 949, "assert(" "metadata_index > 0" ") failed", "must be a pool-resident metadata" ); ::breakpoint(); } } while (0); | |||
| 950 | RelocationHolder rh = newHolder(); | |||
| 951 | new(rh) metadata_Relocation(metadata_index, offset); | |||
| 952 | return rh; | |||
| 953 | } | |||
| 954 | // an metadata in the instruction stream | |||
| 955 | static RelocationHolder spec_for_immediate() { | |||
| 956 | const int metadata_index = 0; | |||
| 957 | const int offset = 0; // if you want an offset, use the metadata pool | |||
| 958 | RelocationHolder rh = newHolder(); | |||
| 959 | new(rh) metadata_Relocation(metadata_index, offset); | |||
| 960 | return rh; | |||
| 961 | } | |||
| 962 | ||||
| 963 | private: | |||
| 964 | jint _metadata_index; // if > 0, index into nmethod::metadata_at | |||
| 965 | jint _offset; // byte offset to apply to the metadata itself | |||
| 966 | ||||
| 967 | metadata_Relocation(int metadata_index, int offset) | |||
| 968 | : DataRelocation(relocInfo::metadata_type), _metadata_index(metadata_index), _offset(offset) { } | |||
| 969 | ||||
| 970 | friend class RelocIterator; | |||
| 971 | metadata_Relocation() : DataRelocation(relocInfo::metadata_type) { } | |||
| 972 | ||||
| 973 | // Fixes a Metadata pointer in the code. Most platforms embeds the | |||
| 974 | // Metadata pointer in the code at compile time so this is empty | |||
| 975 | // for them. | |||
| 976 | void pd_fix_value(address x); | |||
| 977 | ||||
| 978 | public: | |||
| 979 | int metadata_index() { return _metadata_index; } | |||
| 980 | int offset() { return _offset; } | |||
| 981 | ||||
| 982 | // data is packed in "2_ints" format: [i o] or [Ii Oo] | |||
| 983 | void pack_data_to(CodeSection* dest); | |||
| 984 | void unpack_data(); | |||
| 985 | ||||
| 986 | void fix_metadata_relocation(); // reasserts metadata value | |||
| 987 | ||||
| 988 | address value() { return (address) *metadata_addr(); } | |||
| 989 | ||||
| 990 | bool metadata_is_immediate() { return metadata_index() == 0; } | |||
| 991 | ||||
| 992 | Metadata** metadata_addr(); // addr or &pool[jint_data] | |||
| 993 | Metadata* metadata_value(); // *metadata_addr | |||
| 994 | // Note: metadata_value transparently converts Universe::non_metadata_word to NULL. | |||
| 995 | }; | |||
| 996 | ||||
| 997 | ||||
| 998 | class virtual_call_Relocation : public CallRelocation { | |||
| 999 | ||||
| 1000 | public: | |||
| 1001 | // "cached_value" points to the first associated set-oop. | |||
| 1002 | // The oop_limit helps find the last associated set-oop. | |||
| 1003 | // (See comments at the top of this file.) | |||
| 1004 | static RelocationHolder spec(address cached_value, jint method_index = 0) { | |||
| 1005 | RelocationHolder rh = newHolder(); | |||
| 1006 | new(rh) virtual_call_Relocation(cached_value, method_index); | |||
| 1007 | return rh; | |||
| 1008 | } | |||
| 1009 | ||||
| 1010 | private: | |||
| 1011 | address _cached_value; // location of set-value instruction | |||
| 1012 | jint _method_index; // resolved method for a Java call | |||
| 1013 | ||||
| 1014 | virtual_call_Relocation(address cached_value, int method_index) | |||
| 1015 | : CallRelocation(relocInfo::virtual_call_type), | |||
| 1016 | _cached_value(cached_value), | |||
| 1017 | _method_index(method_index) { | |||
| 1018 | assert(cached_value != NULL, "first oop address must be specified")do { if (!(cached_value != __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1018, "assert(" "cached_value != __null" ") failed", "first oop address must be specified" ); ::breakpoint(); } } while (0); | |||
| 1019 | } | |||
| 1020 | ||||
| 1021 | friend class RelocIterator; | |||
| 1022 | virtual_call_Relocation() : CallRelocation(relocInfo::virtual_call_type) { } | |||
| 1023 | ||||
| 1024 | public: | |||
| 1025 | address cached_value(); | |||
| 1026 | ||||
| 1027 | int method_index() { return _method_index; } | |||
| 1028 | Method* method_value(); | |||
| 1029 | ||||
| 1030 | // data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll] | |||
| 1031 | // oop_limit is set to 0 if the limit falls somewhere within the call. | |||
| 1032 | // When unpacking, a zero oop_limit is taken to refer to the end of the call. | |||
| 1033 | // (This has the effect of bringing in the call's delay slot on SPARC.) | |||
| 1034 | void pack_data_to(CodeSection* dest); | |||
| 1035 | void unpack_data(); | |||
| 1036 | ||||
| 1037 | bool clear_inline_cache(); | |||
| 1038 | }; | |||
| 1039 | ||||
| 1040 | ||||
| 1041 | class opt_virtual_call_Relocation : public CallRelocation { | |||
| 1042 | public: | |||
| 1043 | static RelocationHolder spec(int method_index = 0) { | |||
| 1044 | RelocationHolder rh = newHolder(); | |||
| 1045 | new(rh) opt_virtual_call_Relocation(method_index); | |||
| 1046 | return rh; | |||
| 1047 | } | |||
| 1048 | ||||
| 1049 | private: | |||
| 1050 | jint _method_index; // resolved method for a Java call | |||
| 1051 | ||||
| 1052 | opt_virtual_call_Relocation(int method_index) | |||
| 1053 | : CallRelocation(relocInfo::opt_virtual_call_type), | |||
| 1054 | _method_index(method_index) { } | |||
| 1055 | ||||
| 1056 | friend class RelocIterator; | |||
| 1057 | opt_virtual_call_Relocation() : CallRelocation(relocInfo::opt_virtual_call_type) {} | |||
| 1058 | ||||
| 1059 | public: | |||
| 1060 | int method_index() { return _method_index; } | |||
| 1061 | Method* method_value(); | |||
| 1062 | ||||
| 1063 | void pack_data_to(CodeSection* dest); | |||
| 1064 | void unpack_data(); | |||
| 1065 | ||||
| 1066 | bool clear_inline_cache(); | |||
| 1067 | ||||
| 1068 | // find the matching static_stub | |||
| 1069 | address static_stub(); | |||
| 1070 | }; | |||
| 1071 | ||||
| 1072 | ||||
| 1073 | class static_call_Relocation : public CallRelocation { | |||
| 1074 | public: | |||
| 1075 | static RelocationHolder spec(int method_index = 0) { | |||
| 1076 | RelocationHolder rh = newHolder(); | |||
| 1077 | new(rh) static_call_Relocation(method_index); | |||
| 1078 | return rh; | |||
| 1079 | } | |||
| 1080 | ||||
| 1081 | private: | |||
| 1082 | jint _method_index; // resolved method for a Java call | |||
| 1083 | ||||
| 1084 | static_call_Relocation(int method_index) | |||
| 1085 | : CallRelocation(relocInfo::static_call_type), | |||
| 1086 | _method_index(method_index) { } | |||
| 1087 | ||||
| 1088 | friend class RelocIterator; | |||
| 1089 | static_call_Relocation() : CallRelocation(relocInfo::static_call_type) {} | |||
| 1090 | ||||
| 1091 | public: | |||
| 1092 | int method_index() { return _method_index; } | |||
| 1093 | Method* method_value(); | |||
| 1094 | ||||
| 1095 | void pack_data_to(CodeSection* dest); | |||
| 1096 | void unpack_data(); | |||
| 1097 | ||||
| 1098 | bool clear_inline_cache(); | |||
| 1099 | ||||
| 1100 | // find the matching static_stub | |||
| 1101 | address static_stub(); | |||
| 1102 | }; | |||
| 1103 | ||||
| 1104 | class static_stub_Relocation : public Relocation { | |||
| 1105 | public: | |||
| 1106 | static RelocationHolder spec(address static_call) { | |||
| 1107 | RelocationHolder rh = newHolder(); | |||
| 1108 | new(rh) static_stub_Relocation(static_call); | |||
| 1109 | return rh; | |||
| 1110 | } | |||
| 1111 | ||||
| 1112 | private: | |||
| 1113 | address _static_call; // location of corresponding static_call | |||
| 1114 | ||||
| 1115 | static_stub_Relocation(address static_call) | |||
| 1116 | : Relocation(relocInfo::static_stub_type), | |||
| 1117 | _static_call(static_call) { } | |||
| 1118 | ||||
| 1119 | friend class RelocIterator; | |||
| 1120 | static_stub_Relocation() : Relocation(relocInfo::static_stub_type) { } | |||
| 1121 | ||||
| 1122 | public: | |||
| 1123 | bool clear_inline_cache(); | |||
| 1124 | ||||
| 1125 | address static_call() { return _static_call; } | |||
| 1126 | ||||
| 1127 | // data is packed as a scaled offset in "1_int" format: [c] or [Cc] | |||
| 1128 | void pack_data_to(CodeSection* dest); | |||
| 1129 | void unpack_data(); | |||
| 1130 | }; | |||
| 1131 | ||||
| 1132 | class runtime_call_Relocation : public CallRelocation { | |||
| 1133 | ||||
| 1134 | public: | |||
| 1135 | static RelocationHolder spec() { | |||
| 1136 | RelocationHolder rh = newHolder(); | |||
| 1137 | new(rh) runtime_call_Relocation(); | |||
| 1138 | return rh; | |||
| 1139 | } | |||
| 1140 | ||||
| 1141 | private: | |||
| 1142 | friend class RelocIterator; | |||
| 1143 | runtime_call_Relocation() : CallRelocation(relocInfo::runtime_call_type) { } | |||
| 1144 | ||||
| 1145 | public: | |||
| 1146 | }; | |||
| 1147 | ||||
| 1148 | ||||
| 1149 | class runtime_call_w_cp_Relocation : public CallRelocation { | |||
| 1150 | public: | |||
| 1151 | static RelocationHolder spec() { | |||
| 1152 | RelocationHolder rh = newHolder(); | |||
| 1153 | new(rh) runtime_call_w_cp_Relocation(); | |||
| 1154 | return rh; | |||
| 1155 | } | |||
| 1156 | ||||
| 1157 | private: | |||
| 1158 | friend class RelocIterator; | |||
| 1159 | runtime_call_w_cp_Relocation() | |||
| 1160 | : CallRelocation(relocInfo::runtime_call_w_cp_type), | |||
| 1161 | _offset(-4) /* <0 = invalid */ { } | |||
| 1162 | ||||
| 1163 | // On z/Architecture, runtime calls are either a sequence | |||
| 1164 | // of two instructions (load destination of call from constant pool + do call) | |||
| 1165 | // or a pc-relative call. The pc-relative call is faster, but it can only | |||
| 1166 | // be used if the destination of the call is not too far away. | |||
| 1167 | // In order to be able to patch a pc-relative call back into one using | |||
| 1168 | // the constant pool, we have to remember the location of the call's destination | |||
| 1169 | // in the constant pool. | |||
| 1170 | int _offset; | |||
| 1171 | ||||
| 1172 | public: | |||
| 1173 | void set_constant_pool_offset(int offset) { _offset = offset; } | |||
| 1174 | int get_constant_pool_offset() { return _offset; } | |||
| 1175 | void pack_data_to(CodeSection * dest); | |||
| 1176 | void unpack_data(); | |||
| 1177 | }; | |||
| 1178 | ||||
| 1179 | // Trampoline Relocations. | |||
| 1180 | // A trampoline allows to encode a small branch in the code, even if there | |||
| 1181 | // is the chance that this branch can not reach all possible code locations. | |||
| 1182 | // If the relocation finds that a branch is too far for the instruction | |||
| 1183 | // in the code, it can patch it to jump to the trampoline where is | |||
| 1184 | // sufficient space for a far branch. Needed on PPC. | |||
| 1185 | class trampoline_stub_Relocation : public Relocation { | |||
| 1186 | public: | |||
| 1187 | static RelocationHolder spec(address static_call) { | |||
| 1188 | RelocationHolder rh = newHolder(); | |||
| 1189 | return (new (rh) trampoline_stub_Relocation(static_call)); | |||
| 1190 | } | |||
| 1191 | ||||
| 1192 | private: | |||
| 1193 | address _owner; // Address of the NativeCall that owns the trampoline. | |||
| 1194 | ||||
| 1195 | trampoline_stub_Relocation(address owner) | |||
| 1196 | : Relocation(relocInfo::trampoline_stub_type), | |||
| 1197 | _owner(owner) { } | |||
| 1198 | ||||
| 1199 | friend class RelocIterator; | |||
| 1200 | trampoline_stub_Relocation() : Relocation(relocInfo::trampoline_stub_type) { } | |||
| 1201 | ||||
| 1202 | public: | |||
| 1203 | ||||
| 1204 | // Return the address of the NativeCall that owns the trampoline. | |||
| 1205 | address owner() { return _owner; } | |||
| 1206 | ||||
| 1207 | void pack_data_to(CodeSection * dest); | |||
| 1208 | void unpack_data(); | |||
| 1209 | ||||
| 1210 | // Find the trampoline stub for a call. | |||
| 1211 | static address get_trampoline_for(address call, nmethod* code); | |||
| 1212 | }; | |||
| 1213 | ||||
| 1214 | class external_word_Relocation : public DataRelocation { | |||
| 1215 | public: | |||
| 1216 | static RelocationHolder spec(address target) { | |||
| 1217 | assert(target != NULL, "must not be null")do { if (!(target != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1217, "assert(" "target != __null" ") failed", "must not be null" ); ::breakpoint(); } } while (0); | |||
| 1218 | RelocationHolder rh = newHolder(); | |||
| 1219 | new(rh) external_word_Relocation(target); | |||
| 1220 | return rh; | |||
| 1221 | } | |||
| 1222 | ||||
| 1223 | // Use this one where all 32/64 bits of the target live in the code stream. | |||
| 1224 | // The target must be an intptr_t, and must be absolute (not relative). | |||
| 1225 | static RelocationHolder spec_for_immediate() { | |||
| 1226 | RelocationHolder rh = newHolder(); | |||
| 1227 | new(rh) external_word_Relocation(NULL__null); | |||
| 1228 | return rh; | |||
| 1229 | } | |||
| 1230 | ||||
| 1231 | // Some address looking values aren't safe to treat as relocations | |||
| 1232 | // and should just be treated as constants. | |||
| 1233 | static bool can_be_relocated(address target) { | |||
| 1234 | assert(target == NULL || (uintptr_t)target >= (uintptr_t)os::vm_page_size(), INTPTR_FORMAT, (intptr_t)target)do { if (!(target == __null || (uintptr_t)target >= (uintptr_t )os::vm_page_size())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1234, "assert(" "target == __null || (uintptr_t)target >= (uintptr_t)os::vm_page_size()" ") failed", "0x%016" "l" "x", (intptr_t)target); ::breakpoint (); } } while (0); | |||
| 1235 | return target != NULL__null; | |||
| 1236 | } | |||
| 1237 | ||||
| 1238 | private: | |||
| 1239 | address _target; // address in runtime | |||
| 1240 | ||||
| 1241 | external_word_Relocation(address target) | |||
| 1242 | : DataRelocation(relocInfo::external_word_type), _target(target) { } | |||
| 1243 | ||||
| 1244 | friend class RelocIterator; | |||
| 1245 | external_word_Relocation() : DataRelocation(relocInfo::external_word_type) { } | |||
| 1246 | ||||
| 1247 | public: | |||
| 1248 | // data is packed as a well-known address in "1_int" format: [a] or [Aa] | |||
| 1249 | // The function runtime_address_to_index is used to turn full addresses | |||
| 1250 | // to short indexes, if they are pre-registered by the stub mechanism. | |||
| 1251 | // If the "a" value is 0 (i.e., _target is NULL), the address is stored | |||
| 1252 | // in the code stream. See external_word_Relocation::target(). | |||
| 1253 | void pack_data_to(CodeSection* dest); | |||
| 1254 | void unpack_data(); | |||
| 1255 | ||||
| 1256 | void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); | |||
| 1257 | address target(); // if _target==NULL, fetch addr from code stream | |||
| 1258 | address value() { return target(); } | |||
| 1259 | }; | |||
| 1260 | ||||
| 1261 | class internal_word_Relocation : public DataRelocation { | |||
| 1262 | ||||
| 1263 | public: | |||
| 1264 | static RelocationHolder spec(address target) { | |||
| 1265 | assert(target != NULL, "must not be null")do { if (!(target != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1265, "assert(" "target != __null" ") failed", "must not be null" ); ::breakpoint(); } } while (0); | |||
| 1266 | RelocationHolder rh = newHolder(); | |||
| 1267 | new(rh) internal_word_Relocation(target); | |||
| 1268 | return rh; | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | // use this one where all the bits of the target can fit in the code stream: | |||
| 1272 | static RelocationHolder spec_for_immediate() { | |||
| 1273 | RelocationHolder rh = newHolder(); | |||
| 1274 | new(rh) internal_word_Relocation(NULL__null); | |||
| 1275 | return rh; | |||
| 1276 | } | |||
| 1277 | ||||
| 1278 | // default section -1 means self-relative | |||
| 1279 | internal_word_Relocation(address target, int section = -1, | |||
| 1280 | relocInfo::relocType type = relocInfo::internal_word_type) | |||
| 1281 | : DataRelocation(type), _target(target), _section(section) { } | |||
| 1282 | ||||
| 1283 | protected: | |||
| 1284 | address _target; // address in CodeBlob | |||
| 1285 | int _section; // section providing base address, if any | |||
| 1286 | ||||
| 1287 | friend class RelocIterator; | |||
| 1288 | internal_word_Relocation(relocInfo::relocType type = relocInfo::internal_word_type) | |||
| 1289 | : DataRelocation(type) { } | |||
| 1290 | ||||
| 1291 | // bit-width of LSB field in packed offset, if section >= 0 | |||
| 1292 | enum { section_width = 2 }; // must equal CodeBuffer::sect_bits | |||
| 1293 | ||||
| 1294 | public: | |||
| 1295 | // data is packed as a scaled offset in "1_int" format: [o] or [Oo] | |||
| 1296 | // If the "o" value is 0 (i.e., _target is NULL), the offset is stored | |||
| 1297 | // in the code stream. See internal_word_Relocation::target(). | |||
| 1298 | // If _section is not -1, it is appended to the low bits of the offset. | |||
| 1299 | void pack_data_to(CodeSection* dest); | |||
| 1300 | void unpack_data(); | |||
| 1301 | ||||
| 1302 | void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); | |||
| 1303 | address target(); // if _target==NULL, fetch addr from code stream | |||
| 1304 | int section() { return _section; } | |||
| 1305 | address value() { return target(); } | |||
| 1306 | }; | |||
| 1307 | ||||
| 1308 | class section_word_Relocation : public internal_word_Relocation { | |||
| 1309 | public: | |||
| 1310 | static RelocationHolder spec(address target, int section) { | |||
| 1311 | RelocationHolder rh = newHolder(); | |||
| 1312 | new(rh) section_word_Relocation(target, section); | |||
| 1313 | return rh; | |||
| 1314 | } | |||
| 1315 | ||||
| 1316 | section_word_Relocation(address target, int section) | |||
| 1317 | : internal_word_Relocation(target, section, relocInfo::section_word_type) { | |||
| 1318 | assert(target != NULL, "must not be null")do { if (!(target != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1318, "assert(" "target != __null" ") failed", "must not be null" ); ::breakpoint(); } } while (0); | |||
| 1319 | assert(section >= 0 && section < RelocIterator::SECT_LIMIT, "must be a valid section")do { if (!(section >= 0 && section < RelocIterator ::SECT_LIMIT)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1319, "assert(" "section >= 0 && section < RelocIterator::SECT_LIMIT" ") failed", "must be a valid section"); ::breakpoint(); } } while (0); | |||
| 1320 | } | |||
| 1321 | ||||
| 1322 | //void pack_data_to -- inherited | |||
| 1323 | void unpack_data(); | |||
| 1324 | ||||
| 1325 | private: | |||
| 1326 | friend class RelocIterator; | |||
| 1327 | section_word_Relocation() : internal_word_Relocation(relocInfo::section_word_type) { } | |||
| 1328 | }; | |||
| 1329 | ||||
| 1330 | ||||
| 1331 | class poll_Relocation : public Relocation { | |||
| 1332 | bool is_data() { return true; } | |||
| 1333 | void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); | |||
| 1334 | public: | |||
| 1335 | poll_Relocation(relocInfo::relocType type = relocInfo::poll_type) : Relocation(type) { } | |||
| 1336 | }; | |||
| 1337 | ||||
| 1338 | class poll_return_Relocation : public poll_Relocation { | |||
| 1339 | public: | |||
| 1340 | poll_return_Relocation() : poll_Relocation(relocInfo::relocInfo::poll_return_type) { } | |||
| 1341 | }; | |||
| 1342 | ||||
| 1343 | // We know all the xxx_Relocation classes, so now we can define these: | |||
| 1344 | #define EACH_CASE(name) \ | |||
| 1345 | inline name##_Relocation* RelocIterator::name##_reloc() { \ | |||
| 1346 | assert(type() == relocInfo::name##_type, "type must agree")do { if (!(type() == relocInfo::name##_type)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/code/relocInfo.hpp" , 1346, "assert(" "type() == relocInfo::name##_type" ") failed" , "type must agree"); ::breakpoint(); } } while (0); \ | |||
| 1347 | /* The purpose of the placed "new" is to re-use the same */ \ | |||
| 1348 | /* stack storage for each new iteration. */ \ | |||
| 1349 | name##_Relocation* r = new(_rh) name##_Relocation(); \ | |||
| 1350 | r->set_binding(this); \ | |||
| 1351 | r->name##_Relocation::unpack_data(); \ | |||
| 1352 | return r; \ | |||
| 1353 | } | |||
| 1354 | APPLY_TO_RELOCATIONS(EACH_CASE)EACH_CASE(oop) EACH_CASE(metadata) EACH_CASE(virtual_call) EACH_CASE (opt_virtual_call) EACH_CASE(static_call) EACH_CASE(static_stub ) EACH_CASE(runtime_call) EACH_CASE(runtime_call_w_cp) EACH_CASE (external_word) EACH_CASE(internal_word) EACH_CASE(poll) EACH_CASE (poll_return) EACH_CASE(section_word) EACH_CASE(trampoline_stub ); | |||
| 1355 | #undef EACH_CASE | |||
| 1356 | ||||
| 1357 | inline RelocIterator::RelocIterator(CompiledMethod* nm, address begin, address limit) { | |||
| 1358 | initialize(nm, begin, limit); | |||
| 1359 | } | |||
| 1360 | ||||
| 1361 | #endif // SHARE_CODE_RELOCINFO_HPP |