# HG changeset patch # User dcubed # Date 1236211242 25200 # Node ID af0128fec442bf9c6b1c2afaef0ec9bb41b1fb3d # Parent 987a209dea4da842c6da5f4392c9a02313c25c0f# Parent 70998f2e05ef07766fa33343f039c37a6d9e4cf1 Merge diff -r 987a209dea4d -r af0128fec442 src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -2465,7 +2465,10 @@ // 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 @@ 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 -r 987a209dea4d -r af0128fec442 src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -2161,6 +2161,18 @@ __ 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 -r 987a209dea4d -r af0128fec442 src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -1512,6 +1512,15 @@ 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 -r 987a209dea4d -r af0128fec442 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -1593,6 +1593,14 @@ 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 -r 987a209dea4d -r af0128fec442 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -1532,6 +1532,14 @@ 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 -r 987a209dea4d -r af0128fec442 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -1506,6 +1506,17 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/includeDB_core --- a/src/share/vm/includeDB_core Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/includeDB_core Wed Mar 04 17:00:42 2009 -0700 @@ -2093,6 +2093,7 @@ 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 @@ -3669,6 +3670,7 @@ 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 @@ -3698,6 +3700,7 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/oops/klassVtable.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -992,6 +992,10 @@ 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 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } - break; } ime++; } diff -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiEnv.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -99,6 +99,9 @@ } // 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 @@ // 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 @@ 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 @@ // 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 @@ 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 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiEnvBase.cpp --- a/src/share/vm/prims/jvmtiEnvBase.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -1322,6 +1322,12 @@ 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 +1335,6 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiEventController.cpp --- a/src/share/vm/prims/jvmtiEventController.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiEventController.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -478,6 +478,11 @@ // 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 @@ { 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 -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiExport.cpp --- a/src/share/vm/prims/jvmtiExport.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiExport.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -1872,6 +1872,9 @@ { // 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 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 -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -831,6 +831,9 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiRedefineClassesTrace.hpp --- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Wed Mar 04 17:00:42 2009 -0700 @@ -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 -r 987a209dea4d -r af0128fec442 src/share/vm/prims/jvmtiThreadState.hpp --- a/src/share/vm/prims/jvmtiThreadState.hpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/prims/jvmtiThreadState.hpp Wed Mar 04 17:00:42 2009 -0700 @@ -314,17 +314,24 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 04 17:00:42 2009 -0700 @@ -395,6 +395,32 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 04 17:00:42 2009 -0700 @@ -166,6 +166,9 @@ 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 -r 987a209dea4d -r af0128fec442 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Mar 04 09:12:08 2009 -0800 +++ b/src/share/vm/runtime/thread.hpp Wed Mar 04 17:00:42 2009 -0700 @@ -1345,6 +1345,13 @@ 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; }