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) { |