| File: | jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp |
| Warning: | line 1048, 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 |