X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fmips%2Fmd.c;h=e9eed202b16e4c7dce53574fd7f61013ba7f46ef;hb=06a2b8142759d0c45fc2cc8de4a9e66e0e3790e5;hp=e82a8ad2e6473ab6f14a07f3e8947db43048b4a9;hpb=e81b0a2c87f33d463e92e310ab24514f54213ccd;p=cacao.git diff --git a/src/vm/jit/mips/md.c b/src/vm/jit/mips/md.c index e82a8ad2e..e9eed202b 100644 --- a/src/vm/jit/mips/md.c +++ b/src/vm/jit/mips/md.c @@ -1,9 +1,9 @@ /* src/vm/jit/mips/md.c - machine dependent MIPS functions - Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -19,40 +19,93 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - Contact: cacao@complang.tuwien.ac.at + Contact: cacao@cacaojvm.org Authors: Christian Thalinger + Edwin Steiner - Changes: - - $Id: md.c 3557 2005-11-03 22:42:00Z twisti $ + $Id: md.c 6180 2006-12-11 23:29:26Z twisti $ */ +#include "config.h" + #include -#include #include +#include -#include "config.h" #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 + + +/* md_codegen_patch_branch ***************************************************** -void docacheflush(u1 *p, long bytelen) + 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); + } } @@ -63,29 +116,50 @@ void docacheflush(u1 *p, long bytelen) *******************************************************************************/ -functionptr md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) +u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) { - functionptr ra; + u1 *ra; /* on MIPS the return address is located on the top of the stackframe */ /* XXX change this if we ever want to use 4-byte stackslots */ - /* ra = (functionptr) *((u1 **) (sp + framesize - SIZEOF_VOID_P)); */ - ra = (functionptr) (ptrint) *((u1 **) (sp + framesize - 8)); + /* ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P)); */ + ra = *((u1 **) (sp + framesize - 8)); return ra; } -/* 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; @@ -113,14 +187,11 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) mcode = *((u4 *) (ra + 1 * 4)); - if ((mcode >> 16) != 0x6739) { - log_text("No `daddiu' instruction found on return address!"); - assert(0); - } + assert((mcode >> 16) != 0x6739); offset += (s2) (mcode & 0x0000ffff); - - } else { + } + else { /* get first instruction (ld) */ mcode = *((u4 *) ra); @@ -138,19 +209,21 @@ 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) */ + + if (mptr == NULL) + return NULL; - } else { + pa = mptr + offset; + } + else { /* in the normal case we check for a `ld s8,x(s8)' instruction */ #if SIZEOF_VOID_P == 8 - if ((mcode >> 16) != 0xdfde) { + assert((mcode >> 16) == 0xdfde); #else - if ((mcode >> 16) != 0x8fde) { + assert((mcode >> 16) == 0x8fde); #endif - log_text("No `ld s8,x(s8)' instruction found!"); - assert(0); - } /* and get the final data segment address */ @@ -162,7 +235,7 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) } -/* codegen_findmethod ********************************************************** +/* md_codegen_get_pv_from_pc *************************************************** Machine code: @@ -172,18 +245,14 @@ u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) *******************************************************************************/ -functionptr codegen_findmethod(functionptr pc) +u1 *md_codegen_get_pv_from_pc(u1 *ra) { - u1 *ra; u1 *pv; u4 mcode; s4 offset; - ra = (u1 *) (ptrint) pc; - /* get the offset of the instructions */ - /* get first instruction word after jump */ mcode = *((u4 *) ra); @@ -200,29 +269,23 @@ functionptr codegen_findmethod(functionptr pc) mcode = *((u4 *) (ra + 1 * 4)); #if SIZEOF_VOID_P == 8 - if ((mcode >> 16) != 0x6739) { -#else - if ((mcode >> 16) != 0x2739) { + assert((mcode >> 16) == 0x6739); +#else + assert((mcode >> 16) == 0x2739); #endif - log_text("No `daddiu' instruction found on return address!"); - assert(0); - } offset += (s2) (mcode & 0x0000ffff); - - } else { + } + else { /* get offset of first instruction (daddiu) */ mcode = *((u4 *) ra); #if SIZEOF_VOID_P == 8 - if ((mcode >> 16) != 0x67fe) { + assert((mcode >> 16) == 0x67fe); #else - if ((mcode >> 16) != 0x27fe) { + assert((mcode >> 16) == 0x27fe); #endif - log_text("No `daddiu s8,ra,x' instruction found on return address!"); - assert(0); - } offset = (s2) (mcode & 0x0000ffff); } @@ -231,10 +294,104 @@ functionptr codegen_findmethod(functionptr pc) pv = ra + offset; - return (functionptr) (ptrint) pv; + return pv; } +/* 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 @@ -246,4 +403,5 @@ functionptr codegen_findmethod(functionptr pc) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */