Index: trunk/vm/port/include/m2n.h =================================================================== --- trunk/vm/port/include/m2n.h (revision 554873) +++ trunk/vm/port/include/m2n.h (working copy) @@ -41,24 +41,20 @@ struct M2nFrame; -enum frame_type { - FRAME_UNKNOWN = 0x00, - FRAME_NON_UNWINDABLE = 0x80, - FRAME_JNI = 0x01 | FRAME_NON_UNWINDABLE, - FRAME_COMPILATION = 0x02 | FRAME_NON_UNWINDABLE, +typedef uint32 frame_type; - FRAME_UNPOPABLE = 0x0000, - FRAME_POPABLE = 0x0100, - FRAME_POP_NOW = 0x0200, - FRAME_POP_DONE = FRAME_POPABLE | FRAME_POP_NOW, +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; - FRAME_POP_MASK = 0x0700, - - FRAME_SAFE_POINT = 0x0800, - - FRAME_MODIFIED_STACK = 0x1000 -}; - // 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 // necessarily architecture specific and some facilities that are not needed Index: trunk/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp =================================================================== --- trunk/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp (revision 542523) +++ trunk/vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp (working copy) @@ -600,6 +600,10 @@ return 16 + stk_output_size; } + bool has_push_m2n() { + return has_m2n; + } + private: //***************** // helper functions, used by visitor functions @@ -1966,7 +1970,13 @@ // 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 @@ 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 Index: trunk/vm/port/src/lil/ipf/pim/m2n_ipf.cpp =================================================================== --- trunk/vm/port/src/lil/ipf/pim/m2n_ipf.cpp (revision 542523) +++ trunk/vm/port/src/lil/ipf/pim/m2n_ipf.cpp (working copy) @@ -74,6 +74,7 @@ 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 @@ //***** 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 @@ // 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 @@ 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 @@ } 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 Index: trunk/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h =================================================================== --- trunk/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h (revision 542523) +++ trunk/vm/port/src/lil/ipf/pim/m2n_ipf_internal.h (working copy) @@ -100,11 +100,14 @@ 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 @@ #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. Index: trunk/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp =================================================================== --- trunk/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp (revision 542523) +++ trunk/vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp (working copy) @@ -71,8 +71,8 @@ M2nFrame* m2nfl; uint64 ip; uint64* bsp; - uint64* last_legal_rsnat; - uint64 extra_nats; + uint64 extra_rnats; + uint64 extra_unats; }; ////////////////////////////////////////////////////////////////////////// @@ -82,28 +82,60 @@ // 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 @@ 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 @@ { 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; + + assert(sol<=96); - // Direct computation, see IPF arch manual, volume 3, table 6.2. - uint64 b = (uint64)bsp; - uint64 s = sol<<3; + 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 @@ ////////////////////////////////////////////////////////////////////////// // 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 @@ #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. Index: trunk/vm/port/src/lil/pim/m2n.cpp =================================================================== --- trunk/vm/port/src/lil/pim/m2n.cpp (revision 0) +++ trunk/vm/port/src/lil/pim/m2n.cpp (revision 0) @@ -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; Index: trunk/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp =================================================================== --- trunk/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp (revision 542523) +++ trunk/vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp (working copy) @@ -72,7 +72,7 @@ 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 Index: trunk/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp =================================================================== --- trunk/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp (revision 542523) +++ trunk/vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp (working copy) @@ -222,7 +222,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ 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 **)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 @@ 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 @@ 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 @@ { 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 @@ // 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); Index: trunk/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp =================================================================== --- trunk/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp (revision 542523) +++ trunk/vm/vmcore/src/util/ipf/base/stub_code_utils.cpp (working copy) @@ -75,10 +75,11 @@ 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 @@ 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_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 @@ 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 @@ 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 Index: trunk/vm/vmcore/src/util/ipf/include/Code_Emitter.h =================================================================== --- trunk/vm/vmcore/src/util/ipf/include/Code_Emitter.h (revision 542523) +++ trunk/vm/vmcore/src/util/ipf/include/Code_Emitter.h (working copy) @@ -331,6 +331,10 @@ { 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); Index: trunk/vm/vmcore/src/util/ipf/include/stub_code_utils.h =================================================================== --- trunk/vm/vmcore/src/util/ipf/include/stub_code_utils.h (revision 542523) +++ trunk/vm/vmcore/src/util/ipf/include/stub_code_utils.h (working copy) @@ -68,13 +68,14 @@ // 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); Index: trunk/vm/vmcore/src/util/ipf/include/vm_ipf.h =================================================================== --- trunk/vm/vmcore/src/util/ipf/include/vm_ipf.h (revision 542523) +++ trunk/vm/vmcore/src/util/ipf/include/vm_ipf.h (working copy) @@ -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