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 |