/* src/vm/jit/powerpc/md.c - machine dependent PowerPC functions
- 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
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+ Copyright (C) 2009 Theobroma Systems Ltd.
This file is part of CACAO.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Christian Thalinger
- Edwin Steiner
-
- $Id: md.c 5942 2006-11-09 10:52:34Z twisti $
-
*/
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include "vm/types.h"
#include "md-abi.h"
#include "vm/jit/powerpc/codegen.h"
+#include "vm/jit/powerpc/md.h"
#include "vm/global.h"
-#include "vm/jit/asmpart.h"
+#include "vm/vm.hpp"
-#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
-#include "vm/options.h" /* XXX debug */
-#include "vm/jit/disass.h" /* XXX debug */
-#endif
+#include "vm/jit/jit.hpp"
+#include "vm/jit/trap.hpp"
/* md_init *********************************************************************
}
-/* md_codegen_patch_branch *****************************************************
-
- Back-patches a branch instruction.
-
-*******************************************************************************/
-
-void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
-{
- s4 *mcodeptr;
- s4 mcode;
- s4 disp; /* branch displacement */
-
- /* calculate the patch position */
-
- mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
-
- /* get the instruction before the exception point */
-
- mcode = mcodeptr[-1];
-
- /* Calculate the branch displacement. */
-
- disp = targetmpc - branchmpc + 4;
-
- /* Check which branch instruction we have. Then mask it and patch
- the displacement. */
-
- if ((mcode & 0xfc000000) == 0x48000000) {
- /* bx (0x48000000) */
-
- if ((disp < (s4) 0xfe000000) || (disp > (s4) 0x01fffffc))
- vm_abort("md_codegen_patch_branch: branch displacement out of range: %d > +/-%d", disp, 0x03fffffc);
-
- mcode &= ~M_BMASK; /* mask out previous displacement, probably +4 */
- mcode |= (disp & M_BMASK);
- }
- else if ((mcode & 0xfc000000) == 0x40000000) {
- /* bcx (0x40000000) */
-
- if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff))
- vm_abort("md_codegen_patch_branch: branch displacement out of range: %d > +/-%d", disp, 0x00007fff);
-
- mcode &= ~M_BCMASK; /* mask out previous displacement, probably +4 */
- mcode |= (disp & M_BCMASK);
- }
- else
- vm_abort("md_codegen_patch_branch: unknown instruction 0x%08x", mcode);
-
- /* patch the branch instruction before the mcodeptr */
-
- mcodeptr[-1] = mcode;
-}
-
-
-/* md_stacktrace_get_returnaddress *********************************************
-
- Returns the return address of the current stackframe, specified by
- the passed stack pointer and the stack frame size.
-
-*******************************************************************************/
-
-u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
-{
- u1 *ra;
-
- /* on PowerPC the return address is located in the linkage area */
-
- ra = *((u1 **) (sp + framesize + LA_LR_OFFSET));
-
- return ra;
-}
-
-
-/* md_get_method_patch_address *************************************************
+/* md_jit_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
*******************************************************************************/
-u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
+void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
{
- u4 mcode;
- s4 offset;
- u1 *pa;
+ uint32_t *pc;
+ uint32_t mcode;
+ int32_t offset;
+ void *pa;
/* go back to the actual load instruction (3 instructions) */
- ra = ra - 3 * 4;
+ pc = ((uint32_t *) ra) - 3;
/* get first instruction word (lwz) */
- mcode = *((u4 *) ra);
+ mcode = *pc;
/* check if we have 2 instructions (addis, addi) */
if ((mcode >> 16) == 0x3c19) {
/* XXX write a regression for this */
+ pa = NULL;
assert(0);
/* get displacement of first instruction (addis) */
- offset = (s4) (mcode << 16);
+ offset = (int32_t) (mcode << 16);
/* get displacement of second instruction (addi) */
- mcode = *((u4 *) (ra + 1 * 4));
+ mcode = *(pc + 1);
assert((mcode >> 16) != 0x6739);
- offset += (s2) (mcode & 0x0000ffff);
-
- } else {
+ offset += (int16_t) (mcode & 0x0000ffff);
+ }
+ else {
/* get the offset from the instruction */
- offset = (s2) (mcode & 0x0000ffff);
+ offset = (int16_t) (mcode & 0x0000ffff);
/* check for load from PV */
if ((mcode >> 16) == 0x81ad) {
/* get the final data segment address */
- pa = sfi->pv + offset;
-
- } else if ((mcode >> 16) == 0x81ac) {
+ pa = ((uint8_t *) pv) + offset;
+ }
+ else if ((mcode >> 16) == 0x81ac) {
/* in this case we use the passed method pointer */
- pa = mptr + offset;
+ /* return NULL if no mptr was specified (used for replacement) */
- } else {
- /* catch any problems */
+ if (mptr == NULL)
+ return NULL;
- assert(0);
+ pa = ((uint8_t *) mptr) + offset;
}
- }
-
- return pa;
-}
-
-
-/* md_codegen_get_pv_from_pc ***************************************************
-
- Machine code:
-
- 7d6802a6 mflr r11
- 39abffe0 addi r13,r11,-32
-
- or
-
- 7d6802a6 mflr r11
- 3dabffff addis r13,r11,-1
- 39ad68b0 addi r13,r13,26800
-
-*******************************************************************************/
-
-u1 *md_codegen_get_pv_from_pc(u1 *ra)
-{
- u1 *pv;
- u4 mcode;
- s4 offset;
-
- /* get first instruction word after jump */
-
- mcode = *((u4 *) (ra + 1 * 4));
-
- /* check if we have 2 instructions (addis, addi) */
-
- if ((mcode >> 16) == 0x3dab) {
- /* get displacement of first instruction (addis) */
-
- offset = (s4) (mcode << 16);
-
- /* get displacement of second instruction (addi) */
-
- mcode = *((u4 *) (ra + 2 * 4));
-
- /* check for addi instruction */
-
- assert((mcode >> 16) == 0x39ad);
-
- offset += (s2) (mcode & 0x0000ffff);
-
- } else {
- /* check for addi instruction */
+ else {
+ /* catch any problems */
- assert((mcode >> 16) == 0x39ab);
+ vm_abort("md_jit_method_patch_address: unknown instruction %x",
+ mcode);
- /* get offset of first instruction (addi) */
+ /* keep compiler happy */
- offset = (s2) (mcode & 0x0000ffff);
+ pa = NULL;
+ }
}
- /* calculate PV via RA + offset */
-
- pv = ra + offset;
-
- return pv;
+ return pa;
}
-/* md_cacheflush ***************************************************************
-
- Calls the system's function to flush the instruction and data
- cache.
-
-*******************************************************************************/
-
-void md_cacheflush(u1 *addr, s4 nbytes)
+/**
+ * Decode the trap instruction at the given PC.
+ *
+ * @param trp information about trap to be filled
+ * @param sig signal number
+ * @param xpc exception PC
+ * @param es execution state of the machine
+ * @return true if trap was decoded successfully, false otherwise.
+ */
+bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es)
{
- asm_cacheflush(addr, nbytes);
-}
-
-
-/* md_icacheflush **************************************************************
-
- Calls the system's function to flush the instruction cache.
-
-*******************************************************************************/
+ // Get the exception-throwing instruction.
+ uint32_t mcode = *((uint32_t*) xpc);
+
+ switch (sig) {
+ case TRAP_SIGILL:
+ // Check for valid trap instruction.
+ if (patcher_is_valid_trap_instruction_at(xpc)) {
+ trp->type = TRAP_PATCHER;
+ trp->value = 0;
+ return true;
+ }
+ return false;
-void md_icacheflush(u1 *addr, s4 nbytes)
-{
- asm_cacheflush(addr, nbytes);
-}
+ case TRAP_SIGTRAP:
+ {
+ int s1 = M_OP3_GET_A(mcode);
+ // For now we only handle ArrayIndexOutOfBoundsException.
+ trp->type = TRAP_ArrayIndexOutOfBoundsException;
+ trp->value = es->intregs[s1];
+ return true;
+ }
-/* md_dcacheflush **************************************************************
+ case TRAP_SIGSEGV:
+ {
+ int s1 = M_INSTR_OP2_IMM_A(mcode);
+ uintptr_t addr = es->intregs[s1];
+
+ // Check for special-load.
+ if (s1 == REG_ZERO) {
+ int16_t disp = M_INSTR_OP2_IMM_I(mcode);
+ int d = M_INSTR_OP2_IMM_D(mcode);
+
+ // We use the exception type as load displacement.
+ trp->type = disp;
+ trp->value = es->intregs[d];
+ return true;
+ }
- Calls the system's function to flush the data cache.
+ // Check for implicit NullPointerException.
+ if (addr == 0) {
+ trp->type = TRAP_NullPointerException;
+ trp->value = 0;
+ return true;
+ }
-*******************************************************************************/
+ return false;
+ }
-void md_dcacheflush(u1 *addr, s4 nbytes)
-{
- asm_cacheflush(addr, nbytes);
+ default:
+ return false;
+ }
}
*******************************************************************************/
-void md_patch_replacement_point(rplpoint *rp)
+#if defined(ENABLE_REPLACEMENT)
+void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
{
- u8 mcode;
+ u4 mcode;
- /* save the current machine code */
- mcode = *(u4*)rp->pc;
+ if (revert) {
+ /* restore the patched-over instruction */
+ *(u4*)(pc) = *(u4*)(savedmcode);
+ }
+ else {
+ /* save the current machine code */
+ *(u4*)(savedmcode) = *(u4*)(pc);
- /* write the new machine code */
- *(u4*)(rp->pc) = (u4) rp->mcode;
+ /* build the machine code for the patch */
+ assert(0); /* XXX build trap instruction below */
+ mcode = 0;
- /* store saved mcode */
- rp->mcode = mcode;
-
-#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
- {
- u1* u1ptr = rp->pc;
- DISASSINSTR(u1ptr);
- fflush(stdout);
+ /* write the new machine code */
+ *(u4*)(pc) = (u4) mcode;
}
-#endif
-
+
/* flush instruction cache */
- md_icacheflush(rp->pc,4);
+ md_icacheflush(pc,4);
}
+#endif /* defined(ENABLE_REPLACEMENT) */
+
/*
* These are local overrides for various environment variables in Emacs.