Mercurial > hg > truffle
annotate src/share/vm/compiler/oopMap.cpp @ 9126:bc26f978b0ce
HotSpotResolvedObjectType: implement hasFinalizeSubclass() correctly
don't use the (wrong) cached value, but ask the runtime on each request.
Fixes regression on xml.* benchmarks @ specjvm2008. The problem was:
After the constructor of Object was deoptimized due to an assumption violation,
it was recompiled again after some time. However, on recompilation, the value
of hasFinalizeSubclass for the class was not updated and it was compiled again
with a, now wrong, assumption, which then triggers deoptimization again.
This was repeated until it hit the recompilation limit (defined by
PerMethodRecompilationCutoff), and therefore only executed by the interpreter
from now on, causing the performance regression.
author | Bernhard Urban <bernhard.urban@jku.at> |
---|---|
date | Mon, 15 Apr 2013 19:54:58 +0200 |
parents | 3ac7d10a6572 |
children | cefad50507d8 |
rev | line source |
---|---|
0 | 1 /* |
6842
b9a9ed0f8eeb
7197424: update copyright year to match last edit in jdk8 hotspot repository
mikael
parents:
6197
diff
changeset
|
2 * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
948
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
948
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
948
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "code/codeBlob.hpp" | |
27 #include "code/codeCache.hpp" | |
28 #include "code/nmethod.hpp" | |
29 #include "code/scopeDesc.hpp" | |
30 #include "compiler/oopMap.hpp" | |
31 #include "gc_interface/collectedHeap.hpp" | |
32 #include "memory/allocation.inline.hpp" | |
33 #include "memory/resourceArea.hpp" | |
34 #include "runtime/frame.inline.hpp" | |
35 #include "runtime/signature.hpp" | |
36 #ifdef COMPILER1 | |
37 #include "c1/c1_Defs.hpp" | |
38 #endif | |
0 | 39 |
40 // OopMapStream | |
41 | |
42 OopMapStream::OopMapStream(OopMap* oop_map) { | |
43 if(oop_map->omv_data() == NULL) { | |
44 _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); | |
45 } else { | |
46 _stream = new CompressedReadStream(oop_map->omv_data()); | |
47 } | |
48 _mask = OopMapValue::type_mask_in_place; | |
49 _size = oop_map->omv_count(); | |
50 _position = 0; | |
51 _valid_omv = false; | |
52 } | |
53 | |
54 | |
55 OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) { | |
56 if(oop_map->omv_data() == NULL) { | |
57 _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); | |
58 } else { | |
59 _stream = new CompressedReadStream(oop_map->omv_data()); | |
60 } | |
61 _mask = oop_types_mask; | |
62 _size = oop_map->omv_count(); | |
63 _position = 0; | |
64 _valid_omv = false; | |
65 } | |
66 | |
67 | |
68 void OopMapStream::find_next() { | |
69 while(_position++ < _size) { | |
70 _omv.read_from(_stream); | |
71 if(((int)_omv.type() & _mask) > 0) { | |
72 _valid_omv = true; | |
73 return; | |
74 } | |
75 } | |
76 _valid_omv = false; | |
77 } | |
78 | |
79 | |
80 // OopMap | |
81 | |
82 // frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd | |
83 // slots to hold 4-byte values like ints and floats in the LP64 build. | |
84 OopMap::OopMap(int frame_size, int arg_count) { | |
85 // OopMaps are usually quite so small, so pick a small initial size | |
86 set_write_stream(new CompressedWriteStream(32)); | |
87 set_omv_data(NULL); | |
88 set_omv_count(0); | |
89 | |
90 #ifdef ASSERT | |
91 _locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count; | |
92 _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length); | |
93 for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value; | |
94 #endif | |
95 } | |
96 | |
97 | |
98 OopMap::OopMap(OopMap::DeepCopyToken, OopMap* source) { | |
99 // This constructor does a deep copy | |
100 // of the source OopMap. | |
101 set_write_stream(new CompressedWriteStream(source->omv_count() * 2)); | |
102 set_omv_data(NULL); | |
103 set_omv_count(0); | |
104 set_offset(source->offset()); | |
105 | |
106 #ifdef ASSERT | |
107 _locs_length = source->_locs_length; | |
108 _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length); | |
109 for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value; | |
110 #endif | |
111 | |
112 // We need to copy the entries too. | |
113 for (OopMapStream oms(source); !oms.is_done(); oms.next()) { | |
114 OopMapValue omv = oms.current(); | |
115 omv.write_on(write_stream()); | |
116 increment_count(); | |
117 } | |
118 } | |
119 | |
120 | |
121 OopMap* OopMap::deep_copy() { | |
122 return new OopMap(_deep_copy_token, this); | |
123 } | |
124 | |
125 | |
126 void OopMap::copy_to(address addr) { | |
127 memcpy(addr,this,sizeof(OopMap)); | |
128 memcpy(addr + sizeof(OopMap),write_stream()->buffer(),write_stream()->position()); | |
129 OopMap* new_oop = (OopMap*)addr; | |
130 new_oop->set_omv_data_size(write_stream()->position()); | |
131 new_oop->set_omv_data((unsigned char *)(addr + sizeof(OopMap))); | |
132 new_oop->set_write_stream(NULL); | |
133 } | |
134 | |
135 | |
136 int OopMap::heap_size() const { | |
137 int size = sizeof(OopMap); | |
138 int align = sizeof(void *) - 1; | |
139 if(write_stream() != NULL) { | |
140 size += write_stream()->position(); | |
141 } else { | |
142 size += omv_data_size(); | |
143 } | |
144 // Align to a reasonable ending point | |
145 size = ((size+align) & ~align); | |
146 return size; | |
147 } | |
148 | |
149 // frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd | |
150 // slots to hold 4-byte values like ints and floats in the LP64 build. | |
151 void OopMap::set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional) { | |
152 | |
153 assert(reg->value() < _locs_length, "too big reg value for stack size"); | |
154 assert( _locs_used[reg->value()] == OopMapValue::unused_value, "cannot insert twice" ); | |
155 debug_only( _locs_used[reg->value()] = x; ) | |
156 | |
157 OopMapValue o(reg, x); | |
158 | |
159 if(x == OopMapValue::callee_saved_value) { | |
160 // This can never be a stack location, so we don't need to transform it. | |
161 assert(optional->is_reg(), "Trying to callee save a stack location"); | |
162 o.set_content_reg(optional); | |
163 } else if(x == OopMapValue::derived_oop_value) { | |
164 o.set_content_reg(optional); | |
165 } | |
166 | |
167 o.write_on(write_stream()); | |
168 increment_count(); | |
169 } | |
170 | |
171 | |
172 void OopMap::set_oop(VMReg reg) { | |
173 set_xxx(reg, OopMapValue::oop_value, VMRegImpl::Bad()); | |
174 } | |
175 | |
176 | |
177 void OopMap::set_value(VMReg reg) { | |
178 // At this time, we only need value entries in our OopMap when ZapDeadCompiledLocals is active. | |
179 if (ZapDeadCompiledLocals) | |
180 set_xxx(reg, OopMapValue::value_value, VMRegImpl::Bad()); | |
181 } | |
182 | |
183 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
184 void OopMap::set_narrowoop(VMReg reg) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
185 set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad()); |
0 | 186 } |
187 | |
188 | |
189 void OopMap::set_callee_saved(VMReg reg, VMReg caller_machine_register ) { | |
190 set_xxx(reg, OopMapValue::callee_saved_value, caller_machine_register); | |
191 } | |
192 | |
193 | |
194 void OopMap::set_derived_oop(VMReg reg, VMReg derived_from_local_register ) { | |
195 if( reg == derived_from_local_register ) { | |
196 // Actually an oop, derived shares storage with base, | |
197 set_oop(reg); | |
198 } else { | |
199 set_xxx(reg, OopMapValue::derived_oop_value, derived_from_local_register); | |
200 } | |
201 } | |
202 | |
203 // OopMapSet | |
204 | |
205 OopMapSet::OopMapSet() { | |
206 set_om_size(MinOopMapAllocation); | |
207 set_om_count(0); | |
208 OopMap** temp = NEW_RESOURCE_ARRAY(OopMap*, om_size()); | |
209 set_om_data(temp); | |
210 } | |
211 | |
212 | |
213 void OopMapSet::grow_om_data() { | |
214 int new_size = om_size() * 2; | |
215 OopMap** new_data = NEW_RESOURCE_ARRAY(OopMap*, new_size); | |
216 memcpy(new_data,om_data(),om_size() * sizeof(OopMap*)); | |
217 set_om_size(new_size); | |
218 set_om_data(new_data); | |
219 } | |
220 | |
221 | |
222 void OopMapSet::copy_to(address addr) { | |
223 address temp = addr; | |
224 int align = sizeof(void *) - 1; | |
225 // Copy this | |
226 memcpy(addr,this,sizeof(OopMapSet)); | |
227 temp += sizeof(OopMapSet); | |
228 temp = (address)((intptr_t)(temp + align) & ~align); | |
229 // Do the needed fixups to the new OopMapSet | |
230 OopMapSet* new_set = (OopMapSet*)addr; | |
231 new_set->set_om_data((OopMap**)temp); | |
232 // Allow enough space for the OopMap pointers | |
233 temp += (om_count() * sizeof(OopMap*)); | |
234 | |
235 for(int i=0; i < om_count(); i++) { | |
236 OopMap* map = at(i); | |
237 map->copy_to((address)temp); | |
238 new_set->set(i,(OopMap*)temp); | |
239 temp += map->heap_size(); | |
240 } | |
241 // This "locks" the OopMapSet | |
242 new_set->set_om_size(-1); | |
243 } | |
244 | |
245 | |
246 void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) { | |
247 assert(om_size() != -1,"Cannot grow a fixed OopMapSet"); | |
248 | |
249 if(om_count() >= om_size()) { | |
250 grow_om_data(); | |
251 } | |
252 map->set_offset(pc_offset); | |
253 | |
254 #ifdef ASSERT | |
255 if(om_count() > 0) { | |
256 OopMap* last = at(om_count()-1); | |
257 if (last->offset() == map->offset() ) { | |
258 fatal("OopMap inserted twice"); | |
259 } | |
260 if(last->offset() > map->offset()) { | |
261 tty->print_cr( "WARNING, maps not sorted: pc[%d]=%d, pc[%d]=%d", | |
262 om_count(),last->offset(),om_count()+1,map->offset()); | |
263 } | |
264 } | |
265 #endif // ASSERT | |
266 | |
267 set(om_count(),map); | |
268 increment_count(); | |
269 } | |
270 | |
271 | |
272 int OopMapSet::heap_size() const { | |
273 // The space we use | |
274 int size = sizeof(OopMap); | |
275 int align = sizeof(void *) - 1; | |
276 size = ((size+align) & ~align); | |
277 size += om_count() * sizeof(OopMap*); | |
278 | |
279 // Now add in the space needed for the indivdiual OopMaps | |
280 for(int i=0; i < om_count(); i++) { | |
281 size += at(i)->heap_size(); | |
282 } | |
283 // We don't need to align this, it will be naturally pointer aligned | |
284 return size; | |
285 } | |
286 | |
287 | |
288 OopMap* OopMapSet::singular_oop_map() { | |
289 guarantee(om_count() == 1, "Make sure we only have a single gc point"); | |
290 return at(0); | |
291 } | |
292 | |
293 | |
294 OopMap* OopMapSet::find_map_at_offset(int pc_offset) const { | |
295 int i, len = om_count(); | |
296 assert( len > 0, "must have pointer maps" ); | |
297 | |
298 // Scan through oopmaps. Stop when current offset is either equal or greater | |
299 // than the one we are looking for. | |
300 for( i = 0; i < len; i++) { | |
301 if( at(i)->offset() >= pc_offset ) | |
302 break; | |
303 } | |
304 | |
305 assert( i < len, "oopmap not found" ); | |
306 | |
307 OopMap* m = at(i); | |
308 assert( m->offset() == pc_offset, "oopmap not found" ); | |
309 return m; | |
310 } | |
311 | |
312 class DoNothingClosure: public OopClosure { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
313 public: |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
314 void do_oop(oop* p) {} |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
315 void do_oop(narrowOop* p) {} |
0 | 316 }; |
317 static DoNothingClosure do_nothing; | |
318 | |
319 static void add_derived_oop(oop* base, oop* derived) { | |
320 #ifndef TIERED | |
321 COMPILER1_PRESENT(ShouldNotReachHere();) | |
7125
1baf7f1e3f23
decoupled C++ Graal runtime from C1
Doug Simon <doug.simon@oracle.com>
parents:
7066
diff
changeset
|
322 GRAAL_ONLY(ShouldNotReachHere();) |
0 | 323 #endif // TIERED |
324 #ifdef COMPILER2 | |
325 DerivedPointerTable::add(derived, base); | |
326 #endif // COMPILER2 | |
327 } | |
328 | |
329 | |
330 #ifndef PRODUCT | |
331 static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) { | |
332 // Print oopmap and regmap | |
333 tty->print_cr("------ "); | |
334 CodeBlob* cb = fr->cb(); | |
335 OopMapSet* maps = cb->oop_maps(); | |
336 OopMap* map = cb->oop_map_for_return_address(fr->pc()); | |
337 map->print(); | |
338 if( cb->is_nmethod() ) { | |
339 nmethod* nm = (nmethod*)cb; | |
340 // native wrappers have no scope data, it is implied | |
341 if (nm->is_native_method()) { | |
342 tty->print("bci: 0 (native)"); | |
343 } else { | |
344 ScopeDesc* scope = nm->scope_desc_at(fr->pc()); | |
345 tty->print("bci: %d ",scope->bci()); | |
346 } | |
347 } | |
348 tty->cr(); | |
349 fr->print_on(tty); | |
350 tty->print(" "); | |
351 cb->print_value_on(tty); tty->cr(); | |
352 reg_map->print(); | |
353 tty->print_cr("------ "); | |
354 | |
355 } | |
356 #endif // PRODUCT | |
357 | |
358 void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f) { | |
359 // add derived oops to a table | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
360 all_do(fr, reg_map, f, add_derived_oop, &do_nothing); |
0 | 361 } |
362 | |
363 | |
364 void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map, | |
365 OopClosure* oop_fn, void derived_oop_fn(oop*, oop*), | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
366 OopClosure* value_fn) { |
0 | 367 CodeBlob* cb = fr->cb(); |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
368 assert(cb != NULL, "no codeblob"); |
0 | 369 |
370 NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) | |
371 | |
372 OopMapSet* maps = cb->oop_maps(); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
373 OopMap* map = cb->oop_map_for_return_address(fr->pc()); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
374 assert(map != NULL, "no ptr map found"); |
0 | 375 |
376 // handle derived pointers first (otherwise base pointer may be | |
377 // changed before derived pointer offset has been collected) | |
378 OopMapValue omv; | |
379 { | |
380 OopMapStream oms(map,OopMapValue::derived_oop_value); | |
381 if (!oms.is_done()) { | |
382 #ifndef TIERED | |
383 COMPILER1_PRESENT(ShouldNotReachHere();) | |
7125
1baf7f1e3f23
decoupled C++ Graal runtime from C1
Doug Simon <doug.simon@oracle.com>
parents:
7066
diff
changeset
|
384 GRAAL_ONLY(ShouldNotReachHere();) |
0 | 385 #endif // !TIERED |
386 // Protect the operation on the derived pointers. This | |
387 // protects the addition of derived pointers to the shared | |
388 // derived pointer table in DerivedPointerTable::add(). | |
389 MutexLockerEx x(DerivedPointerTableGC_lock, Mutex::_no_safepoint_check_flag); | |
390 do { | |
391 omv = oms.current(); | |
392 oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); | |
393 if ( loc != NULL ) { | |
394 oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); | |
395 oop *derived_loc = loc; | |
858 | 396 oop val = *base_loc; |
397 if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { | |
398 // Ignore NULL oops and decoded NULL narrow oops which | |
399 // equal to Universe::narrow_oop_base when a narrow oop | |
400 // implicit null check is used in compiled code. | |
401 // The narrow_oop_base could be NULL or be the address | |
402 // of the page below heap depending on compressed oops mode. | |
403 } else | |
404 derived_oop_fn(base_loc, derived_loc); | |
0 | 405 } |
406 oms.next(); | |
407 } while (!oms.is_done()); | |
408 } | |
409 } | |
410 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
411 // We want coop, value and oop oop_types |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
412 int mask = OopMapValue::oop_value | OopMapValue::value_value | OopMapValue::narrowoop_value; |
0 | 413 { |
414 for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) { | |
415 omv = oms.current(); | |
416 oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); | |
417 if ( loc != NULL ) { | |
418 if ( omv.type() == OopMapValue::oop_value ) { | |
858 | 419 oop val = *loc; |
420 if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { | |
421 // Ignore NULL oops and decoded NULL narrow oops which | |
422 // equal to Universe::narrow_oop_base when a narrow oop | |
423 // implicit null check is used in compiled code. | |
424 // The narrow_oop_base could be NULL or be the address | |
425 // of the page below heap depending on compressed oops mode. | |
426 continue; | |
427 } | |
0 | 428 #ifdef ASSERT |
244
524eca34ea76
6684714: Optimize EA Connection Graph build performance
kvn
parents:
113
diff
changeset
|
429 if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
430 !Universe::heap()->is_in_or_null(*loc)) { |
0 | 431 tty->print_cr("# Found non oop pointer. Dumping state at failure"); |
432 // try to dump out some helpful debugging information | |
433 trace_codeblob_maps(fr, reg_map); | |
434 omv.print(); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
435 tty->print_cr("register r"); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
436 omv.reg()->print(); |
0 | 437 tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); |
438 // do the real assert. | |
439 assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); | |
440 } | |
441 #endif // ASSERT | |
442 oop_fn->do_oop(loc); | |
443 } else if ( omv.type() == OopMapValue::value_value ) { | |
858 | 444 assert((*loc) == (oop)NULL || !Universe::is_narrow_oop_base(*loc), |
445 "found invalid value pointer"); | |
0 | 446 value_fn->do_oop(loc); |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
447 } else if ( omv.type() == OopMapValue::narrowoop_value ) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
448 narrowOop *nl = (narrowOop*)loc; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
449 #ifndef VM_LITTLE_ENDIAN |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
450 if (!omv.reg()->is_stack()) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
451 // compressed oops in registers only take up 4 bytes of an |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
452 // 8 byte register but they are in the wrong part of the |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
453 // word so adjust loc to point at the right place. |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
454 nl = (narrowOop*)((address)nl + 4); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
455 } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
456 #endif |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
457 oop_fn->do_oop(nl); |
0 | 458 } |
459 } | |
460 } | |
461 } | |
462 } | |
463 | |
464 | |
465 // Update callee-saved register info for the following frame | |
466 void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) { | |
467 ResourceMark rm; | |
468 CodeBlob* cb = fr->cb(); | |
469 assert(cb != NULL, "no codeblob"); | |
470 | |
471 // Any reg might be saved by a safepoint handler (see generate_handler_blob). | |
472 const int max_saved_on_entry_reg_count = ConcreteRegisterImpl::number_of_registers; | |
473 assert( reg_map->_update_for_id == NULL || fr->is_older(reg_map->_update_for_id), | |
474 "already updated this map; do not 'update' it twice!" ); | |
475 debug_only(reg_map->_update_for_id = fr->id()); | |
476 | |
477 // Check if caller must update oop argument | |
478 assert((reg_map->include_argument_oops() || | |
479 !cb->caller_must_gc_arguments(reg_map->thread())), | |
480 "include_argument_oops should already be set"); | |
481 | |
482 int nof_callee = 0; | |
483 oop* locs[2*max_saved_on_entry_reg_count+1]; | |
484 VMReg regs[2*max_saved_on_entry_reg_count+1]; | |
485 // ("+1" because max_saved_on_entry_reg_count might be zero) | |
486 | |
487 // Scan through oopmap and find location of all callee-saved registers | |
488 // (we do not do update in place, since info could be overwritten) | |
489 | |
490 address pc = fr->pc(); | |
491 | |
492 OopMap* map = cb->oop_map_for_return_address(pc); | |
493 | |
494 assert(map != NULL, " no ptr map found"); | |
495 | |
496 OopMapValue omv; | |
497 for(OopMapStream oms(map,OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) { | |
498 omv = oms.current(); | |
499 assert(nof_callee < 2*max_saved_on_entry_reg_count, "overflow"); | |
500 regs[nof_callee] = omv.content_reg(); | |
501 locs[nof_callee] = fr->oopmapreg_to_location(omv.reg(),reg_map); | |
502 nof_callee++; | |
503 } | |
504 | |
505 // Check that runtime stubs save all callee-saved registers | |
506 #ifdef COMPILER2 | |
7125
1baf7f1e3f23
decoupled C++ Graal runtime from C1
Doug Simon <doug.simon@oracle.com>
parents:
7066
diff
changeset
|
507 assert(cb->is_compiled_by_c1() || cb->is_compiled_by_graal() || !cb->is_runtime_stub() || |
0 | 508 (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT), |
509 "must save all"); | |
510 #endif // COMPILER2 | |
511 | |
512 // Copy found callee-saved register to reg_map | |
513 for(int i = 0; i < nof_callee; i++) { | |
514 reg_map->set_location(regs[i], (address)locs[i]); | |
515 } | |
516 } | |
517 | |
518 //============================================================================= | |
519 // Non-Product code | |
520 | |
521 #ifndef PRODUCT | |
522 | |
523 bool OopMap::has_derived_pointer() const { | |
524 #ifndef TIERED | |
525 COMPILER1_PRESENT(return false); | |
7125
1baf7f1e3f23
decoupled C++ Graal runtime from C1
Doug Simon <doug.simon@oracle.com>
parents:
7066
diff
changeset
|
526 GRAAL_ONLY(return false); |
0 | 527 #endif // !TIERED |
528 #ifdef COMPILER2 | |
529 OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value); | |
530 return oms.is_done(); | |
531 #else | |
532 return false; | |
533 #endif // COMPILER2 | |
534 } | |
535 | |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
536 #endif //PRODUCT |
0 | 537 |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
538 // Printing code is present in product build for -XX:+PrintAssembly. |
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
539 |
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
540 static |
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
541 void print_register_type(OopMapValue::oop_types x, VMReg optional, |
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
542 outputStream* st) { |
0 | 543 switch( x ) { |
544 case OopMapValue::oop_value: | |
25
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
545 st->print("Oop"); |
0 | 546 break; |
547 case OopMapValue::value_value: | |
7636
a7114d3d712e
8005055: pass outputStream to more opto debug routines
kvn
parents:
6842
diff
changeset
|
548 st->print("Value"); |
0 | 549 break; |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
100
diff
changeset
|
550 case OopMapValue::narrowoop_value: |
7636
a7114d3d712e
8005055: pass outputStream to more opto debug routines
kvn
parents:
6842
diff
changeset
|
551 st->print("NarrowOop"); |
0 | 552 break; |
553 case OopMapValue::callee_saved_value: | |
7636
a7114d3d712e
8005055: pass outputStream to more opto debug routines
kvn
parents:
6842
diff
changeset
|
554 st->print("Callers_"); |
25
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
555 optional->print_on(st); |
0 | 556 break; |
557 case OopMapValue::derived_oop_value: | |
7636
a7114d3d712e
8005055: pass outputStream to more opto debug routines
kvn
parents:
6842
diff
changeset
|
558 st->print("Derived_oop_"); |
25
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
559 optional->print_on(st); |
0 | 560 break; |
561 default: | |
562 ShouldNotReachHere(); | |
563 } | |
564 } | |
565 | |
566 | |
25
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
567 void OopMapValue::print_on(outputStream* st) const { |
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
568 reg()->print_on(st); |
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
569 st->print("="); |
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
570 print_register_type(type(),content_reg(),st); |
c5cbd367e4d1
6621094: PrintOptoAssembly is broken for oops information in DebugInfo
kvn
parents:
0
diff
changeset
|
571 st->print(" "); |
0 | 572 } |
573 | |
574 | |
575 void OopMap::print_on(outputStream* st) const { | |
576 OopMapValue omv; | |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
577 st->print("OopMap{"); |
0 | 578 for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) { |
579 omv = oms.current(); | |
580 omv.print_on(st); | |
581 } | |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
582 st->print("off=%d}", (int) offset()); |
0 | 583 } |
584 | |
585 | |
586 void OopMapSet::print_on(outputStream* st) const { | |
587 int i, len = om_count(); | |
588 | |
589 st->print_cr("OopMapSet contains %d OopMaps\n",len); | |
590 | |
591 for( i = 0; i < len; i++) { | |
592 OopMap* m = at(i); | |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
593 st->print_cr("#%d ",i); |
0 | 594 m->print_on(st); |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
595 st->cr(); |
0 | 596 } |
597 } | |
100
c7c777385a15
6667042: PrintAssembly option does not work without special plugin
jrose
parents:
25
diff
changeset
|
598 |
0 | 599 |
600 | |
601 //------------------------------DerivedPointerTable--------------------------- | |
602 | |
603 #ifdef COMPILER2 | |
604 | |
6197 | 605 class DerivedPointerEntry : public CHeapObj<mtCompiler> { |
0 | 606 private: |
607 oop* _location; // Location of derived pointer (also pointing to the base) | |
608 intptr_t _offset; // Offset from base pointer | |
609 public: | |
610 DerivedPointerEntry(oop* location, intptr_t offset) { _location = location; _offset = offset; } | |
611 oop* location() { return _location; } | |
612 intptr_t offset() { return _offset; } | |
613 }; | |
614 | |
615 | |
616 GrowableArray<DerivedPointerEntry*>* DerivedPointerTable::_list = NULL; | |
617 bool DerivedPointerTable::_active = false; | |
618 | |
619 | |
620 void DerivedPointerTable::clear() { | |
621 // The first time, we create the list. Otherwise it should be | |
622 // empty. If not, then we have probably forgotton to call | |
623 // update_pointers after last GC/Scavenge. | |
624 assert (!_active, "should not be active"); | |
625 assert(_list == NULL || _list->length() == 0, "table not empty"); | |
626 if (_list == NULL) { | |
6197 | 627 _list = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray<DerivedPointerEntry*>(10, true); // Allocated on C heap |
0 | 628 } |
629 _active = true; | |
630 } | |
631 | |
632 | |
633 // Returns value of location as an int | |
634 intptr_t value_of_loc(oop *pointer) { return (intptr_t)(*pointer); } | |
635 | |
636 | |
637 void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) { | |
638 assert(Universe::heap()->is_in_or_null(*base_loc), "not an oop"); | |
639 assert(derived_loc != base_loc, "Base and derived in same location"); | |
640 if (_active) { | |
641 assert(*derived_loc != (oop)base_loc, "location already added"); | |
642 assert(_list != NULL, "list must exist"); | |
643 intptr_t offset = value_of_loc(derived_loc) - value_of_loc(base_loc); | |
3442
f7d55ea6ee56
7045514: SPARC assembly code for JSR 292 ricochet frames
never
parents:
1972
diff
changeset
|
644 // This assert is invalid because derived pointers can be |
f7d55ea6ee56
7045514: SPARC assembly code for JSR 292 ricochet frames
never
parents:
1972
diff
changeset
|
645 // arbitrarily far away from their base. |
f7d55ea6ee56
7045514: SPARC assembly code for JSR 292 ricochet frames
never
parents:
1972
diff
changeset
|
646 // assert(offset >= -1000000, "wrong derived pointer info"); |
0 | 647 |
648 if (TraceDerivedPointers) { | |
649 tty->print_cr( | |
650 "Add derived pointer@" INTPTR_FORMAT | |
651 " - Derived: " INTPTR_FORMAT | |
652 " Base: " INTPTR_FORMAT " (@" INTPTR_FORMAT ") (Offset: %d)", | |
653 derived_loc, (address)*derived_loc, (address)*base_loc, base_loc, offset | |
654 ); | |
655 } | |
656 // Set derived oop location to point to base. | |
657 *derived_loc = (oop)base_loc; | |
658 assert_lock_strong(DerivedPointerTableGC_lock); | |
659 DerivedPointerEntry *entry = new DerivedPointerEntry(derived_loc, offset); | |
660 _list->append(entry); | |
661 } | |
662 } | |
663 | |
664 | |
665 void DerivedPointerTable::update_pointers() { | |
666 assert(_list != NULL, "list must exist"); | |
667 for(int i = 0; i < _list->length(); i++) { | |
668 DerivedPointerEntry* entry = _list->at(i); | |
669 oop* derived_loc = entry->location(); | |
670 intptr_t offset = entry->offset(); | |
671 // The derived oop was setup to point to location of base | |
672 oop base = **(oop**)derived_loc; | |
673 assert(Universe::heap()->is_in_or_null(base), "must be an oop"); | |
674 | |
675 *derived_loc = (oop)(((address)base) + offset); | |
676 assert(value_of_loc(derived_loc) - value_of_loc(&base) == offset, "sanity check"); | |
677 | |
678 if (TraceDerivedPointers) { | |
679 tty->print_cr("Updating derived pointer@" INTPTR_FORMAT | |
680 " - Derived: " INTPTR_FORMAT " Base: " INTPTR_FORMAT " (Offset: %d)", | |
681 derived_loc, (address)*derived_loc, (address)base, offset); | |
682 } | |
683 | |
684 // Delete entry | |
685 delete entry; | |
686 _list->at_put(i, NULL); | |
687 } | |
688 // Clear list, so it is ready for next traversal (this is an invariant) | |
689 if (TraceDerivedPointers && !_list->is_empty()) { | |
690 tty->print_cr("--------------------------"); | |
691 } | |
692 _list->clear(); | |
693 _active = false; | |
694 } | |
695 | |
696 #endif // COMPILER2 |