From nobody Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Thu, 21 Sep 2006 18:54:52 +0400 Subject: [DRLVM] Implement advanced scheme of jvmti PopFrame and several fixes into JVMTI - Implement advanced scheme of jvmti PopFrame. It provides opportunity to evaluate locals on the stack after pop, and allow several frames popping. This scheme can works for safe_point only. - Fix possible bug in GC stack enumeration after PopFrame. After pop frame nobody enumerate methods arguments for GC. This patch fixes it. - JVMTI PopFrame support in the JET (VM Part). To provide correct pop of the method frame, popped frame should be compiled with special flags. It’s provide opportunity to find corresponding “this” and restore context before method call. - ExceptionCatch event does not send in some cases. The source of the bug is missed callback setting. So after add missed callback set, bug was fixed. - Fixed m2n frame registers in breakpoint dispatcher function. Depends on HARMONY-1523 --- vm/port/include/m2n.h | 21 ++ vm/port/include/stack_iterator.h | 13 + vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp | 2 vm/port/src/lil/ia32/pim/m2n_ia32.cpp | 21 ++ vm/port/src/lil/ia32/pim/m2n_ia32_internal.h | 5 - vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp | 32 +++ vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp | 2 vm/vmcore/include/exceptions_jit.h | 3 vm/vmcore/include/jit_export.h | 13 + vm/vmcore/include/jvmti_direct.h | 2 vm/vmcore/include/jvmti_internal.h | 11 + vm/vmcore/src/exception/exceptions.cpp | 4 vm/vmcore/src/exception/exceptions_jit.cpp | 14 +- vm/vmcore/src/gc/root_set_enum_common.cpp | 2 vm/vmcore/src/jit/compile.cpp | 11 - vm/vmcore/src/jvmti/jvmti.cpp | 9 + vm/vmcore/src/jvmti/jvmti_break.cpp | 4 vm/vmcore/src/jvmti/jvmti_capability.cpp | 6 + vm/vmcore/src/jvmti/jvmti_pop_frame.cpp | 186 ++++++++++++++++++-- vm/vmcore/src/util/linux/signals_ia32.cpp | 3 .../src/util/win/ia32/nt_exception_filter.cpp | 8 - 21 files changed, 306 insertions(+), 66 deletions(-) mode change 100644 => 100755 vm/vmcore/src/exception/exceptions_jit.cpp e8c042783ae1f2dc47859e001ac99afda6fb9f01 diff --git a/vm/port/include/m2n.h b/vm/port/include/m2n.h index 465026c..ea98638 100644 --- a/vm/port/include/m2n.h +++ b/vm/port/include/m2n.h @@ -41,14 +41,19 @@ #include "vm_core_types.h" struct M2nFrame; enum frame_type { - FRAME_UNKNOWN = 0x0, - FRAME_NON_UNWINDABLE = 0x1000, - FRAME_JNI = 0x1 | FRAME_NON_UNWINDABLE, - FRAME_COMPILATION = 0x2 | FRAME_NON_UNWINDABLE, + FRAME_UNKNOWN = 0x00, + FRAME_NON_UNWINDABLE = 0x80, + FRAME_JNI = 0x01 | FRAME_NON_UNWINDABLE, + FRAME_COMPILATION = 0x02 | FRAME_NON_UNWINDABLE, + FRAME_UNPOPABLE = 0x0000, FRAME_POPABLE = 0x0100, FRAME_POP_NOW = 0x0200, - FRAME_SAFE_POINT = 0x0400 + FRAME_POP_DONE = FRAME_POPABLE | FRAME_POP_NOW, + + FRAME_POP_MASK = 0x0700, + + FRAME_SAFE_POINT = 0x0800 }; // The pushing and popping of native frames is done only by stubs that @@ -136,4 +141,10 @@ M2nFrame* m2n_push_suspended_frame(VM_th // answers true if passed in m2n frame represents suspended frame bool m2n_is_suspended_frame(M2nFrame *); +// returns pointer to the registers used for jvmti PopFrame +Registers* get_pop_frame_registers(M2nFrame* ); + +// sets pointer to the registers used for jvmti PopFrame +void set_pop_frame_registers(M2nFrame* , Registers*); + #endif //!_M2N_H_ diff --git a/vm/port/include/stack_iterator.h b/vm/port/include/stack_iterator.h index 8fcc070..a903785 100644 --- a/vm/port/include/stack_iterator.h +++ b/vm/port/include/stack_iterator.h @@ -138,8 +138,9 @@ bool si_is_past_end(StackIterator* si ); * * @param[in] si - the pointer to the stack iterator that will be iterated to the previous * frame + * @param[in] over_popped - take into account the intermediate result of pop frame operation. */ -void si_goto_previous(StackIterator* si); +void si_goto_previous(StackIterator* si, bool over_popped = true); /** * Gets the instruction pointer for the current frame. @@ -286,4 +287,14 @@ Method_Handle si_get_method(StackIterato */ uint32 si_get_inline_depth(StackIterator* si); +/** + * Gets the method handle for the frame iterated by the stack iterator. + * + * @param[in] si - the pointer to the stack iterator indicating the frame, + * from which control will be transfered + * @param[in] callback - pointer to the native cose adress which should be + * called, after transfer control + */ +void si_set_callbak(StackIterator* si, NativeCodePtr* callback); + #endif //!_STACK_ITERATOR_H_ diff --git a/vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp b/vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp index 7025186..62df9f4 100644 --- a/vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp +++ b/vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp @@ -240,7 +240,7 @@ bool si_is_past_end(StackIterator * si) return si->cci == NULL && si->m2n_frame == NULL; } -void si_goto_previous(StackIterator * si) { +void si_goto_previous(StackIterator * si, bool over_popped) { ASSERT_NO_INTERPRETER if (si_is_native(si)) { TRACE2("si", "si_goto_previous from ip = " diff --git a/vm/port/src/lil/ia32/pim/m2n_ia32.cpp b/vm/port/src/lil/ia32/pim/m2n_ia32.cpp index dbe967f..e21294a 100644 --- a/vm/port/src/lil/ia32/pim/m2n_ia32.cpp +++ b/vm/port/src/lil/ia32/pim/m2n_ia32.cpp @@ -28,6 +28,7 @@ #include "open/types.h" #include "encoder.h" #include "interpreter.h" // for asserts only + ////////////////////////////////////////////////////////////////////////// // M2nFrame Interface @@ -184,7 +185,7 @@ char* m2n_gen_ts_to_register(char* buf, unsigned m2n_push_m2n_size(bool UNREF handles, unsigned num_callee_saves) { - return 20+(4-num_callee_saves)+m2n_ts_to_register_size()+11; + return 20+(4-num_callee_saves)+m2n_ts_to_register_size()+11+8; } char* m2n_gen_push_m2n(char* buf, Method_Handle method, frame_type current_frame_type, bool UNREF handles, unsigned num_callee_saves) @@ -199,6 +200,7 @@ char* m2n_gen_push_m2n(char* buf, Method buf = m2n_gen_ts_to_register(buf, &eax_opnd); + buf = push(buf, Imm_Opnd(size_32, 0)); //MVM APN 20050513 work with frame_type set up current_frame_type to NULL //int frame_type_offset = (int)&((VM_thread*)0)->current_frame_type; buf = push(buf, Imm_Opnd(current_frame_type)); @@ -239,7 +241,7 @@ unsigned m2n_pop_m2n_size(bool handles, if (handles) size += (extra_on_stack+8<128 ? 12 : 15)+preserve_ret*2; else size += 11; if (extra_on_stack) size += (extra_on_stack<128 ? 3 : 6); - return size; + return size + 128; } void m2n_pop_local_handles() { @@ -288,8 +290,8 @@ char* m2n_gen_pop_m2n(char* buf, bool ha buf = pop(buf, esi_opnd); buf = pop(buf, ebx_opnd); buf = mov(buf, M_Base_Opnd(ebx_reg, +0), esi_opnd); - buf = alu(buf, add_opc, esp_opnd, Imm_Opnd(+12)); - + buf = alu(buf, add_opc, esp_opnd, Imm_Opnd(+16)); + if (num_callee_saves<4) buf = pop(buf, edi_opnd); if (num_callee_saves<3) buf = pop(buf, esi_opnd); if (num_callee_saves<2) buf = pop(buf, ebx_opnd); @@ -297,3 +299,14 @@ char* m2n_gen_pop_m2n(char* buf, bool ha return buf; } + +// returns pointer to the registers used for jvmti PopFrame +Registers* get_pop_frame_registers(M2nFrame* m2nf) { + return m2nf->pop_regs; +} + +// sets pointer to the registers used for jvmti PopFrame +void set_pop_frame_registers(M2nFrame* m2nf, Registers* regs) { + m2nf->pop_regs = regs; +} + diff --git a/vm/port/src/lil/ia32/pim/m2n_ia32_internal.h b/vm/port/src/lil/ia32/pim/m2n_ia32_internal.h index b52e178..8018e36 100644 --- a/vm/port/src/lil/ia32/pim/m2n_ia32_internal.h +++ b/vm/port/src/lil/ia32/pim/m2n_ia32_internal.h @@ -40,7 +40,7 @@ uint32* m2n_get_args(M2nFrame*); // It takes up space below and including the return address to the managed code, and thus is immediately below the arguments. // This is the size of the structure that goes on the stack. -const unsigned m2n_sizeof_m2n_frame = 40; +const unsigned m2n_sizeof_m2n_frame = 44; // Generate code to put the thread local storage pointer into a given register unsigned m2n_ts_to_register_size(); @@ -95,12 +95,13 @@ struct M2nFrame { ObjectHandles* local_object_handles; Method_Handle method; frame_type current_frame_type; // type of the current frame also shows is the frame unwindable + Registers* pop_regs; // This is only for M2nFrames for suspended managed code (as against ones that call stubs and prepare jvmtiPopFrame) uint32 edi; uint32 esi; uint32 ebx; uint32 ebp; uint32 eip; - Registers* regs; // This is only for M2nFrames for suspended managed code (as against ones that call stubs) + Registers* regs; // This is only for M2nFrames for suspended managed code (as against ones that call stubs and prepare jvmtiPopFrame) }; #endif //!_M2N_IA32_INTERNAL_H_ diff --git a/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp b/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp index 48e66c4..858c10b 100644 --- a/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp +++ b/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp @@ -59,7 +59,7 @@ struct StackIterator { // Utilities // Goto the managed frame immediately prior to m2nfl -static void si_unwind_from_m2n(StackIterator* si) +static void si_unwind_from_m2n(StackIterator* si, bool over_popped = true) { #ifdef VM_STATS VM_Statistics::get_vm_stats().num_unwind_native_frames_all++; @@ -87,6 +87,18 @@ #endif si->c.p_esi = &m2nfl->regs->esi; si->c.p_edi = &m2nfl->regs->edi; si->c.p_ebp = &m2nfl->regs->ebp; + } else if (over_popped && + (FRAME_POP_DONE == (FRAME_POP_MASK & m2n_get_frame_type(m2nfl)))) { + si->c.esp = m2nfl->pop_regs->esp; + si->c.p_eip = &(m2nfl->pop_regs->eip); + si->c.is_ip_past = FALSE; + si->c.p_eax = &m2nfl->pop_regs->eax; + si->c.p_ebx = &m2nfl->pop_regs->ebx; + si->c.p_ecx = &m2nfl->pop_regs->ecx; + si->c.p_edx = &m2nfl->pop_regs->edx; + si->c.p_esi = &m2nfl->pop_regs->esi; + si->c.p_edi = &m2nfl->pop_regs->edi; + si->c.p_ebp = &m2nfl->pop_regs->ebp; } else { // Normal M2nFrame, eip is past instruction, esp is implicitly address just beyond the frame, callee saves registers in M2nFrame si->c.esp = (uint32)m2nfl + m2n_sizeof_m2n_frame; @@ -137,9 +149,6 @@ #endif M_Base_Opnd m2(edx_reg, (int)&((StackIterator*)0)->c.esp); ss = mov(ss, ecx_opnd, m2); - M_Base_Opnd m3(ecx_reg, -4); - ss = mov(ss, m3, ebx_opnd); - ss = alu(ss, sub_opc, ecx_opnd, Imm_Opnd(4)); ss = mov(ss, m1, ecx_opnd); @@ -147,6 +156,9 @@ #endif ss = get_reg(ss, &edi_opnd, edi_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_edi); ss = get_reg(ss, &ebp_opnd, ebp_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_ebp); + M_Base_Opnd m3(ecx_reg, 0); + ss = mov(ss, m3, ebx_opnd); + ss = get_reg(ss, &eax_opnd, eax_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_eax); ss = get_reg(ss, &ebx_opnd, ebx_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_ebx); ss = get_reg(ss, &ecx_opnd, ecx_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_ecx); @@ -165,7 +177,6 @@ #endif mov ebx,dword ptr [edx+0Ch] mov ebx,dword ptr [ebx] mov ecx,dword ptr [edx+4] - mov dword ptr [ecx-4],ebx sub ecx,4 mov dword ptr [esp+4],ecx mov esi,dword ptr [edx+14h] @@ -174,6 +185,7 @@ #endif mov edi,dword ptr [edi] mov ebp,dword ptr [edx+8] mov ebp,dword ptr [ebp] + mov dword ptr [ecx],ebx mov eax,dword ptr [edx+1Ch] mov eax,dword ptr [eax] mov ebx,dword ptr [edx+18h] @@ -265,7 +277,7 @@ bool si_is_past_end(StackIterator* si) return si->cci==NULL && si->m2nfl==NULL; } -void si_goto_previous(StackIterator* si) +void si_goto_previous(StackIterator* si, bool over_popped) { ASSERT_NO_INTERPRETER if (si->cci) { @@ -280,7 +292,7 @@ void si_goto_previous(StackIterator* si) TRACE2("si", ("si_goto_previous from ip = %p (M2N)", (void*)si_get_ip(si))); if (!si->m2nfl) return; - si_unwind_from_m2n(si); + si_unwind_from_m2n(si, over_popped); } si->cci = vm_methods->find(si_get_ip(si), true); if (si->cci) { @@ -495,6 +507,12 @@ void si_copy_to_registers(StackIterator* regs->eax = *si->c.p_eax; } +void si_set_callbak(StackIterator* si, NativeCodePtr* callback) { + si->c.esp = si->c.esp - 4; + *((uint32*) si->c.esp) = *(si->c.p_eip); + si->c.p_eip = ((uint32*)callback); +} + void si_reload_registers() { // Do nothing diff --git a/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp b/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp index 693a5b8..87472a5 100644 --- a/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp +++ b/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp @@ -501,7 +501,7 @@ bool si_is_past_end(StackIterator* si) return si->cci==NULL && si->m2nfl==NULL; } -void si_goto_previous(StackIterator* si) +void si_goto_previous(StackIterator* si, bool over_popped) { if (si->cci) { assert(si->cci->get_jit() && si->cci->get_method()); diff --git a/vm/vmcore/include/exceptions_jit.h b/vm/vmcore/include/exceptions_jit.h index 67d39ed..0e8b4e3 100644 --- a/vm/vmcore/include/exceptions_jit.h +++ b/vm/vmcore/include/exceptions_jit.h @@ -92,4 +92,7 @@ NativeCodePtr exn_get_rth_throw_illegal_ Class_Handle exn_get_class_cast_exception_type(); +// Exception catch callback for jvm ti support implementation +void asm_jvmti_exception_catch_callback(); + #endif // _EXCEPTIONS_JIT_H_ diff --git a/vm/vmcore/include/jit_export.h b/vm/vmcore/include/jit_export.h index 7e1db2b..a64aef3 100644 --- a/vm/vmcore/include/jit_export.h +++ b/vm/vmcore/include/jit_export.h @@ -162,6 +162,19 @@ typedef struct OpenMethodExecutionParams /** call corresponding VM helper upon setting a value of any field of reference type */ Boolean exe_insert_write_barriers : 1; + /** + * Provide possibility to obtain reference to the current 'this' object by + * means of get_address_of_this method. Used for JVMTI debug support. + */ + Boolean exe_provide_access_to_this : 1; + + /** + * Provide restoring of arguments in the stack after the call + * of the unwind_frame method so that method could be called again + * with the same arguments. Used for JVMTI debug support. + */ + Boolean exe_restore_context_after_unwind : 1; + } OpenMethodExecutionParams; diff --git a/vm/vmcore/include/jvmti_direct.h b/vm/vmcore/include/jvmti_direct.h index 9644f91..bb03fdc 100644 --- a/vm/vmcore/include/jvmti_direct.h +++ b/vm/vmcore/include/jvmti_direct.h @@ -81,6 +81,8 @@ void jvmti_get_compilation_flags(OpenMet // Marks topmost frame of the specified thead to be popped jvmtiError jvmti_jit_pop_frame(jthread thread); // On current thread perform popping of topmost frame +void jvmti_jit_prepare_pop_frame(); +void jvmti_jit_complete_pop_frame(); void jvmti_jit_do_pop_frame(); /* Events functions */ diff --git a/vm/vmcore/include/jvmti_internal.h b/vm/vmcore/include/jvmti_internal.h index e68bfea..d9bcea7 100644 --- a/vm/vmcore/include/jvmti_internal.h +++ b/vm/vmcore/include/jvmti_internal.h @@ -461,13 +461,14 @@ class DebugUtilsTI { void ReleaseNotifyLists(); enum GlobalCapabilities { - TI_GC_ENABLE_METHOD_ENTRY = 0x01, - TI_GC_ENABLE_METHOD_EXIT = 0x02, - TI_GC_ENABLE_FRAME_POP_NOTIFICATION = 0x04, - TI_GC_ENABLE_SINGLE_STEP = 0x08, + TI_GC_ENABLE_METHOD_ENTRY = 0x01, + TI_GC_ENABLE_METHOD_EXIT = 0x02, + TI_GC_ENABLE_FRAME_POP_NOTIFICATION = 0x04, + TI_GC_ENABLE_SINGLE_STEP = 0x08, TI_GC_ENABLE_EXCEPTION_EVENT = 0x10, TI_GC_ENABLE_FIELD_ACCESS_EVENT = 0x20, - TI_GC_ENABLE_FIELD_MODIFICATION_EVENT = 0x40 + TI_GC_ENABLE_FIELD_MODIFICATION_EVENT = 0x40, + TI_GC_ENABLE_POP_FRAME = 0x80 }; void set_global_capability(GlobalCapabilities ti_gc) diff --git a/vm/vmcore/src/exception/exceptions.cpp b/vm/vmcore/src/exception/exceptions.cpp index 7195ec6..cd43454 100644 --- a/vm/vmcore/src/exception/exceptions.cpp +++ b/vm/vmcore/src/exception/exceptions.cpp @@ -316,10 +316,12 @@ void exn_raise_by_name(const char* exc_n static void check_pop_frame(ManagedObject *exn) { if (exn == VM_Global_State::loader_env->popFrameException->object) { + exn_clear(); frame_type type = m2n_get_frame_type(m2n_get_last_frame()); - if (FRAME_POP_NOW == (FRAME_POP_NOW & type)) + if (FRAME_POP_NOW == (FRAME_POP_MASK & type)) { jvmti_jit_do_pop_frame(); + } } } diff --git a/vm/vmcore/src/exception/exceptions_jit.cpp b/vm/vmcore/src/exception/exceptions_jit.cpp old mode 100644 new mode 100755 index 803b7dd..9ec400b --- a/vm/vmcore/src/exception/exceptions_jit.cpp +++ b/vm/vmcore/src/exception/exceptions_jit.cpp @@ -28,6 +28,7 @@ #include "open/types.h" #include "classloader.h" #include "exceptions.h" #include "exceptions_impl.h" +#include "exceptions_jit.h" #include "environment.h" #include "dump.h" #include "heap.h" @@ -424,8 +425,18 @@ #endif // _IPF_ } si_transfer_all_preserved_registers(si); + + DebugUtilsTI* ti = VM_Global_State::loader_env->TI; + exn_propagate_exception(si, &local_exn_obj, exn_class, exn_constr, jit_exn_constr_args, vm_exn_constr_args); + + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { + NativeCodePtr callback = (NativeCodePtr) + asm_jvmti_exception_catch_callback; + si_set_callbak(si, &callback); + } + si_transfer_control(si); } //exn_throw_for_JIT @@ -483,9 +494,6 @@ #endif M2nFrame *m2nf = m2n_push_suspended_frame(regs); - printf("jvmti_exception_catch_callback\n"); - st_print(); - StackIterator *si = si_create_from_native(); if (si_is_native(si)) { diff --git a/vm/vmcore/src/gc/root_set_enum_common.cpp b/vm/vmcore/src/gc/root_set_enum_common.cpp index d224e09..f913249 100644 --- a/vm/vmcore/src/gc/root_set_enum_common.cpp +++ b/vm/vmcore/src/gc/root_set_enum_common.cpp @@ -275,7 +275,7 @@ #endif << (m2n_get_method(si_get_m2n(si)) ? method_get_descriptor(m2n_get_method(si_get_m2n(si))) : "")); oh_enumerate_handles(m2n_get_local_handles(si_get_m2n(si))); } - si_goto_previous(si); + si_goto_previous(si, false); } si_free(si); } diff --git a/vm/vmcore/src/jit/compile.cpp b/vm/vmcore/src/jit/compile.cpp index 968f659..06e3ec9 100644 --- a/vm/vmcore/src/jit/compile.cpp +++ b/vm/vmcore/src/jit/compile.cpp @@ -691,14 +691,6 @@ JIT_Result compile_do_compilation_jit(Me jvmti_get_compilation_flags(&flags); flags.exe_insert_write_barriers = gc_requires_barriers(); - DebugUtilsTI *ti = VM_Global_State::loader_env->TI; - if ( ti->isEnabled() ) { - if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT)) - flags.exe_notify_field_access = true; - if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT)) - flags.exe_notify_field_modification = true; - } - Compilation_Handle ch; ch.env = VM_Global_State::loader_env; ch.jit = jit; @@ -732,6 +724,9 @@ JIT_Result compile_do_compilation_jit(Me p_jit_a_method_lock->_unlock(); } + // Find TI environment + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + // Call TI callbacks if (ti->isEnabled() && ti->getPhase() == JVMTI_PHASE_LIVE) { jvmti_send_compiled_method_load_event(method); diff --git a/vm/vmcore/src/jvmti/jvmti.cpp b/vm/vmcore/src/jvmti/jvmti.cpp index 1565011..c08d8b5 100644 --- a/vm/vmcore/src/jvmti/jvmti.cpp +++ b/vm/vmcore/src/jvmti/jvmti.cpp @@ -744,5 +744,14 @@ void jvmti_get_compilation_flags(OpenMet ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FRAME_POP_NOTIFICATION)) flags->exe_notify_method_exit = 1; + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT)) + flags->exe_notify_field_access = true; + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT)) + flags->exe_notify_field_modification = true; + + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_POP_FRAME)) { + flags->exe_restore_context_after_unwind = true; + flags->exe_provide_access_to_this = true; + } } diff --git a/vm/vmcore/src/jvmti/jvmti_break.cpp b/vm/vmcore/src/jvmti/jvmti_break.cpp index 4574985..5b55f5f 100644 --- a/vm/vmcore/src/jvmti/jvmti_break.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break.cpp @@ -201,7 +201,9 @@ #endif assert(ti->isEnabled()); assert(!interpreter_enabled()); - M2nFrame *m2nf = m2n_push_suspended_frame(regs); + Registers orig_regs = *regs; + + M2nFrame *m2nf = m2n_push_suspended_frame(&orig_regs); BEGIN_RAISE_AREA; // need to be able to pop the frame diff --git a/vm/vmcore/src/jvmti/jvmti_capability.cpp b/vm/vmcore/src/jvmti/jvmti_capability.cpp index 503b04b..102ae23 100644 --- a/vm/vmcore/src/jvmti/jvmti_capability.cpp +++ b/vm/vmcore/src/jvmti/jvmti_capability.cpp @@ -272,6 +272,9 @@ jvmtiAddCapabilities(jvmtiEnv* env, if (capabilities_ptr->can_generate_field_modification_events) ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT); + if (capabilities_ptr->can_pop_frame) + ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_POP_FRAME); + return JVMTI_ERROR_NONE; } @@ -357,6 +360,9 @@ jvmtiRelinquishCapabilities(jvmtiEnv* en if (removed_caps.can_generate_field_modification_events) ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT); + if (capabilities_ptr->can_pop_frame) + ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_POP_FRAME); + return JVMTI_ERROR_NONE; } diff --git a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp index 662b59a..853a5e1 100644 --- a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp +++ b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp @@ -41,8 +41,12 @@ static void jvmti_pop_frame_callback() if (FRAME_POP_NOW != (FRAME_POP_NOW & type)) return; - // if we are in hythread_safe_point() or frame is unwindable - if (FRAME_SAFE_POINT == (FRAME_SAFE_POINT & type) || is_unwindable()) { + // if we are in hythread_safe_point() frame is unwindable + if (FRAME_SAFE_POINT == (FRAME_SAFE_POINT & type)) { + jvmti_jit_prepare_pop_frame(); + + // if we in unwindable frame + } else if (is_unwindable()) { // wait for resume TRACE(("entering safe_point")); hythread_safe_point(); @@ -51,6 +55,8 @@ static void jvmti_pop_frame_callback() // 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 exn_raise_object(VM_Global_State::loader_env->popFrameException); @@ -61,6 +67,12 @@ jvmtiError jvmti_jit_pop_frame(jthread j { assert(hythread_is_suspend_enabled()); + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + + if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_POP_FRAME)) { + return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; + } + hythread_t hy_thread = jthread_get_native_thread(java_thread); VM_thread* vm_thread = get_vm_thread(hy_thread); @@ -89,7 +101,10 @@ jvmtiError jvmti_jit_pop_frame(jthread j si_free(si); - type = (frame_type) (type | FRAME_POP_NOW); + // change type from popable to pop_now, pop_done should'n be changed + if (FRAME_POPABLE == (type & FRAME_POP_MASK)) { + type = (frame_type)((type & ~FRAME_POP_MASK) | FRAME_POP_NOW); + } m2n_set_frame_type(top_frame, type); // Install safepoint callback that would perform popping job @@ -98,14 +113,39 @@ jvmtiError jvmti_jit_pop_frame(jthread j return JVMTI_ERROR_NONE; } //jvmti_jit_pop_frame -void jvmti_jit_do_pop_frame() -{ - // Destructive Unwinding!!! NO CXZ Logging put here. - // create stack iterator from native - StackIterator* si = si_create_from_native(); - si_transfer_all_preserved_registers(si); +#ifdef _IPF_ + +void jvmti_jit_prepare_pop_frame(){ + assert(0); +} + +void jvmti_jit_complete_pop_frame(){ + assert(0); +} + +void jvmti_jit_do_pop_frame(){ + assert(0); +} + +#elif defined _EM64T_ + +void jvmti_jit_prepare_pop_frame(){ + assert(0); +} + +void jvmti_jit_complete_pop_frame(){ + assert(0); +} + +void jvmti_jit_do_pop_frame(){ + assert(0); +} +#else // _IA32_ + +// requires stack iterator and buffer to save intermediate information +static void jvmti_jit_prepare_pop_frame(StackIterator* si, uint32* buf) { // pop native frame assert(si_is_native(si)); si_goto_previous(si); @@ -162,25 +202,27 @@ void jvmti_jit_do_pop_frame() } else if (0xd0ff == (*((unsigned short*)(((char*)ip)-2)))) { ip_reduce = 2; current_method_addr = cci->get_code_block_addr(); - jitContext->p_eax = (uint32*)¤t_method_addr; + *buf = (uint32)current_method_addr; + jitContext->p_eax = buf; // invoke virtual and special } else { VTable_Handle vtable = class_get_vtable( method_class); + *buf = (uint32) vtable; unsigned short code = (*((unsigned short*)(((char*)ip)-3))); // invoke virtual if (0x50ff == code) { - jitContext->p_eax = (uint32*) &vtable; + jitContext->p_eax = buf; ip_reduce = 3; } else if (0x51ff == code) { - jitContext->p_ecx = (uint32*) &vtable; + jitContext->p_ecx = buf; ip_reduce = 3; } else if (0x52ff == code) { - jitContext->p_edx = (uint32*) &vtable; + jitContext->p_edx = buf; ip_reduce = 3; } else if (0x53ff == code) { - jitContext->p_ebx = (uint32*) &vtable; + jitContext->p_ebx = buf; ip_reduce = 3; // invoke special @@ -192,19 +234,123 @@ void jvmti_jit_do_pop_frame() // set corrrrect ip ip = (NativeCodePtr)(((char*)ip) - ip_reduce); si_set_ip(si, ip, false); +} + +void jvmti_jit_prepare_pop_frame() { + // Find top m2n frame + M2nFrame* top_frame = m2n_get_last_frame(); + frame_type type = m2n_get_frame_type(top_frame); + + // Check that frame has correct type + assert((FRAME_POP_NOW == (FRAME_POP_MASK & type)) + ||(FRAME_POP_DONE == (FRAME_POP_MASK & type))); + + // create stack iterator from native + StackIterator* si = si_create_from_native(); + si_transfer_all_preserved_registers(si); + + // preare pop frame - find regs values + uint32 buf = 0; + jvmti_jit_prepare_pop_frame(si, &buf); + + // save regs value from jit context to m2n + JitFrameContext* jitContext = si_get_jit_context(si); + Registers* regs = get_pop_frame_registers(top_frame); + + regs->esp = jitContext->esp; + regs->eip = *(jitContext->p_eip); + regs->esi = *(jitContext->p_esi); + regs->edi = *(jitContext->p_edi); + regs->ebp = *(jitContext->p_ebp); + + if (0 == jitContext->p_eax) { + regs->eax = 0; + } else { + regs->eax = *(jitContext->p_eax); + } + + if (0 == jitContext->p_ebx) { + regs->ebx = 0; + } else { + regs->ebx = *(jitContext->p_ebx); + } + + if (0 == jitContext->p_ecx) { + regs->ecx = 0; + } else { + regs->ecx = *(jitContext->p_ecx); + } + + if (0 == jitContext->p_edx) { + regs->edx = 0; + } else { + regs->edx = *(jitContext->p_edx); + } + + // set pop done frame state + m2n_set_frame_type(top_frame, FRAME_POP_DONE); +} + +void jvmti_jit_complete_pop_frame() { + // Destructive Unwinding!!! NO CXX Logging put here. + + // Find top m2n frame + M2nFrame* top_frame = m2n_get_last_frame(); + frame_type type = m2n_get_frame_type(top_frame); + + // Check that frame has correct type + assert(FRAME_POP_DONE == (FRAME_POP_MASK & type)); + + // create stack iterator from native + StackIterator* si = si_create_from_native(); + si_transfer_all_preserved_registers(si); + + // pop native frame + assert(si_is_native(si)); + si_goto_previous(si); // transfer cdontrol si_transfer_control(si); -} // jvmti_jit_do_pop_frame +} + +void jvmti_jit_do_pop_frame() { + // Destructive Unwinding!!! NO CXX Logging put here. + + // Find top m2n frame + M2nFrame* top_frame = m2n_get_last_frame(); + frame_type type = m2n_get_frame_type(top_frame); + + // Check that frame has correct type + assert(FRAME_POP_NOW == (FRAME_POP_MASK & type)); + + // create stack iterator from native + StackIterator* si = si_create_from_native(); + si_transfer_all_preserved_registers(si); + + // preare pop frame - find regs values + uint32 buf = 0; + jvmti_jit_prepare_pop_frame(si, &buf); + + // transfer cdontrol + si_transfer_control(si); +} +#endif // _IA32_ void jvmti_safe_point() { -// TRACE(("entering safe_point")); + Registers regs; + M2nFrame* top_frame = m2n_get_last_frame(); + set_pop_frame_registers(top_frame, ®s); + + TRACE(("entering safe_point")); hythread_safe_point(); + TRACE(("left safe_point")); - //TRACE(("left safe_point")); - //frame_type type = m2n_get_frame_type(m2n_get_last_frame()); + // find frame type + frame_type type = m2n_get_frame_type(top_frame); - //if (FRAME_POP_NOW == (FRAME_POP_NOW & type)) - // jvmti_jit_do_pop_frame(); + // complete pop frame if frame has correct type + if (FRAME_POP_DONE == (FRAME_POP_MASK & type)){ + jvmti_jit_complete_pop_frame(); + } } diff --git a/vm/vmcore/src/util/linux/signals_ia32.cpp b/vm/vmcore/src/util/linux/signals_ia32.cpp index 8510b81..de3cb58 100644 --- a/vm/vmcore/src/util/linux/signals_ia32.cpp +++ b/vm/vmcore/src/util/linux/signals_ia32.cpp @@ -109,7 +109,7 @@ extern "C" { } } -static void __attribute__ ((cdecl)) asm_jvmti_exception_catch_callback() { +void __attribute__ ((cdecl)) asm_jvmti_exception_catch_callback() { //naked_jvmti_exception_catch_callback: asm ( "addl $-36, %%esp;\n" @@ -154,7 +154,6 @@ static void throw_from_sigcontext(uconte regs.esp = regs.esp - 4; *((uint32*) regs.esp) = regs.eip; regs.eip = ((uint32)asm_jvmti_exception_catch_callback); - //regs.eip = ((uint32)naked_jvmti_exception_catch_callback); } linux_regs_to_ucontext(uc, ®s); diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp index 0e1d76a..0f82645 100644 --- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp @@ -227,7 +227,7 @@ static void __cdecl jvmti_exception_catc jvmti_exception_catch_callback(®s); } -static void __declspec(naked) __stdcall naked_exception_catch_callback() { +static void __declspec(naked) asm_exception_catch_callback() { __asm { push ebp mov ebp, esp @@ -245,7 +245,7 @@ static void __declspec(naked) __stdcall } } -static void __declspec(naked) __stdcall naked_jvmti_exception_catch_callback() { +void __declspec(naked) asm_jvmti_exception_catch_callback() { __asm { push ebp mov ebp, esp @@ -443,11 +443,11 @@ LONG NTAPI vectored_exception_handler(LP if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { regs.esp = regs.esp - 4; *((uint32*) regs.esp) = regs.eip; - regs.eip = ((uint32)naked_jvmti_exception_catch_callback); + regs.eip = ((uint32)asm_jvmti_exception_catch_callback); } else if (p_TLS_vmthread->restore_guard_page) { regs.esp = regs.esp - 4; *((uint32*) regs.esp) = regs.eip; - regs.eip = ((uint32)naked_exception_catch_callback); + regs.eip = ((uint32)asm_exception_catch_callback); } vm_to_nt_context(®s, context); -- 1.3.3