From 22889d7ede85d2a0fe7d26f0bf57c9c089d299f9 Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Mon, 23 Jul 2007 20:03:21 +0400 Subject: [PATCH] Fix iterate over stack trace of non current thread on IPF. Any attempt to iterate over stack trace of non current thread yields to crash on IPF. Thus it is impossible to execute any mult-ithread application which envolves GC or exception creation. Currently this problem leads to crashes on stress.WeakHashmapTest and SpecJBB2005 on the second or third warehouse. With the current pach all smoke tests and SpecJBB2005 passed successfully (except SpecJBB2005 reporter crashed on awt...this is another issue though). --- vm/port/include/m2n.h | 30 ++-- vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp | 1 - vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp | 13 +-- vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp | 19 ++- vm/port/src/lil/ipf/pim/m2n_ipf.cpp | 101 +++++++++++- vm/port/src/lil/ipf/pim/m2n_ipf_internal.h | 25 ++- vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp | 179 ++++++-------------- vm/port/src/lil/pim/m2n.cpp | 34 ++++ vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp | 2 +- .../src/util/ipf/base/jit_runtime_support_ipf.cpp | 42 +++--- vm/vmcore/src/util/ipf/base/stub_code_utils.cpp | 18 ++- vm/vmcore/src/util/ipf/include/Code_Emitter.h | 4 + vm/vmcore/src/util/ipf/include/stub_code_utils.h | 3 +- vm/vmcore/src/util/ipf/include/vm_ipf.h | 5 + 14 files changed, 279 insertions(+), 197 deletions(-) create mode 100644 vm/port/src/lil/pim/m2n.cpp diff --git a/vm/port/include/m2n.h b/vm/port/include/m2n.h index 8d0dd11..d5b3d97 100644 --- a/vm/port/include/m2n.h +++ b/vm/port/include/m2n.h @@ -41,23 +41,19 @@ struct M2nFrame; -enum frame_type { - 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_POP_DONE = FRAME_POPABLE | FRAME_POP_NOW, - - FRAME_POP_MASK = 0x0700, - - FRAME_SAFE_POINT = 0x0800, - - FRAME_MODIFIED_STACK = 0x1000 -}; +typedef uint32 frame_type; + +extern const uint32 FRAME_UNKNOWN; +extern const uint32 FRAME_NON_UNWINDABLE; +extern const uint32 FRAME_JNI; +extern const uint32 FRAME_COMPILATION; +extern const uint32 FRAME_UNPOPABLE; +extern const uint32 FRAME_POPABLE; +extern const uint32 FRAME_POP_NOW; +extern const uint32 FRAME_POP_DONE; +extern const uint32 FRAME_POP_MASK; +extern const uint32 FRAME_SAFE_POINT; +extern const uint32 FRAME_MODIFIED_STACK; // The pushing and popping of native frames is done only by stubs that // implement the managed to native transitions. These stubs use code that is 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 b77558a..ac132af 100644 --- a/vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp +++ b/vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp @@ -311,7 +311,6 @@ __label15__ // Stack Iterator Interface StackIterator * si_create_from_native() { - ASSERT_NO_INTERPRETER return si_create_from_native(p_TLS_vmthread); } 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 2c1a446..9996b73 100644 --- a/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp +++ b/vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp @@ -232,18 +232,7 @@ _label_: StackIterator* si_create_from_native() { - ASSERT_NO_INTERPRETER - // Allocate iterator - StackIterator* res = (StackIterator*)STD_MALLOC(sizeof(StackIterator)); - assert(res); - memset(res, 0, sizeof(StackIterator)); - - res->cci = NULL; - res->m2nfl = m2n_get_last_frame(); - res->ip = 0; - res->c.p_eip = &res->ip; - - return res; + return si_create_from_native(p_TLS_vmthread); } StackIterator* si_create_from_native(VM_thread* thread) diff --git a/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp b/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp index a4181c0..c9772f7 100644 --- a/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp +++ b/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp @@ -600,6 +600,10 @@ public: return 16 + stk_output_size; } + bool has_push_m2n() { + return has_m2n; + } + private: //***************** // helper functions, used by visitor functions @@ -1966,7 +1970,13 @@ public: // Set new gp emit_mov_imm_compactor(emitter, GP_REG, (uint64)gp_new); } - emitter.ipf_brl_call(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, (uint64)fn_addr); + emit_mov_imm_compactor(emitter, tmp_res->addr, (uint64)fn_addr, 0); + if (context.has_push_m2n()) { + emitter.ipf_mtbr(BRANCH_CALL_REG, tmp_res->addr); + emit_mov_imm_compactor(emitter, tmp_res->addr, (uint64)m2n_gen_flush_and_call(), 0); + } + emitter.ipf_mtbr(tmp_br, tmp_res->addr); + emitter.ipf_bricall(br_few, br_sptk, br_none, BRANCH_RETURN_LINK_REG, tmp_br); if (gp_new != gp_old) { // Restore gp const LcgIpfLoc* gp_save_gr = context.get_gp_save_gr(); @@ -1990,9 +2000,12 @@ public: else { ASSERT(0, "Unexpected kind"); // address can't be FP! } + if (context.has_push_m2n()) { + emitter.ipf_mtbr(BRANCH_CALL_REG, call_addr_gr); + emit_mov_imm_compactor(emitter, call_addr_gr, (uint64)m2n_gen_flush_and_call(), 0); + } emitter.ipf_mtbr(tmp_br, call_addr_gr); - emitter.ipf_bricall(br_few, br_sptk, br_none, - BRANCH_RETURN_LINK_REG, tmp_br); + emitter.ipf_bricall(br_few, br_sptk, br_none, BRANCH_RETURN_LINK_REG, tmp_br); } } // call diff --git a/vm/port/src/lil/ipf/pim/m2n_ipf.cpp b/vm/port/src/lil/ipf/pim/m2n_ipf.cpp index afc41b6..c3569d8 100644 --- a/vm/port/src/lil/ipf/pim/m2n_ipf.cpp +++ b/vm/port/src/lil/ipf/pim/m2n_ipf.cpp @@ -74,6 +74,7 @@ uint64* m2n_get_bsp(M2nFrame* m2nf) uint64* m2n_get_extra_saved(M2nFrame* m2nf) { + do_flushrs(); return (uint64*)*get_stacked_register_address(m2n_get_bsp(m2nf), M2N_EXTRA_SAVED_PTR); } @@ -194,6 +195,44 @@ void m2n_set_frame_type(M2nFrame* m2nf, frame_type m2nf_type) { //***** Stub Interface +// Flushes register stack of the current thread into backing store and calls target procedure. +NativeCodePtr m2n_gen_flush_and_call() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + tl::MemoryPool mem_pool; + Merced_Code_Emitter emitter(mem_pool, 2, 0); + emitter.disallow_instruction_exchange(); + emitter.memory_type_is_unknown(); + + // We need to remember pfs & b0 here but there is no space to save them in. + // Register stack contains valid outputs and we don't know how many registers are used. + // Memory stack holds output values beyound those 8 which are on register stack. + // The only place is general caller-saves registers. It is save to use them with out preserving + // because they are alredy preserved by the corresponding M2N frame. + + // r4 is used to keep a thread pointer...so let's use r5 & r6. + + emitter.ipf_mfap(PRESERV_GENERAL_REG1, AR_pfs); + emitter.ipf_mfbr(PRESERV_GENERAL_REG2, BRANCH_RETURN_LINK_REG); + + emitter.flush_buffer(); + emitter.ipf_flushrs(); + + emitter.ipf_bricall(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, BRANCH_CALL_REG); + + emitter.ipf_mtbr(BRANCH_RETURN_LINK_REG, PRESERV_GENERAL_REG2); + emitter.ipf_mtap(AR_pfs, PRESERV_GENERAL_REG1); + + emitter.ipf_brret(br_few, br_sptk, br_none, BRANCH_RETURN_LINK_REG); + + addr = finalize_stub(emitter, ""); + return addr; +} + unsigned m2n_gen_push_m2n(Merced_Code_Emitter* emitter, Method_Handle method, frame_type current_frame_type, bool handles, unsigned num_on_stack, unsigned num_local, unsigned num_out, bool do_alloc) { // Allocate new frame @@ -211,7 +250,8 @@ unsigned m2n_gen_push_m2n(Merced_Code_Emitter* emitter, Method_Handle method, fr // Save predicates, SP, and callee saves general registers emitter->ipf_adds(M2N_SAVED_SP, num_on_stack, SP_REG); - emitter->ipf_mfpr(M2N_SAVED_PR ); + emitter->ipf_mfpr(M2N_SAVED_PR ); + emitter->ipf_mfap(M2N_SAVED_UNAT, AR_unat); emitter->ipf_mov (M2N_SAVED_R4, 4); emitter->ipf_mov (M2N_SAVED_R5, 5); emitter->ipf_mov (M2N_SAVED_R6, 6); @@ -222,6 +262,61 @@ unsigned m2n_gen_push_m2n(Merced_Code_Emitter* emitter, Method_Handle method, fr emit_mov_imm_compactor(*emitter, M2N_METHOD, (uint64)method); emit_mov_imm_compactor(*emitter, M2N_FRAME_TYPE, (uint64)current_frame_type); + const int P1 = SCRATCH_PRED_REG; + const int P2 = SCRATCH_PRED_REG2; + const int OLD_RSE_MODE = SCRATCH_GENERAL_REG2; + const int NEW_RSE_MODE = SCRATCH_GENERAL_REG3; + // SCRATCH_GENERAL_REG4 & SCRATCH_GENERAL_REG5 are reserved for std places. + const int BSP = SCRATCH_GENERAL_REG6; + const int IMM_8 = SCRATCH_GENERAL_REG7; + const int IMM_1F8 = SCRATCH_GENERAL_REG8; + const int TMP_REG = SCRATCH_GENERAL_REG9; + // Scratch branch register. + const int TMP_BRANCH_REG = 6; + + // Switch RSE to "forced lazy" mode. This is required to access RNAT. + emitter->ipf_mfap(OLD_RSE_MODE, AR_rsc); + emitter->ipf_dep(NEW_RSE_MODE, 0, OLD_RSE_MODE, 0, 2); + emitter->ipf_mtap(AR_rsc, NEW_RSE_MODE); + + // Flush must be the first instruction in the group. + emitter->flush_buffer(); + // Spill parent frames so that corresponding RNAT bits become valid. + emitter->ipf_flushrs(); + // Extract backing store pointer + emitter->ipf_mfap(BSP, AR_bsp); + // Remember parent RNAT collection. + emitter->ipf_mfap(M2N_EXTRA_RNAT, AR_rnat); + + // TODO: This is not fully legal reset nat bits for the whole m2n frame because it + // contains r4-r7 general registers which may have corresponding unat bits up. + emitter->ipf_mov(M2N_EXTRA_UNAT, 0); + +/* The following code spills M2N into backing store. + emitter->ipf_movl(IMM_1F8, 0, (uint64)0x1f8); + emitter->ipf_movl(IMM_8, 0, (uint64)0x8); + + // Forcebly spill M2N frame into backing store. + for(int i = M2N_NUMBER_INPUTS; i < M2N_NUMBER_LOCALS; i++) { + emitter->ipf_and(TMP_REG, IMM_1F8, BSP); + emitter->ipf_cmp(icmp_eq, cmp_none, P1, P2, IMM_1F8, TMP_REG); + emitter->ipf_add(BSP, BSP, IMM_8, P1); + emitter->ipf_st_inc_imm(int_mem_size_8, mem_st_spill, mem_none, BSP, 32 + i, 8); + } + + // Remember UNAT collection for the current frame. + emitter->ipf_sub(BSP, BSP, IMM_8); + emitter->ipf_mfap(M2N_EXTRA_UNAT, AR_unat); + emitter->ipf_st(int_mem_size_8, mem_st_none, mem_none, BSP, M2N_EXTRA_UNAT); + + // Restore original UNAT. + emitter->ipf_mtap(AR_unat, M2N_SAVED_UNAT); + emitter->flush_buffer(); +*/ + + // Switch RSE to the original mode. + emitter->ipf_mtap(AR_rsc, OLD_RSE_MODE); + // Link M2nFrame into list of current thread size_t offset_lm2nf = (size_t)&((VM_thread*)0)->last_m2n_frame; emitter->ipf_adds(SCRATCH_GENERAL_REG2, (int)offset_lm2nf, THREAD_PTR_REG); @@ -284,9 +379,9 @@ void m2n_gen_pop_m2n(Merced_Code_Emitter* emitter, bool handles, M2nPreserveRet } if (handles) { - emit_call_with_gp(*emitter, (void**)m2n_pop_local_handles); + emit_call_with_gp(*emitter, (void**)m2n_pop_local_handles, false); } else { - emit_call_with_gp(*emitter, (void**)m2n_free_local_handles); + emit_call_with_gp(*emitter, (void**)m2n_free_local_handles, false); } // Restore return register diff --git a/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h b/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h index 4d27d6e..b9c9eef 100644 --- a/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h +++ b/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h @@ -100,11 +100,14 @@ uint64* m2n_get_arg_word(M2nFrame*, unsigned n); uint64* m2n_get_bsp(M2nFrame*); uint64* m2n_get_extra_saved(M2nFrame*); +// Flushes register stack of the current thread into backing store and calls target procedure. +NativeCodePtr m2n_gen_flush_and_call(); + // An M2nFrame will always have 8 input registers, some local stacked registers to save stuff, and some outputs #define M2N_NUMBER_ALIGNS 2 #define M2N_NUMBER_INPUTS 8 -#define M2N_NUMBER_LOCALS 14 +#define M2N_NUMBER_LOCALS 17 // The following registers are used in M2nFrames to hold the indicated values // The register numbers must be distinct, at least 40 (so they don't conflict with inputs), and less than 40+M2N_NUMBER_LOCALS @@ -115,14 +118,18 @@ uint64* m2n_get_extra_saved(M2nFrame*); #define M2N_SAVED_SP 43 #define M2N_SAVED_GP 44 #define M2N_SAVED_PR 45 -#define M2N_SAVED_R4 46 -#define M2N_SAVED_R5 47 -#define M2N_SAVED_R6 48 -#define M2N_SAVED_R7 49 -#define M2N_EXTRA_SAVED_PTR 50 -#define M2N_OBJECT_HANDLES 51 -#define M2N_METHOD 52 -#define M2N_FRAME_TYPE 53 +#define M2N_SAVED_UNAT 46 +#define M2N_SAVED_R4 47 +#define M2N_SAVED_R5 48 +#define M2N_SAVED_R6 49 +#define M2N_SAVED_R7 50 +#define M2N_EXTRA_SAVED_PTR 51 +#define M2N_OBJECT_HANDLES 52 +#define M2N_METHOD 53 +#define M2N_FRAME_TYPE 54 +#define M2N_EXTRA_RNAT 55 +// this must be last register +#define M2N_EXTRA_UNAT 56 // Only the callee saves general registers are normally saved in the M2nFrame along with special things like pfs, return address, etc. // The full set of preserved registers includes callee saves floating point and branch registers as well. 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 e43934f..4430c29 100644 --- a/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp +++ b/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp @@ -71,8 +71,8 @@ struct StackIterator { M2nFrame* m2nfl; uint64 ip; uint64* bsp; - uint64* last_legal_rsnat; - uint64 extra_nats; + uint64 extra_rnats; + uint64 extra_unats; }; ////////////////////////////////////////////////////////////////////////// @@ -82,28 +82,60 @@ struct StackIterator { // this flush. We assume that all nat bits we are interested in do not change from the time of flush // to after we are finished with the iterator that calls this function, even if the rse engine has // returned to a point prior to bsp. +/* static void si_init_nats(StackIterator* si, uint64* bsp, uint64 rnat) { si->last_legal_rsnat = (uint64*)((uint64)bsp & ~0x1f8); si->extra_nats = rnat; } +*/ // This function flushes the rse and puts the value of bsp/bspstore into res[1] and rnat into res[0] +/* extern "C" void get_rnat_and_bsp(uint64* res); extern "C" void get_rnat_and_bspstore(uint64* res); +*/ + +static uint64 get_rnat(uint64 * bsp) { + uint64 * last_m2n = (uint64 *)m2n_get_last_frame(); + uint64 * rnat_ptr = (uint64*)((uint64)bsp | (uint64)0x1f8); + uint64 * extra_nat_ptr; + + if (rnat_ptr <= last_m2n) { + return *rnat_ptr; + } + + // All nat bits for last M2N are stored at M2N_EXTRA_UNAT. + // All nat bits for parent frames are stored at M2N_EXTRA_RNAT. + + if (bsp >= last_m2n) { + extra_nat_ptr = last_m2n + (M2N_EXTRA_UNAT - 32); + } else { + extra_nat_ptr = last_m2n + (M2N_EXTRA_RNAT - 32); + } + + if (rnat_ptr <= extra_nat_ptr) { + // There is rnat collection inside M2N. Need to adjust... + extra_nat_ptr += 1; + } + + return *extra_nat_ptr; +} // Setup the stacked register for the current frame given bsp and ar.pfs (cfm for current frame) static void si_setup_stacked_registers(StackIterator* si) { + const uint64 ALL_ONES = ~0; uint64 pfs = *si->c.p_ar_pfs; unsigned sof = (unsigned)EXTRACT64_SOF(pfs); uint64 nats_lo = si->c.nats_lo & 0xffffffff; uint64 nats_hi = 0; uint64* bsp = si->bsp; - uint64 nats = (bsp<=si->last_legal_rsnat ? *(uint64*)((uint64)bsp|(uint64)0x1f8) : si->extra_nats); + uint64 nats = get_rnat(bsp); + unsigned index = (unsigned)(((uint64)bsp & (uint64)0x1f8) >> 3); - uint64 mask = 1 << index; + uint64 mask = ((uint64)1) << index; for(unsigned i=0; ilast_legal_rsnat) - nats = *bsp; - else - nats = si->extra_nats; bsp++; mask = 1; + nats = get_rnat(bsp); } } @@ -154,11 +183,12 @@ static void si_unwind_from_m2n(StackIterator* si) assert(M2N_SAVED_R7 < 64); si->c.nats_lo = si->c.nats_lo & ~(uint64)0xf0 | (si->c.nats_lo >> (M2N_SAVED_R4-4)) & (uint64)0xf0; - // IP, SP, PFS, preds, m2nfl + // IP, SP, PFS, preds, unat, m2nfl si->c.p_eip = si->c.p_gr[M2N_SAVED_RETURN_ADDRESS]; si->c.sp = *si->c.p_gr[M2N_SAVED_SP]; si->c.p_ar_pfs = si->c.p_gr[M2N_SAVED_PFS]; si->c.preds = *si->c.p_gr[M2N_SAVED_PR]; + si->c.ar_unat = *si->c.p_gr[M2N_SAVED_UNAT]; si->m2nfl = m2n_get_previous_frame(si->m2nfl); } @@ -167,18 +197,17 @@ static void si_unwind_bsp(StackIterator* si) { uint64 pfs = *si->c.p_ar_pfs; unsigned sol = (unsigned)EXTRACT64_SOL(pfs); - assert(sol<=96); // ichebyki - // ichebyki assert(sol<96); - uint64* bsp = si->bsp; - // Direct computation, see IPF arch manual, volume 3, table 6.2. - uint64 b = (uint64)bsp; - uint64 s = sol<<3; + assert(sol<=96); + + uint64 bsp = (uint64)si->bsp; + uint64 local_area_size = sol << 3; - uint64 d2 = b-s; - uint64 d3 = 62*8-(b&0x1f8)+s; - if (d3>=63*8) - if (d3>=126*8) + // Direct computation, see IPF arch manual, volume 3, table 6.2. + uint64 d2 = bsp - local_area_size; + uint64 d3 = 62*8 - (bsp & 0x1f8) + local_area_size; + if (d3 >= 63*8) + if (d3 >= 126*8) d2 -= 16; else d2 -= 8; @@ -327,126 +356,27 @@ static transfer_control_stub_type gen_transfer_control_stub() ////////////////////////////////////////////////////////////////////////// // Stack Iterator Interface -StackIterator* si_create_from_native() -{ - hythread_suspend_disable(); - // Allocate iterator - StackIterator* res = (StackIterator*)STD_MALLOC(sizeof(StackIterator)); - assert(res); - - // Setup last_legal_rsnat and extra_nats - uint64 t[2]; - get_rnat_and_bsp(t); - si_init_nats(res, (uint64*)t[1], t[0]); - - // Setup current frame - res->cci = NULL; - res->m2nfl = m2n_get_last_frame(); - res->ip = 0; - res->c.p_eip = &res->ip; - hythread_suspend_enable(); - return res; -} - -#if defined (PLATFORM_POSIX) StackIterator* si_create_from_native(VM_thread* thread) { - hythread_suspend_disable(); // Allocate iterator StackIterator* res = (StackIterator*)STD_MALLOC(sizeof(StackIterator)); assert(res); - // Setup last_legal_rsnat and extra_nats - uint64 t[2]; - get_rnat_and_bsp(t); - si_init_nats(res, (uint64*)t[1], t[0]); - // Setup current frame res->cci = NULL; res->m2nfl = m2n_get_last_frame(thread); res->ip = 0; res->c.p_eip = &res->ip; - hythread_suspend_enable(); return res; +} -#if 0 - // FIXME: code is outdated - assert(0); - abort(); - - // Allocate iterator - StackIterator* res = (StackIterator*)malloc(sizeof(StackIterator)); - assert(res); - - TRACE2("SIGNALLING", "stack iterator: create from native pthread_t " << ((pthread_t)GetCurrentThreadId())); - - if (thread == p_TLS_vmthread) { - get_rnat_and_bspstore(thread->t); - } else { - assert(thread->suspend_request > 0); - - TRACE2("SIGNALLING", "thread state before " << thread << " " << - thread->t[0] << " " << thread->t[1] << " " << thread->suspended_state); - //if (thread->suspended_state == NOT_SUSPENDED) { - TRACE2("SIGNALLING", "sending SIGUSR2 to thread " << thread); - assert(thread->thread_id != 0); - - if (sem_init(&thread->suspend_self, 0, 0) != 0) { - DIE("sem_init() failed" << strerror(errno)); - } - - thread->t[0] = NOT_VALID; - thread->t[1] = NOT_VALID; - - TRACE2("SIGNALLING", "BEFORE KILL thread = " << thread << " killing " << thread->thread_id); - - if (pthread_kill(thread->thread_id, SIGUSR2) != 0) { - DIE("pthread_kill(" << thread->thread_id << ", SIGUSR2) failed :" << strerror(errno)); - } - - si_reload_registers(); - - TRACE2("SIGNALLING", "BEFORE WAIT thread = " << thread); - - int ret; - do { - ret = sem_wait(&thread->suspend_self); - TRACE2("SIGNALLING", "sem_wait " << (&thread->suspend_self) << - " exited, errno = " << errno); - } while((ret != 0) && (errno == EINTR)); - - TRACE2("SIGNALLING", "AFTER WAIT thread = " << thread); - - sem_destroy(&thread->suspend_self); - assert(thread->suspended_state == SUSPENDED_IN_SIGNAL_HANDLER); - thread->suspended_state = NOT_SUSPENDED; - // assert(thread->t[0] != NOT_VALID); - // assert(thread->t[1] != NOT_VALID); - } - - TRACE2("SIGNALLING", "thread state after " << thread << " " << thread->t[0] << " " << thread->t[1] << " " << m2n_get_last_frame(thread)); - - TRACE2("SIGNALLING", "stack iterator: create from native, rnat, bsp/bspstore " << thread->t[0] << " " << thread->t[1]); - - // Setup last_legal_rsnat and extra_nats - uint64 rnat = thread->t[0]; - uint64* bsp = (uint64*)thread->t[1]; - - si_init_nats(res, bsp, rnat); - - // Check that bsp covers everything - assert((uint64)m2n_get_last_frame(thread)+(M2N_NUMBER_LOCALS+9)*8 <= (uint64)bsp); - - // Setup current frame - res->cci = NULL; - res->m2nfl = m2n_get_last_frame(thread); - res->ip = 0; - res->c.p_eip = &res->ip; - - return res; -#endif +StackIterator* si_create_from_native() +{ + return si_create_from_native(p_TLS_vmthread); } +/* +#if defined (PLATFORM_POSIX) #elif defined (PLATFORM_NT) // Get the bspstore and rnat values of another thread from the OS. @@ -488,6 +418,7 @@ StackIterator* si_create_from_native(VM_thread* thread) #else #error Stack iterator is not implemented for the given platform #endif +*/ // On IPF stack iterators must be created from threads (suspended) in native code. // We do not support threads suspended in managed code yet. diff --git a/vm/port/src/lil/pim/m2n.cpp b/vm/port/src/lil/pim/m2n.cpp new file mode 100644 index 0000000..172c82f --- /dev/null +++ b/vm/port/src/lil/pim/m2n.cpp @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Evgueni Brevnov + * @version $Revision: 1.1 $ + */ + +#include "m2n.h" + +const uint32 FRAME_UNKNOWN = 0x00; +const uint32 FRAME_NON_UNWINDABLE = 0x80; +const uint32 FRAME_JNI = 0x01 | FRAME_NON_UNWINDABLE; +const uint32 FRAME_COMPILATION = 0x02 | FRAME_NON_UNWINDABLE; +const uint32 FRAME_UNPOPABLE = 0x0000; +const uint32 FRAME_POPABLE = 0x0100; +const uint32 FRAME_POP_NOW = 0x0200; +const uint32 FRAME_POP_DONE = FRAME_POPABLE | FRAME_POP_NOW; +const uint32 FRAME_POP_MASK = 0x0700; +const uint32 FRAME_SAFE_POINT = 0x0800; +const uint32 FRAME_MODIFIED_STACK = 0x1000; diff --git a/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp b/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp index c092daa..ebedc61 100644 --- a/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp +++ b/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp @@ -72,7 +72,7 @@ void gen_vm_rt_athrow_internal_compactor(Merced_Code_Emitter &emitter) emitter.ipf_mov(out_arg0+1, IN_REG1); emitter.ipf_mov(out_arg0+2, 0); emitter.ipf_mov(out_arg0+3, 0); - emit_call_with_gp(emitter, (void **)exn_athrow, 5); + emit_call_with_gp(emitter, (void **)exn_athrow, true, 5); } //gen_vm_rt_athrow_internal_compactor diff --git a/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp b/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp index 5aa7981..be22025 100644 --- a/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp +++ b/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp @@ -222,7 +222,7 @@ static void gen_vm_rt_ljf_wrapper_code_compactor(Merced_Code_Emitter &emitter, emitter.ipf_mov(out_arg0 + arg, IN_REG0 + arg); } - emit_call_with_gp(emitter, func); + emit_call_with_gp(emitter, func, true); // 20030512 If compressing references, translate a NULL result to a managed null (heap_base). if (translate_returned_ref) { @@ -320,7 +320,7 @@ static void get_vm_rt_new_with_thread_pointer_compactor(Merced_Code_Emitter &emi emitter.ipf_mov(out0+0, IN_REG0); emitter.ipf_mov(out0+1, IN_REG1); emitter.ipf_adds(out0+2, (int)offset_gc_local, THREAD_PTR_REG); - emit_call_with_gp(emitter, (void **)p_update_allocation_stats); + emit_call_with_gp(emitter, (void **)p_update_allocation_stats, false); emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); enforce_calling_conventions(&emitter); #endif // VM_STATS @@ -371,7 +371,7 @@ static void get_vm_rt_new_with_thread_pointer_compactor(Merced_Code_Emitter &emi emitter.ipf_mov(out0+0, IN_REG0); emitter.ipf_mov(out0+1, IN_REG1); emitter.ipf_adds(out0+2, (int)offset_gc_local, THREAD_PTR_REG); - emit_call_with_gp(emitter, fast_obj_alloc_proc); + emit_call_with_gp(emitter, fast_obj_alloc_proc, false); // If the fast allocation procedure returned a non-NULL result then return, else fall through to the slow allocation path. emitter.ipf_cmp(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, 0, RETURN_VALUE_REG); @@ -387,7 +387,7 @@ static void get_vm_rt_new_with_thread_pointer_compactor(Merced_Code_Emitter &emi emitter.ipf_mov(out_arg0+0, IN_REG0); emitter.ipf_mov(out_arg0+1, IN_REG1); emitter.ipf_adds(out_arg0+2, (int)offset_gc_local, THREAD_PTR_REG); - emit_call_with_gp(emitter, slow_obj_alloc_proc); + emit_call_with_gp(emitter, slow_obj_alloc_proc, true); // pop m2n frame and return m2n_gen_pop_m2n(&emitter, false, MPR_Gr); @@ -416,7 +416,7 @@ static void get_vm_rt_new_vector_with_thread_pointer_compactor(Merced_Code_Emitt emitter.ipf_mov(out0+0, IN_REG0); emitter.ipf_mov(out0+1, IN_REG1); emitter.ipf_adds(out0+2, (int)offset_gc_local, THREAD_PTR_REG); - emit_call_with_gp(emitter, (void **)p_vm_new_vector_update_stats); + emit_call_with_gp(emitter, (void **)p_vm_new_vector_update_stats, false); emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); enforce_calling_conventions(&emitter); } @@ -434,7 +434,7 @@ static void get_vm_rt_new_vector_with_thread_pointer_compactor(Merced_Code_Emitt emitter.ipf_mov(out0, IN_REG0); emitter.ipf_mov(out0+1, IN_REG1); emitter.ipf_adds(out0+2, (int)offset_gc_local, THREAD_PTR_REG); - emit_call_with_gp(emitter, fast_obj_alloc_proc); + emit_call_with_gp(emitter, fast_obj_alloc_proc, false); // If the fast allocation procedure returned a non-NULL result then return, else fall through to the slow allocation path. emitter.ipf_cmp(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, 0, RETURN_VALUE_REG); @@ -449,7 +449,7 @@ static void get_vm_rt_new_vector_with_thread_pointer_compactor(Merced_Code_Emitt emitter.ipf_mov(out_arg0+0, IN_REG0); emitter.ipf_mov(out_arg0+1, IN_REG1); emitter.ipf_adds(out_arg0+2, (int)offset_gc_local, THREAD_PTR_REG); - emit_call_with_gp(emitter, slow_obj_alloc_proc); + emit_call_with_gp(emitter, slow_obj_alloc_proc, true); // pop m2n frame and return m2n_gen_pop_m2n(&emitter, false, MPR_Gr); @@ -761,7 +761,7 @@ static void emit_fast_type_check_without_vm_stats(Merced_Code_Emitter& emitter, emitter.ipf_add(sc1, sc2, sc3); emitter.ipf_ld(int_mem_size_8, mem_ld_none, mem_none, out0+0, sc1); emitter.ipf_mov(out0+1, super_class); - emit_call_with_gp(emitter, (void **)p_class_is_subtype); + emit_call_with_gp(emitter, (void **)p_class_is_subtype, false); emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); if (is_instanceof) @@ -793,7 +793,7 @@ static void emit_vm_stats_update_call(Merced_Code_Emitter& emitter, void **funct emitter.ipf_mov(out0+i, IN_REG0+i); } - emit_call_with_gp(emitter, function); + emit_call_with_gp(emitter, function, false); emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); enforce_calling_conventions(&emitter); @@ -828,7 +828,7 @@ static void *get_vm_rt_aastore_address_compactor() emitter.ipf_mov(out0+0, IN_REG0); emitter.ipf_mov(out0+1, IN_REG1); emitter.ipf_mov(out0+2, IN_REG2); - emit_call_with_gp(emitter, (void **)p_vm_rt_aastore); + emit_call_with_gp(emitter, (void **)p_vm_rt_aastore, false); // Restore pfs, b0, and gp emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); @@ -1105,7 +1105,7 @@ static void *get_vm_rt_initialize_class_compactor() Boolean (*p_is_class_initialized)(Class *clss); p_is_class_initialized = is_class_initialized; - emit_call_with_gp(emitter, (void**)p_is_class_initialized); + emit_call_with_gp(emitter, (void**)p_is_class_initialized, false); emitter.ipf_cmp(icmp_ne, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, RETURN_VALUE_REG, SCRATCH_GENERAL_REG3); emitter.ipf_brret(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_PRED_REG); @@ -1115,7 +1115,7 @@ static void *get_vm_rt_initialize_class_compactor() emitter.ipf_mov(out_arg0+0, IN_REG0); void (*p_class_initialize)(Class *clss); p_class_initialize = vm_rt_class_initialize; - emit_call_with_gp(emitter, (void **)p_class_initialize); + emit_call_with_gp(emitter, (void **)p_class_initialize, true); // pop m2n frame and return m2n_gen_pop_m2n(&emitter, false, MPR_None); enforce_calling_conventions(&emitter); @@ -1364,7 +1364,7 @@ void gen_convert_class_arg(Merced_Code_Emitter &emitter, bool check_null) // Call struct_Class_to_java_lang_Class() to convert the struct Class* argument to a java_lang_Class reference. int out_arg0 = m2n_gen_push_m2n(&emitter, 0, FRAME_UNKNOWN, false, 0, 0, 1); emitter.ipf_mov(out_arg0, IN_REG0); - emit_call_with_gp(emitter, (void **)p_struct_Class_to_java_lang_Class); + emit_call_with_gp(emitter, (void **)p_struct_Class_to_java_lang_Class, true); m2n_gen_pop_m2n(&emitter, false, MPR_Gr); enforce_calling_conventions(&emitter); @@ -1376,7 +1376,7 @@ void gen_convert_class_arg(Merced_Code_Emitter &emitter, bool check_null) // Call struct_Class_to_java_lang_Class() to convert the struct Class* argument to a java_lang_Class reference. int out_arg0 = m2n_gen_push_m2n(&emitter, 0, FRAME_UNKNOWN, false, 0, 0, 1); emitter.ipf_mov(out_arg0, IN_REG0); - emit_call_with_gp(emitter, (void **)p_struct_Class_to_java_lang_Class); + emit_call_with_gp(emitter, (void **)p_struct_Class_to_java_lang_Class, true); m2n_gen_pop_m2n(&emitter, false, MPR_Gr); enforce_calling_conventions(&emitter); @@ -1522,7 +1522,7 @@ void emit_hashcode_override(Emitter_Handle eh, Method *method) out0, save_pfs, save_b0, save_gp); emitter.ipf_mov(out0, IN_REG0); - emit_call_with_gp(emitter, (void **)p_generic_hashcode); + emit_call_with_gp(emitter, (void **)p_generic_hashcode, false); // Restore pfs, b0, and gp emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); @@ -1549,7 +1549,7 @@ void emit_arraycopy_override(Emitter_Handle eh, Method *method) emitter.ipf_mov(out0+3, IN_REG3); emitter.ipf_mov(out0+4, IN_REG4); - emit_call_with_gp(emitter, (void **)p_array_copy); + emit_call_with_gp(emitter, (void **)p_array_copy, false); // Restore pfs, b0, and gp emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); @@ -1572,7 +1572,7 @@ void emit_system_currenttimemillis_override(Emitter_Handle eh, Method *method) (void **)func, out0, save_pfs, save_b0, save_gp); - emit_call_with_gp(emitter, (void **)func); + emit_call_with_gp(emitter, (void **)func, false); // Restore pfs, b0, and gp emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); @@ -1647,7 +1647,7 @@ void emit_readinternal_override(Emitter_Handle eh, Method *method) emitter.ipf_mov(out0+5, IN_REG4); int (*func)(JNIEnv*, Java_java_io_FileInputStream*, int, Vector_Handle, int, int) = readinternal_override; - emit_call_with_gp(emitter, (void **)func); + emit_call_with_gp(emitter, (void **)func, false); // Restore pfs, b0, and gp emitter.ipf_mov(GP_REG, save_gp); @@ -2186,7 +2186,7 @@ static void *gen_faster_char_arraycopy_no_exc() emitter.ipf_adds(out0+0, first_element_offset, sc2); emitter.ipf_adds(out0+1, first_element_offset, sc1); emitter.ipf_add(out0+2, length, length); - emit_call_with_gp(emitter, (void **)p_memmove); + emit_call_with_gp(emitter, (void **)p_memmove, false); // Restore pfs, b0, and gp emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); @@ -2331,7 +2331,7 @@ static void *create_direct_helper_call_wrapper(void **fptr, int num_args, const { emitter.ipf_mov(out0+i, IN_REG0+i); } - emit_call_with_gp(emitter, fptr); + emit_call_with_gp(emitter, fptr, false); // Restore pfs, b0, and gp emit_dealloc_for_single_call(emitter, save_pfs, save_b0, save_gp); @@ -2530,7 +2530,7 @@ void *emit_counting_wrapper_for_jit_helper(VM_RT_SUPPORT f, void *helper, int nu // Call increment_helper_count. emit_movl_compactor(emitter, out0, (uint64)f); - emit_call_with_gp(emitter, (void **)p_increment_helper_count); + emit_call_with_gp(emitter, (void **)p_increment_helper_count, false); // Restore fp args emitter.ipf_adds(SP_REG, 16, SP_REG); diff --git a/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp b/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp index 8c7afb6..34fb28a 100644 --- a/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp +++ b/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp @@ -75,10 +75,11 @@ void emit_dealloc_for_single_call(Merced_Code_Emitter& emitter, emitter.ipf_mtbr(BRANCH_RETURN_LINK_REG, save_b0_reg, pred); } - +NativeCodePtr m2n_gen_flush_and_call(); void emit_call_with_gp(Merced_Code_Emitter& emitter, void **proc_ptr, + bool flushrs, int saved_gp_reg) { void *new_gp = proc_ptr[1]; @@ -94,7 +95,14 @@ void emit_call_with_gp(Merced_Code_Emitter& emitter, uint64 branch_target = (uint64)(*proc_ptr); - emitter.ipf_brl_call(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, branch_target); + emit_mov_imm_compactor(emitter, SCRATCH_GENERAL_REG, branch_target, 0); + if (flushrs) { + emitter.ipf_mtbr(BRANCH_CALL_REG, SCRATCH_GENERAL_REG); + emit_mov_imm_compactor(emitter, SCRATCH_GENERAL_REG, (uint64)m2n_gen_flush_and_call(), 0); + } + emitter.ipf_mtbr(SCRATCH_BRANCH_REG, SCRATCH_GENERAL_REG); + emitter.ipf_bricall(br_few, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_BRANCH_REG); + // Restore the saved GP. if (new_gp != vm_gp && saved_gp_reg != 0) emitter.ipf_mov(GP_REG, saved_gp_reg); @@ -102,7 +110,7 @@ void emit_call_with_gp(Merced_Code_Emitter& emitter, void emit_branch_with_gp(Merced_Code_Emitter& emitter, - void **proc_ptr) + void **proc_ptr) { void *new_gp = proc_ptr[1]; void *vm_gp = get_vm_gp_value(); @@ -115,7 +123,7 @@ void emit_branch_with_gp(Merced_Code_Emitter& emitter, uint64 branch_target = (uint64)(*proc_ptr); - emit_movl_compactor(emitter, SCRATCH_GENERAL_REG, branch_target, 0); + emit_mov_imm_compactor(emitter, SCRATCH_GENERAL_REG, branch_target, 0); emitter.ipf_mtbr(SCRATCH_BRANCH_REG, SCRATCH_GENERAL_REG); emitter.ipf_bri(br_cond, br_few, br_sptk, br_none, SCRATCH_BRANCH_REG); @@ -241,7 +249,7 @@ void emit_print_reg(Merced_Code_Emitter &emitter, char *msg, unsigned print_reg, emit_movl_compactor(emitter, out0, (uint64) msg); emitter.ipf_mov(out0+1, print_reg); // call a helper function - emit_call_with_gp(emitter, (void **) print_helper); + emit_call_with_gp(emitter, (void **) print_helper, false); emitter.ipf_adds(SP_REG, 16, SP_REG); // restore the scratch regs diff --git a/vm/vmcore/src/util/ipf/include/Code_Emitter.h b/vm/vmcore/src/util/ipf/include/Code_Emitter.h index 0a51b68..75f5ebf 100644 --- a/vm/vmcore/src/util/ipf/include/Code_Emitter.h +++ b/vm/vmcore/src/util/ipf/include/Code_Emitter.h @@ -331,6 +331,10 @@ public: { encoder->ipf_movl(dest, upper_32, lower_32, pred); _gen_an_IR_1i_0(curr_bc_addr, ST_il, pred, dest/**/); } + void ipf_movi64 (unsigned dest, uint64 imm64, unsigned pred=0) + { encoder->ipf_movi64(dest, imm64, pred); + _gen_an_IR_1i_0(curr_bc_addr, ST_il, pred, dest/**/); } + void ipf_brl_call(Branch_Prefetch_Hint ph, Branch_Whether_Hint wh, Branch_Dealloc_Hint dh, unsigned b1, uint64 imm64, unsigned pred=0) { encoder->ipf_brl_call(ph, wh, dh, b1, imm64, pred); diff --git a/vm/vmcore/src/util/ipf/include/stub_code_utils.h b/vm/vmcore/src/util/ipf/include/stub_code_utils.h index 13f7e49..a3d5d2e 100644 --- a/vm/vmcore/src/util/ipf/include/stub_code_utils.h +++ b/vm/vmcore/src/util/ipf/include/stub_code_utils.h @@ -68,13 +68,14 @@ void emit_dealloc_for_single_call(Merced_Code_Emitter& emitter, // If saved_gp_reg is not specified, then gp is neither saved nor restored. void emit_call_with_gp(Merced_Code_Emitter& emitter, void **proc_ptr, + bool flushrs, int saved_gp_reg = 0); // Emit a branch instruction. Before the branch, the gp is set to the // value specified in the function pointer. // This function is normally used to implement tail calls. void emit_branch_with_gp(Merced_Code_Emitter& emitter, - void **proc_ptr); + void **proc_ptr); void emit_movl_compactor(Merced_Code_Emitter& emitter, unsigned dst_reg, uint64 u64_value, unsigned pred=0); diff --git a/vm/vmcore/src/util/ipf/include/vm_ipf.h b/vm/vmcore/src/util/ipf/include/vm_ipf.h index a5183ff..96935fd 100644 --- a/vm/vmcore/src/util/ipf/include/vm_ipf.h +++ b/vm/vmcore/src/util/ipf/include/vm_ipf.h @@ -39,6 +39,7 @@ #define SCRATCH_PRED_REG9 14 #define SCRATCH_PRED_REG10 15 #define SCRATCH_BRANCH_REG 6 +#define SCRATCH_BRANCH_REG2 7 #define BRANCH_RETURN_LINK_REG 0 #define GP_REG 1 #define RETURN_VALUE_REG 8 @@ -60,12 +61,16 @@ #define SCRATCH_GENERAL_REG16 29 #define SCRATCH_GENERAL_REG17 30 #define SCRATCH_GENERAL_REG18 31 +#define PRESERV_GENERAL_REG1 5 +#define PRESERV_GENERAL_REG2 6 #define SP_REG 12 #define FIRST_PRES_FP_REG 16 #define LAST_PRES_FP_REG 31 #define FIRST_FP_ARG_REG 8 #define LAST_FP_ARG_REG 15 +// br2 is used for keeping function address to be called. +#define BRANCH_CALL_REG SCRATCH_BRANCH_REG2 #define IN_REG0 32 #define IN_REG1 33 -- 1.5.0.3