+/* src/vm/jit/sparc64/md.c - machine dependent SPARC 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
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
-#include <assert.h>
#include "config.h"
+#include <assert.h>
+
+
#include "vm/types.h"
#include "vm/jit/sparc64/md-abi.h"
#include "vm/jit/asmpart.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
+/* assembler function prototypes **********************************************/
+void asm_store_fp_state_reg(u8 *mem);
+void asm_load_fp_state_reg(u8 *mem);
+
+
/* shift away 13-bit immediate, mask rd and rs1 */
#define SHIFT_AND_MASK(instr) \
((instr >> 13) & 0x60fc1)
+/* NOP is defined as a SETHI instruction with rd and imm. set to zero */
+/* therefore we check if the 22-bit immediate is zero */
#define IS_SETHI(instr) \
- ((instr & 0xc1c00000) == 0x00800000)
+ (((instr & 0xc1c00000) == 0x01000000) \
+ && ((instr & 0x3fffff) != 0x0))
+
+#define IS_LDX_IMM(instr) \
+ (((instr >> 13) & 0x60fc1) == 0x602c1)
+
+#define IS_SUB(instr) \
+ (((instr >> 13) & 0x60fc0) == 0x40100)
inline s2 decode_13bit_imm(u4 instr) {
s2 imm;
}
-/* 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];
-
- /* check for BPcc or FBPfcc instruction */
- if (((mcode >> 16) & 0xc1c0) == 0x0040) {
-
-
- /* Calculate the branch displacement. For branches we need a
- displacement relative and shifted to the branch PC. */
-
- disp = (targetmpc - branchmpc) >> 2;
-
- /* check branch displacement (19-bit)*/
-
- if ((disp < (s4) 0xfffc0000) || (disp > (s4) 0x003ffff))
- vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x003ffff);
-
- /* patch the branch instruction before the mcodeptr */
-
- mcodeptr[-1] |= (disp & 0x003ffff);
- }
- /* check for BPr instruction */
- else if (((mcode >> 16) & 0xd1c0) == 0x00c0) {
-
- /* check branch displacement (16-bit)*/
-
- disp = (targetmpc - branchmpc) >> 2;
-
- if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x0007fff))
- vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x0007fff);
-
- /* patch the upper 2-bit of the branch displacement */
- mcodeptr[-1] |= ((disp & 0xc000) << 6);
-
- /* patch the lower 14-bit of the branch displacement */
- mcodeptr[-1] |= (disp & 0x003fff);
-
- }
- else
- assert(0);
-}
-
-
/* md_stacktrace_get_returnaddress *********************************************
Returns the return address of the current stackframe, specified by
*/
ra = *((u1 **) (sp + 120 + BIAS));
- /* ra is the address of the call instr, advance to the real return address */
- ra += 8;
+ /* NOTE: on SPARC ra is the address of the call instruction */
return ra;
}
+u1 *md_get_framepointer(u1 *sp)
+{
+ u1 *fp;
+ /* flush register windows to the stack */
+ __asm__ ("flushw");
+
+ fp = *((u1 **) (sp + 112 + BIAS));
+
+ return fp;
+}
+
+u1 *md_get_pv_from_stackframe(u1 *sp)
+{
+ u1 *pv;
+ /* flush register windows to the stack */
+ __asm__ ("flushw");
+
+ pv = *((u1 **) (sp + 104 + BIAS));
+
+ return pv;
+}
/* md_codegen_get_pv_from_pc ***************************************************
{
u1 *pv;
u8 mcode;
- u4 mcode_masked;
- s2 offset;
+ s4 offset;
pv = ra;
/* get the instruction word after jump and nop */
mcode = *((u4 *) (ra+8) );
- /* check if we have 2 instructions (ldah, lda) */
-
- mcode_masked = SHIFT_AND_MASK(mcode);
-
- if (mcode_masked == 0x40001) {
-#if 0
- /* get displacement of first instruction (ldah) */
-
- offset = (s4) (mcode << 16);
- pv += offset;
-
- /* get displacement of second instruction (lda) */
-
- mcode = *((u4 *) (ra + 1 * 4));
-
- assert((mcode >> 16) == 0x237b);
-
- offset = (s2) (mcode & 0x0000ffff);
- pv += offset;
+ /* check if we have a sethi insruction */
+ if (IS_SETHI(mcode)) {
+ s4 xor_imm;
+
+ /* get 22-bit immediate of sethi instruction */
+ offset = (s4) (mcode & 0x3fffff);
+ offset = offset << 10;
+
+ /* now the xor */
+ mcode = *((u4 *) (ra+12) );
+ xor_imm = decode_13bit_imm(mcode);
+
+ offset ^= xor_imm;
+ }
+ else {
+ u4 mcode_masked;
+
+ mcode_masked = SHIFT_AND_MASK(mcode);
- } else {
- /* get displacement of first instruction (lda) */
+ assert(mcode_masked == 0x40001);
- assert((mcode >> 16) == 0x237a);
-#endif
/* mask and extend the negative sign for the 13 bit immediate */
offset = decode_13bit_imm(mcode);
-
- pv += offset;
- }
- else
- {
- assert(0);
}
+
+ pv += offset;
return pv;
}
INVOKESTATIC/SPECIAL:
- dfdeffb8 ldx [i5 - 72],o5
- 03c0f809 jmp o5
- 00000000 nop
+ ???????? ldx [i5 - 72],o5
+ ???????? jmp o5 <-- ra
+ ???????? nop
+
+ w/ sethi (mptr in dseg out of 13-bit simm range)
+
+ ???????? sethi hi(0x2000),o5
+ ???????? sub i5,o5,o5
+ ???????? ldx [o5 - 72],o5
+ ???????? jmp o5 <-- ra
+ ???????? nop
INVOKEVIRTUAL:
- dc990000 ld t9,0(a0)
- df3e0000 ld [g2 + 0],o5
- 03c0f809 jmp o5
- 00000000 nop
+ ???????? ldx [o0 + 0},g2
+ ???????? ldx [g2 + 0],o5
+ ???????? jmp o5 <-- ra
+ ???????? nop
INVOKEINTERFACE:
- dc990000 ld t9,0(a0)
- df39ff90 ld [g2 - 112],g2
- df3e0018 ld [g2 + 24],o5
- 03c0f809 jmp o5
- 00000000 nop
+ ???????? ldx [o0 + 0},g2
+ ???????? ldx [g2 - 112],g2
+ ???????? ldx [g2 + 24],o5
+ ???????? jmp o5 <-- ra
+ ???????? nop
*******************************************************************************/
u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
{
- u4 mcode, mcode_masked;
+ u4 mcode, mcode_sethi, mcode_masked;
s4 offset;
- u1 *pa;
+ u1 *pa, *iptr;
- /* go back to the actual load instruction (1 instruction before jump) */
- /* ra is the address of the jump instruction on SPARC */
- ra -= 1 * 4;
+ /* go back to the location of a possible sethi (3 instruction before jump) */
+ /* note: ra is the address of the jump instruction on SPARC */
- /* get first instruction word on current PC */
+ mcode_sethi = *((u4 *) (ra - 3 * 4));
- mcode = *((u4 *) ra);
+ /* check for sethi instruction */
+ if (IS_SETHI(mcode_sethi)) {
+ u4 mcode_sub, mcode_ldx;
- /* check if we have 2 instructions (lui) */
+ mcode_sub = *((u4 *) (ra - 2 * 4));
+ mcode_ldx = *((u4 *) (ra - 1 * 4));
- if (IS_SETHI(mcode)) {
- /* XXX write a regression for this */
- assert(0);
+ /* make sure the sequence of instructions is a loadhi */
+ if ((IS_SUB(mcode_sub)) && (IS_LDX_IMM(mcode_ldx)))
+ {
- /* get displacement of first instruction (lui) */
- offset = (s4) (mcode << 16);
+ /* get 22-bit immediate of sethi instruction */
- /* get displacement of second instruction (daddiu) */
+ offset = (s4) (mcode_sethi & 0x3fffff);
+ offset = offset << 10;
+
+ /* goto next instruction */
+
+ /* make sure it's a sub instruction (pv - big_disp) */
+ assert(IS_SUB(mcode_sub));
+ offset = -offset;
- mcode = *((u4 *) (ra + 1 * 4));
+ /* get displacement of load instruction */
- assert((mcode >> 16) != 0x6739);
+ assert(IS_LDX_IMM(mcode_ldx));
- offset += (s2) (mcode & 0x0000ffff);
+ offset += decode_13bit_imm(mcode_ldx);
+
+ pa = sfi->pv + offset;
- } else {
+ return pa;
+ }
+ }
- /* shift and maks rd */
+ /* we didn't find a sethi, or it didn't belong to a loadhi */
+ /* check for simple (one-instruction) load */
+ iptr = ra - 1 * 4;
+ mcode = *((u4 *) iptr);
- mcode_masked = (mcode >> 13) & 0x060fff;
-
- /* get the offset from the instruction */
+ /* shift and mask rd */
- offset = decode_13bit_imm(mcode);
+ mcode_masked = (mcode >> 13) & 0x060fff;
+
+ /* get the offset from the instruction */
- /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
+ offset = decode_13bit_imm(mcode);
- if (mcode_masked == 0x0602c5) {
- /* in this case we use the passed method pointer */
+ /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
- pa = mptr + offset;
+ if (mcode_masked == 0x0602c5) {
+ /* in this case we use the passed method pointer */
- } else {
- /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
+ /* return NULL if no mptr was specified (used for replacement) */
- assert(mcode_masked == 0x0602fb);
+ if (mptr == NULL)
+ return NULL;
- printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
+ pa = mptr + offset;
- /* and get the final data segment address */
+ } else {
+ /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
- pa = sfi->pv + offset;
- }
+ assert(mcode_masked == 0x0602fb);
+
+ /* and get the final data segment address */
+
+ pa = sfi->pv + offset;
}
+
return pa;
}
}
-/* md_icacheflush **************************************************************
-
- Calls the system's function to flush the instruction cache.
-
-*******************************************************************************/
-
-void md_icacheflush(u1 *addr, s4 nbytes)
-{
- /* XXX don't know yet */
-}
-
/* md_dcacheflush **************************************************************
Calls the system's function to flush the data cache.
void md_dcacheflush(u1 *addr, s4 nbytes)
{
/* XXX don't know yet */
+ /* printf("md_dcacheflush\n"); */
+ __asm__ __volatile__ ( "membar 0x7F" : : : "memory" );
}
*******************************************************************************/
-void md_patch_replacement_point(rplpoint *rp)
+#if defined(ENABLE_REPLACEMENT)
+void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
{
- u8 mcode;
+ u4 mcode;
- /* save the current machine code */
- mcode = *(u4*)rp->pc;
+ if (index < 0) {
+ /* restore the patched-over instruction */
+ *(u4*)(rp->pc) = *(u4*)(savedmcode);
+ }
+ else {
+ /* save the current machine code */
+ *(u4*)(savedmcode) = *(u4*)(rp->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;
+ /* write the new machine code */
+ *(u4*)(rp->pc) = (u4) mcode;
+ }
#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
{
/* flush instruction cache */
/* md_icacheflush(rp->pc,4); */
}
+#endif /* defined(ENABLE_REPLACEMENT) */
/*
* These are local overrides for various environment variables in Emacs.