File: | jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp |
Warning: | line 1047, column 5 Null pointer passed to 1st parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||||
2 | * Copyright (c) 2003, 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 "classfile/classLoaderDataGraph.hpp" | ||||||
27 | #include "classfile/javaClasses.hpp" | ||||||
28 | #include "classfile/moduleEntry.hpp" | ||||||
29 | #include "jvmtifiles/jvmtiEnv.hpp" | ||||||
30 | #include "memory/iterator.hpp" | ||||||
31 | #include "memory/resourceArea.hpp" | ||||||
32 | #include "oops/klass.inline.hpp" | ||||||
33 | #include "oops/objArrayKlass.hpp" | ||||||
34 | #include "oops/objArrayOop.hpp" | ||||||
35 | #include "oops/oop.inline.hpp" | ||||||
36 | #include "oops/oopHandle.inline.hpp" | ||||||
37 | #include "prims/jvmtiEnvBase.hpp" | ||||||
38 | #include "prims/jvmtiEventController.inline.hpp" | ||||||
39 | #include "prims/jvmtiExtensions.hpp" | ||||||
40 | #include "prims/jvmtiImpl.hpp" | ||||||
41 | #include "prims/jvmtiManageCapabilities.hpp" | ||||||
42 | #include "prims/jvmtiTagMap.hpp" | ||||||
43 | #include "prims/jvmtiThreadState.inline.hpp" | ||||||
44 | #include "runtime/deoptimization.hpp" | ||||||
45 | #include "runtime/frame.inline.hpp" | ||||||
46 | #include "runtime/handles.inline.hpp" | ||||||
47 | #include "runtime/interfaceSupport.inline.hpp" | ||||||
48 | #include "runtime/jfieldIDWorkaround.hpp" | ||||||
49 | #include "runtime/jniHandles.inline.hpp" | ||||||
50 | #include "runtime/objectMonitor.inline.hpp" | ||||||
51 | #include "runtime/osThread.hpp" | ||||||
52 | #include "runtime/signature.hpp" | ||||||
53 | #include "runtime/thread.inline.hpp" | ||||||
54 | #include "runtime/threadSMR.hpp" | ||||||
55 | #include "runtime/vframe.inline.hpp" | ||||||
56 | #include "runtime/vframe_hp.hpp" | ||||||
57 | #include "runtime/vmThread.hpp" | ||||||
58 | #include "runtime/vmOperations.hpp" | ||||||
59 | |||||||
60 | |||||||
61 | /////////////////////////////////////////////////////////////// | ||||||
62 | // | ||||||
63 | // JvmtiEnvBase | ||||||
64 | // | ||||||
65 | |||||||
66 | JvmtiEnvBase* JvmtiEnvBase::_head_environment = NULL__null; | ||||||
67 | |||||||
68 | bool JvmtiEnvBase::_globally_initialized = false; | ||||||
69 | volatile bool JvmtiEnvBase::_needs_clean_up = false; | ||||||
70 | |||||||
71 | jvmtiPhase JvmtiEnvBase::_phase = JVMTI_PHASE_PRIMORDIAL; | ||||||
72 | |||||||
73 | volatile int JvmtiEnvBase::_dying_thread_env_iteration_count = 0; | ||||||
74 | |||||||
75 | extern jvmtiInterface_1_ jvmti_Interface; | ||||||
76 | extern jvmtiInterface_1_ jvmtiTrace_Interface; | ||||||
77 | |||||||
78 | |||||||
79 | // perform initializations that must occur before any JVMTI environments | ||||||
80 | // are released but which should only be initialized once (no matter | ||||||
81 | // how many environments are created). | ||||||
82 | void | ||||||
83 | JvmtiEnvBase::globally_initialize() { | ||||||
84 | assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check")do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 84, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
85 | assert(_globally_initialized == false, "bad call")do { if (!(_globally_initialized == false)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 85, "assert(" "_globally_initialized == false" ") failed", "bad call" ); ::breakpoint(); } } while (0); | ||||||
86 | |||||||
87 | JvmtiManageCapabilities::initialize(); | ||||||
88 | |||||||
89 | // register extension functions and events | ||||||
90 | JvmtiExtensions::register_extensions(); | ||||||
91 | |||||||
92 | #ifdef JVMTI_TRACE | ||||||
93 | JvmtiTrace::initialize(); | ||||||
94 | #endif | ||||||
95 | |||||||
96 | _globally_initialized = true; | ||||||
97 | } | ||||||
98 | |||||||
99 | |||||||
100 | void | ||||||
101 | JvmtiEnvBase::initialize() { | ||||||
102 | assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check")do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 102, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
103 | |||||||
104 | // Add this environment to the end of the environment list (order is important) | ||||||
105 | { | ||||||
106 | // This block of code must not contain any safepoints, as list deallocation | ||||||
107 | // (which occurs at a safepoint) cannot occur simultaneously with this list | ||||||
108 | // addition. Note: NoSafepointVerifier cannot, currently, be used before | ||||||
109 | // threads exist. | ||||||
110 | JvmtiEnvIterator it; | ||||||
111 | JvmtiEnvBase *previous_env = NULL__null; | ||||||
112 | for (JvmtiEnvBase* env = it.first(); env != NULL__null; env = it.next(env)) { | ||||||
113 | previous_env = env; | ||||||
114 | } | ||||||
115 | if (previous_env == NULL__null) { | ||||||
116 | _head_environment = this; | ||||||
117 | } else { | ||||||
118 | previous_env->set_next_environment(this); | ||||||
119 | } | ||||||
120 | } | ||||||
121 | |||||||
122 | if (_globally_initialized == false) { | ||||||
123 | globally_initialize(); | ||||||
124 | } | ||||||
125 | } | ||||||
126 | |||||||
127 | jvmtiPhase | ||||||
128 | JvmtiEnvBase::phase() { | ||||||
129 | // For the JVMTI environments possessed the can_generate_early_vmstart: | ||||||
130 | // replace JVMTI_PHASE_PRIMORDIAL with JVMTI_PHASE_START | ||||||
131 | if (_phase == JVMTI_PHASE_PRIMORDIAL && | ||||||
132 | JvmtiExport::early_vmstart_recorded() && | ||||||
133 | early_vmstart_env()) { | ||||||
134 | return JVMTI_PHASE_START; | ||||||
135 | } | ||||||
136 | return _phase; // Normal case | ||||||
137 | } | ||||||
138 | |||||||
139 | bool | ||||||
140 | JvmtiEnvBase::is_valid() { | ||||||
141 | jint value = 0; | ||||||
142 | |||||||
143 | // This object might not be a JvmtiEnvBase so we can't assume | ||||||
144 | // the _magic field is properly aligned. Get the value in a safe | ||||||
145 | // way and then check against JVMTI_MAGIC. | ||||||
146 | |||||||
147 | switch (sizeof(_magic)) { | ||||||
148 | case 2: | ||||||
149 | value = Bytes::get_native_u2((address)&_magic); | ||||||
150 | break; | ||||||
151 | |||||||
152 | case 4: | ||||||
153 | value = Bytes::get_native_u4((address)&_magic); | ||||||
154 | break; | ||||||
155 | |||||||
156 | case 8: | ||||||
157 | value = Bytes::get_native_u8((address)&_magic); | ||||||
158 | break; | ||||||
159 | |||||||
160 | default: | ||||||
161 | guarantee(false, "_magic field is an unexpected size")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 161, "guarantee(" "false" ") failed", "_magic field is an unexpected size" ); ::breakpoint(); } } while (0); | ||||||
162 | } | ||||||
163 | |||||||
164 | return value == JVMTI_MAGIC; | ||||||
165 | } | ||||||
166 | |||||||
167 | |||||||
168 | bool | ||||||
169 | JvmtiEnvBase::use_version_1_0_semantics() { | ||||||
170 | int major, minor, micro; | ||||||
171 | |||||||
172 | JvmtiExport::decode_version_values(_version, &major, &minor, µ); | ||||||
173 | return major == 1 && minor == 0; // micro version doesn't matter here | ||||||
174 | } | ||||||
175 | |||||||
176 | |||||||
177 | bool | ||||||
178 | JvmtiEnvBase::use_version_1_1_semantics() { | ||||||
179 | int major, minor, micro; | ||||||
180 | |||||||
181 | JvmtiExport::decode_version_values(_version, &major, &minor, µ); | ||||||
182 | return major == 1 && minor == 1; // micro version doesn't matter here | ||||||
183 | } | ||||||
184 | |||||||
185 | bool | ||||||
186 | JvmtiEnvBase::use_version_1_2_semantics() { | ||||||
187 | int major, minor, micro; | ||||||
188 | |||||||
189 | JvmtiExport::decode_version_values(_version, &major, &minor, µ); | ||||||
190 | return major == 1 && minor == 2; // micro version doesn't matter here | ||||||
191 | } | ||||||
192 | |||||||
193 | |||||||
194 | JvmtiEnvBase::JvmtiEnvBase(jint version) : _env_event_enable() { | ||||||
195 | _version = version; | ||||||
196 | _env_local_storage = NULL__null; | ||||||
197 | _tag_map = NULL__null; | ||||||
198 | _native_method_prefix_count = 0; | ||||||
199 | _native_method_prefixes = NULL__null; | ||||||
200 | _next = NULL__null; | ||||||
201 | _class_file_load_hook_ever_enabled = false; | ||||||
202 | |||||||
203 | // Moot since ClassFileLoadHook not yet enabled. | ||||||
204 | // But "true" will give a more predictable ClassFileLoadHook behavior | ||||||
205 | // for environment creation during ClassFileLoadHook. | ||||||
206 | _is_retransformable = true; | ||||||
207 | |||||||
208 | // all callbacks initially NULL | ||||||
209 | memset(&_event_callbacks,0,sizeof(jvmtiEventCallbacks)); | ||||||
210 | |||||||
211 | // all capabilities initially off | ||||||
212 | memset(&_current_capabilities, 0, sizeof(_current_capabilities)); | ||||||
213 | |||||||
214 | // all prohibited capabilities initially off | ||||||
215 | memset(&_prohibited_capabilities, 0, sizeof(_prohibited_capabilities)); | ||||||
216 | |||||||
217 | _magic = JVMTI_MAGIC; | ||||||
218 | |||||||
219 | JvmtiEventController::env_initialize((JvmtiEnv*)this); | ||||||
220 | |||||||
221 | #ifdef JVMTI_TRACE | ||||||
222 | _jvmti_external.functions = TraceJVMTI != NULL__null ? &jvmtiTrace_Interface : &jvmti_Interface; | ||||||
223 | #else | ||||||
224 | _jvmti_external.functions = &jvmti_Interface; | ||||||
225 | #endif | ||||||
226 | } | ||||||
227 | |||||||
228 | |||||||
229 | void | ||||||
230 | JvmtiEnvBase::dispose() { | ||||||
231 | |||||||
232 | #ifdef JVMTI_TRACE | ||||||
233 | JvmtiTrace::shutdown(); | ||||||
234 | #endif | ||||||
235 | |||||||
236 | // Dispose of event info and let the event controller call us back | ||||||
237 | // in a locked state (env_dispose, below) | ||||||
238 | JvmtiEventController::env_dispose(this); | ||||||
239 | } | ||||||
240 | |||||||
241 | void | ||||||
242 | JvmtiEnvBase::env_dispose() { | ||||||
243 | assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check")do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 243, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
244 | |||||||
245 | // We have been entered with all events disabled on this environment. | ||||||
246 | // A race to re-enable events (by setting callbacks) is prevented by | ||||||
247 | // checking for a valid environment when setting callbacks (while | ||||||
248 | // holding the JvmtiThreadState_lock). | ||||||
249 | |||||||
250 | // Mark as invalid. | ||||||
251 | _magic = DISPOSED_MAGIC; | ||||||
252 | |||||||
253 | // Relinquish all capabilities. | ||||||
254 | jvmtiCapabilities *caps = get_capabilities(); | ||||||
255 | JvmtiManageCapabilities::relinquish_capabilities(caps, caps, caps); | ||||||
256 | |||||||
257 | // Same situation as with events (see above) | ||||||
258 | set_native_method_prefixes(0, NULL__null); | ||||||
259 | |||||||
260 | JvmtiTagMap* tag_map_to_clear = tag_map_acquire(); | ||||||
261 | // A tag map can be big, clear it now to save memory until | ||||||
262 | // the destructor runs. | ||||||
263 | if (tag_map_to_clear != NULL__null) { | ||||||
264 | tag_map_to_clear->clear(); | ||||||
265 | } | ||||||
266 | |||||||
267 | _needs_clean_up = true; | ||||||
268 | } | ||||||
269 | |||||||
270 | |||||||
271 | JvmtiEnvBase::~JvmtiEnvBase() { | ||||||
272 | assert(SafepointSynchronize::is_at_safepoint(), "sanity check")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 272, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "sanity check"); ::breakpoint(); } } while (0); | ||||||
273 | |||||||
274 | // There is a small window of time during which the tag map of a | ||||||
275 | // disposed environment could have been reallocated. | ||||||
276 | // Make sure it is gone. | ||||||
277 | JvmtiTagMap* tag_map_to_deallocate = _tag_map; | ||||||
278 | set_tag_map(NULL__null); | ||||||
279 | // A tag map can be big, deallocate it now | ||||||
280 | if (tag_map_to_deallocate != NULL__null) { | ||||||
281 | delete tag_map_to_deallocate; | ||||||
282 | } | ||||||
283 | |||||||
284 | _magic = BAD_MAGIC; | ||||||
285 | } | ||||||
286 | |||||||
287 | |||||||
288 | void | ||||||
289 | JvmtiEnvBase::periodic_clean_up() { | ||||||
290 | assert(SafepointSynchronize::is_at_safepoint(), "sanity check")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 290, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "sanity check"); ::breakpoint(); } } while (0); | ||||||
291 | |||||||
292 | // JvmtiEnvBase reference is saved in JvmtiEnvThreadState. So | ||||||
293 | // clean up JvmtiThreadState before deleting JvmtiEnv pointer. | ||||||
294 | JvmtiThreadState::periodic_clean_up(); | ||||||
295 | |||||||
296 | // Unlink all invalid environments from the list of environments | ||||||
297 | // and deallocate them | ||||||
298 | JvmtiEnvIterator it; | ||||||
299 | JvmtiEnvBase* previous_env = NULL__null; | ||||||
300 | JvmtiEnvBase* env = it.first(); | ||||||
301 | while (env != NULL__null) { | ||||||
302 | if (env->is_valid()) { | ||||||
303 | previous_env = env; | ||||||
304 | env = it.next(env); | ||||||
305 | } else { | ||||||
306 | // This one isn't valid, remove it from the list and deallocate it | ||||||
307 | JvmtiEnvBase* defunct_env = env; | ||||||
308 | env = it.next(env); | ||||||
309 | if (previous_env == NULL__null) { | ||||||
310 | _head_environment = env; | ||||||
311 | } else { | ||||||
312 | previous_env->set_next_environment(env); | ||||||
313 | } | ||||||
314 | delete defunct_env; | ||||||
315 | } | ||||||
316 | } | ||||||
317 | |||||||
318 | } | ||||||
319 | |||||||
320 | |||||||
321 | void | ||||||
322 | JvmtiEnvBase::check_for_periodic_clean_up() { | ||||||
323 | assert(SafepointSynchronize::is_at_safepoint(), "sanity check")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 323, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "sanity check"); ::breakpoint(); } } while (0); | ||||||
324 | |||||||
325 | class ThreadInsideIterationClosure: public ThreadClosure { | ||||||
326 | private: | ||||||
327 | bool _inside; | ||||||
328 | public: | ||||||
329 | ThreadInsideIterationClosure() : _inside(false) {}; | ||||||
330 | |||||||
331 | void do_thread(Thread* thread) { | ||||||
332 | _inside |= thread->is_inside_jvmti_env_iteration(); | ||||||
333 | } | ||||||
334 | |||||||
335 | bool is_inside_jvmti_env_iteration() { | ||||||
336 | return _inside; | ||||||
337 | } | ||||||
338 | }; | ||||||
339 | |||||||
340 | if (_needs_clean_up) { | ||||||
341 | // Check if we are currently iterating environment, | ||||||
342 | // deallocation should not occur if we are | ||||||
343 | ThreadInsideIterationClosure tiic; | ||||||
344 | Threads::threads_do(&tiic); | ||||||
345 | if (!tiic.is_inside_jvmti_env_iteration() && | ||||||
346 | !is_inside_dying_thread_env_iteration()) { | ||||||
347 | _needs_clean_up = false; | ||||||
348 | JvmtiEnvBase::periodic_clean_up(); | ||||||
349 | } | ||||||
350 | } | ||||||
351 | } | ||||||
352 | |||||||
353 | |||||||
354 | void | ||||||
355 | JvmtiEnvBase::record_first_time_class_file_load_hook_enabled() { | ||||||
356 | assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(),do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 357, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0) | ||||||
357 | "sanity check")do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 357, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
358 | |||||||
359 | if (!_class_file_load_hook_ever_enabled) { | ||||||
360 | _class_file_load_hook_ever_enabled = true; | ||||||
361 | |||||||
362 | if (get_capabilities()->can_retransform_classes) { | ||||||
363 | _is_retransformable = true; | ||||||
364 | } else { | ||||||
365 | _is_retransformable = false; | ||||||
366 | |||||||
367 | // cannot add retransform capability after ClassFileLoadHook has been enabled | ||||||
368 | get_prohibited_capabilities()->can_retransform_classes = 1; | ||||||
369 | } | ||||||
370 | } | ||||||
371 | } | ||||||
372 | |||||||
373 | |||||||
374 | void | ||||||
375 | JvmtiEnvBase::record_class_file_load_hook_enabled() { | ||||||
376 | if (!_class_file_load_hook_ever_enabled) { | ||||||
377 | if (Threads::number_of_threads() == 0) { | ||||||
378 | record_first_time_class_file_load_hook_enabled(); | ||||||
379 | } else { | ||||||
380 | MutexLocker mu(JvmtiThreadState_lock); | ||||||
381 | record_first_time_class_file_load_hook_enabled(); | ||||||
382 | } | ||||||
383 | } | ||||||
384 | } | ||||||
385 | |||||||
386 | |||||||
387 | jvmtiError | ||||||
388 | JvmtiEnvBase::set_native_method_prefixes(jint prefix_count, char** prefixes) { | ||||||
389 | assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(),do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 390, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0) | ||||||
390 | "sanity check")do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 390, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
391 | |||||||
392 | int old_prefix_count = get_native_method_prefix_count(); | ||||||
393 | char **old_prefixes = get_native_method_prefixes(); | ||||||
394 | |||||||
395 | // allocate and install the new prefixex | ||||||
396 | if (prefix_count == 0 || !is_valid()) { | ||||||
397 | _native_method_prefix_count = 0; | ||||||
398 | _native_method_prefixes = NULL__null; | ||||||
399 | } else { | ||||||
400 | // there are prefixes, allocate an array to hold them, and fill it | ||||||
401 | char** new_prefixes = (char**)os::malloc((prefix_count) * sizeof(char*), mtInternal); | ||||||
402 | if (new_prefixes == NULL__null) { | ||||||
403 | return JVMTI_ERROR_OUT_OF_MEMORY; | ||||||
404 | } | ||||||
405 | for (int i = 0; i < prefix_count; i++) { | ||||||
406 | char* prefix = prefixes[i]; | ||||||
407 | if (prefix == NULL__null) { | ||||||
408 | for (int j = 0; j < (i-1); j++) { | ||||||
409 | os::free(new_prefixes[j]); | ||||||
410 | } | ||||||
411 | os::free(new_prefixes); | ||||||
412 | return JVMTI_ERROR_NULL_POINTER; | ||||||
413 | } | ||||||
414 | prefix = os::strdup(prefixes[i]); | ||||||
415 | if (prefix == NULL__null) { | ||||||
416 | for (int j = 0; j < (i-1); j++) { | ||||||
417 | os::free(new_prefixes[j]); | ||||||
418 | } | ||||||
419 | os::free(new_prefixes); | ||||||
420 | return JVMTI_ERROR_OUT_OF_MEMORY; | ||||||
421 | } | ||||||
422 | new_prefixes[i] = prefix; | ||||||
423 | } | ||||||
424 | _native_method_prefix_count = prefix_count; | ||||||
425 | _native_method_prefixes = new_prefixes; | ||||||
426 | } | ||||||
427 | |||||||
428 | // now that we know the new prefixes have been successfully installed we can | ||||||
429 | // safely remove the old ones | ||||||
430 | if (old_prefix_count != 0) { | ||||||
431 | for (int i = 0; i < old_prefix_count; i++) { | ||||||
432 | os::free(old_prefixes[i]); | ||||||
433 | } | ||||||
434 | os::free(old_prefixes); | ||||||
435 | } | ||||||
436 | |||||||
437 | return JVMTI_ERROR_NONE; | ||||||
438 | } | ||||||
439 | |||||||
440 | |||||||
441 | // Collect all the prefixes which have been set in any JVM TI environments | ||||||
442 | // by the SetNativeMethodPrefix(es) functions. Be sure to maintain the | ||||||
443 | // order of environments and the order of prefixes within each environment. | ||||||
444 | // Return in a resource allocated array. | ||||||
445 | char** | ||||||
446 | JvmtiEnvBase::get_all_native_method_prefixes(int* count_ptr) { | ||||||
447 | assert(Threads::number_of_threads() == 0 ||do { if (!(Threads::number_of_threads() == 0 || SafepointSynchronize ::is_at_safepoint() || JvmtiThreadState_lock->is_locked()) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 450, "assert(" "Threads::number_of_threads() == 0 || SafepointSynchronize::is_at_safepoint() || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0) | ||||||
448 | SafepointSynchronize::is_at_safepoint() ||do { if (!(Threads::number_of_threads() == 0 || SafepointSynchronize ::is_at_safepoint() || JvmtiThreadState_lock->is_locked()) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 450, "assert(" "Threads::number_of_threads() == 0 || SafepointSynchronize::is_at_safepoint() || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0) | ||||||
449 | JvmtiThreadState_lock->is_locked(),do { if (!(Threads::number_of_threads() == 0 || SafepointSynchronize ::is_at_safepoint() || JvmtiThreadState_lock->is_locked()) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 450, "assert(" "Threads::number_of_threads() == 0 || SafepointSynchronize::is_at_safepoint() || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0) | ||||||
450 | "sanity check")do { if (!(Threads::number_of_threads() == 0 || SafepointSynchronize ::is_at_safepoint() || JvmtiThreadState_lock->is_locked()) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 450, "assert(" "Threads::number_of_threads() == 0 || SafepointSynchronize::is_at_safepoint() || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
451 | |||||||
452 | int total_count = 0; | ||||||
453 | GrowableArray<char*>* prefix_array =new GrowableArray<char*>(5); | ||||||
454 | |||||||
455 | JvmtiEnvIterator it; | ||||||
456 | for (JvmtiEnvBase* env = it.first(); env != NULL__null; env = it.next(env)) { | ||||||
457 | int prefix_count = env->get_native_method_prefix_count(); | ||||||
458 | char** prefixes = env->get_native_method_prefixes(); | ||||||
459 | for (int j = 0; j < prefix_count; j++) { | ||||||
460 | // retrieve a prefix and so that it is safe against asynchronous changes | ||||||
461 | // copy it into the resource area | ||||||
462 | char* prefix = prefixes[j]; | ||||||
463 | char* prefix_copy = NEW_RESOURCE_ARRAY(char, strlen(prefix)+1)(char*) resource_allocate_bytes((strlen(prefix)+1) * sizeof(char )); | ||||||
464 | strcpy(prefix_copy, prefix); | ||||||
465 | prefix_array->at_put_grow(total_count++, prefix_copy); | ||||||
466 | } | ||||||
467 | } | ||||||
468 | |||||||
469 | char** all_prefixes = NEW_RESOURCE_ARRAY(char*, total_count)(char**) resource_allocate_bytes((total_count) * sizeof(char* )); | ||||||
470 | char** p = all_prefixes; | ||||||
471 | for (int i = 0; i < total_count; ++i) { | ||||||
472 | *p++ = prefix_array->at(i); | ||||||
473 | } | ||||||
474 | *count_ptr = total_count; | ||||||
475 | return all_prefixes; | ||||||
476 | } | ||||||
477 | |||||||
478 | void | ||||||
479 | JvmtiEnvBase::set_event_callbacks(const jvmtiEventCallbacks* callbacks, | ||||||
480 | jint size_of_callbacks) { | ||||||
481 | assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check")do { if (!(Threads::number_of_threads() == 0 || JvmtiThreadState_lock ->is_locked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 481, "assert(" "Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | ||||||
482 | |||||||
483 | size_t byte_cnt = sizeof(jvmtiEventCallbacks); | ||||||
484 | |||||||
485 | // clear in either case to be sure we got any gap between sizes | ||||||
486 | memset(&_event_callbacks, 0, byte_cnt); | ||||||
487 | |||||||
488 | // Now that JvmtiThreadState_lock is held, prevent a possible race condition where events | ||||||
489 | // are re-enabled by a call to set event callbacks where the DisposeEnvironment | ||||||
490 | // occurs after the boiler-plate environment check and before the lock is acquired. | ||||||
491 | if (callbacks != NULL__null && is_valid()) { | ||||||
492 | if (size_of_callbacks < (jint)byte_cnt) { | ||||||
493 | byte_cnt = size_of_callbacks; | ||||||
494 | } | ||||||
495 | memcpy(&_event_callbacks, callbacks, byte_cnt); | ||||||
496 | } | ||||||
497 | } | ||||||
498 | |||||||
499 | |||||||
500 | // In the fullness of time, all users of the method should instead | ||||||
501 | // directly use allocate, besides being cleaner and faster, this will | ||||||
502 | // mean much better out of memory handling | ||||||
503 | unsigned char * | ||||||
504 | JvmtiEnvBase::jvmtiMalloc(jlong size) { | ||||||
505 | unsigned char* mem = NULL__null; | ||||||
506 | jvmtiError result = allocate(size, &mem); | ||||||
507 | assert(result == JVMTI_ERROR_NONE, "Allocate failed")do { if (!(result == JVMTI_ERROR_NONE)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 507, "assert(" "result == JVMTI_ERROR_NONE" ") failed", "Allocate failed" ); ::breakpoint(); } } while (0); | ||||||
508 | return mem; | ||||||
509 | } | ||||||
510 | |||||||
511 | |||||||
512 | // Handle management | ||||||
513 | |||||||
514 | jobject JvmtiEnvBase::jni_reference(Handle hndl) { | ||||||
515 | return JNIHandles::make_local(hndl()); | ||||||
516 | } | ||||||
517 | |||||||
518 | jobject JvmtiEnvBase::jni_reference(JavaThread *thread, Handle hndl) { | ||||||
519 | return JNIHandles::make_local(thread, hndl()); | ||||||
520 | } | ||||||
521 | |||||||
522 | void JvmtiEnvBase::destroy_jni_reference(jobject jobj) { | ||||||
523 | JNIHandles::destroy_local(jobj); | ||||||
524 | } | ||||||
525 | |||||||
526 | void JvmtiEnvBase::destroy_jni_reference(JavaThread *thread, jobject jobj) { | ||||||
527 | JNIHandles::destroy_local(jobj); // thread is unused. | ||||||
528 | } | ||||||
529 | |||||||
530 | // | ||||||
531 | // Threads | ||||||
532 | // | ||||||
533 | |||||||
534 | jobject * | ||||||
535 | JvmtiEnvBase::new_jobjectArray(int length, Handle *handles) { | ||||||
536 | if (length == 0) { | ||||||
537 | return NULL__null; | ||||||
538 | } | ||||||
539 | |||||||
540 | jobject *objArray = (jobject *) jvmtiMalloc(sizeof(jobject) * length); | ||||||
541 | NULL_CHECK(objArray, NULL)if ((objArray) == __null) { return (__null); }; | ||||||
542 | |||||||
543 | for (int i=0; i<length; i++) { | ||||||
544 | objArray[i] = jni_reference(handles[i]); | ||||||
545 | } | ||||||
546 | return objArray; | ||||||
547 | } | ||||||
548 | |||||||
549 | jthread * | ||||||
550 | JvmtiEnvBase::new_jthreadArray(int length, Handle *handles) { | ||||||
551 | return (jthread *) new_jobjectArray(length,handles); | ||||||
552 | } | ||||||
553 | |||||||
554 | jthreadGroup * | ||||||
555 | JvmtiEnvBase::new_jthreadGroupArray(int length, Handle *handles) { | ||||||
556 | return (jthreadGroup *) new_jobjectArray(length,handles); | ||||||
557 | } | ||||||
558 | |||||||
559 | // return the vframe on the specified thread and depth, NULL if no such frame | ||||||
560 | // The thread and the oops in the returned vframe might not have been process. | ||||||
561 | vframe* | ||||||
562 | JvmtiEnvBase::vframeForNoProcess(JavaThread* java_thread, jint depth) { | ||||||
563 | if (!java_thread->has_last_Java_frame()) { | ||||||
564 | return NULL__null; | ||||||
565 | } | ||||||
566 | RegisterMap reg_map(java_thread, true /* update_map */, false /* process_frames */); | ||||||
567 | vframe *vf = java_thread->last_java_vframe(®_map); | ||||||
568 | int d = 0; | ||||||
569 | while ((vf != NULL__null) && (d < depth)) { | ||||||
570 | vf = vf->java_sender(); | ||||||
571 | d++; | ||||||
572 | } | ||||||
573 | return vf; | ||||||
574 | } | ||||||
575 | |||||||
576 | |||||||
577 | // | ||||||
578 | // utilities: JNI objects | ||||||
579 | // | ||||||
580 | |||||||
581 | |||||||
582 | jclass | ||||||
583 | JvmtiEnvBase::get_jni_class_non_null(Klass* k) { | ||||||
584 | assert(k != NULL, "k != NULL")do { if (!(k != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 584, "assert(" "k != __null" ") failed", "k != NULL"); ::breakpoint (); } } while (0); | ||||||
585 | Thread *thread = Thread::current(); | ||||||
586 | return (jclass)jni_reference(Handle(thread, k->java_mirror())); | ||||||
587 | } | ||||||
588 | |||||||
589 | // | ||||||
590 | // Field Information | ||||||
591 | // | ||||||
592 | |||||||
593 | bool | ||||||
594 | JvmtiEnvBase::get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd) { | ||||||
595 | if (!jfieldIDWorkaround::is_valid_jfieldID(k, field)) { | ||||||
596 | return false; | ||||||
597 | } | ||||||
598 | bool found = false; | ||||||
599 | if (jfieldIDWorkaround::is_static_jfieldID(field)) { | ||||||
600 | JNIid* id = jfieldIDWorkaround::from_static_jfieldID(field); | ||||||
601 | found = id->find_local_field(fd); | ||||||
602 | } else { | ||||||
603 | // Non-static field. The fieldID is really the offset of the field within the object. | ||||||
604 | int offset = jfieldIDWorkaround::from_instance_jfieldID(k, field); | ||||||
605 | found = InstanceKlass::cast(k)->find_field_from_offset(offset, false, fd); | ||||||
606 | } | ||||||
607 | return found; | ||||||
608 | } | ||||||
609 | |||||||
610 | // | ||||||
611 | // Object Monitor Information | ||||||
612 | // | ||||||
613 | |||||||
614 | // | ||||||
615 | // Count the number of objects for a lightweight monitor. The hobj | ||||||
616 | // parameter is object that owns the monitor so this routine will | ||||||
617 | // count the number of times the same object was locked by frames | ||||||
618 | // in java_thread. | ||||||
619 | // | ||||||
620 | jint | ||||||
621 | JvmtiEnvBase::count_locked_objects(JavaThread *java_thread, Handle hobj) { | ||||||
622 | jint ret = 0; | ||||||
623 | if (!java_thread->has_last_Java_frame()) { | ||||||
624 | return ret; // no Java frames so no monitors | ||||||
625 | } | ||||||
626 | |||||||
627 | Thread* current_thread = Thread::current(); | ||||||
628 | ResourceMark rm(current_thread); | ||||||
629 | HandleMark hm(current_thread); | ||||||
630 | RegisterMap reg_map(java_thread); | ||||||
631 | |||||||
632 | for(javaVFrame *jvf=java_thread->last_java_vframe(®_map); jvf != NULL__null; | ||||||
633 | jvf = jvf->java_sender()) { | ||||||
634 | GrowableArray<MonitorInfo*>* mons = jvf->monitors(); | ||||||
635 | if (!mons->is_empty()) { | ||||||
636 | for (int i = 0; i < mons->length(); i++) { | ||||||
637 | MonitorInfo *mi = mons->at(i); | ||||||
638 | if (mi->owner_is_scalar_replaced()) continue; | ||||||
639 | |||||||
640 | // see if owner of the monitor is our object | ||||||
641 | if (mi->owner() != NULL__null && mi->owner() == hobj()) { | ||||||
642 | ret++; | ||||||
643 | } | ||||||
644 | } | ||||||
645 | } | ||||||
646 | } | ||||||
647 | return ret; | ||||||
648 | } | ||||||
649 | |||||||
650 | |||||||
651 | |||||||
652 | jvmtiError | ||||||
653 | JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThread *java_thread, jobject *monitor_ptr) { | ||||||
654 | Thread *current_thread = Thread::current(); | ||||||
655 | assert(java_thread->is_handshake_safe_for(current_thread),do { if (!(java_thread->is_handshake_safe_for(current_thread ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 656, "assert(" "java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself or at handshake"); ::breakpoint( ); } } while (0) | ||||||
656 | "call by myself or at handshake")do { if (!(java_thread->is_handshake_safe_for(current_thread ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 656, "assert(" "java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself or at handshake"); ::breakpoint( ); } } while (0); | ||||||
657 | oop obj = NULL__null; | ||||||
658 | // The ObjectMonitor* can't be async deflated since we are either | ||||||
659 | // at a safepoint or the calling thread is operating on itself so | ||||||
660 | // it cannot leave the underlying wait()/enter() call. | ||||||
661 | ObjectMonitor *mon = java_thread->current_waiting_monitor(); | ||||||
662 | if (mon == NULL__null) { | ||||||
663 | // thread is not doing an Object.wait() call | ||||||
664 | mon = java_thread->current_pending_monitor(); | ||||||
665 | if (mon != NULL__null) { | ||||||
666 | // The thread is trying to enter() an ObjectMonitor. | ||||||
667 | obj = mon->object(); | ||||||
668 | assert(obj != NULL, "ObjectMonitor should have a valid object!")do { if (!(obj != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 668, "assert(" "obj != __null" ") failed", "ObjectMonitor should have a valid object!" ); ::breakpoint(); } } while (0); | ||||||
669 | } | ||||||
670 | // implied else: no contended ObjectMonitor | ||||||
671 | } else { | ||||||
672 | // thread is doing an Object.wait() call | ||||||
673 | obj = mon->object(); | ||||||
674 | assert(obj != NULL, "Object.wait() should have an object")do { if (!(obj != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 674, "assert(" "obj != __null" ") failed", "Object.wait() should have an object" ); ::breakpoint(); } } while (0); | ||||||
675 | } | ||||||
676 | |||||||
677 | if (obj == NULL__null) { | ||||||
678 | *monitor_ptr = NULL__null; | ||||||
679 | } else { | ||||||
680 | HandleMark hm(current_thread); | ||||||
681 | Handle hobj(current_thread, obj); | ||||||
682 | *monitor_ptr = jni_reference(calling_thread, hobj); | ||||||
683 | } | ||||||
684 | return JVMTI_ERROR_NONE; | ||||||
685 | } | ||||||
686 | |||||||
687 | |||||||
688 | jvmtiError | ||||||
689 | JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_thread, | ||||||
690 | GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) { | ||||||
691 | // Note: | ||||||
692 | // calling_thread is the thread that requested the list of monitors for java_thread. | ||||||
693 | // java_thread is the thread owning the monitors. | ||||||
694 | // current_thread is the thread executing this code, can be a non-JavaThread (e.g. VM Thread). | ||||||
695 | // And they all may be different threads. | ||||||
696 | jvmtiError err = JVMTI_ERROR_NONE; | ||||||
697 | Thread *current_thread = Thread::current(); | ||||||
698 | assert(java_thread->is_handshake_safe_for(current_thread),do { if (!(java_thread->is_handshake_safe_for(current_thread ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 699, "assert(" "java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself or at handshake"); ::breakpoint( ); } } while (0) | ||||||
699 | "call by myself or at handshake")do { if (!(java_thread->is_handshake_safe_for(current_thread ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 699, "assert(" "java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself or at handshake"); ::breakpoint( ); } } while (0); | ||||||
700 | |||||||
701 | if (java_thread->has_last_Java_frame()) { | ||||||
702 | ResourceMark rm(current_thread); | ||||||
703 | HandleMark hm(current_thread); | ||||||
704 | RegisterMap reg_map(java_thread); | ||||||
705 | |||||||
706 | int depth = 0; | ||||||
707 | for (javaVFrame *jvf = java_thread->last_java_vframe(®_map); jvf != NULL__null; | ||||||
708 | jvf = jvf->java_sender()) { | ||||||
709 | if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) { // check for stack too deep | ||||||
710 | // add locked objects for this frame into list | ||||||
711 | err = get_locked_objects_in_frame(calling_thread, java_thread, jvf, owned_monitors_list, depth-1); | ||||||
712 | if (err != JVMTI_ERROR_NONE) { | ||||||
713 | return err; | ||||||
714 | } | ||||||
715 | } | ||||||
716 | } | ||||||
717 | } | ||||||
718 | |||||||
719 | // Get off stack monitors. (e.g. acquired via jni MonitorEnter). | ||||||
720 | JvmtiMonitorClosure jmc(calling_thread, owned_monitors_list, this); | ||||||
721 | ObjectSynchronizer::monitors_iterate(&jmc, java_thread); | ||||||
722 | err = jmc.error(); | ||||||
723 | |||||||
724 | return err; | ||||||
725 | } | ||||||
726 | |||||||
727 | // Save JNI local handles for any objects that this frame owns. | ||||||
728 | jvmtiError | ||||||
729 | JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread* java_thread, | ||||||
730 | javaVFrame *jvf, GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitors_list, jint stack_depth) { | ||||||
731 | jvmtiError err = JVMTI_ERROR_NONE; | ||||||
732 | Thread* current_thread = Thread::current(); | ||||||
733 | ResourceMark rm(current_thread); | ||||||
734 | HandleMark hm(current_thread); | ||||||
735 | |||||||
736 | GrowableArray<MonitorInfo*>* mons = jvf->monitors(); | ||||||
737 | if (mons->is_empty()) { | ||||||
738 | return err; // this javaVFrame holds no monitors | ||||||
739 | } | ||||||
740 | |||||||
741 | oop wait_obj = NULL__null; | ||||||
742 | { | ||||||
743 | // The ObjectMonitor* can't be async deflated since we are either | ||||||
744 | // at a safepoint or the calling thread is operating on itself so | ||||||
745 | // it cannot leave the underlying wait() call. | ||||||
746 | // Save object of current wait() call (if any) for later comparison. | ||||||
747 | ObjectMonitor *mon = java_thread->current_waiting_monitor(); | ||||||
748 | if (mon != NULL__null) { | ||||||
749 | wait_obj = mon->object(); | ||||||
750 | } | ||||||
751 | } | ||||||
752 | oop pending_obj = NULL__null; | ||||||
753 | { | ||||||
754 | // The ObjectMonitor* can't be async deflated since we are either | ||||||
755 | // at a safepoint or the calling thread is operating on itself so | ||||||
756 | // it cannot leave the underlying enter() call. | ||||||
757 | // Save object of current enter() call (if any) for later comparison. | ||||||
758 | ObjectMonitor *mon = java_thread->current_pending_monitor(); | ||||||
759 | if (mon != NULL__null) { | ||||||
760 | pending_obj = mon->object(); | ||||||
761 | } | ||||||
762 | } | ||||||
763 | |||||||
764 | for (int i = 0; i < mons->length(); i++) { | ||||||
765 | MonitorInfo *mi = mons->at(i); | ||||||
766 | |||||||
767 | if (mi->owner_is_scalar_replaced()) continue; | ||||||
768 | |||||||
769 | oop obj = mi->owner(); | ||||||
770 | if (obj == NULL__null) { | ||||||
771 | // this monitor doesn't have an owning object so skip it | ||||||
772 | continue; | ||||||
773 | } | ||||||
774 | |||||||
775 | if (wait_obj == obj) { | ||||||
776 | // the thread is waiting on this monitor so it isn't really owned | ||||||
777 | continue; | ||||||
778 | } | ||||||
779 | |||||||
780 | if (pending_obj == obj) { | ||||||
781 | // the thread is pending on this monitor so it isn't really owned | ||||||
782 | continue; | ||||||
783 | } | ||||||
784 | |||||||
785 | if (owned_monitors_list->length() > 0) { | ||||||
786 | // Our list has at least one object on it so we have to check | ||||||
787 | // for recursive object locking | ||||||
788 | bool found = false; | ||||||
789 | for (int j = 0; j < owned_monitors_list->length(); j++) { | ||||||
790 | jobject jobj = ((jvmtiMonitorStackDepthInfo*)owned_monitors_list->at(j))->monitor; | ||||||
791 | oop check = JNIHandles::resolve(jobj); | ||||||
792 | if (check == obj) { | ||||||
793 | found = true; // we found the object | ||||||
794 | break; | ||||||
795 | } | ||||||
796 | } | ||||||
797 | |||||||
798 | if (found) { | ||||||
799 | // already have this object so don't include it | ||||||
800 | continue; | ||||||
801 | } | ||||||
802 | } | ||||||
803 | |||||||
804 | // add the owning object to our list | ||||||
805 | jvmtiMonitorStackDepthInfo *jmsdi; | ||||||
806 | err = allocate(sizeof(jvmtiMonitorStackDepthInfo), (unsigned char **)&jmsdi); | ||||||
807 | if (err != JVMTI_ERROR_NONE) { | ||||||
808 | return err; | ||||||
809 | } | ||||||
810 | Handle hobj(Thread::current(), obj); | ||||||
811 | jmsdi->monitor = jni_reference(calling_thread, hobj); | ||||||
812 | jmsdi->stack_depth = stack_depth; | ||||||
813 | owned_monitors_list->append(jmsdi); | ||||||
814 | } | ||||||
815 | |||||||
816 | return err; | ||||||
817 | } | ||||||
818 | |||||||
819 | jvmtiError | ||||||
820 | JvmtiEnvBase::get_stack_trace(JavaThread *java_thread, | ||||||
821 | jint start_depth, jint max_count, | ||||||
822 | jvmtiFrameInfo* frame_buffer, jint* count_ptr) { | ||||||
823 | #ifdef ASSERT1 | ||||||
824 | uint32_t debug_bits = 0; | ||||||
825 | #endif | ||||||
826 | Thread *current_thread = Thread::current(); | ||||||
827 | assert(SafepointSynchronize::is_at_safepoint() ||do { if (!(SafepointSynchronize::is_at_safepoint() || java_thread ->is_handshake_safe_for(current_thread))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 829, "assert(" "SafepointSynchronize::is_at_safepoint() || java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself / at safepoint / at handshake"); ::breakpoint(); } } while (0) | ||||||
828 | java_thread->is_handshake_safe_for(current_thread),do { if (!(SafepointSynchronize::is_at_safepoint() || java_thread ->is_handshake_safe_for(current_thread))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 829, "assert(" "SafepointSynchronize::is_at_safepoint() || java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself / at safepoint / at handshake"); ::breakpoint(); } } while (0) | ||||||
829 | "call by myself / at safepoint / at handshake")do { if (!(SafepointSynchronize::is_at_safepoint() || java_thread ->is_handshake_safe_for(current_thread))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 829, "assert(" "SafepointSynchronize::is_at_safepoint() || java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself / at safepoint / at handshake"); ::breakpoint(); } } while (0); | ||||||
830 | int count = 0; | ||||||
831 | if (java_thread->has_last_Java_frame()) { | ||||||
832 | RegisterMap reg_map(java_thread, false /* update_map */, false /* process_frames */); | ||||||
833 | ResourceMark rm(current_thread); | ||||||
834 | javaVFrame *jvf = java_thread->last_java_vframe(®_map); | ||||||
835 | HandleMark hm(current_thread); | ||||||
836 | if (start_depth != 0) { | ||||||
837 | if (start_depth > 0) { | ||||||
838 | for (int j = 0; j < start_depth && jvf != NULL__null; j++) { | ||||||
839 | jvf = jvf->java_sender(); | ||||||
840 | } | ||||||
841 | if (jvf == NULL__null) { | ||||||
842 | // start_depth is deeper than the stack depth | ||||||
843 | return JVMTI_ERROR_ILLEGAL_ARGUMENT; | ||||||
844 | } | ||||||
845 | } else { // start_depth < 0 | ||||||
846 | // we are referencing the starting depth based on the oldest | ||||||
847 | // part of the stack. | ||||||
848 | // optimize to limit the number of times that java_sender() is called | ||||||
849 | javaVFrame *jvf_cursor = jvf; | ||||||
850 | javaVFrame *jvf_prev = NULL__null; | ||||||
851 | javaVFrame *jvf_prev_prev = NULL__null; | ||||||
852 | int j = 0; | ||||||
853 | while (jvf_cursor != NULL__null) { | ||||||
854 | jvf_prev_prev = jvf_prev; | ||||||
855 | jvf_prev = jvf_cursor; | ||||||
856 | for (j = 0; j > start_depth && jvf_cursor != NULL__null; j--) { | ||||||
857 | jvf_cursor = jvf_cursor->java_sender(); | ||||||
858 | } | ||||||
859 | } | ||||||
860 | if (j == start_depth) { | ||||||
861 | // previous pointer is exactly where we want to start | ||||||
862 | jvf = jvf_prev; | ||||||
863 | } else { | ||||||
864 | // we need to back up further to get to the right place | ||||||
865 | if (jvf_prev_prev == NULL__null) { | ||||||
866 | // the -start_depth is greater than the stack depth | ||||||
867 | return JVMTI_ERROR_ILLEGAL_ARGUMENT; | ||||||
868 | } | ||||||
869 | // j now is the number of frames on the stack starting with | ||||||
870 | // jvf_prev, we start from jvf_prev_prev and move older on | ||||||
871 | // the stack that many, the result is -start_depth frames | ||||||
872 | // remaining. | ||||||
873 | jvf = jvf_prev_prev; | ||||||
874 | for (; j < 0; j++) { | ||||||
875 | jvf = jvf->java_sender(); | ||||||
876 | } | ||||||
877 | } | ||||||
878 | } | ||||||
879 | } | ||||||
880 | for (; count < max_count && jvf != NULL__null; count++) { | ||||||
881 | frame_buffer[count].method = jvf->method()->jmethod_id(); | ||||||
882 | frame_buffer[count].location = (jvf->method()->is_native() ? -1 : jvf->bci()); | ||||||
883 | jvf = jvf->java_sender(); | ||||||
884 | } | ||||||
885 | } else { | ||||||
886 | if (start_depth != 0) { | ||||||
887 | // no frames and there is a starting depth | ||||||
888 | return JVMTI_ERROR_ILLEGAL_ARGUMENT; | ||||||
889 | } | ||||||
890 | } | ||||||
891 | *count_ptr = count; | ||||||
892 | return JVMTI_ERROR_NONE; | ||||||
893 | } | ||||||
894 | |||||||
895 | jvmtiError | ||||||
896 | JvmtiEnvBase::get_frame_count(JvmtiThreadState *state, jint *count_ptr) { | ||||||
897 | assert((state != NULL),do { if (!((state != __null))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 898, "assert(" "(state != __null)" ") failed", "JavaThread should create JvmtiThreadState before calling this method" ); ::breakpoint(); } } while (0) | ||||||
898 | "JavaThread should create JvmtiThreadState before calling this method")do { if (!((state != __null))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 898, "assert(" "(state != __null)" ") failed", "JavaThread should create JvmtiThreadState before calling this method" ); ::breakpoint(); } } while (0); | ||||||
899 | *count_ptr = state->count_frames(); | ||||||
900 | return JVMTI_ERROR_NONE; | ||||||
901 | } | ||||||
902 | |||||||
903 | jvmtiError | ||||||
904 | JvmtiEnvBase::get_frame_location(JavaThread *java_thread, jint depth, | ||||||
905 | jmethodID* method_ptr, jlocation* location_ptr) { | ||||||
906 | #ifdef ASSERT1 | ||||||
907 | uint32_t debug_bits = 0; | ||||||
908 | #endif | ||||||
909 | Thread* current_thread = Thread::current(); | ||||||
910 | assert(java_thread->is_handshake_safe_for(current_thread),do { if (!(java_thread->is_handshake_safe_for(current_thread ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 911, "assert(" "java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself or at handshake"); ::breakpoint( ); } } while (0) | ||||||
911 | "call by myself or at handshake")do { if (!(java_thread->is_handshake_safe_for(current_thread ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 911, "assert(" "java_thread->is_handshake_safe_for(current_thread)" ") failed", "call by myself or at handshake"); ::breakpoint( ); } } while (0); | ||||||
912 | ResourceMark rm(current_thread); | ||||||
913 | |||||||
914 | vframe *vf = vframeForNoProcess(java_thread, depth); | ||||||
915 | if (vf == NULL__null) { | ||||||
916 | return JVMTI_ERROR_NO_MORE_FRAMES; | ||||||
917 | } | ||||||
918 | |||||||
919 | // vframeFor should return a java frame. If it doesn't | ||||||
920 | // it means we've got an internal error and we return the | ||||||
921 | // error in product mode. In debug mode we will instead | ||||||
922 | // attempt to cast the vframe to a javaVFrame and will | ||||||
923 | // cause an assertion/crash to allow further diagnosis. | ||||||
924 | #ifdef PRODUCT | ||||||
925 | if (!vf->is_java_frame()) { | ||||||
926 | return JVMTI_ERROR_INTERNAL; | ||||||
927 | } | ||||||
928 | #endif | ||||||
929 | |||||||
930 | HandleMark hm(current_thread); | ||||||
931 | javaVFrame *jvf = javaVFrame::cast(vf); | ||||||
932 | Method* method = jvf->method(); | ||||||
933 | if (method->is_native()) { | ||||||
934 | *location_ptr = -1; | ||||||
935 | } else { | ||||||
936 | *location_ptr = jvf->bci(); | ||||||
937 | } | ||||||
938 | *method_ptr = method->jmethod_id(); | ||||||
939 | |||||||
940 | return JVMTI_ERROR_NONE; | ||||||
941 | } | ||||||
942 | |||||||
943 | |||||||
944 | jvmtiError | ||||||
945 | JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject object, jvmtiMonitorUsage* info_ptr) { | ||||||
946 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 946, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "must be at safepoint"); ::breakpoint(); } } while (0); | ||||||
| |||||||
947 | Thread* current_thread = VMThread::vm_thread(); | ||||||
948 | assert(current_thread == Thread::current(), "must be")do { if (!(current_thread == Thread::current())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 948, "assert(" "current_thread == Thread::current()" ") failed" , "must be"); ::breakpoint(); } } while (0); | ||||||
949 | |||||||
950 | HandleMark hm(current_thread); | ||||||
951 | Handle hobj; | ||||||
952 | |||||||
953 | // Check arguments | ||||||
954 | { | ||||||
955 | oop mirror = JNIHandles::resolve_external_guard(object); | ||||||
956 | NULL_CHECK(mirror, JVMTI_ERROR_INVALID_OBJECT)if ((mirror) == __null) { return (JVMTI_ERROR_INVALID_OBJECT) ; }; | ||||||
957 | NULL_CHECK(info_ptr, JVMTI_ERROR_NULL_POINTER)if ((info_ptr) == __null) { return (JVMTI_ERROR_NULL_POINTER) ; }; | ||||||
958 | |||||||
959 | hobj = Handle(current_thread, mirror); | ||||||
960 | } | ||||||
961 | |||||||
962 | ThreadsListHandle tlh(current_thread); | ||||||
963 | JavaThread *owning_thread = NULL__null; | ||||||
964 | ObjectMonitor *mon = NULL__null; | ||||||
965 | jvmtiMonitorUsage ret = { | ||||||
966 | NULL__null, 0, 0, NULL__null, 0, NULL__null | ||||||
967 | }; | ||||||
968 | |||||||
969 | uint32_t debug_bits = 0; | ||||||
970 | // first derive the object's owner and entry_count (if any) | ||||||
971 | { | ||||||
972 | address owner = NULL__null; | ||||||
973 | { | ||||||
974 | markWord mark = hobj()->mark(); | ||||||
975 | |||||||
976 | if (!mark.has_monitor()) { | ||||||
977 | // this object has a lightweight monitor | ||||||
978 | |||||||
979 | if (mark.has_locker()) { | ||||||
980 | owner = (address)mark.locker(); // save the address of the Lock word | ||||||
981 | } | ||||||
982 | // implied else: no owner | ||||||
983 | } else { | ||||||
984 | // this object has a heavyweight monitor | ||||||
985 | mon = mark.monitor(); | ||||||
986 | |||||||
987 | // The owner field of a heavyweight monitor may be NULL for no | ||||||
988 | // owner, a JavaThread * or it may still be the address of the | ||||||
989 | // Lock word in a JavaThread's stack. A monitor can be inflated | ||||||
990 | // by a non-owning JavaThread, but only the owning JavaThread | ||||||
991 | // can change the owner field from the Lock word to the | ||||||
992 | // JavaThread * and it may not have done that yet. | ||||||
993 | owner = (address)mon->owner(); | ||||||
994 | } | ||||||
995 | } | ||||||
996 | |||||||
997 | if (owner
| ||||||
998 | // This monitor is owned so we have to find the owning JavaThread. | ||||||
999 | owning_thread = Threads::owning_thread_from_monitor_owner(tlh.list(), owner); | ||||||
1000 | assert(owning_thread != NULL, "owning JavaThread must not be NULL")do { if (!(owning_thread != __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1000, "assert(" "owning_thread != __null" ") failed", "owning JavaThread must not be NULL" ); ::breakpoint(); } } while (0); | ||||||
1001 | Handle th(current_thread, owning_thread->threadObj()); | ||||||
1002 | ret.owner = (jthread)jni_reference(calling_thread, th); | ||||||
1003 | } | ||||||
1004 | |||||||
1005 | if (owning_thread
| ||||||
1006 | // The recursions field of a monitor does not reflect recursions | ||||||
1007 | // as lightweight locks before inflating the monitor are not included. | ||||||
1008 | // We have to count the number of recursive monitor entries the hard way. | ||||||
1009 | // We pass a handle to survive any GCs along the way. | ||||||
1010 | ret.entry_count = count_locked_objects(owning_thread, hobj); | ||||||
1011 | } | ||||||
1012 | // implied else: entry_count == 0 | ||||||
1013 | } | ||||||
1014 | |||||||
1015 | jint nWant = 0, nWait = 0; | ||||||
1016 | if (mon
| ||||||
1017 | // this object has a heavyweight monitor | ||||||
1018 | nWant = mon->contentions(); // # of threads contending for monitor | ||||||
1019 | nWait = mon->waiters(); // # of threads in Object.wait() | ||||||
1020 | ret.waiter_count = nWant + nWait; | ||||||
1021 | ret.notify_waiter_count = nWait; | ||||||
1022 | } else { | ||||||
1023 | // this object has a lightweight monitor | ||||||
1024 | ret.waiter_count = 0; | ||||||
1025 | ret.notify_waiter_count = 0; | ||||||
1026 | } | ||||||
1027 | |||||||
1028 | // Allocate memory for heavyweight and lightweight monitor. | ||||||
1029 | jvmtiError err; | ||||||
1030 | err = allocate(ret.waiter_count * sizeof(jthread *), (unsigned char**)&ret.waiters); | ||||||
1031 | if (err
| ||||||
1032 | return err; | ||||||
1033 | } | ||||||
1034 | err = allocate(ret.notify_waiter_count * sizeof(jthread *), | ||||||
1035 | (unsigned char**)&ret.notify_waiters); | ||||||
1036 | if (err
| ||||||
1037 | deallocate((unsigned char*)ret.waiters); | ||||||
1038 | return err; | ||||||
1039 | } | ||||||
1040 | |||||||
1041 | // now derive the rest of the fields | ||||||
1042 | if (mon
| ||||||
1043 | // this object has a heavyweight monitor | ||||||
1044 | |||||||
1045 | // Number of waiters may actually be less than the waiter count. | ||||||
1046 | // So NULL out memory so that unused memory will be NULL. | ||||||
1047 | memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *)); | ||||||
| |||||||
1048 | memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *)); | ||||||
1049 | |||||||
1050 | if (ret.waiter_count > 0) { | ||||||
1051 | // we have contending and/or waiting threads | ||||||
1052 | if (nWant > 0) { | ||||||
1053 | // we have contending threads | ||||||
1054 | ResourceMark rm(current_thread); | ||||||
1055 | // get_pending_threads returns only java thread so we do not need to | ||||||
1056 | // check for non java threads. | ||||||
1057 | GrowableArray<JavaThread*>* wantList = Threads::get_pending_threads(tlh.list(), nWant, (address)mon); | ||||||
1058 | if (wantList->length() < nWant) { | ||||||
1059 | // robustness: the pending list has gotten smaller | ||||||
1060 | nWant = wantList->length(); | ||||||
1061 | } | ||||||
1062 | for (int i = 0; i < nWant; i++) { | ||||||
1063 | JavaThread *pending_thread = wantList->at(i); | ||||||
1064 | Handle th(current_thread, pending_thread->threadObj()); | ||||||
1065 | ret.waiters[i] = (jthread)jni_reference(calling_thread, th); | ||||||
1066 | } | ||||||
1067 | } | ||||||
1068 | if (nWait > 0) { | ||||||
1069 | // we have threads in Object.wait() | ||||||
1070 | int offset = nWant; // add after any contending threads | ||||||
1071 | ObjectWaiter *waiter = mon->first_waiter(); | ||||||
1072 | for (int i = 0, j = 0; i < nWait; i++) { | ||||||
1073 | if (waiter == NULL__null) { | ||||||
1074 | // robustness: the waiting list has gotten smaller | ||||||
1075 | nWait = j; | ||||||
1076 | break; | ||||||
1077 | } | ||||||
1078 | JavaThread *w = mon->thread_of_waiter(waiter); | ||||||
1079 | if (w != NULL__null) { | ||||||
1080 | // If the thread was found on the ObjectWaiter list, then | ||||||
1081 | // it has not been notified. This thread can't change the | ||||||
1082 | // state of the monitor so it doesn't need to be suspended. | ||||||
1083 | Handle th(current_thread, w->threadObj()); | ||||||
1084 | ret.waiters[offset + j] = (jthread)jni_reference(calling_thread, th); | ||||||
1085 | ret.notify_waiters[j++] = (jthread)jni_reference(calling_thread, th); | ||||||
1086 | } | ||||||
1087 | waiter = mon->next_waiter(waiter); | ||||||
1088 | } | ||||||
1089 | } | ||||||
1090 | } // ThreadsListHandle is destroyed here. | ||||||
1091 | |||||||
1092 | // Adjust count. nWant and nWait count values may be less than original. | ||||||
1093 | ret.waiter_count = nWant + nWait; | ||||||
1094 | ret.notify_waiter_count = nWait; | ||||||
1095 | } else { | ||||||
1096 | // this object has a lightweight monitor and we have nothing more | ||||||
1097 | // to do here because the defaults are just fine. | ||||||
1098 | } | ||||||
1099 | |||||||
1100 | // we don't update return parameter unless everything worked | ||||||
1101 | *info_ptr = ret; | ||||||
1102 | |||||||
1103 | return JVMTI_ERROR_NONE; | ||||||
1104 | } | ||||||
1105 | |||||||
1106 | ResourceTracker::ResourceTracker(JvmtiEnv* env) { | ||||||
1107 | _env = env; | ||||||
1108 | _allocations = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<unsigned char*>(20, mtServiceability); | ||||||
1109 | _failed = false; | ||||||
1110 | } | ||||||
1111 | ResourceTracker::~ResourceTracker() { | ||||||
1112 | if (_failed) { | ||||||
1113 | for (int i=0; i<_allocations->length(); i++) { | ||||||
1114 | _env->deallocate(_allocations->at(i)); | ||||||
1115 | } | ||||||
1116 | } | ||||||
1117 | delete _allocations; | ||||||
1118 | } | ||||||
1119 | |||||||
1120 | jvmtiError ResourceTracker::allocate(jlong size, unsigned char** mem_ptr) { | ||||||
1121 | unsigned char *ptr; | ||||||
1122 | jvmtiError err = _env->allocate(size, &ptr); | ||||||
1123 | if (err == JVMTI_ERROR_NONE) { | ||||||
1124 | _allocations->append(ptr); | ||||||
1125 | *mem_ptr = ptr; | ||||||
1126 | } else { | ||||||
1127 | *mem_ptr = NULL__null; | ||||||
1128 | _failed = true; | ||||||
1129 | } | ||||||
1130 | return err; | ||||||
1131 | } | ||||||
1132 | |||||||
1133 | unsigned char* ResourceTracker::allocate(jlong size) { | ||||||
1134 | unsigned char* ptr; | ||||||
1135 | allocate(size, &ptr); | ||||||
1136 | return ptr; | ||||||
1137 | } | ||||||
1138 | |||||||
1139 | char* ResourceTracker::strdup(const char* str) { | ||||||
1140 | char *dup_str = (char*)allocate(strlen(str)+1); | ||||||
1141 | if (dup_str != NULL__null) { | ||||||
1142 | strcpy(dup_str, str); | ||||||
1143 | } | ||||||
1144 | return dup_str; | ||||||
1145 | } | ||||||
1146 | |||||||
1147 | struct StackInfoNode { | ||||||
1148 | struct StackInfoNode *next; | ||||||
1149 | jvmtiStackInfo info; | ||||||
1150 | }; | ||||||
1151 | |||||||
1152 | // Create a jvmtiStackInfo inside a linked list node and create a | ||||||
1153 | // buffer for the frame information, both allocated as resource objects. | ||||||
1154 | // Fill in both the jvmtiStackInfo and the jvmtiFrameInfo. | ||||||
1155 | // Note that either or both of thr and thread_oop | ||||||
1156 | // may be null if the thread is new or has exited. | ||||||
1157 | void | ||||||
1158 | MultipleStackTracesCollector::fill_frames(jthread jt, JavaThread *thr, oop thread_oop) { | ||||||
1159 | #ifdef ASSERT1 | ||||||
1160 | Thread *current_thread = Thread::current(); | ||||||
1161 | assert(SafepointSynchronize::is_at_safepoint() ||do { if (!(SafepointSynchronize::is_at_safepoint() || thr-> is_handshake_safe_for(current_thread))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1163, "assert(" "SafepointSynchronize::is_at_safepoint() || thr->is_handshake_safe_for(current_thread)" ") failed", "call by myself / at safepoint / at handshake"); ::breakpoint(); } } while (0) | ||||||
1162 | thr->is_handshake_safe_for(current_thread),do { if (!(SafepointSynchronize::is_at_safepoint() || thr-> is_handshake_safe_for(current_thread))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1163, "assert(" "SafepointSynchronize::is_at_safepoint() || thr->is_handshake_safe_for(current_thread)" ") failed", "call by myself / at safepoint / at handshake"); ::breakpoint(); } } while (0) | ||||||
1163 | "call by myself / at safepoint / at handshake")do { if (!(SafepointSynchronize::is_at_safepoint() || thr-> is_handshake_safe_for(current_thread))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1163, "assert(" "SafepointSynchronize::is_at_safepoint() || thr->is_handshake_safe_for(current_thread)" ") failed", "call by myself / at safepoint / at handshake"); ::breakpoint(); } } while (0); | ||||||
1164 | #endif | ||||||
1165 | |||||||
1166 | jint state = 0; | ||||||
1167 | struct StackInfoNode *node = NEW_RESOURCE_OBJ(struct StackInfoNode)(struct StackInfoNode*) resource_allocate_bytes((1) * sizeof( struct StackInfoNode)); | ||||||
1168 | jvmtiStackInfo *infop = &(node->info); | ||||||
1169 | node->next = head(); | ||||||
1170 | set_head(node); | ||||||
1171 | infop->frame_count = 0; | ||||||
1172 | infop->thread = jt; | ||||||
1173 | |||||||
1174 | if (thread_oop != NULL__null) { | ||||||
1175 | // get most state bits | ||||||
1176 | state = (jint)java_lang_Thread::get_thread_status(thread_oop); | ||||||
1177 | } | ||||||
1178 | |||||||
1179 | if (thr != NULL__null) { // add more state bits if there is a JavaThead to query | ||||||
1180 | if (thr->is_suspended()) { | ||||||
1181 | state |= JVMTI_THREAD_STATE_SUSPENDED; | ||||||
1182 | } | ||||||
1183 | JavaThreadState jts = thr->thread_state(); | ||||||
1184 | if (jts == _thread_in_native) { | ||||||
1185 | state |= JVMTI_THREAD_STATE_IN_NATIVE; | ||||||
1186 | } | ||||||
1187 | if (thr->is_interrupted(false)) { | ||||||
1188 | state |= JVMTI_THREAD_STATE_INTERRUPTED; | ||||||
1189 | } | ||||||
1190 | } | ||||||
1191 | infop->state = state; | ||||||
1192 | |||||||
1193 | if (thr != NULL__null && (state & JVMTI_THREAD_STATE_ALIVE) != 0) { | ||||||
1194 | infop->frame_buffer = NEW_RESOURCE_ARRAY(jvmtiFrameInfo, max_frame_count())(jvmtiFrameInfo*) resource_allocate_bytes((max_frame_count()) * sizeof(jvmtiFrameInfo)); | ||||||
1195 | env()->get_stack_trace(thr, 0, max_frame_count(), | ||||||
1196 | infop->frame_buffer, &(infop->frame_count)); | ||||||
1197 | } else { | ||||||
1198 | infop->frame_buffer = NULL__null; | ||||||
1199 | infop->frame_count = 0; | ||||||
1200 | } | ||||||
1201 | _frame_count_total += infop->frame_count; | ||||||
1202 | } | ||||||
1203 | |||||||
1204 | // Based on the stack information in the linked list, allocate memory | ||||||
1205 | // block to return and fill it from the info in the linked list. | ||||||
1206 | void | ||||||
1207 | MultipleStackTracesCollector::allocate_and_fill_stacks(jint thread_count) { | ||||||
1208 | // do I need to worry about alignment issues? | ||||||
1209 | jlong alloc_size = thread_count * sizeof(jvmtiStackInfo) | ||||||
1210 | + _frame_count_total * sizeof(jvmtiFrameInfo); | ||||||
1211 | env()->allocate(alloc_size, (unsigned char **)&_stack_info); | ||||||
1212 | |||||||
1213 | // pointers to move through the newly allocated space as it is filled in | ||||||
1214 | jvmtiStackInfo *si = _stack_info + thread_count; // bottom of stack info | ||||||
1215 | jvmtiFrameInfo *fi = (jvmtiFrameInfo *)si; // is the top of frame info | ||||||
1216 | |||||||
1217 | // copy information in resource area into allocated buffer | ||||||
1218 | // insert stack info backwards since linked list is backwards | ||||||
1219 | // insert frame info forwards | ||||||
1220 | // walk the StackInfoNodes | ||||||
1221 | for (struct StackInfoNode *sin = head(); sin != NULL__null; sin = sin->next) { | ||||||
1222 | jint frame_count = sin->info.frame_count; | ||||||
1223 | size_t frames_size = frame_count * sizeof(jvmtiFrameInfo); | ||||||
1224 | --si; | ||||||
1225 | memcpy(si, &(sin->info), sizeof(jvmtiStackInfo)); | ||||||
1226 | if (frames_size == 0) { | ||||||
1227 | si->frame_buffer = NULL__null; | ||||||
1228 | } else { | ||||||
1229 | memcpy(fi, sin->info.frame_buffer, frames_size); | ||||||
1230 | si->frame_buffer = fi; // point to the new allocated copy of the frames | ||||||
1231 | fi += frame_count; | ||||||
1232 | } | ||||||
1233 | } | ||||||
1234 | assert(si == _stack_info, "the last copied stack info must be the first record")do { if (!(si == _stack_info)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1234, "assert(" "si == _stack_info" ") failed", "the last copied stack info must be the first record" ); ::breakpoint(); } } while (0); | ||||||
1235 | assert((unsigned char *)fi == ((unsigned char *)_stack_info) + alloc_size,do { if (!((unsigned char *)fi == ((unsigned char *)_stack_info ) + alloc_size)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1236, "assert(" "(unsigned char *)fi == ((unsigned char *)_stack_info) + alloc_size" ") failed", "the last copied frame info must be the last record" ); ::breakpoint(); } } while (0) | ||||||
1236 | "the last copied frame info must be the last record")do { if (!((unsigned char *)fi == ((unsigned char *)_stack_info ) + alloc_size)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1236, "assert(" "(unsigned char *)fi == ((unsigned char *)_stack_info) + alloc_size" ") failed", "the last copied frame info must be the last record" ); ::breakpoint(); } } while (0); | ||||||
1237 | } | ||||||
1238 | |||||||
1239 | |||||||
1240 | void | ||||||
1241 | VM_GetThreadListStackTraces::doit() { | ||||||
1242 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1242, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "must be at safepoint"); ::breakpoint(); } } while (0); | ||||||
1243 | |||||||
1244 | ResourceMark rm; | ||||||
1245 | ThreadsListHandle tlh; | ||||||
1246 | for (int i = 0; i < _thread_count; ++i) { | ||||||
1247 | jthread jt = _thread_list[i]; | ||||||
1248 | JavaThread* java_thread = NULL__null; | ||||||
1249 | oop thread_oop = NULL__null; | ||||||
1250 | jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), jt, &java_thread, &thread_oop); | ||||||
1251 | if (err != JVMTI_ERROR_NONE) { | ||||||
1252 | // We got an error code so we don't have a JavaThread *, but | ||||||
1253 | // only return an error from here if we didn't get a valid | ||||||
1254 | // thread_oop. | ||||||
1255 | if (thread_oop == NULL__null) { | ||||||
1256 | _collector.set_result(err); | ||||||
1257 | return; | ||||||
1258 | } | ||||||
1259 | // We have a valid thread_oop. | ||||||
1260 | } | ||||||
1261 | _collector.fill_frames(jt, java_thread, thread_oop); | ||||||
1262 | } | ||||||
1263 | _collector.allocate_and_fill_stacks(_thread_count); | ||||||
1264 | } | ||||||
1265 | |||||||
1266 | void | ||||||
1267 | GetSingleStackTraceClosure::do_thread(Thread *target) { | ||||||
1268 | JavaThread *jt = JavaThread::cast(target); | ||||||
1269 | oop thread_oop = jt->threadObj(); | ||||||
1270 | |||||||
1271 | if (!jt->is_exiting() && thread_oop != NULL__null) { | ||||||
1272 | ResourceMark rm; | ||||||
1273 | _collector.fill_frames(_jthread, jt, thread_oop); | ||||||
1274 | _collector.allocate_and_fill_stacks(1); | ||||||
1275 | } | ||||||
1276 | } | ||||||
1277 | |||||||
1278 | void | ||||||
1279 | VM_GetAllStackTraces::doit() { | ||||||
1280 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1280, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "must be at safepoint"); ::breakpoint(); } } while (0); | ||||||
1281 | |||||||
1282 | ResourceMark rm; | ||||||
1283 | _final_thread_count = 0; | ||||||
1284 | for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { | ||||||
1285 | oop thread_oop = jt->threadObj(); | ||||||
1286 | if (thread_oop != NULL__null && | ||||||
1287 | !jt->is_exiting() && | ||||||
1288 | java_lang_Thread::is_alive(thread_oop) && | ||||||
1289 | !jt->is_hidden_from_external_view()) { | ||||||
1290 | ++_final_thread_count; | ||||||
1291 | // Handle block of the calling thread is used to create local refs. | ||||||
1292 | _collector.fill_frames((jthread)JNIHandles::make_local(_calling_thread, thread_oop), | ||||||
1293 | jt, thread_oop); | ||||||
1294 | } | ||||||
1295 | } | ||||||
1296 | _collector.allocate_and_fill_stacks(_final_thread_count); | ||||||
1297 | } | ||||||
1298 | |||||||
1299 | // Verifies that the top frame is a java frame in an expected state. | ||||||
1300 | // Deoptimizes frame if needed. | ||||||
1301 | // Checks that the frame method signature matches the return type (tos). | ||||||
1302 | // HandleMark must be defined in the caller only. | ||||||
1303 | // It is to keep a ret_ob_h handle alive after return to the caller. | ||||||
1304 | jvmtiError | ||||||
1305 | JvmtiEnvBase::check_top_frame(Thread* current_thread, JavaThread* java_thread, | ||||||
1306 | jvalue value, TosState tos, Handle* ret_ob_h) { | ||||||
1307 | ResourceMark rm(current_thread); | ||||||
1308 | |||||||
1309 | vframe *vf = vframeForNoProcess(java_thread, 0); | ||||||
1310 | NULL_CHECK(vf, JVMTI_ERROR_NO_MORE_FRAMES)if ((vf) == __null) { return (JVMTI_ERROR_NO_MORE_FRAMES); }; | ||||||
1311 | |||||||
1312 | javaVFrame *jvf = (javaVFrame*) vf; | ||||||
1313 | if (!vf->is_java_frame() || jvf->method()->is_native()) { | ||||||
1314 | return JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1315 | } | ||||||
1316 | |||||||
1317 | // If the frame is a compiled one, need to deoptimize it. | ||||||
1318 | if (vf->is_compiled_frame()) { | ||||||
1319 | if (!vf->fr().can_be_deoptimized()) { | ||||||
1320 | return JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1321 | } | ||||||
1322 | Deoptimization::deoptimize_frame(java_thread, jvf->fr().id()); | ||||||
1323 | } | ||||||
1324 | |||||||
1325 | // Get information about method return type | ||||||
1326 | Symbol* signature = jvf->method()->signature(); | ||||||
1327 | |||||||
1328 | ResultTypeFinder rtf(signature); | ||||||
1329 | TosState fr_tos = as_TosState(rtf.type()); | ||||||
1330 | if (fr_tos != tos) { | ||||||
1331 | if (tos != itos || (fr_tos != btos && fr_tos != ztos && fr_tos != ctos && fr_tos != stos)) { | ||||||
1332 | return JVMTI_ERROR_TYPE_MISMATCH; | ||||||
1333 | } | ||||||
1334 | } | ||||||
1335 | |||||||
1336 | // Check that the jobject class matches the return type signature. | ||||||
1337 | jobject jobj = value.l; | ||||||
1338 | if (tos == atos && jobj != NULL__null) { // NULL reference is allowed | ||||||
1339 | Handle ob_h(current_thread, JNIHandles::resolve_external_guard(jobj)); | ||||||
1340 | NULL_CHECK(ob_h, JVMTI_ERROR_INVALID_OBJECT)if ((ob_h) == __null) { return (JVMTI_ERROR_INVALID_OBJECT); }; | ||||||
1341 | Klass* ob_k = ob_h()->klass(); | ||||||
1342 | NULL_CHECK(ob_k, JVMTI_ERROR_INVALID_OBJECT)if ((ob_k) == __null) { return (JVMTI_ERROR_INVALID_OBJECT); }; | ||||||
1343 | |||||||
1344 | // Method return type signature. | ||||||
1345 | char* ty_sign = 1 + strchr(signature->as_C_string(), JVM_SIGNATURE_ENDFUNC); | ||||||
1346 | |||||||
1347 | if (!VM_GetOrSetLocal::is_assignable(ty_sign, ob_k, current_thread)) { | ||||||
1348 | return JVMTI_ERROR_TYPE_MISMATCH; | ||||||
1349 | } | ||||||
1350 | *ret_ob_h = ob_h; | ||||||
1351 | } | ||||||
1352 | return JVMTI_ERROR_NONE; | ||||||
1353 | } /* end check_top_frame */ | ||||||
1354 | |||||||
1355 | |||||||
1356 | // ForceEarlyReturn<type> follows the PopFrame approach in many aspects. | ||||||
1357 | // Main difference is on the last stage in the interpreter. | ||||||
1358 | // The PopFrame stops method execution to continue execution | ||||||
1359 | // from the same method call instruction. | ||||||
1360 | // The ForceEarlyReturn forces return from method so the execution | ||||||
1361 | // continues at the bytecode following the method call. | ||||||
1362 | |||||||
1363 | // java_thread - protected by ThreadsListHandle and pre-checked | ||||||
1364 | |||||||
1365 | jvmtiError | ||||||
1366 | JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState tos) { | ||||||
1367 | // retrieve or create the state | ||||||
1368 | JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); | ||||||
1369 | if (state == NULL__null) { | ||||||
1370 | return JVMTI_ERROR_THREAD_NOT_ALIVE; | ||||||
1371 | } | ||||||
1372 | |||||||
1373 | // Eagerly reallocate scalar replaced objects. | ||||||
1374 | JavaThread* current_thread = JavaThread::current(); | ||||||
1375 | EscapeBarrier eb(true, current_thread, java_thread); | ||||||
1376 | if (!eb.deoptimize_objects(0)) { | ||||||
1377 | // Reallocation of scalar replaced objects failed -> return with error | ||||||
1378 | return JVMTI_ERROR_OUT_OF_MEMORY; | ||||||
1379 | } | ||||||
1380 | |||||||
1381 | SetForceEarlyReturn op(state, value, tos); | ||||||
1382 | if (java_thread == current_thread) { | ||||||
1383 | op.doit(java_thread, true /* self */); | ||||||
1384 | } else { | ||||||
1385 | Handshake::execute(&op, java_thread); | ||||||
1386 | } | ||||||
1387 | return op.result(); | ||||||
1388 | } | ||||||
1389 | |||||||
1390 | void | ||||||
1391 | SetForceEarlyReturn::doit(Thread *target, bool self) { | ||||||
1392 | JavaThread* java_thread = JavaThread::cast(target); | ||||||
1393 | Thread* current_thread = Thread::current(); | ||||||
1394 | HandleMark hm(current_thread); | ||||||
1395 | |||||||
1396 | if (java_thread->is_exiting()) { | ||||||
1397 | return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||||||
1398 | } | ||||||
1399 | if (!self) { | ||||||
1400 | if (!java_thread->is_suspended()) { | ||||||
1401 | _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; | ||||||
1402 | return; | ||||||
1403 | } | ||||||
1404 | } | ||||||
1405 | |||||||
1406 | // Check to see if a ForceEarlyReturn was already in progress | ||||||
1407 | if (_state->is_earlyret_pending()) { | ||||||
1408 | // Probably possible for JVMTI clients to trigger this, but the | ||||||
1409 | // JPDA backend shouldn't allow this to happen | ||||||
1410 | _result = JVMTI_ERROR_INTERNAL; | ||||||
1411 | return; | ||||||
1412 | } | ||||||
1413 | { | ||||||
1414 | // The same as for PopFrame. Workaround bug: | ||||||
1415 | // 4812902: popFrame hangs if the method is waiting at a synchronize | ||||||
1416 | // Catch this condition and return an error to avoid hanging. | ||||||
1417 | // Now JVMTI spec allows an implementation to bail out with an opaque | ||||||
1418 | // frame error. | ||||||
1419 | OSThread* osThread = java_thread->osthread(); | ||||||
1420 | if (osThread->get_state() == MONITOR_WAIT) { | ||||||
1421 | _result = JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1422 | return; | ||||||
1423 | } | ||||||
1424 | } | ||||||
1425 | |||||||
1426 | Handle ret_ob_h; | ||||||
1427 | _result = JvmtiEnvBase::check_top_frame(current_thread, java_thread, _value, _tos, &ret_ob_h); | ||||||
1428 | if (_result != JVMTI_ERROR_NONE) { | ||||||
1429 | return; | ||||||
1430 | } | ||||||
1431 | assert(_tos != atos || _value.l == NULL || ret_ob_h() != NULL,do { if (!(_tos != atos || _value.l == __null || ret_ob_h() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1432, "assert(" "_tos != atos || _value.l == __null || ret_ob_h() != __null" ") failed", "return object oop must not be NULL if jobject is not NULL" ); ::breakpoint(); } } while (0) | ||||||
1432 | "return object oop must not be NULL if jobject is not NULL")do { if (!(_tos != atos || _value.l == __null || ret_ob_h() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1432, "assert(" "_tos != atos || _value.l == __null || ret_ob_h() != __null" ") failed", "return object oop must not be NULL if jobject is not NULL" ); ::breakpoint(); } } while (0); | ||||||
1433 | |||||||
1434 | // Update the thread state to reflect that the top frame must be | ||||||
1435 | // forced to return. | ||||||
1436 | // The current frame will be returned later when the suspended | ||||||
1437 | // thread is resumed and right before returning from VM to Java. | ||||||
1438 | // (see call_VM_base() in assembler_<cpu>.cpp). | ||||||
1439 | |||||||
1440 | _state->set_earlyret_pending(); | ||||||
1441 | _state->set_earlyret_oop(ret_ob_h()); | ||||||
1442 | _state->set_earlyret_value(_value, _tos); | ||||||
1443 | |||||||
1444 | // Set pending step flag for this early return. | ||||||
1445 | // It is cleared when next step event is posted. | ||||||
1446 | _state->set_pending_step_for_earlyret(); | ||||||
1447 | } | ||||||
1448 | |||||||
1449 | void | ||||||
1450 | JvmtiMonitorClosure::do_monitor(ObjectMonitor* mon) { | ||||||
1451 | if ( _error != JVMTI_ERROR_NONE) { | ||||||
1452 | // Error occurred in previous iteration so no need to add | ||||||
1453 | // to the list. | ||||||
1454 | return; | ||||||
1455 | } | ||||||
1456 | // Filter out on stack monitors collected during stack walk. | ||||||
1457 | oop obj = mon->object(); | ||||||
1458 | bool found = false; | ||||||
1459 | for (int j = 0; j < _owned_monitors_list->length(); j++) { | ||||||
1460 | jobject jobj = ((jvmtiMonitorStackDepthInfo*)_owned_monitors_list->at(j))->monitor; | ||||||
1461 | oop check = JNIHandles::resolve(jobj); | ||||||
1462 | if (check == obj) { | ||||||
1463 | // On stack monitor already collected during the stack walk. | ||||||
1464 | found = true; | ||||||
1465 | break; | ||||||
1466 | } | ||||||
1467 | } | ||||||
1468 | if (found == false) { | ||||||
1469 | // This is off stack monitor (e.g. acquired via jni MonitorEnter). | ||||||
1470 | jvmtiError err; | ||||||
1471 | jvmtiMonitorStackDepthInfo *jmsdi; | ||||||
1472 | err = _env->allocate(sizeof(jvmtiMonitorStackDepthInfo), (unsigned char **)&jmsdi); | ||||||
1473 | if (err != JVMTI_ERROR_NONE) { | ||||||
1474 | _error = err; | ||||||
1475 | return; | ||||||
1476 | } | ||||||
1477 | Handle hobj(Thread::current(), obj); | ||||||
1478 | jmsdi->monitor = _env->jni_reference(_calling_thread, hobj); | ||||||
1479 | // stack depth is unknown for this monitor. | ||||||
1480 | jmsdi->stack_depth = -1; | ||||||
1481 | _owned_monitors_list->append(jmsdi); | ||||||
1482 | } | ||||||
1483 | } | ||||||
1484 | |||||||
1485 | GrowableArray<OopHandle>* JvmtiModuleClosure::_tbl = NULL__null; | ||||||
1486 | |||||||
1487 | void JvmtiModuleClosure::do_module(ModuleEntry* entry) { | ||||||
1488 | assert_locked_or_safepoint(Module_lock); | ||||||
1489 | OopHandle module = entry->module_handle(); | ||||||
1490 | guarantee(module.resolve() != NULL, "module object is NULL")do { if (!(module.resolve() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1490, "guarantee(" "module.resolve() != NULL" ") failed", "module object is NULL" ); ::breakpoint(); } } while (0); | ||||||
1491 | _tbl->push(module); | ||||||
1492 | } | ||||||
1493 | |||||||
1494 | jvmtiError | ||||||
1495 | JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr) { | ||||||
1496 | ResourceMark rm; | ||||||
1497 | MutexLocker mcld(ClassLoaderDataGraph_lock); | ||||||
1498 | MutexLocker ml(Module_lock); | ||||||
1499 | |||||||
1500 | _tbl = new GrowableArray<OopHandle>(77); | ||||||
1501 | if (_tbl == NULL__null) { | ||||||
1502 | return JVMTI_ERROR_OUT_OF_MEMORY; | ||||||
1503 | } | ||||||
1504 | |||||||
1505 | // Iterate over all the modules loaded to the system. | ||||||
1506 | ClassLoaderDataGraph::modules_do(&do_module); | ||||||
1507 | |||||||
1508 | jint len = _tbl->length(); | ||||||
1509 | guarantee(len > 0, "at least one module must be present")do { if (!(len > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1509, "guarantee(" "len > 0" ") failed", "at least one module must be present" ); ::breakpoint(); } } while (0); | ||||||
1510 | |||||||
1511 | jobject* array = (jobject*)env->jvmtiMalloc((jlong)(len * sizeof(jobject))); | ||||||
1512 | if (array == NULL__null) { | ||||||
1513 | return JVMTI_ERROR_OUT_OF_MEMORY; | ||||||
1514 | } | ||||||
1515 | for (jint idx = 0; idx < len; idx++) { | ||||||
1516 | array[idx] = JNIHandles::make_local(_tbl->at(idx).resolve()); | ||||||
1517 | } | ||||||
1518 | _tbl = NULL__null; | ||||||
1519 | *modules_ptr = array; | ||||||
1520 | *module_count_ptr = len; | ||||||
1521 | return JVMTI_ERROR_NONE; | ||||||
1522 | } | ||||||
1523 | |||||||
1524 | void | ||||||
1525 | UpdateForPopTopFrameClosure::doit(Thread *target, bool self) { | ||||||
1526 | Thread* current_thread = Thread::current(); | ||||||
1527 | HandleMark hm(current_thread); | ||||||
1528 | JavaThread* java_thread = JavaThread::cast(target); | ||||||
1529 | |||||||
1530 | if (java_thread->is_exiting()) { | ||||||
1531 | return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||||||
1532 | } | ||||||
1533 | assert(java_thread == _state->get_thread(), "Must be")do { if (!(java_thread == _state->get_thread())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1533, "assert(" "java_thread == _state->get_thread()" ") failed" , "Must be"); ::breakpoint(); } } while (0); | ||||||
1534 | |||||||
1535 | if (!self && !java_thread->is_suspended()) { | ||||||
1536 | _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; | ||||||
1537 | return; | ||||||
1538 | } | ||||||
1539 | |||||||
1540 | // Check to see if a PopFrame was already in progress | ||||||
1541 | if (java_thread->popframe_condition() != JavaThread::popframe_inactive) { | ||||||
1542 | // Probably possible for JVMTI clients to trigger this, but the | ||||||
1543 | // JPDA backend shouldn't allow this to happen | ||||||
1544 | _result = JVMTI_ERROR_INTERNAL; | ||||||
1545 | return; | ||||||
1546 | } | ||||||
1547 | |||||||
1548 | // Was workaround bug | ||||||
1549 | // 4812902: popFrame hangs if the method is waiting at a synchronize | ||||||
1550 | // Catch this condition and return an error to avoid hanging. | ||||||
1551 | // Now JVMTI spec allows an implementation to bail out with an opaque frame error. | ||||||
1552 | OSThread* osThread = java_thread->osthread(); | ||||||
1553 | if (osThread->get_state() == MONITOR_WAIT) { | ||||||
1554 | _result = JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1555 | return; | ||||||
1556 | } | ||||||
1557 | |||||||
1558 | ResourceMark rm(current_thread); | ||||||
1559 | // Check if there is more than one Java frame in this thread, that the top two frames | ||||||
1560 | // are Java (not native) frames, and that there is no intervening VM frame | ||||||
1561 | int frame_count = 0; | ||||||
1562 | bool is_interpreted[2]; | ||||||
1563 | intptr_t *frame_sp[2]; | ||||||
1564 | // The 2-nd arg of constructor is needed to stop iterating at java entry frame. | ||||||
1565 | for (vframeStream vfs(java_thread, true, false /* process_frames */); !vfs.at_end(); vfs.next()) { | ||||||
1566 | methodHandle mh(current_thread, vfs.method()); | ||||||
1567 | if (mh->is_native()) { | ||||||
1568 | _result = JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1569 | return; | ||||||
1570 | } | ||||||
1571 | is_interpreted[frame_count] = vfs.is_interpreted_frame(); | ||||||
1572 | frame_sp[frame_count] = vfs.frame_id(); | ||||||
1573 | if (++frame_count > 1) break; | ||||||
1574 | } | ||||||
1575 | if (frame_count < 2) { | ||||||
1576 | // We haven't found two adjacent non-native Java frames on the top. | ||||||
1577 | // There can be two situations here: | ||||||
1578 | // 1. There are no more java frames | ||||||
1579 | // 2. Two top java frames are separated by non-java native frames | ||||||
1580 | if(JvmtiEnvBase::vframeForNoProcess(java_thread, 1) == NULL__null) { | ||||||
1581 | _result = JVMTI_ERROR_NO_MORE_FRAMES; | ||||||
1582 | return; | ||||||
1583 | } else { | ||||||
1584 | // Intervening non-java native or VM frames separate java frames. | ||||||
1585 | // Current implementation does not support this. See bug #5031735. | ||||||
1586 | // In theory it is possible to pop frames in such cases. | ||||||
1587 | _result = JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1588 | return; | ||||||
1589 | } | ||||||
1590 | } | ||||||
1591 | |||||||
1592 | // If any of the top 2 frames is a compiled one, need to deoptimize it | ||||||
1593 | for (int i = 0; i < 2; i++) { | ||||||
1594 | if (!is_interpreted[i]) { | ||||||
1595 | Deoptimization::deoptimize_frame(java_thread, frame_sp[i]); | ||||||
1596 | } | ||||||
1597 | } | ||||||
1598 | |||||||
1599 | // Update the thread state to reflect that the top frame is popped | ||||||
1600 | // so that cur_stack_depth is maintained properly and all frameIDs | ||||||
1601 | // are invalidated. | ||||||
1602 | // The current frame will be popped later when the suspended thread | ||||||
1603 | // is resumed and right before returning from VM to Java. | ||||||
1604 | // (see call_VM_base() in assembler_<cpu>.cpp). | ||||||
1605 | |||||||
1606 | // It's fine to update the thread state here because no JVMTI events | ||||||
1607 | // shall be posted for this PopFrame. | ||||||
1608 | |||||||
1609 | _state->update_for_pop_top_frame(); | ||||||
1610 | java_thread->set_popframe_condition(JavaThread::popframe_pending_bit); | ||||||
1611 | // Set pending step flag for this popframe and it is cleared when next | ||||||
1612 | // step event is posted. | ||||||
1613 | _state->set_pending_step_for_popframe(); | ||||||
1614 | _result = JVMTI_ERROR_NONE; | ||||||
1615 | } | ||||||
1616 | |||||||
1617 | void | ||||||
1618 | SetFramePopClosure::doit(Thread *target, bool self) { | ||||||
1619 | ResourceMark rm; | ||||||
1620 | JavaThread* java_thread = JavaThread::cast(target); | ||||||
1621 | |||||||
1622 | if (java_thread->is_exiting()) { | ||||||
1623 | return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||||||
1624 | } | ||||||
1625 | assert(_state->get_thread() == java_thread, "Must be")do { if (!(_state->get_thread() == java_thread)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1625, "assert(" "_state->get_thread() == java_thread" ") failed" , "Must be"); ::breakpoint(); } } while (0); | ||||||
1626 | |||||||
1627 | if (!self && !java_thread->is_suspended()) { | ||||||
1628 | _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; | ||||||
1629 | return; | ||||||
1630 | } | ||||||
1631 | |||||||
1632 | vframe *vf = JvmtiEnvBase::vframeForNoProcess(java_thread, _depth); | ||||||
1633 | if (vf == NULL__null) { | ||||||
1634 | _result = JVMTI_ERROR_NO_MORE_FRAMES; | ||||||
1635 | return; | ||||||
1636 | } | ||||||
1637 | |||||||
1638 | if (!vf->is_java_frame() || ((javaVFrame*) vf)->method()->is_native()) { | ||||||
1639 | _result = JVMTI_ERROR_OPAQUE_FRAME; | ||||||
1640 | return; | ||||||
1641 | } | ||||||
1642 | |||||||
1643 | assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL")do { if (!(vf->frame_pointer() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1643, "assert(" "vf->frame_pointer() != __null" ") failed" , "frame pointer mustn't be NULL"); ::breakpoint(); } } while (0); | ||||||
1644 | int frame_number = _state->count_frames() - _depth; | ||||||
1645 | _state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number); | ||||||
1646 | _result = JVMTI_ERROR_NONE; | ||||||
1647 | } | ||||||
1648 | |||||||
1649 | void | ||||||
1650 | GetOwnedMonitorInfoClosure::do_thread(Thread *target) { | ||||||
1651 | JavaThread *jt = JavaThread::cast(target); | ||||||
1652 | if (!jt->is_exiting() && (jt->threadObj() != NULL__null)) { | ||||||
1653 | _result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, | ||||||
1654 | jt, | ||||||
1655 | _owned_monitors_list); | ||||||
1656 | } | ||||||
1657 | } | ||||||
1658 | |||||||
1659 | void | ||||||
1660 | GetCurrentContendedMonitorClosure::do_thread(Thread *target) { | ||||||
1661 | JavaThread *jt = JavaThread::cast(target); | ||||||
1662 | if (!jt->is_exiting() && (jt->threadObj() != NULL__null)) { | ||||||
1663 | _result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread, | ||||||
1664 | jt, | ||||||
1665 | _owned_monitor_ptr); | ||||||
1666 | } | ||||||
1667 | } | ||||||
1668 | |||||||
1669 | void | ||||||
1670 | GetStackTraceClosure::do_thread(Thread *target) { | ||||||
1671 | JavaThread *jt = JavaThread::cast(target); | ||||||
1672 | if (!jt->is_exiting() && jt->threadObj() != NULL__null) { | ||||||
1673 | _result = ((JvmtiEnvBase *)_env)->get_stack_trace(jt, | ||||||
1674 | _start_depth, _max_count, | ||||||
1675 | _frame_buffer, _count_ptr); | ||||||
1676 | } | ||||||
1677 | } | ||||||
1678 | |||||||
1679 | void | ||||||
1680 | GetFrameCountClosure::do_thread(Thread *target) { | ||||||
1681 | JavaThread* jt = _state->get_thread(); | ||||||
1682 | assert(target == jt, "just checking")do { if (!(target == jt)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp" , 1682, "assert(" "target == jt" ") failed", "just checking") ; ::breakpoint(); } } while (0); | ||||||
1683 | if (!jt->is_exiting() && jt->threadObj() != NULL__null) { | ||||||
1684 | _result = ((JvmtiEnvBase*)_env)->get_frame_count(_state, _count_ptr); | ||||||
1685 | } | ||||||
1686 | } | ||||||
1687 | |||||||
1688 | void | ||||||
1689 | GetFrameLocationClosure::do_thread(Thread *target) { | ||||||
1690 | JavaThread *jt = JavaThread::cast(target); | ||||||
1691 | if (!jt->is_exiting() && jt->threadObj() != NULL__null) { | ||||||
1692 | _result = ((JvmtiEnvBase*)_env)->get_frame_location(jt, _depth, | ||||||
1693 | _method_ptr, _location_ptr); | ||||||
1694 | } | ||||||
1695 | } |
1 | /* |
2 | * Copyright (c) 1997, 2020, 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_OOPS_OOPSHIERARCHY_HPP |
26 | #define SHARE_OOPS_OOPSHIERARCHY_HPP |
27 | |
28 | #include "metaprogramming/integralConstant.hpp" |
29 | #include "metaprogramming/primitiveConversions.hpp" |
30 | #include "utilities/globalDefinitions.hpp" |
31 | |
32 | // OBJECT hierarchy |
33 | // This hierarchy is a representation hierarchy, i.e. if A is a superclass |
34 | // of B, A's representation is a prefix of B's representation. |
35 | |
36 | // Global offset instead of address for an oop within a java object. |
37 | enum class narrowOop : uint32_t { null = 0 }; |
38 | |
39 | // If compressed klass pointers then use narrowKlass. |
40 | typedef juint narrowKlass; |
41 | |
42 | typedef void* OopOrNarrowOopStar; |
43 | |
44 | #ifndef CHECK_UNHANDLED_OOPS1 |
45 | |
46 | typedef class oopDesc* oop; |
47 | typedef class instanceOopDesc* instanceOop; |
48 | typedef class arrayOopDesc* arrayOop; |
49 | typedef class objArrayOopDesc* objArrayOop; |
50 | typedef class typeArrayOopDesc* typeArrayOop; |
51 | |
52 | #else |
53 | |
54 | // When CHECK_UNHANDLED_OOPS is defined, an "oop" is a class with a |
55 | // carefully chosen set of constructors and conversion operators to go |
56 | // to and from the underlying oopDesc pointer type. |
57 | // |
58 | // Because oop and its subclasses <type>Oop are class types, arbitrary |
59 | // conversions are not accepted by the compiler. Applying a cast to |
60 | // an oop will cause the best matched conversion operator to be |
61 | // invoked returning the underlying oopDesc* type if appropriate. |
62 | // No copy constructors, explicit user conversions or operators of |
63 | // numerical type should be defined within the oop class. Most C++ |
64 | // compilers will issue a compile time error concerning the overloading |
65 | // ambiguity between operators of numerical and pointer types. If |
66 | // a conversion to or from an oop to a numerical type is needed, |
67 | // use the inline template methods, cast_*_oop, defined below. |
68 | // |
69 | // Converting NULL to oop to Handle implicit is no longer accepted by the |
70 | // compiler because there are too many steps in the conversion. Use Handle() |
71 | // instead, which generates less code anyway. |
72 | |
73 | class Thread; |
74 | class oopDesc; |
75 | |
76 | extern "C" bool CheckUnhandledOops; |
77 | |
78 | class oop { |
79 | oopDesc* _o; |
80 | |
81 | void register_oop(); |
82 | void unregister_oop(); |
83 | |
84 | void register_if_checking() { |
85 | if (CheckUnhandledOops) register_oop(); |
86 | } |
87 | |
88 | public: |
89 | oop() : _o(nullptr) { register_if_checking(); } |
90 | oop(const oop& o) : _o(o._o) { register_if_checking(); } |
91 | oop(oopDesc* o) : _o(o) { register_if_checking(); } |
92 | ~oop() { |
93 | if (CheckUnhandledOops) unregister_oop(); |
94 | } |
95 | |
96 | oopDesc* obj() const { return _o; } |
97 | oopDesc* operator->() const { return _o; } |
98 | operator oopDesc* () const { return _o; } |
99 | |
100 | bool operator==(const oop& o) const { return _o == o._o; } |
101 | bool operator!=(const oop& o) const { return _o != o._o; } |
102 | |
103 | bool operator==(std::nullptr_t) const { return _o == nullptr; } |
104 | bool operator!=(std::nullptr_t) const { return _o != nullptr; } |
105 | |
106 | oop& operator=(const oop& o) { _o = o._o; return *this; } |
107 | }; |
108 | |
109 | template<> |
110 | struct PrimitiveConversions::Translate<oop> : public TrueType { |
111 | typedef oop Value; |
112 | typedef oopDesc* Decayed; |
113 | |
114 | static Decayed decay(Value x) { return x.obj(); } |
115 | static Value recover(Decayed x) { return oop(x); } |
116 | }; |
117 | |
118 | #define DEF_OOP(type)class typeOopDesc; class typeOop : public oop { public: typeOop () : oop() {} typeOop(const typeOop& o) : oop(o) {} typeOop (const oop& o) : oop(o) {} typeOop(typeOopDesc* o) : oop( (oopDesc*)o) {} operator typeOopDesc* () const { return (typeOopDesc *)obj(); } typeOopDesc* operator->() const { return (typeOopDesc *)obj(); } typeOop& operator=(const typeOop& o) { oop ::operator=(o); return *this; } }; template<> struct PrimitiveConversions ::Translate<typeOop> : public TrueType { typedef typeOop Value; typedef typeOopDesc* Decayed; static Decayed decay(Value x) { return (typeOopDesc*)x.obj(); } static Value recover(Decayed x) { return typeOop(x); } }; \ |
119 | class type##OopDesc; \ |
120 | class type##Oop : public oop { \ |
121 | public: \ |
122 | type##Oop() : oop() {} \ |
123 | type##Oop(const type##Oop& o) : oop(o) {} \ |
124 | type##Oop(const oop& o) : oop(o) {} \ |
125 | type##Oop(type##OopDesc* o) : oop((oopDesc*)o) {} \ |
126 | operator type##OopDesc* () const { return (type##OopDesc*)obj(); } \ |
127 | type##OopDesc* operator->() const { \ |
128 | return (type##OopDesc*)obj(); \ |
129 | } \ |
130 | type##Oop& operator=(const type##Oop& o) { \ |
131 | oop::operator=(o); \ |
132 | return *this; \ |
133 | } \ |
134 | }; \ |
135 | \ |
136 | template<> \ |
137 | struct PrimitiveConversions::Translate<type##Oop> : public TrueType { \ |
138 | typedef type##Oop Value; \ |
139 | typedef type##OopDesc* Decayed; \ |
140 | \ |
141 | static Decayed decay(Value x) { return (type##OopDesc*)x.obj(); } \ |
142 | static Value recover(Decayed x) { return type##Oop(x); } \ |
143 | }; |
144 | |
145 | DEF_OOP(instance)class instanceOopDesc; class instanceOop : public oop { public : instanceOop() : oop() {} instanceOop(const instanceOop& o) : oop(o) {} instanceOop(const oop& o) : oop(o) {} instanceOop (instanceOopDesc* o) : oop((oopDesc*)o) {} operator instanceOopDesc * () const { return (instanceOopDesc*)obj(); } instanceOopDesc * operator->() const { return (instanceOopDesc*)obj(); } instanceOop & operator=(const instanceOop& o) { oop::operator=(o) ; return *this; } }; template<> struct PrimitiveConversions ::Translate<instanceOop> : public TrueType { typedef instanceOop Value; typedef instanceOopDesc* Decayed; static Decayed decay (Value x) { return (instanceOopDesc*)x.obj(); } static Value recover (Decayed x) { return instanceOop(x); } };; |
146 | DEF_OOP(array)class arrayOopDesc; class arrayOop : public oop { public: arrayOop () : oop() {} arrayOop(const arrayOop& o) : oop(o) {} arrayOop (const oop& o) : oop(o) {} arrayOop(arrayOopDesc* o) : oop ((oopDesc*)o) {} operator arrayOopDesc* () const { return (arrayOopDesc *)obj(); } arrayOopDesc* operator->() const { return (arrayOopDesc *)obj(); } arrayOop& operator=(const arrayOop& o) { oop ::operator=(o); return *this; } }; template<> struct PrimitiveConversions ::Translate<arrayOop> : public TrueType { typedef arrayOop Value; typedef arrayOopDesc* Decayed; static Decayed decay(Value x) { return (arrayOopDesc*)x.obj(); } static Value recover(Decayed x) { return arrayOop(x); } };; |
147 | DEF_OOP(objArray)class objArrayOopDesc; class objArrayOop : public oop { public : objArrayOop() : oop() {} objArrayOop(const objArrayOop& o) : oop(o) {} objArrayOop(const oop& o) : oop(o) {} objArrayOop (objArrayOopDesc* o) : oop((oopDesc*)o) {} operator objArrayOopDesc * () const { return (objArrayOopDesc*)obj(); } objArrayOopDesc * operator->() const { return (objArrayOopDesc*)obj(); } objArrayOop & operator=(const objArrayOop& o) { oop::operator=(o) ; return *this; } }; template<> struct PrimitiveConversions ::Translate<objArrayOop> : public TrueType { typedef objArrayOop Value; typedef objArrayOopDesc* Decayed; static Decayed decay (Value x) { return (objArrayOopDesc*)x.obj(); } static Value recover (Decayed x) { return objArrayOop(x); } };; |
148 | DEF_OOP(typeArray)class typeArrayOopDesc; class typeArrayOop : public oop { public : typeArrayOop() : oop() {} typeArrayOop(const typeArrayOop& o) : oop(o) {} typeArrayOop(const oop& o) : oop(o) {} typeArrayOop (typeArrayOopDesc* o) : oop((oopDesc*)o) {} operator typeArrayOopDesc * () const { return (typeArrayOopDesc*)obj(); } typeArrayOopDesc * operator->() const { return (typeArrayOopDesc*)obj(); } typeArrayOop & operator=(const typeArrayOop& o) { oop::operator=(o ); return *this; } }; template<> struct PrimitiveConversions ::Translate<typeArrayOop> : public TrueType { typedef typeArrayOop Value; typedef typeArrayOopDesc* Decayed; static Decayed decay (Value x) { return (typeArrayOopDesc*)x.obj(); } static Value recover(Decayed x) { return typeArrayOop(x); } };; |
149 | |
150 | #endif // CHECK_UNHANDLED_OOPS |
151 | |
152 | // Cast functions to convert to and from oops. |
153 | template <typename T> inline oop cast_to_oop(T value) { |
154 | return (oopDesc*)value; |
155 | } |
156 | template <typename T> inline T cast_from_oop(oop o) { |
157 | return (T)(CHECK_UNHANDLED_OOPS_ONLY((oopDesc*))(oopDesc*)o); |
158 | } |
159 | |
160 | // The metadata hierarchy is separate from the oop hierarchy |
161 | |
162 | // class MetaspaceObj |
163 | class ConstMethod; |
164 | class ConstantPoolCache; |
165 | class MethodData; |
166 | // class Metadata |
167 | class Method; |
168 | class ConstantPool; |
169 | // class CHeapObj |
170 | class CompiledICHolder; |
171 | |
172 | |
173 | // The klass hierarchy is separate from the oop hierarchy. |
174 | |
175 | class Klass; |
176 | class InstanceKlass; |
177 | class InstanceMirrorKlass; |
178 | class InstanceClassLoaderKlass; |
179 | class InstanceRefKlass; |
180 | class ArrayKlass; |
181 | class ObjArrayKlass; |
182 | class TypeArrayKlass; |
183 | |
184 | #endif // SHARE_OOPS_OOPSHIERARCHY_HPP |
1 | /* | ||||||
2 | * Copyright (c) 2003, 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_PRIMS_JVMTIENVBASE_HPP | ||||||
26 | #define SHARE_PRIMS_JVMTIENVBASE_HPP | ||||||
27 | |||||||
28 | #include "prims/jvmtiEnvThreadState.hpp" | ||||||
29 | #include "prims/jvmtiEventController.hpp" | ||||||
30 | #include "prims/jvmtiThreadState.hpp" | ||||||
31 | #include "oops/oopHandle.hpp" | ||||||
32 | #include "runtime/atomic.hpp" | ||||||
33 | #include "runtime/fieldDescriptor.hpp" | ||||||
34 | #include "runtime/frame.hpp" | ||||||
35 | #include "runtime/thread.hpp" | ||||||
36 | #include "runtime/vmOperation.hpp" | ||||||
37 | #include "utilities/growableArray.hpp" | ||||||
38 | #include "utilities/macros.hpp" | ||||||
39 | |||||||
40 | // | ||||||
41 | // Forward Declarations | ||||||
42 | // | ||||||
43 | |||||||
44 | class JvmtiEnv; | ||||||
45 | class JvmtiThreadState; | ||||||
46 | class JvmtiRawMonitor; // for jvmtiEnv.hpp | ||||||
47 | class JvmtiEventControllerPrivate; | ||||||
48 | class JvmtiTagMap; | ||||||
49 | |||||||
50 | |||||||
51 | |||||||
52 | // One JvmtiEnv object is created per jvmti attachment; | ||||||
53 | // done via JNI GetEnv() call. Multiple attachments are | ||||||
54 | // allowed in jvmti. | ||||||
55 | |||||||
56 | class JvmtiEnvBase : public CHeapObj<mtInternal> { | ||||||
57 | |||||||
58 | private: | ||||||
59 | |||||||
60 | #if INCLUDE_JVMTI1 | ||||||
61 | static JvmtiEnvBase* _head_environment; // head of environment list | ||||||
62 | #endif // INCLUDE_JVMTI | ||||||
63 | |||||||
64 | static bool _globally_initialized; | ||||||
65 | static jvmtiPhase _phase; | ||||||
66 | static volatile int _dying_thread_env_iteration_count; | ||||||
67 | |||||||
68 | public: | ||||||
69 | |||||||
70 | enum { | ||||||
71 | JDK15_JVMTI_VERSION = JVMTI_VERSION_1_0 + 33, /* version: 1.0.33 */ | ||||||
72 | JDK16_JVMTI_VERSION = JVMTI_VERSION_1_1 + 102, /* version: 1.1.102 */ | ||||||
73 | JDK17_JVMTI_VERSION = JVMTI_VERSION_1_2 + 2 /* version: 1.2.2 */ | ||||||
74 | }; | ||||||
75 | |||||||
76 | static jvmtiPhase get_phase() { return _phase; } | ||||||
77 | static jvmtiPhase get_phase(jvmtiEnv* env) { return ((JvmtiEnvBase*)JvmtiEnv_from_jvmti_env(env))->phase(); } | ||||||
78 | static void set_phase(jvmtiPhase phase) { _phase = phase; } | ||||||
79 | static bool is_vm_live() { return _phase == JVMTI_PHASE_LIVE; } | ||||||
80 | |||||||
81 | static void entering_dying_thread_env_iteration() { ++_dying_thread_env_iteration_count; } | ||||||
82 | static void leaving_dying_thread_env_iteration() { --_dying_thread_env_iteration_count; } | ||||||
83 | static bool is_inside_dying_thread_env_iteration(){ return _dying_thread_env_iteration_count > 0; } | ||||||
84 | |||||||
85 | private: | ||||||
86 | |||||||
87 | enum { | ||||||
88 | JVMTI_MAGIC = 0x71EE, | ||||||
89 | DISPOSED_MAGIC = 0xDEFC, | ||||||
90 | BAD_MAGIC = 0xDEAD | ||||||
91 | }; | ||||||
92 | |||||||
93 | jvmtiEnv _jvmti_external; | ||||||
94 | jint _magic; | ||||||
95 | jint _version; // version value passed to JNI GetEnv() | ||||||
96 | JvmtiEnvBase* _next; | ||||||
97 | bool _is_retransformable; | ||||||
98 | const void *_env_local_storage; // per env agent allocated data. | ||||||
99 | jvmtiEventCallbacks _event_callbacks; | ||||||
100 | jvmtiExtEventCallbacks _ext_event_callbacks; | ||||||
101 | JvmtiTagMap* volatile _tag_map; | ||||||
102 | JvmtiEnvEventEnable _env_event_enable; | ||||||
103 | jvmtiCapabilities _current_capabilities; | ||||||
104 | jvmtiCapabilities _prohibited_capabilities; | ||||||
105 | volatile bool _class_file_load_hook_ever_enabled; | ||||||
106 | static volatile bool _needs_clean_up; | ||||||
107 | char** _native_method_prefixes; | ||||||
108 | int _native_method_prefix_count; | ||||||
109 | |||||||
110 | protected: | ||||||
111 | JvmtiEnvBase(jint version); | ||||||
112 | ~JvmtiEnvBase(); | ||||||
113 | void dispose(); | ||||||
114 | void env_dispose(); | ||||||
115 | |||||||
116 | void set_env_local_storage(const void* data) { _env_local_storage = data; } | ||||||
117 | const void* get_env_local_storage() { return _env_local_storage; } | ||||||
118 | |||||||
119 | void record_class_file_load_hook_enabled(); | ||||||
120 | void record_first_time_class_file_load_hook_enabled(); | ||||||
121 | |||||||
122 | char** get_native_method_prefixes() { return _native_method_prefixes; } | ||||||
123 | int get_native_method_prefix_count() { return _native_method_prefix_count; } | ||||||
124 | jvmtiError set_native_method_prefixes(jint prefix_count, char** prefixes); | ||||||
125 | |||||||
126 | private: | ||||||
127 | friend class JvmtiEventControllerPrivate; | ||||||
128 | void initialize(); | ||||||
129 | void set_event_callbacks(const jvmtiEventCallbacks* callbacks, jint size_of_callbacks); | ||||||
130 | static void globally_initialize(); | ||||||
131 | static void periodic_clean_up(); | ||||||
132 | |||||||
133 | friend class JvmtiEnvIterator; | ||||||
134 | JvmtiEnv* next_environment() { return (JvmtiEnv*)_next; } | ||||||
135 | void set_next_environment(JvmtiEnvBase* env) { _next = env; } | ||||||
136 | static JvmtiEnv* head_environment() { | ||||||
137 | JVMTI_ONLY(return (JvmtiEnv*)_head_environment)return (JvmtiEnv*)_head_environment; | ||||||
138 | NOT_JVMTI(return NULL); | ||||||
139 | } | ||||||
140 | |||||||
141 | public: | ||||||
142 | |||||||
143 | jvmtiPhase phase(); | ||||||
144 | bool is_valid(); | ||||||
145 | |||||||
146 | bool use_version_1_0_semantics(); // agent asked for version 1.0 | ||||||
147 | bool use_version_1_1_semantics(); // agent asked for version 1.1 | ||||||
148 | bool use_version_1_2_semantics(); // agent asked for version 1.2 | ||||||
149 | |||||||
150 | bool is_retransformable() { return _is_retransformable; } | ||||||
151 | |||||||
152 | static ByteSize jvmti_external_offset() { | ||||||
153 | return byte_offset_of(JvmtiEnvBase, _jvmti_external)in_ByteSize((int)(size_t)((intx)&(((JvmtiEnvBase*)16)-> _jvmti_external) - 16)); | ||||||
154 | }; | ||||||
155 | |||||||
156 | static JvmtiEnv* JvmtiEnv_from_jvmti_env(jvmtiEnv *env) { | ||||||
157 | return (JvmtiEnv*)((intptr_t)env - in_bytes(jvmti_external_offset())); | ||||||
158 | }; | ||||||
159 | |||||||
160 | jvmtiCapabilities *get_capabilities() { return &_current_capabilities; } | ||||||
161 | |||||||
162 | jvmtiCapabilities *get_prohibited_capabilities() { return &_prohibited_capabilities; } | ||||||
163 | |||||||
164 | bool early_class_hook_env() { | ||||||
165 | return get_capabilities()->can_generate_early_class_hook_events != 0 | ||||||
166 | && get_capabilities()->can_generate_all_class_hook_events != 0; | ||||||
167 | } | ||||||
168 | |||||||
169 | bool early_vmstart_env() { | ||||||
170 | return get_capabilities()->can_generate_early_vmstart != 0; | ||||||
171 | } | ||||||
172 | |||||||
173 | static char** get_all_native_method_prefixes(int* count_ptr); | ||||||
174 | |||||||
175 | // This test will answer true when all environments have been disposed and some have | ||||||
176 | // not yet been deallocated. As a result, this test should only be used as an | ||||||
177 | // optimization for the no environment case. | ||||||
178 | static bool environments_might_exist() { | ||||||
179 | return head_environment() != NULL__null; | ||||||
180 | } | ||||||
181 | |||||||
182 | static void check_for_periodic_clean_up(); | ||||||
183 | |||||||
184 | JvmtiEnvEventEnable *env_event_enable() { | ||||||
185 | return &_env_event_enable; | ||||||
186 | } | ||||||
187 | |||||||
188 | jvmtiError allocate(jlong size, unsigned char** mem_ptr) { | ||||||
189 | if (size
| ||||||
190 | return JVMTI_ERROR_ILLEGAL_ARGUMENT; | ||||||
191 | } | ||||||
192 | if (size == 0) { | ||||||
193 | *mem_ptr = NULL__null; | ||||||
194 | } else { | ||||||
195 | *mem_ptr = (unsigned char *)os::malloc((size_t)size, mtInternal); | ||||||
196 | if (*mem_ptr == NULL__null) { | ||||||
197 | return JVMTI_ERROR_OUT_OF_MEMORY; | ||||||
198 | } | ||||||
199 | } | ||||||
200 | return JVMTI_ERROR_NONE; | ||||||
201 | } | ||||||
202 | |||||||
203 | jvmtiError deallocate(unsigned char* mem) { | ||||||
204 | if (mem != NULL__null) { | ||||||
205 | os::free(mem); | ||||||
206 | } | ||||||
207 | return JVMTI_ERROR_NONE; | ||||||
208 | } | ||||||
209 | |||||||
210 | |||||||
211 | // Memory functions | ||||||
212 | unsigned char* jvmtiMalloc(jlong size); // don't use this - call allocate | ||||||
213 | |||||||
214 | // method to create a local handle | ||||||
215 | jobject jni_reference(Handle hndl); | ||||||
216 | |||||||
217 | // method to create a local handle. | ||||||
218 | // This function allows caller to specify which | ||||||
219 | // threads local handle table to use. | ||||||
220 | jobject jni_reference(JavaThread *thread, Handle hndl); | ||||||
221 | |||||||
222 | // method to destroy a local handle | ||||||
223 | void destroy_jni_reference(jobject jobj); | ||||||
224 | |||||||
225 | // method to destroy a local handle. | ||||||
226 | // This function allows caller to specify which | ||||||
227 | // threads local handle table to use. | ||||||
228 | void destroy_jni_reference(JavaThread *thread, jobject jobj); | ||||||
229 | |||||||
230 | jvmtiEnv* jvmti_external() { return &_jvmti_external; }; | ||||||
231 | |||||||
232 | // Event Dispatch | ||||||
233 | |||||||
234 | bool has_callback(jvmtiEvent event_type) { | ||||||
235 | assert(event_type >= JVMTI_MIN_EVENT_TYPE_VAL &&do { if (!(event_type >= JVMTI_MIN_EVENT_TYPE_VAL && event_type <= JVMTI_MAX_EVENT_TYPE_VAL)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.hpp" , 236, "assert(" "event_type >= JVMTI_MIN_EVENT_TYPE_VAL && event_type <= JVMTI_MAX_EVENT_TYPE_VAL" ") failed", "checking"); ::breakpoint(); } } while (0) | ||||||
236 | event_type <= JVMTI_MAX_EVENT_TYPE_VAL, "checking")do { if (!(event_type >= JVMTI_MIN_EVENT_TYPE_VAL && event_type <= JVMTI_MAX_EVENT_TYPE_VAL)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiEnvBase.hpp" , 236, "assert(" "event_type >= JVMTI_MIN_EVENT_TYPE_VAL && event_type <= JVMTI_MAX_EVENT_TYPE_VAL" ") failed", "checking"); ::breakpoint(); } } while (0); | ||||||
237 | return ((void**)&_event_callbacks)[event_type-JVMTI_MIN_EVENT_TYPE_VAL] != NULL__null; | ||||||
238 | } | ||||||
239 | |||||||
240 | jvmtiEventCallbacks* callbacks() { | ||||||
241 | return &_event_callbacks; | ||||||
242 | } | ||||||
243 | |||||||
244 | jvmtiExtEventCallbacks* ext_callbacks() { | ||||||
245 | return &_ext_event_callbacks; | ||||||
246 | } | ||||||
247 | |||||||
248 | void set_tag_map(JvmtiTagMap* tag_map) { | ||||||
249 | _tag_map = tag_map; | ||||||
250 | } | ||||||
251 | |||||||
252 | JvmtiTagMap* tag_map() { | ||||||
253 | return _tag_map; | ||||||
254 | } | ||||||
255 | |||||||
256 | JvmtiTagMap* tag_map_acquire() { | ||||||
257 | return Atomic::load_acquire(&_tag_map); | ||||||
258 | } | ||||||
259 | |||||||
260 | void release_set_tag_map(JvmtiTagMap* tag_map) { | ||||||
261 | Atomic::release_store(&_tag_map, tag_map); | ||||||
262 | } | ||||||
263 | |||||||
264 | // return true if event is enabled globally or for any thread | ||||||
265 | // True only if there is a callback for it. | ||||||
266 | bool is_enabled(jvmtiEvent event_type) { | ||||||
267 | return _env_event_enable.is_enabled(event_type); | ||||||
268 | } | ||||||
269 | |||||||
270 | // Random Utilities | ||||||
271 | |||||||
272 | protected: | ||||||
273 | // helper methods for creating arrays of global JNI Handles from local Handles | ||||||
274 | // allocated into environment specific storage | ||||||
275 | jobject * new_jobjectArray(int length, Handle *handles); | ||||||
276 | jthread * new_jthreadArray(int length, Handle *handles); | ||||||
277 | jthreadGroup * new_jthreadGroupArray(int length, Handle *handles); | ||||||
278 | |||||||
279 | // convert to a jni jclass from a non-null Klass* | ||||||
280 | jclass get_jni_class_non_null(Klass* k); | ||||||
281 | |||||||
282 | jint count_locked_objects(JavaThread *java_thread, Handle hobj); | ||||||
283 | jvmtiError get_locked_objects_in_frame(JavaThread *calling_thread, | ||||||
284 | JavaThread* java_thread, | ||||||
285 | javaVFrame *jvf, | ||||||
286 | GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitors_list, | ||||||
287 | jint depth); | ||||||
288 | public: | ||||||
289 | static vframe* vframeForNoProcess(JavaThread* java_thread, jint depth); | ||||||
290 | |||||||
291 | // get a field descriptor for the specified class and field | ||||||
292 | static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd); | ||||||
293 | |||||||
294 | // JVMTI API helper functions which are called when target thread is suspended | ||||||
295 | // or at safepoint / thread local handshake. | ||||||
296 | jvmtiError get_frame_count(JvmtiThreadState *state, jint *count_ptr); | ||||||
297 | jvmtiError get_frame_location(JavaThread* java_thread, jint depth, | ||||||
298 | jmethodID* method_ptr, jlocation* location_ptr); | ||||||
299 | jvmtiError get_object_monitor_usage(JavaThread *calling_thread, | ||||||
300 | jobject object, jvmtiMonitorUsage* info_ptr); | ||||||
301 | jvmtiError get_stack_trace(JavaThread *java_thread, | ||||||
302 | jint stack_depth, jint max_count, | ||||||
303 | jvmtiFrameInfo* frame_buffer, jint* count_ptr); | ||||||
304 | jvmtiError get_current_contended_monitor(JavaThread *calling_thread, JavaThread *java_thread, | ||||||
305 | jobject *monitor_ptr); | ||||||
306 | jvmtiError get_owned_monitors(JavaThread *calling_thread, JavaThread* java_thread, | ||||||
307 | GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list); | ||||||
308 | static jvmtiError check_top_frame(Thread* current_thread, JavaThread* java_thread, | ||||||
309 | jvalue value, TosState tos, Handle* ret_ob_h); | ||||||
310 | jvmtiError force_early_return(JavaThread* java_thread, jvalue value, TosState tos); | ||||||
311 | }; | ||||||
312 | |||||||
313 | // This class is the only safe means of iterating through environments. | ||||||
314 | // Note that this iteratation includes invalid environments pending | ||||||
315 | // deallocation -- in fact, some uses depend on this behavior. | ||||||
316 | |||||||
317 | class JvmtiEnvIterator : public StackObj { | ||||||
318 | private: | ||||||
319 | bool _entry_was_marked; | ||||||
320 | public: | ||||||
321 | JvmtiEnvIterator() { | ||||||
322 | if (Threads::number_of_threads() == 0) { | ||||||
323 | _entry_was_marked = false; // we are single-threaded, no need | ||||||
324 | } else { | ||||||
325 | Thread::current()->entering_jvmti_env_iteration(); | ||||||
326 | _entry_was_marked = true; | ||||||
327 | } | ||||||
328 | } | ||||||
329 | ~JvmtiEnvIterator() { | ||||||
330 | if (_entry_was_marked) { | ||||||
331 | Thread::current()->leaving_jvmti_env_iteration(); | ||||||
332 | } | ||||||
333 | } | ||||||
334 | JvmtiEnv* first() { return JvmtiEnvBase::head_environment(); } | ||||||
335 | JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); } | ||||||
336 | }; | ||||||
337 | |||||||
338 | class JvmtiHandshakeClosure : public HandshakeClosure { | ||||||
339 | protected: | ||||||
340 | jvmtiError _result; | ||||||
341 | public: | ||||||
342 | JvmtiHandshakeClosure(const char* name) | ||||||
343 | : HandshakeClosure(name), | ||||||
344 | _result(JVMTI_ERROR_THREAD_NOT_ALIVE) {} | ||||||
345 | jvmtiError result() { return _result; } | ||||||
346 | }; | ||||||
347 | |||||||
348 | class SetForceEarlyReturn : public JvmtiHandshakeClosure { | ||||||
349 | private: | ||||||
350 | JvmtiThreadState* _state; | ||||||
351 | jvalue _value; | ||||||
352 | TosState _tos; | ||||||
353 | public: | ||||||
354 | SetForceEarlyReturn(JvmtiThreadState* state, jvalue value, TosState tos) | ||||||
355 | : JvmtiHandshakeClosure("SetForceEarlyReturn"), | ||||||
356 | _state(state), | ||||||
357 | _value(value), | ||||||
358 | _tos(tos) {} | ||||||
359 | void do_thread(Thread *target) { | ||||||
360 | doit(target, false /* self */); | ||||||
361 | } | ||||||
362 | void doit(Thread *target, bool self); | ||||||
363 | }; | ||||||
364 | |||||||
365 | // HandshakeClosure to update for pop top frame. | ||||||
366 | class UpdateForPopTopFrameClosure : public JvmtiHandshakeClosure { | ||||||
367 | private: | ||||||
368 | JvmtiThreadState* _state; | ||||||
369 | |||||||
370 | public: | ||||||
371 | UpdateForPopTopFrameClosure(JvmtiThreadState* state) | ||||||
372 | : JvmtiHandshakeClosure("UpdateForPopTopFrame"), | ||||||
373 | _state(state) {} | ||||||
374 | void do_thread(Thread *target) { | ||||||
375 | doit(target, false /* self */); | ||||||
376 | } | ||||||
377 | void doit(Thread *target, bool self); | ||||||
378 | }; | ||||||
379 | |||||||
380 | // HandshakeClosure to set frame pop. | ||||||
381 | class SetFramePopClosure : public JvmtiHandshakeClosure { | ||||||
382 | private: | ||||||
383 | JvmtiEnv *_env; | ||||||
384 | JvmtiThreadState* _state; | ||||||
385 | jint _depth; | ||||||
386 | |||||||
387 | public: | ||||||
388 | SetFramePopClosure(JvmtiEnv *env, JvmtiThreadState* state, jint depth) | ||||||
389 | : JvmtiHandshakeClosure("SetFramePop"), | ||||||
390 | _env(env), | ||||||
391 | _state(state), | ||||||
392 | _depth(depth) {} | ||||||
393 | void do_thread(Thread *target) { | ||||||
394 | doit(target, false /* self */); | ||||||
395 | } | ||||||
396 | void doit(Thread *target, bool self); | ||||||
397 | }; | ||||||
398 | |||||||
399 | // HandshakeClosure to get monitor information with stack depth. | ||||||
400 | class GetOwnedMonitorInfoClosure : public JvmtiHandshakeClosure { | ||||||
401 | private: | ||||||
402 | JavaThread* _calling_thread; | ||||||
403 | JvmtiEnv *_env; | ||||||
404 | GrowableArray<jvmtiMonitorStackDepthInfo*> *_owned_monitors_list; | ||||||
405 | |||||||
406 | public: | ||||||
407 | GetOwnedMonitorInfoClosure(JavaThread* calling_thread, JvmtiEnv* env, | ||||||
408 | GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitor_list) | ||||||
409 | : JvmtiHandshakeClosure("GetOwnedMonitorInfo"), | ||||||
410 | _calling_thread(calling_thread), | ||||||
411 | _env(env), | ||||||
412 | _owned_monitors_list(owned_monitor_list) {} | ||||||
413 | void do_thread(Thread *target); | ||||||
414 | }; | ||||||
415 | |||||||
416 | |||||||
417 | // VM operation to get object monitor usage. | ||||||
418 | class VM_GetObjectMonitorUsage : public VM_Operation { | ||||||
419 | private: | ||||||
420 | JvmtiEnv *_env; | ||||||
421 | jobject _object; | ||||||
422 | JavaThread* _calling_thread; | ||||||
423 | jvmtiMonitorUsage* _info_ptr; | ||||||
424 | jvmtiError _result; | ||||||
425 | |||||||
426 | public: | ||||||
427 | VM_GetObjectMonitorUsage(JvmtiEnv *env, JavaThread* calling_thread, jobject object, jvmtiMonitorUsage* info_ptr) { | ||||||
428 | _env = env; | ||||||
429 | _object = object; | ||||||
430 | _calling_thread = calling_thread; | ||||||
431 | _info_ptr = info_ptr; | ||||||
432 | } | ||||||
433 | VMOp_Type type() const { return VMOp_GetObjectMonitorUsage; } | ||||||
434 | jvmtiError result() { return _result; } | ||||||
435 | void doit() { | ||||||
436 | _result = ((JvmtiEnvBase*) _env)->get_object_monitor_usage(_calling_thread, _object, _info_ptr); | ||||||
437 | } | ||||||
438 | |||||||
439 | }; | ||||||
440 | |||||||
441 | // HandshakeClosure to get current contended monitor. | ||||||
442 | class GetCurrentContendedMonitorClosure : public JvmtiHandshakeClosure { | ||||||
443 | private: | ||||||
444 | JavaThread *_calling_thread; | ||||||
445 | JvmtiEnv *_env; | ||||||
446 | jobject *_owned_monitor_ptr; | ||||||
447 | |||||||
448 | public: | ||||||
449 | GetCurrentContendedMonitorClosure(JavaThread* calling_thread, JvmtiEnv *env, jobject *mon_ptr) | ||||||
450 | : JvmtiHandshakeClosure("GetCurrentContendedMonitor"), | ||||||
451 | _calling_thread(calling_thread), | ||||||
452 | _env(env), | ||||||
453 | _owned_monitor_ptr(mon_ptr) {} | ||||||
454 | void do_thread(Thread *target); | ||||||
455 | }; | ||||||
456 | |||||||
457 | // HandshakeClosure to get stack trace. | ||||||
458 | class GetStackTraceClosure : public JvmtiHandshakeClosure { | ||||||
459 | private: | ||||||
460 | JvmtiEnv *_env; | ||||||
461 | jint _start_depth; | ||||||
462 | jint _max_count; | ||||||
463 | jvmtiFrameInfo *_frame_buffer; | ||||||
464 | jint *_count_ptr; | ||||||
465 | |||||||
466 | public: | ||||||
467 | GetStackTraceClosure(JvmtiEnv *env, jint start_depth, jint max_count, | ||||||
468 | jvmtiFrameInfo* frame_buffer, jint* count_ptr) | ||||||
469 | : JvmtiHandshakeClosure("GetStackTrace"), | ||||||
470 | _env(env), | ||||||
471 | _start_depth(start_depth), | ||||||
472 | _max_count(max_count), | ||||||
473 | _frame_buffer(frame_buffer), | ||||||
474 | _count_ptr(count_ptr) {} | ||||||
475 | void do_thread(Thread *target); | ||||||
476 | }; | ||||||
477 | |||||||
478 | // forward declaration | ||||||
479 | struct StackInfoNode; | ||||||
480 | |||||||
481 | // Get stack trace at safepoint or at direct handshake. | ||||||
482 | class MultipleStackTracesCollector { | ||||||
483 | private: | ||||||
484 | JvmtiEnv *_env; | ||||||
485 | jint _max_frame_count; | ||||||
486 | jvmtiStackInfo *_stack_info; | ||||||
487 | jvmtiError _result; | ||||||
488 | int _frame_count_total; | ||||||
489 | struct StackInfoNode *_head; | ||||||
490 | |||||||
491 | JvmtiEnvBase *env() { return (JvmtiEnvBase *)_env; } | ||||||
492 | jint max_frame_count() { return _max_frame_count; } | ||||||
493 | struct StackInfoNode *head() { return _head; } | ||||||
494 | void set_head(StackInfoNode *head) { _head = head; } | ||||||
495 | |||||||
496 | public: | ||||||
497 | MultipleStackTracesCollector(JvmtiEnv *env, jint max_frame_count) | ||||||
498 | : _env(env), | ||||||
499 | _max_frame_count(max_frame_count), | ||||||
500 | _stack_info(NULL__null), | ||||||
501 | _result(JVMTI_ERROR_NONE), | ||||||
502 | _frame_count_total(0), | ||||||
503 | _head(NULL__null) { | ||||||
504 | } | ||||||
505 | void set_result(jvmtiError result) { _result = result; } | ||||||
506 | void fill_frames(jthread jt, JavaThread *thr, oop thread_oop); | ||||||
507 | void allocate_and_fill_stacks(jint thread_count); | ||||||
508 | jvmtiStackInfo *stack_info() { return _stack_info; } | ||||||
509 | jvmtiError result() { return _result; } | ||||||
510 | }; | ||||||
511 | |||||||
512 | |||||||
513 | // VM operation to get stack trace at safepoint. | ||||||
514 | class VM_GetAllStackTraces : public VM_Operation { | ||||||
515 | private: | ||||||
516 | JavaThread *_calling_thread; | ||||||
517 | jint _final_thread_count; | ||||||
518 | MultipleStackTracesCollector _collector; | ||||||
519 | |||||||
520 | public: | ||||||
521 | VM_GetAllStackTraces(JvmtiEnv *env, JavaThread *calling_thread, | ||||||
522 | jint max_frame_count) | ||||||
523 | : _calling_thread(calling_thread), | ||||||
524 | _final_thread_count(0), | ||||||
525 | _collector(env, max_frame_count) { | ||||||
526 | } | ||||||
527 | VMOp_Type type() const { return VMOp_GetAllStackTraces; } | ||||||
528 | void doit(); | ||||||
529 | jint final_thread_count() { return _final_thread_count; } | ||||||
530 | jvmtiStackInfo *stack_info() { return _collector.stack_info(); } | ||||||
531 | jvmtiError result() { return _collector.result(); } | ||||||
532 | }; | ||||||
533 | |||||||
534 | // VM operation to get stack trace at safepoint. | ||||||
535 | class VM_GetThreadListStackTraces : public VM_Operation { | ||||||
536 | private: | ||||||
537 | jint _thread_count; | ||||||
538 | const jthread* _thread_list; | ||||||
539 | MultipleStackTracesCollector _collector; | ||||||
540 | |||||||
541 | public: | ||||||
542 | VM_GetThreadListStackTraces(JvmtiEnv *env, jint thread_count, const jthread* thread_list, jint max_frame_count) | ||||||
543 | : _thread_count(thread_count), | ||||||
544 | _thread_list(thread_list), | ||||||
545 | _collector(env, max_frame_count) { | ||||||
546 | } | ||||||
547 | VMOp_Type type() const { return VMOp_GetThreadListStackTraces; } | ||||||
548 | void doit(); | ||||||
549 | jvmtiStackInfo *stack_info() { return _collector.stack_info(); } | ||||||
550 | jvmtiError result() { return _collector.result(); } | ||||||
551 | }; | ||||||
552 | |||||||
553 | // HandshakeClosure to get single stack trace. | ||||||
554 | class GetSingleStackTraceClosure : public HandshakeClosure { | ||||||
555 | private: | ||||||
556 | JavaThread *_calling_thread; | ||||||
557 | jthread _jthread; | ||||||
558 | MultipleStackTracesCollector _collector; | ||||||
559 | |||||||
560 | public: | ||||||
561 | GetSingleStackTraceClosure(JvmtiEnv *env, JavaThread *calling_thread, | ||||||
562 | jthread thread, jint max_frame_count) | ||||||
563 | : HandshakeClosure("GetSingleStackTrace"), | ||||||
564 | _calling_thread(calling_thread), | ||||||
565 | _jthread(thread), | ||||||
566 | _collector(env, max_frame_count) { | ||||||
567 | } | ||||||
568 | void do_thread(Thread *target); | ||||||
569 | jvmtiStackInfo *stack_info() { return _collector.stack_info(); } | ||||||
570 | jvmtiError result() { return _collector.result(); } | ||||||
571 | }; | ||||||
572 | |||||||
573 | // HandshakeClosure to count stack frames. | ||||||
574 | class GetFrameCountClosure : public JvmtiHandshakeClosure { | ||||||
575 | private: | ||||||
576 | JvmtiEnv *_env; | ||||||
577 | JvmtiThreadState *_state; | ||||||
578 | jint *_count_ptr; | ||||||
579 | |||||||
580 | public: | ||||||
581 | GetFrameCountClosure(JvmtiEnv *env, JvmtiThreadState *state, jint *count_ptr) | ||||||
582 | : JvmtiHandshakeClosure("GetFrameCount"), | ||||||
583 | _env(env), | ||||||
584 | _state(state), | ||||||
585 | _count_ptr(count_ptr) {} | ||||||
586 | void do_thread(Thread *target); | ||||||
587 | }; | ||||||
588 | |||||||
589 | // HandshakeClosure to get frame location. | ||||||
590 | class GetFrameLocationClosure : public JvmtiHandshakeClosure { | ||||||
591 | private: | ||||||
592 | JvmtiEnv *_env; | ||||||
593 | jint _depth; | ||||||
594 | jmethodID* _method_ptr; | ||||||
595 | jlocation* _location_ptr; | ||||||
596 | |||||||
597 | public: | ||||||
598 | GetFrameLocationClosure(JvmtiEnv *env, jint depth, | ||||||
599 | jmethodID* method_ptr, jlocation* location_ptr) | ||||||
600 | : JvmtiHandshakeClosure("GetFrameLocation"), | ||||||
601 | _env(env), | ||||||
602 | _depth(depth), | ||||||
603 | _method_ptr(method_ptr), | ||||||
604 | _location_ptr(location_ptr) {} | ||||||
605 | void do_thread(Thread *target); | ||||||
606 | }; | ||||||
607 | |||||||
608 | |||||||
609 | // ResourceTracker | ||||||
610 | // | ||||||
611 | // ResourceTracker works a little like a ResourceMark. All allocates | ||||||
612 | // using the resource tracker are recorded. If an allocate using the | ||||||
613 | // resource tracker fails the destructor will free any resources | ||||||
614 | // that were allocated using the tracker. | ||||||
615 | // The motive for this class is to avoid messy error recovery code | ||||||
616 | // in situations where multiple allocations are done in sequence. If | ||||||
617 | // the second or subsequent allocation fails it avoids any code to | ||||||
618 | // release memory allocated in the previous calls. | ||||||
619 | // | ||||||
620 | // Usage :- | ||||||
621 | // ResourceTracker rt(env); | ||||||
622 | // : | ||||||
623 | // err = rt.allocate(1024, &ptr); | ||||||
624 | |||||||
625 | class ResourceTracker : public StackObj { | ||||||
626 | private: | ||||||
627 | JvmtiEnv* _env; | ||||||
628 | GrowableArray<unsigned char*> *_allocations; | ||||||
629 | bool _failed; | ||||||
630 | public: | ||||||
631 | ResourceTracker(JvmtiEnv* env); | ||||||
632 | ~ResourceTracker(); | ||||||
633 | jvmtiError allocate(jlong size, unsigned char** mem_ptr); | ||||||
634 | unsigned char* allocate(jlong size); | ||||||
635 | char* strdup(const char* str); | ||||||
636 | }; | ||||||
637 | |||||||
638 | |||||||
639 | // Jvmti monitor closure to collect off stack monitors. | ||||||
640 | class JvmtiMonitorClosure: public MonitorClosure { | ||||||
641 | private: | ||||||
642 | JavaThread *_calling_thread; | ||||||
643 | GrowableArray<jvmtiMonitorStackDepthInfo*> *_owned_monitors_list; | ||||||
644 | jvmtiError _error; | ||||||
645 | JvmtiEnvBase *_env; | ||||||
646 | |||||||
647 | public: | ||||||
648 | JvmtiMonitorClosure(JavaThread *calling_thread, | ||||||
649 | GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors, | ||||||
650 | JvmtiEnvBase *env) { | ||||||
651 | _calling_thread = calling_thread; | ||||||
652 | _owned_monitors_list = owned_monitors; | ||||||
653 | _error = JVMTI_ERROR_NONE; | ||||||
654 | _env = env; | ||||||
655 | } | ||||||
656 | void do_monitor(ObjectMonitor* mon); | ||||||
657 | jvmtiError error() { return _error;} | ||||||
658 | }; | ||||||
659 | |||||||
660 | |||||||
661 | // Jvmti module closure to collect all modules loaded to the system. | ||||||
662 | class JvmtiModuleClosure : public StackObj { | ||||||
663 | private: | ||||||
664 | static GrowableArray<OopHandle> *_tbl; // Protected with Module_lock | ||||||
665 | |||||||
666 | static void do_module(ModuleEntry* entry); | ||||||
667 | public: | ||||||
668 | jvmtiError get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr); | ||||||
669 | }; | ||||||
670 | |||||||
671 | #endif // SHARE_PRIMS_JVMTIENVBASE_HPP |