| File: | jdk/src/hotspot/share/prims/jvmtiEnvBase.cpp |
| Warning: | line 1225, 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 != NULL__null) { | |||
| 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 != NULL__null) { // monitor is owned | |||
| 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 != NULL__null) { | |||
| 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 != JVMTI_ERROR_NONE) { | |||
| 1032 | return err; | |||
| 1033 | } | |||
| 1034 | err = allocate(ret.notify_waiter_count * sizeof(jthread *), | |||
| 1035 | (unsigned char**)&ret.notify_waiters); | |||
| 1036 | if (err != JVMTI_ERROR_NONE) { | |||
| 1037 | deallocate((unsigned char*)ret.waiters); | |||
| 1038 | return err; | |||
| 1039 | } | |||
| 1040 | ||||
| 1041 | // now derive the rest of the fields | |||
| 1042 | if (mon != NULL__null) { | |||
| 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 | } |