Mercurial > hg > truffle
comparison src/share/vm/runtime/sweeper.cpp @ 3384:f52ed367b66d
6996747: SIGSEGV in nmethod::cleanup_inline_caches / CompiledIC::verify
Reviewed-by: kvn, iveresov
author | never |
---|---|
date | Mon, 16 May 2011 22:16:44 -0700 |
parents | dbccacb79c63 |
children | dc7902820c9b cfdfbeac0a5b |
comparison
equal
deleted
inserted
replaced
3383:38569792a45a | 3384:f52ed367b66d |
---|---|
35 #include "runtime/sweeper.hpp" | 35 #include "runtime/sweeper.hpp" |
36 #include "runtime/vm_operations.hpp" | 36 #include "runtime/vm_operations.hpp" |
37 #include "utilities/events.hpp" | 37 #include "utilities/events.hpp" |
38 #include "utilities/xmlstream.hpp" | 38 #include "utilities/xmlstream.hpp" |
39 | 39 |
40 #ifdef ASSERT | |
41 | |
42 #define SWEEP(nm) record_sweep(nm, __LINE__) | |
43 // Sweeper logging code | |
44 class SweeperRecord { | |
45 public: | |
46 int traversal; | |
47 int invocation; | |
48 int compile_id; | |
49 long traversal_mark; | |
50 int state; | |
51 const char* kind; | |
52 address vep; | |
53 address uep; | |
54 int line; | |
55 | |
56 void print() { | |
57 tty->print_cr("traversal = %d invocation = %d compile_id = %d %s uep = " PTR_FORMAT " vep = " | |
58 PTR_FORMAT " state = %d traversal_mark %d line = %d", | |
59 traversal, | |
60 invocation, | |
61 compile_id, | |
62 kind == NULL ? "" : kind, | |
63 uep, | |
64 vep, | |
65 state, | |
66 traversal_mark, | |
67 line); | |
68 } | |
69 }; | |
70 | |
71 static int _sweep_index = 0; | |
72 static SweeperRecord* _records = NULL; | |
73 | |
74 void NMethodSweeper::report_events(int id, address entry) { | |
75 if (_records != NULL) { | |
76 for (int i = _sweep_index; i < SweeperLogEntries; i++) { | |
77 if (_records[i].uep == entry || | |
78 _records[i].vep == entry || | |
79 _records[i].compile_id == id) { | |
80 _records[i].print(); | |
81 } | |
82 } | |
83 for (int i = 0; i < _sweep_index; i++) { | |
84 if (_records[i].uep == entry || | |
85 _records[i].vep == entry || | |
86 _records[i].compile_id == id) { | |
87 _records[i].print(); | |
88 } | |
89 } | |
90 } | |
91 } | |
92 | |
93 void NMethodSweeper::report_events() { | |
94 if (_records != NULL) { | |
95 for (int i = _sweep_index; i < SweeperLogEntries; i++) { | |
96 // skip empty records | |
97 if (_records[i].vep == NULL) continue; | |
98 _records[i].print(); | |
99 } | |
100 for (int i = 0; i < _sweep_index; i++) { | |
101 // skip empty records | |
102 if (_records[i].vep == NULL) continue; | |
103 _records[i].print(); | |
104 } | |
105 } | |
106 } | |
107 | |
108 void NMethodSweeper::record_sweep(nmethod* nm, int line) { | |
109 if (_records != NULL) { | |
110 _records[_sweep_index].traversal = _traversals; | |
111 _records[_sweep_index].traversal_mark = nm->_stack_traversal_mark; | |
112 _records[_sweep_index].invocation = _invocations; | |
113 _records[_sweep_index].compile_id = nm->compile_id(); | |
114 _records[_sweep_index].kind = nm->compile_kind(); | |
115 _records[_sweep_index].state = nm->_state; | |
116 _records[_sweep_index].vep = nm->verified_entry_point(); | |
117 _records[_sweep_index].uep = nm->entry_point(); | |
118 _records[_sweep_index].line = line; | |
119 | |
120 _sweep_index = (_sweep_index + 1) % SweeperLogEntries; | |
121 } | |
122 } | |
123 #else | |
124 #define SWEEP(nm) | |
125 #endif | |
126 | |
127 | |
40 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed | 128 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed |
41 nmethod* NMethodSweeper::_current = NULL; // Current nmethod | 129 nmethod* NMethodSweeper::_current = NULL; // Current nmethod |
42 int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache | 130 int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache |
43 | 131 |
44 volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass | 132 volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass |
135 // Only one thread at a time will sweep | 223 // Only one thread at a time will sweep |
136 jint old = Atomic::cmpxchg( 1, &_sweep_started, 0 ); | 224 jint old = Atomic::cmpxchg( 1, &_sweep_started, 0 ); |
137 if (old != 0) { | 225 if (old != 0) { |
138 return; | 226 return; |
139 } | 227 } |
228 #ifdef ASSERT | |
229 if (LogSweeper && _records == NULL) { | |
230 // Create the ring buffer for the logging code | |
231 _records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries); | |
232 memset(_records, 0, sizeof(SweeperRecord) * SweeperLogEntries); | |
233 } | |
234 #endif | |
140 if (_invocations > 0) { | 235 if (_invocations > 0) { |
141 sweep_code_cache(); | 236 sweep_code_cache(); |
142 _invocations--; | 237 _invocations--; |
143 } | 238 } |
144 _sweep_started = 0; | 239 _sweep_started = 0; |
211 if (_invocations == 1) { | 306 if (_invocations == 1) { |
212 log_sweep("finished"); | 307 log_sweep("finished"); |
213 } | 308 } |
214 } | 309 } |
215 | 310 |
311 class NMethodMarker: public StackObj { | |
312 private: | |
313 CompilerThread* _thread; | |
314 public: | |
315 NMethodMarker(nmethod* nm) { | |
316 _thread = CompilerThread::current(); | |
317 _thread->set_scanned_nmethod(nm); | |
318 } | |
319 ~NMethodMarker() { | |
320 _thread->set_scanned_nmethod(NULL); | |
321 } | |
322 }; | |
323 | |
216 | 324 |
217 void NMethodSweeper::process_nmethod(nmethod *nm) { | 325 void NMethodSweeper::process_nmethod(nmethod *nm) { |
218 assert(!CodeCache_lock->owned_by_self(), "just checking"); | 326 assert(!CodeCache_lock->owned_by_self(), "just checking"); |
327 | |
328 // Make sure this nmethod doesn't get unloaded during the scan, | |
329 // since the locks acquired below might safepoint. | |
330 NMethodMarker nmm(nm); | |
331 | |
332 SWEEP(nm); | |
219 | 333 |
220 // Skip methods that are currently referenced by the VM | 334 // Skip methods that are currently referenced by the VM |
221 if (nm->is_locked_by_vm()) { | 335 if (nm->is_locked_by_vm()) { |
222 // But still remember to clean-up inline caches for alive nmethods | 336 // But still remember to clean-up inline caches for alive nmethods |
223 if (nm->is_alive()) { | 337 if (nm->is_alive()) { |
224 // Clean-up all inline caches that points to zombie/non-reentrant methods | 338 // Clean-up all inline caches that points to zombie/non-reentrant methods |
225 MutexLocker cl(CompiledIC_lock); | 339 MutexLocker cl(CompiledIC_lock); |
226 nm->cleanup_inline_caches(); | 340 nm->cleanup_inline_caches(); |
341 SWEEP(nm); | |
227 } else { | 342 } else { |
228 _locked_seen++; | 343 _locked_seen++; |
344 SWEEP(nm); | |
229 } | 345 } |
230 return; | 346 return; |
231 } | 347 } |
232 | 348 |
233 if (nm->is_zombie()) { | 349 if (nm->is_zombie()) { |
245 if (PrintMethodFlushing && Verbose) { | 361 if (PrintMethodFlushing && Verbose) { |
246 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); | 362 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); |
247 } | 363 } |
248 nm->mark_for_reclamation(); | 364 nm->mark_for_reclamation(); |
249 _rescan = true; | 365 _rescan = true; |
366 SWEEP(nm); | |
250 } | 367 } |
251 } else if (nm->is_not_entrant()) { | 368 } else if (nm->is_not_entrant()) { |
252 // If there is no current activations of this method on the | 369 // If there is no current activations of this method on the |
253 // stack we can safely convert it to a zombie method | 370 // stack we can safely convert it to a zombie method |
254 if (nm->can_not_entrant_be_converted()) { | 371 if (nm->can_not_entrant_be_converted()) { |
255 if (PrintMethodFlushing && Verbose) { | 372 if (PrintMethodFlushing && Verbose) { |
256 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); | 373 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); |
257 } | 374 } |
258 nm->make_zombie(); | 375 nm->make_zombie(); |
259 _rescan = true; | 376 _rescan = true; |
377 SWEEP(nm); | |
260 } else { | 378 } else { |
261 // Still alive, clean up its inline caches | 379 // Still alive, clean up its inline caches |
262 MutexLocker cl(CompiledIC_lock); | 380 MutexLocker cl(CompiledIC_lock); |
263 nm->cleanup_inline_caches(); | 381 nm->cleanup_inline_caches(); |
264 // we coudn't transition this nmethod so don't immediately | 382 // we coudn't transition this nmethod so don't immediately |
265 // request a rescan. If this method stays on the stack for a | 383 // request a rescan. If this method stays on the stack for a |
266 // long time we don't want to keep rescanning the code cache. | 384 // long time we don't want to keep rescanning the code cache. |
267 _not_entrant_seen_on_stack++; | 385 _not_entrant_seen_on_stack++; |
386 SWEEP(nm); | |
268 } | 387 } |
269 } else if (nm->is_unloaded()) { | 388 } else if (nm->is_unloaded()) { |
270 // Unloaded code, just make it a zombie | 389 // Unloaded code, just make it a zombie |
271 if (PrintMethodFlushing && Verbose) | 390 if (PrintMethodFlushing && Verbose) |
272 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); | 391 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); |
273 if (nm->is_osr_method()) { | 392 if (nm->is_osr_method()) { |
274 // No inline caches will ever point to osr methods, so we can just remove it | 393 // No inline caches will ever point to osr methods, so we can just remove it |
275 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); | 394 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
395 SWEEP(nm); | |
276 nm->flush(); | 396 nm->flush(); |
277 } else { | 397 } else { |
278 nm->make_zombie(); | 398 nm->make_zombie(); |
279 _rescan = true; | 399 _rescan = true; |
400 SWEEP(nm); | |
280 } | 401 } |
281 } else { | 402 } else { |
282 assert(nm->is_alive(), "should be alive"); | 403 assert(nm->is_alive(), "should be alive"); |
283 | 404 |
284 if (UseCodeCacheFlushing) { | 405 if (UseCodeCacheFlushing) { |
291 } | 412 } |
292 | 413 |
293 // Clean-up all inline caches that points to zombie/non-reentrant methods | 414 // Clean-up all inline caches that points to zombie/non-reentrant methods |
294 MutexLocker cl(CompiledIC_lock); | 415 MutexLocker cl(CompiledIC_lock); |
295 nm->cleanup_inline_caches(); | 416 nm->cleanup_inline_caches(); |
417 SWEEP(nm); | |
296 } | 418 } |
297 } | 419 } |
298 | 420 |
299 // Code cache unloading: when compilers notice the code cache is getting full, | 421 // Code cache unloading: when compilers notice the code cache is getting full, |
300 // they will call a vm op that comes here. This code attempts to speculatively | 422 // they will call a vm op that comes here. This code attempts to speculatively |