diff --git a/src/cpu/sparc/vm/interp_masm_sparc.cpp b/src/cpu/sparc/vm/interp_masm_sparc.cpp index f134852e4d6b2019a753a766da6d3510a7b11584..dee9fcc3cd0ceb7de61d374b3dbd506b6633e6de 100644 --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -2465,7 +2465,10 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { // InterpreterRuntime::post_method_entry(); // } // if (DTraceMethodProbes) { -// SharedRuntime::dtrace_method_entry(method, reciever); +// SharedRuntime::dtrace_method_entry(method, receiver); +// } +// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { +// SharedRuntime::rc_trace_method_entry(method, receiver); // } void InterpreterMacroAssembler::notify_method_entry() { @@ -2497,6 +2500,13 @@ void InterpreterMacroAssembler::notify_method_entry() { CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), G2_thread, Lmethod); } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + call_VM_leaf(noreg, + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + G2_thread, Lmethod); + } } diff --git a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 6fed65b3ddc3bbad2c0cc9f5141d88757dffcb56..5804fbbfe123644c189c885c72f5f4182b4c1e8f 100644 --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -2161,6 +2161,18 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ restore(); } + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + // create inner frame + __ save_frame(0); + __ mov(G2_thread, L7_thread_cache); + __ set_oop_constant(JNIHandles::make_local(method()), O1); + __ call_VM_leaf(L7_thread_cache, + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + G2_thread, O1); + __ restore(); + } + // We are in the jni frame unless saved_frame is true in which case // we are in one frame deeper (the "inner" frame). If we are in the // "inner" frames the args are in the Iregs and if the jni frame then diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp index c11c3bc5404e7e409638d3d6c9d1bda6092891db..bd11f82101e38d997a28e52a2e4b1ab4fc07c4ac 100644 --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1512,6 +1512,15 @@ void InterpreterMacroAssembler::notify_method_entry() { call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), rcx, rbx); } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + get_thread(rcx); + get_method(rbx); + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + rcx, rbx); + } } diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp index ebcac0fddf90d343b09e00c956e12d0981e4bf94..5ab8daeacac82ca10dc221c47707d3a70b3df289 100644 --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1593,6 +1593,14 @@ void InterpreterMacroAssembler::notify_method_entry() { call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), r15_thread, c_rarg1); } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + get_method(c_rarg1); + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + r15_thread, c_rarg1); + } } diff --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 3cf22d7fa05555994607c036d4ba6886c614bc79..478133432c00b522790b26e87ae14693cb3c6837 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1534,6 +1534,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, thread, rax); } + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + __ movoop(rax, JNIHandles::make_local(method())); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + thread, rax); + } // These are register definitions we need for locking/unlocking const Register swap_reg = rax; // Must use rax, for cmpxchg instruction diff --git a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 7fc2b6685e411b0e34a41088d0809dce8ecd1617..e2c418f70b15672e100b574431ff845cc38f871d 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -1508,6 +1508,17 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, restore_args(masm, total_c_args, c_arg, out_regs); } + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + // protect the args we've loaded + save_args(masm, total_c_args, c_arg, out_regs); + __ movoop(c_rarg1, JNIHandles::make_local(method())); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + r15_thread, c_rarg1); + restore_args(masm, total_c_args, c_arg, out_regs); + } + // Lock a synchronized method // Register definitions used by locking and unlocking diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core index 603485132e844c686cf540936c403f556f0650cc..7c20a0af5f55a35ebac1def2eacb7ad1aae86587 100644 --- a/src/share/vm/includeDB_core +++ b/src/share/vm/includeDB_core @@ -2094,6 +2094,7 @@ interp_masm_.cpp interp_masm_.hpp interp_masm_.cpp interpreterRuntime.hpp interp_masm_.cpp interpreter.hpp interp_masm_.cpp jvmtiExport.hpp +interp_masm_.cpp jvmtiRedefineClassesTrace.hpp interp_masm_.cpp jvmtiThreadState.hpp interp_masm_.cpp markOop.hpp interp_masm_.cpp methodDataOop.hpp @@ -3670,6 +3671,7 @@ sharedRuntime.cpp interpreterRuntime.hpp sharedRuntime.cpp interpreter.hpp sharedRuntime.cpp javaCalls.hpp sharedRuntime.cpp jvmtiExport.hpp +sharedRuntime.cpp jvmtiRedefineClassesTrace.hpp sharedRuntime.cpp nativeInst_.hpp sharedRuntime.cpp nativeLookup.hpp sharedRuntime.cpp oop.inline.hpp @@ -3699,6 +3701,7 @@ sharedRuntime_.cpp compiledICHolderOop.hpp sharedRuntime_.cpp debugInfoRec.hpp sharedRuntime_.cpp icBuffer.hpp sharedRuntime_.cpp interpreter.hpp +sharedRuntime_.cpp jvmtiRedefineClassesTrace.hpp sharedRuntime_.cpp sharedRuntime.hpp sharedRuntime_.cpp vframeArray.hpp sharedRuntime_.cpp vmreg_.inline.hpp diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp index 27b32d09760b9d800fd14e401602ea09497e3d10..9411e76509b0b4f5b25dd667a513ae158a36a673 100644 --- a/src/share/vm/oops/klassVtable.cpp +++ b/src/share/vm/oops/klassVtable.cpp @@ -992,6 +992,10 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m methodOop new_method = new_methods[j]; itableMethodEntry* ime = method_entry(0); + // The itable can describe more than one interface and the same + // method signature can be specified by more than one interface. + // This means we have to do an exhaustive search to find all the + // old_method references. for (int i = 0; i < _size_method_table; i++) { if (ime->method() == old_method) { ime->initialize(new_method); @@ -1008,7 +1012,6 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } - break; } ime++; } diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp index a19c48972c834c9a19269bcb03bda2a290018474..95977f0092e2d9fb9b5d473a57142a9fe971e74e 100644 --- a/src/share/vm/prims/jvmtiEnv.cpp +++ b/src/share/vm/prims/jvmtiEnv.cpp @@ -99,6 +99,9 @@ JvmtiEnv::SetThreadLocalStorage(JavaThread* java_thread, const void* data) { } // otherwise, create the state state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } } state->env_thread_state(this)->set_agent_thread_local_storage_data((void*)data); return JVMTI_ERROR_NONE; @@ -1308,6 +1311,9 @@ JvmtiEnv::GetFrameCount(JavaThread* java_thread, jint* count_ptr) { // retrieve or create JvmtiThreadState. JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } uint32_t debug_bits = 0; if (is_thread_fully_suspended(java_thread, true, &debug_bits)) { err = get_frame_count(state, count_ptr); @@ -1329,6 +1335,12 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) { HandleMark hm(current_thread); uint32_t debug_bits = 0; + // retrieve or create the state + JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } + // Check if java_thread is fully suspended if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) { return JVMTI_ERROR_THREAD_NOT_SUSPENDED; @@ -1399,9 +1411,6 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) { // It's fine to update the thread state here because no JVMTI events // shall be posted for this PopFrame. - // retreive or create the state - JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); - state->update_for_pop_top_frame(); java_thread->set_popframe_condition(JavaThread::popframe_pending_bit); // Set pending step flag for this popframe and it is cleared when next @@ -1445,6 +1454,11 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { ResourceMark rm; uint32_t debug_bits = 0; + JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } + if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) { return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } @@ -1464,7 +1478,6 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL"); - JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread); int frame_number = state->count_frames() - depth; state->env_thread_state(this)->set_frame_pop(frame_number); diff --git a/src/share/vm/prims/jvmtiEnvBase.cpp b/src/share/vm/prims/jvmtiEnvBase.cpp index 3152e91c3a52771ccd44851c9b60eb96e9893f02..c0c98f01e53c3b06eac8eecee67ba7fb9ba18289 100644 --- a/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/src/share/vm/prims/jvmtiEnvBase.cpp @@ -94,6 +94,35 @@ JvmtiEnvBase::initialize() { } +bool +JvmtiEnvBase::is_valid() { + jint value = 0; + + // This object might not be a JvmtiEnvBase so we can't assume + // the _magic field is properly aligned. Get the value in a safe + // way and then check against JVMTI_MAGIC. + + switch (sizeof(_magic)) { + case 2: + value = Bytes::get_native_u2((address)&_magic); + break; + + case 4: + value = Bytes::get_native_u4((address)&_magic); + break; + + case 8: + value = Bytes::get_native_u8((address)&_magic); + break; + + default: + guarantee(false, "_magic field is an unexpected size"); + } + + return value == JVMTI_MAGIC; +} + + JvmtiEnvBase::JvmtiEnvBase() : _env_event_enable() { _env_local_storage = NULL; _tag_map = NULL; @@ -1322,6 +1351,12 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState HandleMark hm(current_thread); uint32_t debug_bits = 0; + // retrieve or create the state + JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } + // Check if java_thread is fully suspended if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, @@ -1329,9 +1364,6 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } - // retreive or create the state - JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); - // Check to see if a ForceEarlyReturn was already in progress if (state->is_earlyret_pending()) { // Probably possible for JVMTI clients to trigger this, but the diff --git a/src/share/vm/prims/jvmtiEnvBase.hpp b/src/share/vm/prims/jvmtiEnvBase.hpp index 477725ffec5cd2c172bd61ac9099ce0382071a98..e6dd31e5870c7d22768c9d9784dc47006557ac8d 100644 --- a/src/share/vm/prims/jvmtiEnvBase.hpp +++ b/src/share/vm/prims/jvmtiEnvBase.hpp @@ -120,7 +120,7 @@ class JvmtiEnvBase : public CHeapObj { public: - bool is_valid() { return _magic == JVMTI_MAGIC; } + bool is_valid(); bool is_retransformable() { return _is_retransformable; } diff --git a/src/share/vm/prims/jvmtiEventController.cpp b/src/share/vm/prims/jvmtiEventController.cpp index ebadd45e2c2012728d46346cb7144e2ee3388b11..4e07d6f84c2fe425e1e889d3576d65205772c16c 100644 --- a/src/share/vm/prims/jvmtiEventController.cpp +++ b/src/share/vm/prims/jvmtiEventController.cpp @@ -478,6 +478,11 @@ JvmtiEventControllerPrivate::recompute_env_thread_enabled(JvmtiEnvThreadState* e // set external state accordingly. Only thread-filtered events are included. jlong JvmtiEventControllerPrivate::recompute_thread_enabled(JvmtiThreadState *state) { + if (state == NULL) { + // associated JavaThread is exiting + return (jlong)0; + } + jlong was_any_env_enabled = state->thread_event_enable()->_event_enabled.get_bits(); jlong any_env_enabled = 0; @@ -553,6 +558,7 @@ JvmtiEventControllerPrivate::recompute_enabled() { { 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 diff --git a/src/share/vm/prims/jvmtiExport.cpp b/src/share/vm/prims/jvmtiExport.cpp index a3894b3d66e5c6f5e18b2853b706852842f6e0e4..50ecb4b9559fab621e2b76fd82bca1801ae29fd5 100644 --- a/src/share/vm/prims/jvmtiExport.cpp +++ b/src/share/vm/prims/jvmtiExport.cpp @@ -1872,6 +1872,9 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na { // register the stub with the current dynamic code event collector JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current()); + // state can only be NULL if the current thread is exiting which + // should not happen since we're trying to post an event + guarantee(state != NULL, "attempt to register stub via an exiting thread"); JvmtiDynamicCodeEventCollector* collector = state->get_dynamic_code_event_collector(); guarantee(collector != NULL, "attempt to register stub without event collector"); collector->register_stub(name, code_begin, code_end); @@ -2253,6 +2256,9 @@ void JvmtiExport::cms_ref_processing_epilogue() { void JvmtiEventCollector::setup_jvmti_thread_state() { // set this event collector to be the current one. JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current()); + // state can only be NULL if the current thread is exiting which + // should not happen since we're trying to configure for event collection + guarantee(state != NULL, "exiting thread called setup_jvmti_thread_state"); if (is_vm_object_alloc_event()) { _prev = state->get_vm_object_alloc_event_collector(); state->set_vm_object_alloc_event_collector((JvmtiVMObjectAllocEventCollector *)this); diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp index f9a512c4222b8b579e5b351a27a9afb3bc3288a1..5a174b35bc3e53b712e7cde40231a6108fc9b8c7 100644 --- a/src/share/vm/prims/jvmtiImpl.cpp +++ b/src/share/vm/prims/jvmtiImpl.cpp @@ -238,6 +238,35 @@ JvmtiRawMonitor::~JvmtiRawMonitor() { } +bool +JvmtiRawMonitor::is_valid() { + int value = 0; + + // This object might not be a JvmtiRawMonitor so we can't assume + // the _magic field is properly aligned. Get the value in a safe + // way and then check against JVMTI_RM_MAGIC. + + switch (sizeof(_magic)) { + case 2: + value = Bytes::get_native_u2((address)&_magic); + break; + + case 4: + value = Bytes::get_native_u4((address)&_magic); + break; + + case 8: + value = Bytes::get_native_u8((address)&_magic); + break; + + default: + guarantee(false, "_magic field is an unexpected size"); + } + + return value == JVMTI_RM_MAGIC; +} + + // // class JvmtiBreakpoint // diff --git a/src/share/vm/prims/jvmtiImpl.hpp b/src/share/vm/prims/jvmtiImpl.hpp index d1b8414e61efa6c0cb84364ffda0265c88138899..2605546c62d047574b646b6bebd22a99b6d8e4e3 100644 --- a/src/share/vm/prims/jvmtiImpl.hpp +++ b/src/share/vm/prims/jvmtiImpl.hpp @@ -349,7 +349,7 @@ public: ~JvmtiRawMonitor(); int magic() { return _magic; } const char *get_name() { return _name; } - bool is_valid() { return _magic == JVMTI_RM_MAGIC; } + bool is_valid(); }; // Onload pending raw monitors diff --git a/src/share/vm/prims/jvmtiRedefineClasses.cpp b/src/share/vm/prims/jvmtiRedefineClasses.cpp index 4cc6b577b4718ff1d26bd29d9f73e3cb1a8e4303..3059c731e9f41cdf9bba628750bb250a02dea0fd 100644 --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -831,6 +831,9 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { ResourceMark rm(THREAD); JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current()); + // state can only be NULL if the current thread is exiting which + // should not happen since we're trying to do a RedefineClasses + guarantee(state != NULL, "exiting thread calling load_new_class_versions"); for (int i = 0; i < _class_count; i++) { oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass); // classes for primitives cannot be redefined diff --git a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp index 83192cf16d715d6ad204e1c27dbcbf91ba19e77b..6762e572baae69478d9cd2f01321836c19780690 100644 --- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp +++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp @@ -49,8 +49,8 @@ // 0x00000400 | 1024 - previous class weak reference mgmt during // add previous ops (GC) // 0x00000800 | 2048 - previous class breakpoint mgmt -// 0x00001000 | 4096 - unused -// 0x00002000 | 8192 - unused +// 0x00001000 | 4096 - detect calls to obsolete methods +// 0x00002000 | 8192 - fail a guarantee() in addition to detection // 0x00004000 | 16384 - unused // 0x00008000 | 32768 - old/new method matching/add/delete // 0x00010000 | 65536 - impl details: CP size info diff --git a/src/share/vm/prims/jvmtiThreadState.hpp b/src/share/vm/prims/jvmtiThreadState.hpp index 703d873397f50b67d3cb46dbae63409a797a2b4b..d77d2a8a428a4475657c8e00ecb8c435cb100650 100644 --- a/src/share/vm/prims/jvmtiThreadState.hpp +++ b/src/share/vm/prims/jvmtiThreadState.hpp @@ -314,17 +314,24 @@ class JvmtiThreadState : public CHeapObj { void update_for_pop_top_frame(); // already holding JvmtiThreadState_lock - retrieve or create JvmtiThreadState + // Can return NULL if JavaThread is exiting. inline static JvmtiThreadState *state_for_while_locked(JavaThread *thread) { assert(JvmtiThreadState_lock->is_locked(), "sanity check"); JvmtiThreadState *state = thread->jvmti_thread_state(); if (state == NULL) { + if (thread->is_exiting()) { + // don't add a JvmtiThreadState to a thread that is exiting + return NULL; + } + state = new JvmtiThreadState(thread); } return state; } // retrieve or create JvmtiThreadState + // Can return NULL if JavaThread is exiting. inline static JvmtiThreadState *state_for(JavaThread *thread) { JvmtiThreadState *state = thread->jvmti_thread_state(); if (state == NULL) { diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp index cf69631c0bb35ed740c4f91ed3a5be833c58816d..bccd24056f0d6b63d071f32e0b598d216f209980 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp @@ -377,6 +377,32 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread *thread, symbolOop throw_and_post_jvmti_exception(thread, h_exception); } +// The interpreter code to call this tracing function is only +// called/generated when TraceRedefineClasses has the right bits +// set. Since obsolete methods are never compiled, we don't have +// to modify the compilers to generate calls to this function. +// +JRT_LEAF(int, SharedRuntime::rc_trace_method_entry( + JavaThread* thread, methodOopDesc* method)) + assert(RC_TRACE_IN_RANGE(0x00001000, 0x00002000), "wrong call"); + + if (method->is_obsolete()) { + // We are calling an obsolete method, but this is not necessarily + // an error. Our method could have been redefined just after we + // fetched the methodOop from the constant pool. + + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE_WITH_THREAD(0x00001000, thread, + ("calling obsolete method '%s'", + method->name_and_sig_as_C_string())); + if (RC_TRACE_ENABLED(0x00002000)) { + // this option is provided to debug calls to obsolete methods + guarantee(false, "faulting at call to an obsolete method."); + } + } + return 0; +JRT_END + // ret_pc points into caller; we are returning caller's exception handler // for given exception address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception, diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp index d040660dcfab6f303ffbde010dbdf86c9af8af3d..bea176a9dce78ceb1ecbe7a52ea1e1e7a8a46c9e 100644 --- a/src/share/vm/runtime/sharedRuntime.hpp +++ b/src/share/vm/runtime/sharedRuntime.hpp @@ -166,6 +166,9 @@ class SharedRuntime: AllStatic { static void throw_and_post_jvmti_exception(JavaThread *thread, Handle h_exception); static void throw_and_post_jvmti_exception(JavaThread *thread, symbolOop name, const char *message = NULL); + // RedefineClasses() tracing support for obsolete method entry + static int rc_trace_method_entry(JavaThread* thread, methodOopDesc* m); + // To be used as the entry point for unresolved native methods. static address native_method_throw_unsatisfied_link_error_entry(); diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp index 6e6e88fe318d1dd07322aa974417245f43a73775..59aea77b9303da6aa2739abc9d257a3fda6cb040 100644 --- a/src/share/vm/runtime/thread.hpp +++ b/src/share/vm/runtime/thread.hpp @@ -1345,6 +1345,13 @@ public: public: // Thread local information maintained by JVMTI. void set_jvmti_thread_state(JvmtiThreadState *value) { _jvmti_thread_state = value; } + // A JvmtiThreadState is lazily allocated. This jvmti_thread_state() + // getter is used to get this JavaThread's JvmtiThreadState if it has + // one which means NULL can be returned. JvmtiThreadState::state_for() + // is used to get the specified JavaThread's JvmtiThreadState if it has + // one or it allocates a new JvmtiThreadState for the JavaThread and + // returns it. JvmtiThreadState::state_for() will return NULL only if + // the specified JavaThread is exiting. JvmtiThreadState *jvmti_thread_state() const { return _jvmti_thread_state; } static ByteSize jvmti_thread_state_offset() { return byte_offset_of(JavaThread, _jvmti_thread_state); } void set_jvmti_get_loaded_classes_closure(JvmtiGetLoadedClassesClosure* value) { _jvmti_get_loaded_classes_closure = value; }