diff --git a/vm/vmcore/include/jvmti_internal.h b/vm/vmcore/include/jvmti_internal.h index d9bcea7..d550480 100644 --- a/vm/vmcore/include/jvmti_internal.h +++ b/vm/vmcore/include/jvmti_internal.h @@ -93,6 +93,7 @@ struct jvmti_StepLocation { struct Method* method; unsigned location; + NativeCodePtr native_location; }; struct JVMTISingleStepState diff --git a/vm/vmcore/src/exception/exceptions_jit.cpp b/vm/vmcore/src/exception/exceptions_jit.cpp index 6b80347..a262c9c 100644 --- a/vm/vmcore/src/exception/exceptions_jit.cpp +++ b/vm/vmcore/src/exception/exceptions_jit.cpp @@ -272,12 +272,12 @@ #endif // VM_STATS LMAutoUnlock lock(&ti->brkpntlst_lock); uint16 bc; + NativeCodePtr ip = handler->get_handler_ip(); OpenExeJpdaError UNREF result = - jit->get_bc_location_for_native( - method, handler->get_handler_ip(), &bc); + jit->get_bc_location_for_native(method, ip, &bc); assert(EXE_ERROR_NONE == result); - jvmti_StepLocation method_start = {(Method *)method, bc}; + jvmti_StepLocation method_start = {(Method *)method, bc, ip}; jvmtiError UNREF errorCode = jvmti_set_single_step_breakpoints(ti, vm_thread, diff --git a/vm/vmcore/src/jvmti/jvmti_break.cpp b/vm/vmcore/src/jvmti/jvmti_break.cpp index 5b55f5f..467649c 100644 --- a/vm/vmcore/src/jvmti/jvmti_break.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break.cpp @@ -497,19 +497,21 @@ jvmtiError jvmti_set_jit_mode_breakpoint { // Function is always executed under global TI breakpoints lock // Find native location in the method code - NativeCodePtr np = NULL; Method *m = (Method *)bp->method; assert( m->get_state() == Method::ST_Compiled ); - OpenExeJpdaError res = EXE_ERROR_NONE; - for (CodeChunkInfo* cci = m->get_first_JIT_specific_info(); cci; cci = cci->_next) - { - JIT *jit = cci->get_jit(); - res = jit->get_native_location_for_bc(m, (uint16)bp->location, &np); - if (res == EXE_ERROR_NONE) - break; + NativeCodePtr np = bp->native_location; + if( !np ) { + OpenExeJpdaError res = EXE_ERROR_NONE; + for (CodeChunkInfo* cci = m->get_first_JIT_specific_info(); cci; cci = cci->_next) + { + JIT *jit = cci->get_jit(); + res = jit->get_native_location_for_bc(m, (uint16)bp->location, &np); + if (res == EXE_ERROR_NONE) + break; + } + assert(res == EXE_ERROR_NONE); } - assert(res == EXE_ERROR_NONE); if (NULL == np) return JVMTI_ERROR_INTERNAL; diff --git a/vm/vmcore/src/jvmti/jvmti_event.cpp b/vm/vmcore/src/jvmti/jvmti_event.cpp index c061bca..f567256 100644 --- a/vm/vmcore/src/jvmti/jvmti_event.cpp +++ b/vm/vmcore/src/jvmti/jvmti_event.cpp @@ -315,6 +315,7 @@ jvmtiSetEventNotificationMode(jvmtiEnv* if (JVMTI_ENABLE == mode && !ti->is_single_step_enabled()) { + TRACE2("jvmti.break.ss", "SingleStep event is enabled"); jvmtiError errorCode = ti->jvmti_single_step_start(); if (JVMTI_ERROR_NONE != errorCode) @@ -323,6 +324,7 @@ jvmtiSetEventNotificationMode(jvmtiEnv* else if (JVMTI_DISABLE == mode && ti->is_single_step_enabled()) { // Check that no environment has SingleStep enabled + TRACE2("jvmti.break.ss", "SingleStep event is disabled"); LMAutoUnlock lock(&ti->TIenvs_lock); bool disable = true; diff --git a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp index 853a5e1..e05dacf 100644 --- a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp +++ b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp @@ -34,31 +34,33 @@ #include "clog.h" static void jvmti_pop_frame_callback() { - TRACE(("--->>> JVMTI pop frame callback...")); + TRACE(("JVMTI PopFrame callback is called")); frame_type type = m2n_get_frame_type(p_TLS_vmthread->last_m2n_frame); // frame wasn't requested to be popped - if (FRAME_POP_NOW != (FRAME_POP_NOW & type)) + if (FRAME_POP_NOW != (FRAME_POP_NOW & type)) { + TRACE(("PopFrame callback is not FRAME_POP_NOW")); return; + } // if we are in hythread_safe_point() frame is unwindable if (FRAME_SAFE_POINT == (FRAME_SAFE_POINT & type)) { + TRACE(("PopFrame callback is FRAME_SAFE_POINT")); jvmti_jit_prepare_pop_frame(); - // if we in unwindable frame } else if (is_unwindable()) { - // wait for resume - TRACE(("entering safe_point")); + // unwindable frame, wait for resume + TRACE(("PopFrame callback is entering safe_point")); hythread_safe_point(); - TRACE(("left safe_point")); + TRACE(("PopFrame callback is FRAME_SAFE_POINT")); // switch execution to the previous frame jvmti_jit_do_pop_frame(); assert(0 /* mustn't get here */); - // if we in nonunwindable frame } else { - // raise special exception object + // nonunwindable frame, raise special exception object + TRACE(("PopFrame callback is raising exception")); exn_raise_object(VM_Global_State::loader_env->popFrameException); } } //jvmti_pop_frame_callback @@ -66,6 +68,7 @@ static void jvmti_pop_frame_callback() jvmtiError jvmti_jit_pop_frame(jthread java_thread) { assert(hythread_is_suspend_enabled()); + TRACE(("Called PopFrame for JIT")); DebugUtilsTI *ti = VM_Global_State::loader_env->TI; @@ -90,6 +93,11 @@ jvmtiError jvmti_jit_pop_frame(jthread j // go to 2-d frame & check it's managed si_goto_previous(si); assert(! si_is_native(si)); + TRACE(("PopFrame is called for method %s.%s%s :%p", + class_get_name(method_get_class(si_get_code_chunk_info(si)->get_method())), + method_get_name(si_get_code_chunk_info(si)->get_method()), + method_get_descriptor(si_get_code_chunk_info(si)->get_method()), + si_get_ip(si) )); // go to 3-d frame & check its type si_goto_previous(si); @@ -146,6 +154,7 @@ #else // _IA32_ // requires stack iterator and buffer to save intermediate information static void jvmti_jit_prepare_pop_frame(StackIterator* si, uint32* buf) { + TRACE(("Prepare PopFrame for JIT")); // pop native frame assert(si_is_native(si)); si_goto_previous(si); @@ -160,6 +169,10 @@ static void jvmti_jit_prepare_pop_frame( Method *method = cci->get_method(); Class* method_class = method->get_class(); bool is_method_static = method->is_static(); + TRACE(("PopFrame method %s.%s%s, stop IP: %p", + class_get_name(method_get_class(cci->get_method())), + method_get_name(cci->get_method()), + method_get_descriptor(cci->get_method()), si_get_ip(si) )); // free lock of synchronized method /* @@ -192,6 +205,10 @@ static void jvmti_jit_prepare_pop_frame( // find correct ip and restore required regiksters context NativeCodePtr current_method_addr = NULL; NativeCodePtr ip = si_get_ip(si); + TRACE(("PopFrame method %s.%s%s, set IP begin: %p", + class_get_name(method_get_class(si_get_code_chunk_info(si)->get_method())), + method_get_name(si_get_code_chunk_info(si)->get_method()), + method_get_descriptor(si_get_code_chunk_info(si)->get_method()), ip )); size_t ip_reduce; // invoke static @@ -233,6 +250,10 @@ static void jvmti_jit_prepare_pop_frame( // set corrrrect ip ip = (NativeCodePtr)(((char*)ip) - ip_reduce); + TRACE(("PopFrame method %s.%s%s, set IP end: %p", + class_get_name(method_get_class(si_get_code_chunk_info(si)->get_method())), + method_get_name(si_get_code_chunk_info(si)->get_method()), + method_get_descriptor(si_get_code_chunk_info(si)->get_method()), ip )); si_set_ip(si, ip, false); } @@ -248,6 +269,11 @@ void jvmti_jit_prepare_pop_frame() { // create stack iterator from native StackIterator* si = si_create_from_native(); si_transfer_all_preserved_registers(si); + TRACE(("PopFrame prepare for method %s.%s%s, IP: %p", + class_get_name(method_get_class(si_get_code_chunk_info(si)->get_method())), + method_get_name(si_get_code_chunk_info(si)->get_method()), + method_get_descriptor(si_get_code_chunk_info(si)->get_method()), + si_get_ip(si) )); // preare pop frame - find regs values uint32 buf = 0; @@ -289,10 +315,44 @@ void jvmti_jit_prepare_pop_frame() { // set pop done frame state m2n_set_frame_type(top_frame, FRAME_POP_DONE); + return; } +static void +jvmti_relocate_single_step_breakpoints( StackIterator *si) +{ + // relocate single step + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (ti->isEnabled() && ti->is_single_step_enabled()) + { + VM_thread *vm_thread = p_TLS_vmthread; + if (NULL != vm_thread->ss_state) { + // remove old single step breakpoints + LMAutoUnlock lock(&ti->brkpntlst_lock); + jvmti_remove_single_step_breakpoints(ti, vm_thread); + + // set new single step breakpoints + CodeChunkInfo *cci = si_get_code_chunk_info(si); + Method *method = cci->get_method(); + NativeCodePtr ip = si_get_ip(si); + uint16 bc; + JIT *jit = cci->get_jit(); + OpenExeJpdaError UNREF result = + jit->get_bc_location_for_native(method, ip, &bc); + assert(EXE_ERROR_NONE == result); + + jvmti_StepLocation locations = {method, bc, ip}; + jvmtiError UNREF error = jvmti_set_single_step_breakpoints(ti, vm_thread, + &locations, 1); + assert( error == JVMTI_ERROR_NONE); + } + } + return; +} // jvmti_relocate_single_step_breakpoints + void jvmti_jit_complete_pop_frame() { // Destructive Unwinding!!! NO CXX Logging put here. + TRACE(("Complite PopFrame for JIT")); // Find top m2n frame M2nFrame* top_frame = m2n_get_last_frame(); @@ -309,12 +369,17 @@ void jvmti_jit_complete_pop_frame() { assert(si_is_native(si)); si_goto_previous(si); + // relocate single step breakpoints + jvmti_relocate_single_step_breakpoints(si); + // transfer cdontrol + TRACE(("PopFrame transfer control to: %p", (void*)si_get_ip(si) )); si_transfer_control(si); } void jvmti_jit_do_pop_frame() { // Destructive Unwinding!!! NO CXX Logging put here. + TRACE(("Do PopFrame for JIT")); // Find top m2n frame M2nFrame* top_frame = m2n_get_last_frame(); @@ -331,7 +396,11 @@ void jvmti_jit_do_pop_frame() { uint32 buf = 0; jvmti_jit_prepare_pop_frame(si, &buf); + // relocate single step breakpoints + jvmti_relocate_single_step_breakpoints(si); + // transfer cdontrol + TRACE(("PopFrame transfer control to: %p", (void*)si_get_ip(si) )); si_transfer_control(si); } #endif // _IA32_ diff --git a/vm/vmcore/src/jvmti/jvmti_step.cpp b/vm/vmcore/src/jvmti/jvmti_step.cpp index 27694d3..582ac71 100644 --- a/vm/vmcore/src/jvmti/jvmti_step.cpp +++ b/vm/vmcore/src/jvmti/jvmti_step.cpp @@ -53,7 +53,7 @@ jvmti_get_invoked_virtual_method( VM_thr { ASSERT_NO_INTERPRETER; -#if PLATFORM_NT +#if _IA32_ // create stack iterator from native StackIterator* si = si_create_from_native( thread ); si_transfer_all_preserved_registers(si); @@ -91,10 +91,10 @@ #if PLATFORM_NT Method *method = class_get_method_from_vt_offset( vtable, *((char*)ip + 2) ); return method; -#else // for PLATFORM_POSIX +#else // for !_IA32_ return NULL; -#endif // PLATFORM_NT +#endif // _IA32_ } // jvmti_get_invoked_virtual_method void @@ -160,8 +160,10 @@ jvmti_SingleStepLocation( VM_thread* thr assert( error == JVMTI_ERROR_NONE ); (*next_step)[0].method = method; (*next_step)[0].location = location; + (*next_step)[0].native_location = NULL; (*next_step)[1].method = method; (*next_step)[1].location = offset; + (*next_step)[1].native_location = NULL; break; // goto instructions @@ -174,6 +176,7 @@ jvmti_SingleStepLocation( VM_thread* thr assert( error == JVMTI_ERROR_NONE ); (*next_step)->method = method; (*next_step)->location = offset; + (*next_step)->native_location = NULL; break; case OPCODE_GOTO_W: /* 0xc8 + s4 */ case OPCODE_JSR_W: /* 0xc9 + s4 */ @@ -184,6 +187,7 @@ jvmti_SingleStepLocation( VM_thread* thr assert( error == JVMTI_ERROR_NONE ); (*next_step)->method = method; (*next_step)->location = offset; + (*next_step)->native_location = NULL; break; // tableswitch instruction @@ -201,11 +205,13 @@ jvmti_SingleStepLocation( VM_thread* thr (*next_step)[0].method = method; (*next_step)[0].location = (int)bytecode_index + jvmti_GetWordValue( bytecode, location ); + (*next_step)[0].native_location = NULL; location += 12; for( int index = 1; index < number; index++, location += 4 ) { (*next_step)[index].method = method; (*next_step)[index].location = (int)bytecode_index + jvmti_GetWordValue( bytecode, location ); + (*next_step)[index].native_location = NULL; } } break; @@ -223,11 +229,13 @@ jvmti_SingleStepLocation( VM_thread* thr (*next_step)[0].method = method; (*next_step)[0].location = (int)bytecode_index + jvmti_GetWordValue( bytecode, location ); + (*next_step)[0].native_location = NULL; location += 12; for( int index = 1; index < number; index++, location += 8 ) { (*next_step)[index].method = method; (*next_step)[index].location = (int) + jvmti_GetWordValue( bytecode, location ); + (*next_step)[index].native_location = NULL; } } break; @@ -269,6 +277,7 @@ jvmti_SingleStepLocation( VM_thread* thr assert( error == JVMTI_ERROR_NONE ); (*next_step)->method = klass->const_pool[index].CONSTANT_ref.method; (*next_step)->location = 0; + (*next_step)->native_location = NULL; } } break; @@ -284,6 +293,7 @@ jvmti_SingleStepLocation( VM_thread* thr assert( error == JVMTI_ERROR_NONE ); (*next_step)->method = func; (*next_step)->location = 0; + (*next_step)->native_location = NULL; } } break; @@ -344,18 +354,20 @@ jvmti_SingleStepLocation( VM_thread* thr assert( error == JVMTI_ERROR_NONE ); (*next_step)->method = method; (*next_step)->location = location; + (*next_step)->native_location = NULL; break; // ret instruction case OPCODE_RET: /* 0xa9 + u1|u2 */ // FIXME - need to obtain return address from stack. + DIE2("jvmti", "SingleStepLocation: not implemented ret instruction"); break; } break; } while( true ); for( unsigned index = 0; index < *count; index++ ) { - TRACE2( "jvmti.step", "Step: " << class_get_name(method_get_class(method)) + TRACE2( "jvmti.break.ss", "Step: " << class_get_name(method_get_class(method)) << "." << method_get_name(method) << method_get_descriptor(method) << " :" << bytecode_index << "\n -> " << class_get_name(method_get_class((*next_step)[index].method)) @@ -387,12 +399,13 @@ jvmtiError jvmti_set_single_step_breakpo memset( bp, 0, sizeof(BreakPoint)); bp->method = (jmethodID)locations[iii].method; bp->location = locations[iii].location; + bp->native_location = locations[iii].native_location; TRACE2("jvmti.break.ss", "Set single step breakpoint: " << class_get_name(method_get_class((Method *)bp->method)) << "." << method_get_name((Method *)bp->method) << method_get_descriptor((Method *)bp->method) - << " :" << bp->location); + << " :" << bp->location << " :" << bp->native_location); errorCode = jvmti_set_breakpoint_for_jit(ti, bp); if (JVMTI_ERROR_NONE != errorCode) @@ -413,6 +426,10 @@ void jvmti_remove_single_step_breakpoint // Function is always executed under global TI breakpoints lock JVMTISingleStepState *ss_state = vm_thread->ss_state; + if(!ss_state->predicted_bp_count) { + // nothing to do + return; + } for (unsigned iii = 0; iii < ss_state->predicted_bp_count; iii++) { BreakPoint *bp = ss_state->predicted_breakpoints[iii]; @@ -473,6 +490,7 @@ jvmtiError jvmti_get_next_bytecodes_stac // which caused call of the method. So next location is the 'bc' which // IP points to. (*next_step)->location = bc; + (*next_step)->native_location = ip; } si_free(si); return JVMTI_ERROR_NONE;