void JvmtiEnvBase::periodic_clean_up() { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); // JvmtiEnvBase reference is saved in JvmtiEnvThreadState. So // clean up JvmtiThreadState before deleting JvmtiEnv pointer. JvmtiThreadState::periodic_clean_up(); // Unlink all invalid environments from the list of environments // and deallocate them JvmtiEnvIterator it; JvmtiEnvBase* previous_env = NULL; JvmtiEnvBase* env = it.first(); while (env != NULL) { if (env->is_valid()) { previous_env = env; env = it.next(env); } else { // This one isn't valid, remove it from the list and deallocate it JvmtiEnvBase* defunct_env = env; env = it.next(env); if (previous_env == NULL) { _head_environment = env; } else { previous_env->set_next_environment(env); } delete defunct_env; } } }
void JvmtiEnvBase::initialize() { assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check"); // Add this environment to the end of the environment list (order is important) { // This block of code must not contain any safepoints, as list deallocation // (which occurs at a safepoint) cannot occur simultaneously with this list // addition. Note: No_Safepoint_Verifier cannot, currently, be used before // threads exist. JvmtiEnvIterator it; JvmtiEnvBase *previous_env = NULL; for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { previous_env = env; } if (previous_env == NULL) { _head_environment = this; } else { previous_env->set_next_environment(this); } } if (_globally_initialized == false) { globally_initialize(); } }
JvmtiThreadState::JvmtiThreadState(JavaThread* thread) : _thread_event_enable() { assert(JvmtiThreadState_lock->is_locked(), "sanity check"); _thread = thread; _exception_detected = false; _exception_caught = false; _debuggable = true; _hide_single_stepping = false; _hide_level = 0; _pending_step_for_popframe = false; _class_being_redefined = NULL; _class_load_kind = jvmti_class_load_kind_load; _head_env_thread_state = NULL; _dynamic_code_event_collector = NULL; _vm_object_alloc_event_collector = NULL; _the_class_for_redefinition_verification = NULL; _scratch_class_for_redefinition_verification = NULL; _cur_stack_depth = UNKNOWN_STACK_DEPTH; // JVMTI ForceEarlyReturn support _pending_step_for_earlyret = false; _earlyret_state = earlyret_inactive; _earlyret_tos = ilgl; _earlyret_value.j = 0L; _earlyret_oop = NULL; // add all the JvmtiEnvThreadState to the new JvmtiThreadState { JvmtiEnvIterator it; for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { if (env->is_valid()) { add_env(env); } } } // link us into the list { // The thread state list manipulation code must not have safepoints. // See periodic_clean_up(). debug_only(No_Safepoint_Verifier nosafepoint;) _prev = NULL; _next = _head; if (_head != NULL) { _head->_prev = this; } _head = this; }
// Compute truly enabled events - meaning if the event can and could be // sent. An event is truly enabled if it is user enabled on the thread // or globally user enabled, but only if there is a callback or event hook // for it and, for field watch and frame pop, one has been set. // Compute if truly enabled, per thread, per environment, per combination // (thread x environment), and overall. These merges are true if any is true. // True per thread if some environment has callback set and the event is globally // enabled or enabled for this thread. // True per environment if the callback is set and the event is globally // enabled in this environment or enabled for any thread in this environment. // True per combination if the environment has the callback set and the // event is globally enabled in this environment or the event is enabled // for this thread and environment. // // All states transitions dependent on these transitions are also handled here. void JvmtiEventControllerPrivate::recompute_enabled() { assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check"); // event enabled for any thread in any environment jlong was_any_env_thread_enabled = JvmtiEventController::_universal_global_event_enabled.get_bits(); jlong any_env_thread_enabled = 0; EC_TRACE(("JVMTI [-] # recompute enabled - before " UINT64_FORMAT_X, was_any_env_thread_enabled)); // compute non-thread-filters events. // This must be done separately from thread-filtered events, since some // events can occur before any threads exist. JvmtiEnvIterator it; for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { any_env_thread_enabled |= recompute_env_enabled(env); } // We need to create any missing jvmti_thread_state if there are globally set thread // filtered events and there weren't last time if ( (any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) != 0 && (was_any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) == 0) { assert(JvmtiEnv::is_vm_live() || (JvmtiEnv::get_phase()==JVMTI_PHASE_START), "thread filtered events should not be enabled when VM not in start or live phase"); { MutexLocker mu(Threads_lock); //hold the Threads_lock for the iteration for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) { // state_for_while_locked() makes tp->is_exiting() check JvmtiThreadState::state_for_while_locked(tp); // create the thread state if missing } }// release Threads_lock } // compute and set thread-filtered events for (JvmtiThreadState *state = JvmtiThreadState::first(); state != NULL; state = state->next()) { any_env_thread_enabled |= recompute_thread_enabled(state); } // set universal state (across all envs and threads) jlong delta = any_env_thread_enabled ^ was_any_env_thread_enabled; if (delta != 0) { JvmtiExport::set_should_post_field_access((any_env_thread_enabled & FIELD_ACCESS_BIT) != 0); JvmtiExport::set_should_post_field_modification((any_env_thread_enabled & FIELD_MODIFICATION_BIT) != 0); JvmtiExport::set_should_post_class_load((any_env_thread_enabled & CLASS_LOAD_BIT) != 0); JvmtiExport::set_should_post_class_file_load_hook((any_env_thread_enabled & CLASS_FILE_LOAD_HOOK_BIT) != 0); JvmtiExport::set_should_post_native_method_bind((any_env_thread_enabled & NATIVE_METHOD_BIND_BIT) != 0); JvmtiExport::set_should_post_dynamic_code_generated((any_env_thread_enabled & DYNAMIC_CODE_GENERATED_BIT) != 0); JvmtiExport::set_should_post_data_dump((any_env_thread_enabled & DATA_DUMP_BIT) != 0); JvmtiExport::set_should_post_class_prepare((any_env_thread_enabled & CLASS_PREPARE_BIT) != 0); JvmtiExport::set_should_post_class_unload((any_env_thread_enabled & CLASS_UNLOAD_BIT) != 0); JvmtiExport::set_should_post_monitor_contended_enter((any_env_thread_enabled & MONITOR_CONTENDED_ENTER_BIT) != 0); JvmtiExport::set_should_post_monitor_contended_entered((any_env_thread_enabled & MONITOR_CONTENDED_ENTERED_BIT) != 0); JvmtiExport::set_should_post_monitor_wait((any_env_thread_enabled & MONITOR_WAIT_BIT) != 0); JvmtiExport::set_should_post_monitor_waited((any_env_thread_enabled & MONITOR_WAITED_BIT) != 0); JvmtiExport::set_should_post_garbage_collection_start((any_env_thread_enabled & GARBAGE_COLLECTION_START_BIT) != 0); JvmtiExport::set_should_post_garbage_collection_finish((any_env_thread_enabled & GARBAGE_COLLECTION_FINISH_BIT) != 0); JvmtiExport::set_should_post_object_free((any_env_thread_enabled & OBJECT_FREE_BIT) != 0); JvmtiExport::set_should_post_resource_exhausted((any_env_thread_enabled & RESOURCE_EXHAUSTED_BIT) != 0); JvmtiExport::set_should_post_compiled_method_load((any_env_thread_enabled & COMPILED_METHOD_LOAD_BIT) != 0); JvmtiExport::set_should_post_compiled_method_unload((any_env_thread_enabled & COMPILED_METHOD_UNLOAD_BIT) != 0); JvmtiExport::set_should_post_vm_object_alloc((any_env_thread_enabled & VM_OBJECT_ALLOC_BIT) != 0); // need this if we want thread events or we need them to init data JvmtiExport::set_should_post_thread_life((any_env_thread_enabled & NEED_THREAD_LIFE_EVENTS) != 0); // If single stepping is turned on or off, execute the VM op to change it. if (delta & SINGLE_STEP_BIT) { switch (JvmtiEnv::get_phase()) { case JVMTI_PHASE_DEAD: // If the VM is dying we can't execute VM ops break; case JVMTI_PHASE_LIVE: { VM_ChangeSingleStep op((any_env_thread_enabled & SINGLE_STEP_BIT) != 0); VMThread::execute(&op); break; } default: assert(false, "should never come here before live phase"); break; } } // set global truly enabled, that is, any thread in any environment JvmtiEventController::_universal_global_event_enabled.set_bits(any_env_thread_enabled); // set global should_post_on_exceptions JvmtiExport::set_should_post_on_exceptions((any_env_thread_enabled & SHOULD_POST_ON_EXCEPTIONS_BITS) != 0); } EC_TRACE(("JVMTI [-] # recompute enabled - after " UINT64_FORMAT_X, any_env_thread_enabled)); }