X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fmips%2Fmd.c;h=e9eed202b16e4c7dce53574fd7f61013ba7f46ef;hb=06a2b8142759d0c45fc2cc8de4a9e66e0e3790e5;hp=ccfb4b11fee7586d4a01a025a78e83d42e655c09;hpb=761757ae910976060d4920c4315f2e26baadbd1d;p=cacao.git diff --git a/src/vm/jit/mips/md.c b/src/vm/jit/mips/md.c index ccfb4b11f..e9eed202b 100644 --- a/src/vm/jit/mips/md.c +++ b/src/vm/jit/mips/md.c @@ -25,10 +25,9 @@ Contact: cacao@cacaojvm.org Authors: Christian Thalinger + Edwin Steiner - Changes: - - $Id: md.c 4498 2006-02-12 23:43:09Z twisti $ + $Id: md.c 6180 2006-12-11 23:29:26Z twisti $ */ @@ -36,24 +35,77 @@ #include "config.h" #include -#include #include +#include #include "vm/types.h" #include "toolbox/logging.h" +#include "vm/exceptions.h" #include "vm/global.h" +#include "vm/vm.h" #include "vm/jit/stacktrace.h" +#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) +#include "vm/options.h" /* XXX debug */ +#include "vm/jit/disass.h" /* XXX debug */ +#endif + -void docacheflush(u1 *p, long bytelen) +/* md_codegen_patch_branch ***************************************************** + + Back-patches a branch instruction. + +*******************************************************************************/ + +void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc) { - u1 *e = p + bytelen; - long psize = sysconf(_SC_PAGESIZE); - p -= (long) p & (psize - 1); - e += psize - ((((long) e - 1) & (psize - 1)) + 1); - bytelen = e-p; - mprotect(p, bytelen, PROT_READ | PROT_WRITE | PROT_EXEC); + s4 *mcodeptr; + s4 mcode; + s4 disp; /* branch displacement */ + s4 lo; + s4 hi; + + /* calculate the patch position */ + + mcodeptr = (s4 *) (cd->mcodebase + branchmpc); + + /* get the instruction before the exception point */ + + mcode = mcodeptr[-1]; + + /* check for: ori t9,t9,0 */ + + if ((mcode >> 16) == 0x3739) { + /* Calculate the branch displacement. For jumps we need a + displacement relative to PV. */ + + disp = targetmpc; + + lo = (short) disp; + hi = (short) ((disp - lo) >> 16); + + /* patch the two instructions before the mcodeptr */ + + mcodeptr[-2] |= (hi & 0x0000ffff); + mcodeptr[-1] |= (lo & 0x0000ffff); + } + else { + /* Calculate the branch displacement. For branches we need a + displacement relative and shifted to the branch PC. */ + + disp = (targetmpc - branchmpc) >> 2; + + /* On the MIPS we can only branch signed 16-bit instruction words + (signed 18-bit = 32KB = +/- 16KB). Check this! */ + + if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) + vm_abort("jump displacement is out of range: %d > +/-%d", disp, 0x00007fff); + + /* patch the branch instruction before the mcodeptr */ + + mcodeptr[-1] |= (disp & 0x0000ffff); + } } @@ -78,15 +130,36 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) } -/* md_assembler_get_patch_address ********************************************** +/* md_get_method_patch_address ************************************************* Gets the patch address of the currently compiled method. The offset is extracted from the load instruction(s) before the jump and added to the right base address (PV or REG_METHODPTR). + INVOKESTATIC/SPECIAL: + + dfdeffb8 ld s8,-72(s8) + 03c0f809 jalr s8 + 00000000 nop + + INVOKEVIRTUAL: + + dc990000 ld t9,0(a0) + df3e0000 ld s8,0(t9) + 03c0f809 jalr s8 + 00000000 nop + + INVOKEINTERFACE: + + dc990000 ld t9,0(a0) + df39ff90 ld t9,-112(t9) + df3e0018 ld s8,24(t9) + 03c0f809 jalr s8 + 00000000 nop + *******************************************************************************/ -u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) +u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) { u4 mcode; s4 offset; @@ -117,8 +190,8 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) assert((mcode >> 16) != 0x6739); offset += (s2) (mcode & 0x0000ffff); - - } else { + } + else { /* get first instruction (ld) */ mcode = *((u4 *) ra); @@ -136,9 +209,14 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) #endif /* in this case we use the passed method pointer */ - pa = mptr + offset; + /* return NULL if no mptr was specified (used for replacement) */ - } else { + if (mptr == NULL) + return NULL; + + pa = mptr + offset; + } + else { /* in the normal case we check for a `ld s8,x(s8)' instruction */ #if SIZEOF_VOID_P == 8 @@ -157,7 +235,7 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) } -/* md_codegen_findmethod ******************************************************* +/* md_codegen_get_pv_from_pc *************************************************** Machine code: @@ -167,7 +245,7 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) *******************************************************************************/ -u1 *md_codegen_findmethod(u1 *ra) +u1 *md_codegen_get_pv_from_pc(u1 *ra) { u1 *pv; u4 mcode; @@ -192,13 +270,13 @@ u1 *md_codegen_findmethod(u1 *ra) #if SIZEOF_VOID_P == 8 assert((mcode >> 16) == 0x6739); -#else +#else assert((mcode >> 16) == 0x2739); #endif offset += (s2) (mcode & 0x0000ffff); - - } else { + } + else { /* get offset of first instruction (daddiu) */ mcode = *((u4 *) ra); @@ -220,6 +298,100 @@ u1 *md_codegen_findmethod(u1 *ra) } +/* md_cacheflush *************************************************************** + + Calls the system's function to flush the instruction and data + cache. + +*******************************************************************************/ + +void md_cacheflush(u1 *addr, s4 nbytes) +{ + cacheflush(addr, nbytes, BCACHE); +} + + +/* md_icacheflush ************************************************************** + + Calls the system's function to flush the instruction cache. + +*******************************************************************************/ + +void md_icacheflush(u1 *addr, s4 nbytes) +{ + cacheflush(addr, nbytes, ICACHE); +} + + +/* md_dcacheflush ************************************************************** + + Calls the system's function to flush the data cache. + +*******************************************************************************/ + +void md_dcacheflush(u1 *addr, s4 nbytes) +{ + cacheflush(addr, nbytes, DCACHE); +} + + +/* md_patch_replacement_point ************************************************** + + Patch the given replacement point. + +*******************************************************************************/ + +void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, + u1 *savedmcode) +{ + s4 disp; + union { + u8 both; + u4 words[2]; + } mcode; + + if (index < 0) { + /* restore the patched-over instruction */ + *(u8*)(rp->pc) = *(u8*)(savedmcode); + } + else { + /* save the current machine code */ + *(u8*)(savedmcode) = *(u8*)(rp->pc); + + /* make machine code for patching */ + + disp = ((u4*)code->replacementstubs - (u4*)rp->pc) + + index * REPLACEMENT_STUB_SIZE + - 1; + + if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) { + *exceptionptr = + new_internalerror("Jump offset is out of range: %d > +/-%d", + disp, 0x00007fff); + return; + } + + /* BR */ + mcode.words[0] = (((0x04) << 26) | ((0) << 21) | ((0) << 16) | ((disp) & 0xffff)); + mcode.words[1] = 0; /* NOP in delay slot */ + + /* write the new machine code */ + *(u8*)(rp->pc) = mcode.both; + } + +#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) + { + u1* u1ptr = rp->pc; + DISASSINSTR(u1ptr); + DISASSINSTR(u1ptr); + fflush(stdout); + } +#endif + + /* flush instruction cache */ + md_icacheflush(rp->pc,2*4); +} + /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where @@ -231,4 +403,5 @@ u1 *md_codegen_findmethod(u1 *ra) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */