From nobody Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Wed, 13 Sep 2006 16:41:45 +0400 Subject: [PATCH] [DRLVM] PopFrame for the current thread Implementation of PopFrame for the current thread, using which jvmti pop frame can be implemented. Small fix of transfer control stub is included to provide ecx and edx restore. DEPENDS: HARMONY-1420 --- vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp | 67 +++++++++++--- vm/vmcore/src/jvmti/jvmti_pop_frame.cpp | 109 +++++++++++++++++++++- 2 files changed, 159 insertions(+), 17 deletions(-) 0972006eb3afc705618c362a715b00658cac7a29 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 922a762..48e66c4 100644 --- a/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp +++ b/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp @@ -116,7 +116,7 @@ static transfer_control_stub_type gen_tr return addr; } - const int stub_size = 88; + const int stub_size = 64; char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); #ifdef _DEBUG memset(stub, 0xcc /*int 3*/, stub_size); @@ -129,31 +129,63 @@ #endif // changing the esp at the very end of the sequence. // - // ecx will hold the final esp value - // edx will hold the pointer to the stack iterator - M_Base_Opnd m1(esp_reg, 4); ss = mov(ss, edx_opnd, m1); - // Put esp inot ecx, and restore eax (return value) - 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_eip); + M_Base_Opnd m2(edx_reg, (int)&((StackIterator*)0)->c.esp); ss = mov(ss, ecx_opnd, m2); - // Restore callee saves registers + 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); + ss = get_reg(ss, &esi_opnd, esi_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_esi); ss = get_reg(ss, &edi_opnd, edi_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_edi); - ss = get_reg(ss, &ebx_opnd, ebx_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_ebx); ss = get_reg(ss, &ebp_opnd, ebp_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_ebp); - // Now we are ready, grab the new IP, cut the stack, and jump - ss = get_reg(ss, &edx_opnd, edx_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_eip); - ss = mov(ss, esp_opnd, ecx_opnd); - ss = jump(ss, edx_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); + ss = get_reg(ss, &edx_opnd, edx_reg, edx_reg, (unsigned)&((StackIterator*)0)->c.p_edx); + + ss = mov(ss, esp_opnd, m1); + ss = ret(ss); addr = (transfer_control_stub_type)stub; assert(ss-stub <= stub_size); + /* + The following code will be generated: + + mov edx,dword ptr [esp+4] + 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] + mov esi,dword ptr [esi] + mov edi,dword ptr [edx+10h] + mov edi,dword ptr [edi] + mov ebp,dword ptr [edx+8] + mov ebp,dword ptr [ebp] + mov eax,dword ptr [edx+1Ch] + mov eax,dword ptr [eax] + mov ebx,dword ptr [edx+18h] + mov ebx,dword ptr [ebx] + mov ecx,dword ptr [edx+20h] + mov ecx,dword ptr [ecx] + mov edx,dword ptr [edx+24h] + mov edx,dword ptr [edx] + mov esp,dword ptr [esp+4] + ret + */ + DUMP_STUB(stub, "getaddress__transfer_control", ss - stub); return addr; @@ -419,8 +451,19 @@ void si_transfer_control(StackIterator* /* !!!! NO CXX LOGGER IS ALLOWED IN THIS FUNCTION !!! * !!!! RELEASE BUILD WILL BE BROKEN !!!*/ // 1. Copy si to stack + void* null_pointer = NULL; StackIterator local_si; memcpy(&local_si, si, sizeof(StackIterator)); + + if (NULL == si->c.p_eax) + local_si.c.p_eax = (uint32*)&null_pointer; + if (NULL == si->c.p_ebx) + local_si.c.p_ebx = (uint32*)&null_pointer; + if (NULL == si->c.p_ecx) + local_si.c.p_ecx = (uint32*)&null_pointer; + if (NULL == si->c.p_edx) + local_si.c.p_edx = (uint32*)&null_pointer; + if (si->c.p_eip == &si->ip) local_si.c.p_eip = &local_si.ip; si_free(si); diff --git a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp index df49ec9..46e5618 100755 --- a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp +++ b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp @@ -25,9 +25,12 @@ #include "jvmti_interface.h" #include "exceptions.h" #include "environment.h" #include "vm_threads.h" +#include "jit_intf_cpp.h" #include "m2n.h" +#include "mon_enter_exit.h" #include "stack_iterator.h" -#include "cxxlog.h" +//#include "cxxlog.h" +#include "clog.h" jvmtiError jvmti_jit_pop_frame(VM_thread *thread) { @@ -61,21 +64,117 @@ jvmtiError jvmti_jit_pop_frame(VM_thread type = (frame_type) (type | FRAME_POP_NOW); m2n_set_frame_type(top_frame, type); + si_free(si); + return JVMTI_ERROR_NONE; } void jvmti_jit_do_pop_frame() { - TRACE("jvmti_jit_do_pop_frame() is called"); + // Destructive Unwinding!!! NO CXZ Logging put here. + + // 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); + + // save information about java frame + assert(!si_is_native(si)); + CodeChunkInfo *cci = si_get_code_chunk_info(si); + JitFrameContext* jitContext = si_get_jit_context(si); + + // save information about java method + assert(cci); + Method *method = cci->get_method(); + Class* method_class = method->get_class(); + bool is_method_static = method->is_static(); + + // free lock of synchronized method + /* + Currently JIT does not unlock monitors of synchronized blocks relying + on compiler which generates pseudo finally statement to unlock them. + For correct implementation of PopFrame these monitors will have to be + unlocked by VM, so JIT has to store information about these monitors + somewhere. + */ + if (method->is_synchronized()) { + if (is_method_static) { + assert(!hythread_is_suspend_enabled()); + TRACE2("tm.locks", ("unlock staic sync methods... ")); + vm_monitor_exit(struct_Class_to_java_lang_Class(method-> + get_class())); + exn_clear(); + } else { + JIT *jit = cci->get_jit(); + void **p_this = + (void **) jit->get_address_of_this(method, jitContext); + TRACE2("tm.locks", ("unlock sync methods...%x" , *p_this)); + vm_monitor_exit((ManagedObject *) * p_this); + exn_clear(); + } + } + + // pop java frame + si_goto_previous(si); + + // find correct ip and restore required regiksters context + NativeCodePtr current_method_addr = NULL; + NativeCodePtr ip = si_get_ip(si); + size_t ip_reduce; + + // invoke static + if (is_method_static) { + ip_reduce = 6; + + // invoke interface + } 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; + + // invoke virtual and special + } else { + VTable_Handle vtable = class_get_vtable( method_class); + unsigned short code = (*((unsigned short*)(((char*)ip)-3))); + + // invoke virtual + if (0x50ff == code) { + jitContext->p_eax = (uint32*) &vtable; + ip_reduce = 3; + } else if (0x51ff == code) { + jitContext->p_ecx = (uint32*) &vtable; + ip_reduce = 3; + } else if (0x52ff == code) { + jitContext->p_edx = (uint32*) &vtable; + ip_reduce = 3; + } else if (0x53ff == code) { + jitContext->p_ebx = (uint32*) &vtable; + ip_reduce = 3; + + // invoke special + } else{ + ip_reduce = 6; + } + } + + // set corrrrect ip + ip = (NativeCodePtr)(((char*)ip) - ip_reduce); + si_set_ip(si, ip, false); + + // transfer cdontrol + si_transfer_control(si); } void jvmti_safe_point() { // __asm int 3; - TRACE("entering safe_point"); + 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()); if (FRAME_POP_NOW == (FRAME_POP_NOW & type)) @@ -84,7 +183,7 @@ void jvmti_safe_point() void jvmti_pop_frame_callback() { - TRACE("suspend_disable post callback..."); + TRACE(("suspend_disable post callback...")); frame_type type = m2n_get_frame_type(p_TLS_vmthread->last_m2n_frame); if (FRAME_POP_NOW != (FRAME_POP_NOW & type)) -- 1.3.3