1 | /* |
2 | * Copyright (c) 2014, 2019, 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 "aot/aotLoader.hpp" |
27 | #include "classfile/classLoaderDataGraph.hpp" |
28 | #include "classfile/stringTable.hpp" |
29 | #include "gc/shared/strongRootsScope.hpp" |
30 | #include "jfr/leakprofiler/utilities/unifiedOop.hpp" |
31 | #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" |
32 | #include "memory/iterator.hpp" |
33 | #include "memory/universe.hpp" |
34 | #include "oops/klass.hpp" |
35 | #include "oops/markOop.hpp" |
36 | #include "oops/oop.hpp" |
37 | #include "prims/jvmtiThreadState.hpp" |
38 | #include "runtime/frame.inline.hpp" |
39 | #include "runtime/mutexLocker.hpp" |
40 | #include "runtime/threadSMR.inline.hpp" |
41 | #include "runtime/vframe_hp.hpp" |
42 | #include "services/management.hpp" |
43 | #include "utilities/growableArray.hpp" |
44 | #if INCLUDE_JVMCI |
45 | #include "jvmci/jvmci.hpp" |
46 | #endif |
47 | |
48 | class ReferenceLocateClosure : public OopClosure { |
49 | protected: |
50 | RootCallback& _callback; |
51 | RootCallbackInfo _info; |
52 | bool _complete; |
53 | |
54 | void do_oop_shared(const void* ref); |
55 | |
56 | public: |
57 | ReferenceLocateClosure(RootCallback& callback, |
58 | OldObjectRoot::System system, |
59 | OldObjectRoot::Type type, |
60 | const void* context) : _callback(callback), |
61 | _info(), |
62 | _complete(false) { |
63 | _info._high = NULL; |
64 | _info._low = NULL; |
65 | _info._system = system; |
66 | _info._type = type; |
67 | _info._context = context; |
68 | } |
69 | |
70 | virtual void do_oop(oop* ref); |
71 | virtual void do_oop(narrowOop* ref); |
72 | |
73 | bool complete() const { |
74 | return _complete; |
75 | } |
76 | }; |
77 | |
78 | void ReferenceLocateClosure::do_oop_shared(const void* ref) { |
79 | assert(ref != NULL, "invariant" ); |
80 | if (!_complete) { |
81 | _info._high = ref; |
82 | _complete = _callback.process(_info); |
83 | } |
84 | } |
85 | |
86 | void ReferenceLocateClosure::do_oop(oop* ref) { |
87 | do_oop_shared(ref); |
88 | } |
89 | |
90 | void ReferenceLocateClosure::do_oop(narrowOop* ref) { |
91 | do_oop_shared(ref); |
92 | } |
93 | |
94 | class ReferenceToRootClosure : public StackObj { |
95 | private: |
96 | RootCallback& _callback; |
97 | RootCallbackInfo _info; |
98 | bool _complete; |
99 | |
100 | bool do_cldg_roots(); |
101 | bool do_object_synchronizer_roots(); |
102 | bool do_universe_roots(); |
103 | bool do_jni_handle_roots(); |
104 | bool do_jvmti_roots(); |
105 | bool do_system_dictionary_roots(); |
106 | bool do_management_roots(); |
107 | bool do_string_table_roots(); |
108 | bool do_aot_loader_roots(); |
109 | JVMCI_ONLY(bool do_jvmci_roots();) |
110 | |
111 | bool do_roots(); |
112 | |
113 | public: |
114 | ReferenceToRootClosure(RootCallback& callback) : _callback(callback), |
115 | _info(), |
116 | _complete(false) { |
117 | _info._high = NULL; |
118 | _info._low = NULL; |
119 | _info._context = NULL; |
120 | _info._system = OldObjectRoot::_system_undetermined; |
121 | _info._type = OldObjectRoot::_type_undetermined; |
122 | |
123 | assert_locked_or_safepoint(Threads_lock); |
124 | do_roots(); |
125 | } |
126 | |
127 | bool complete() const { |
128 | return _complete; |
129 | } |
130 | }; |
131 | |
132 | bool ReferenceToRootClosure::do_cldg_roots() { |
133 | assert(!complete(), "invariant" ); |
134 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_class_loader_data, OldObjectRoot::_type_undetermined, NULL); |
135 | CLDToOopClosure cldt_closure(&rlc, ClassLoaderData::_claim_none); |
136 | ClassLoaderDataGraph::always_strong_cld_do(&cldt_closure); |
137 | return rlc.complete(); |
138 | } |
139 | |
140 | bool ReferenceToRootClosure::do_object_synchronizer_roots() { |
141 | assert(!complete(), "invariant" ); |
142 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_object_synchronizer, OldObjectRoot::_type_undetermined, NULL); |
143 | ObjectSynchronizer::oops_do(&rlc); |
144 | return rlc.complete(); |
145 | } |
146 | |
147 | bool ReferenceToRootClosure::do_universe_roots() { |
148 | assert(!complete(), "invariant" ); |
149 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_universe, OldObjectRoot::_type_undetermined, NULL); |
150 | Universe::oops_do(&rlc); |
151 | return rlc.complete(); |
152 | } |
153 | |
154 | bool ReferenceToRootClosure::do_jni_handle_roots() { |
155 | assert(!complete(), "invariant" ); |
156 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_global_jni_handles, OldObjectRoot::_global_jni_handle, NULL); |
157 | JNIHandles::oops_do(&rlc); |
158 | return rlc.complete(); |
159 | } |
160 | |
161 | bool ReferenceToRootClosure::do_jvmti_roots() { |
162 | assert(!complete(), "invariant" ); |
163 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_jvmti, OldObjectRoot::_global_jni_handle, NULL); |
164 | JvmtiExport::oops_do(&rlc); |
165 | return rlc.complete(); |
166 | } |
167 | |
168 | bool ReferenceToRootClosure::do_system_dictionary_roots() { |
169 | assert(!complete(), "invariant" ); |
170 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_system_dictionary, OldObjectRoot::_type_undetermined, NULL); |
171 | SystemDictionary::oops_do(&rlc); |
172 | return rlc.complete(); |
173 | } |
174 | |
175 | bool ReferenceToRootClosure::do_management_roots() { |
176 | assert(!complete(), "invariant" ); |
177 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_management, OldObjectRoot::_type_undetermined, NULL); |
178 | Management::oops_do(&rlc); |
179 | return rlc.complete(); |
180 | } |
181 | |
182 | bool ReferenceToRootClosure::do_string_table_roots() { |
183 | assert(!complete(), "invariant" ); |
184 | ReferenceLocateClosure rlc(_callback, OldObjectRoot::_string_table, OldObjectRoot::_type_undetermined, NULL); |
185 | StringTable::oops_do(&rlc); |
186 | return rlc.complete(); |
187 | } |
188 | |
189 | bool ReferenceToRootClosure::do_aot_loader_roots() { |
190 | assert(!complete(), "invariant" ); |
191 | ReferenceLocateClosure rcl(_callback, OldObjectRoot::_aot, OldObjectRoot::_type_undetermined, NULL); |
192 | AOTLoader::oops_do(&rcl); |
193 | return rcl.complete(); |
194 | } |
195 | |
196 | #if INCLUDE_JVMCI |
197 | bool ReferenceToRootClosure::do_jvmci_roots() { |
198 | assert(!complete(), "invariant" ); |
199 | ReferenceLocateClosure rcl(_callback, OldObjectRoot::_jvmci, OldObjectRoot::_type_undetermined, NULL); |
200 | JVMCI::oops_do(&rcl); |
201 | return rcl.complete(); |
202 | } |
203 | #endif |
204 | |
205 | bool ReferenceToRootClosure::do_roots() { |
206 | assert(!complete(), "invariant" ); |
207 | assert(OldObjectRoot::_system_undetermined == _info._system, "invariant" ); |
208 | assert(OldObjectRoot::_type_undetermined == _info._type, "invariant" ); |
209 | |
210 | if (do_cldg_roots()) { |
211 | _complete = true; |
212 | return true; |
213 | } |
214 | |
215 | if (do_object_synchronizer_roots()) { |
216 | _complete = true; |
217 | return true; |
218 | } |
219 | |
220 | if (do_universe_roots()) { |
221 | _complete = true; |
222 | return true; |
223 | } |
224 | |
225 | if (do_jni_handle_roots()) { |
226 | _complete = true; |
227 | return true; |
228 | } |
229 | |
230 | if (do_jvmti_roots()) { |
231 | _complete = true; |
232 | return true; |
233 | } |
234 | |
235 | if (do_system_dictionary_roots()) { |
236 | _complete = true; |
237 | return true; |
238 | } |
239 | |
240 | if (do_management_roots()) { |
241 | _complete = true; |
242 | return true; |
243 | } |
244 | |
245 | if (do_string_table_roots()) { |
246 | _complete = true; |
247 | return true; |
248 | } |
249 | |
250 | if (do_aot_loader_roots()) { |
251 | _complete = true; |
252 | return true; |
253 | } |
254 | |
255 | #if INCLUDE_JVMCI |
256 | if (do_jvmci_roots()) { |
257 | _complete = true; |
258 | return true; |
259 | } |
260 | #endif |
261 | |
262 | return false; |
263 | } |
264 | |
265 | class ReferenceToThreadRootClosure : public StackObj { |
266 | private: |
267 | RootCallback& _callback; |
268 | bool _complete; |
269 | |
270 | bool do_java_threads_oops(JavaThread* jt); |
271 | bool do_thread_roots(JavaThread* jt); |
272 | bool do_thread_stack_fast(JavaThread* jt); |
273 | bool do_thread_stack_detailed(JavaThread* jt); |
274 | bool do_thread_jni_handles(JavaThread* jt); |
275 | bool do_thread_handle_area(JavaThread* jt); |
276 | |
277 | public: |
278 | ReferenceToThreadRootClosure(RootCallback& callback) :_callback(callback), _complete(false) { |
279 | assert_locked_or_safepoint(Threads_lock); |
280 | for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { |
281 | if (do_thread_roots(jt)) { |
282 | return; |
283 | } |
284 | } |
285 | } |
286 | |
287 | bool complete() const { |
288 | return _complete; |
289 | } |
290 | }; |
291 | |
292 | bool ReferenceToThreadRootClosure::do_thread_handle_area(JavaThread* jt) { |
293 | assert(jt != NULL, "invariant" ); |
294 | assert(!complete(), "invariant" ); |
295 | ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_handle_area, jt); |
296 | jt->handle_area()->oops_do(&rcl); |
297 | return rcl.complete(); |
298 | } |
299 | |
300 | bool ReferenceToThreadRootClosure::do_thread_jni_handles(JavaThread* jt) { |
301 | assert(jt != NULL, "invariant" ); |
302 | assert(!complete(), "invariant" ); |
303 | |
304 | ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_local_jni_handle, jt); |
305 | jt->active_handles()->oops_do(&rcl); |
306 | return rcl.complete(); |
307 | } |
308 | |
309 | bool ReferenceToThreadRootClosure::do_thread_stack_fast(JavaThread* jt) { |
310 | assert(jt != NULL, "invariant" ); |
311 | assert(!complete(), "invariant" ); |
312 | |
313 | if (_callback.entries() == 0) { |
314 | _complete = true; |
315 | return true; |
316 | } |
317 | |
318 | RootCallbackInfo info; |
319 | info._high = NULL; |
320 | info._low = NULL; |
321 | info._context = jt; |
322 | info._system = OldObjectRoot::_threads; |
323 | info._type = OldObjectRoot::_stack_variable; |
324 | |
325 | for (int i = 0; i < _callback.entries(); ++i) { |
326 | const address adr = (address)_callback.at(i); |
327 | if (jt->is_in_usable_stack(adr)) { |
328 | info._high = adr; |
329 | _complete = _callback.process(info); |
330 | if (_complete) { |
331 | return true; |
332 | } |
333 | } |
334 | } |
335 | assert(!complete(), "invariant" ); |
336 | return false; |
337 | } |
338 | |
339 | bool ReferenceToThreadRootClosure::do_thread_stack_detailed(JavaThread* jt) { |
340 | assert(jt != NULL, "invariant" ); |
341 | assert(!complete(), "invariant" ); |
342 | |
343 | ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_stack_variable, jt); |
344 | |
345 | if (jt->has_last_Java_frame()) { |
346 | // traverse the registered growable array gc_array |
347 | // can't do this as it is not reachable from outside |
348 | |
349 | // Traverse the monitor chunks |
350 | MonitorChunk* chunk = jt->monitor_chunks(); |
351 | for (; chunk != NULL; chunk = chunk->next()) { |
352 | chunk->oops_do(&rcl); |
353 | } |
354 | |
355 | if (rcl.complete()) { |
356 | return true; |
357 | } |
358 | |
359 | // Traverse the execution stack |
360 | for (StackFrameStream fst(jt); !fst.is_done(); fst.next()) { |
361 | fst.current()->oops_do(&rcl, NULL, fst.register_map()); |
362 | } |
363 | |
364 | } // last java frame |
365 | |
366 | if (rcl.complete()) { |
367 | return true; |
368 | } |
369 | |
370 | GrowableArray<jvmtiDeferredLocalVariableSet*>* const list = jt->deferred_locals(); |
371 | if (list != NULL) { |
372 | for (int i = 0; i < list->length(); i++) { |
373 | list->at(i)->oops_do(&rcl); |
374 | } |
375 | } |
376 | |
377 | if (rcl.complete()) { |
378 | return true; |
379 | } |
380 | |
381 | // Traverse instance variables at the end since the GC may be moving things |
382 | // around using this function |
383 | /* |
384 | * // can't reach these oop* from the outside |
385 | f->do_oop((oop*) &_threadObj); |
386 | f->do_oop((oop*) &_vm_result); |
387 | f->do_oop((oop*) &_exception_oop); |
388 | f->do_oop((oop*) &_pending_async_exception); |
389 | */ |
390 | |
391 | JvmtiThreadState* const jvmti_thread_state = jt->jvmti_thread_state(); |
392 | if (jvmti_thread_state != NULL) { |
393 | jvmti_thread_state->oops_do(&rcl); |
394 | } |
395 | |
396 | return rcl.complete(); |
397 | } |
398 | |
399 | bool ReferenceToThreadRootClosure::do_java_threads_oops(JavaThread* jt) { |
400 | assert(jt != NULL, "invariant" ); |
401 | assert(!complete(), "invariant" ); |
402 | |
403 | ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_global_jni_handle, jt); |
404 | jt->oops_do(&rcl, NULL); |
405 | return rcl.complete(); |
406 | } |
407 | |
408 | bool ReferenceToThreadRootClosure::do_thread_roots(JavaThread* jt) { |
409 | assert(jt != NULL, "invariant" ); |
410 | |
411 | if (do_thread_stack_fast(jt)) { |
412 | _complete = true; |
413 | return true; |
414 | } |
415 | |
416 | if (do_thread_jni_handles(jt)) { |
417 | _complete = true; |
418 | return true; |
419 | } |
420 | |
421 | if (do_thread_handle_area(jt)) { |
422 | _complete = true; |
423 | return true; |
424 | } |
425 | |
426 | if (do_thread_stack_detailed(jt)) { |
427 | _complete = true; |
428 | return true; |
429 | } |
430 | |
431 | return false; |
432 | } |
433 | |
434 | class RootResolverMarkScope : public MarkScope { |
435 | }; |
436 | |
437 | void RootResolver::resolve(RootCallback& callback) { |
438 | RootResolverMarkScope mark_scope; |
439 | |
440 | // thread local roots |
441 | ReferenceToThreadRootClosure rtrc(callback); |
442 | if (rtrc.complete()) { |
443 | return; |
444 | } |
445 | // system global roots |
446 | ReferenceToRootClosure rrc(callback); |
447 | } |
448 | |