--- /dev/null
+/* src/vm/jit/m68k/linux/md-abi.h - defines for m68k Linux ABI
+
+ 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.
+
+ Contact: cacao@cacaojvm.org
+
+ Authors: Roland Lezuo
+
+ Changes:
+
+ $Id: md-abi.h 5940 2006-11-09 09:59:28Z tbfg $
+
+*/
+
+
+#ifndef _MD_ABI_H
+#define _MD_ABI_H
+
+/* preallocated registers *****************************************************/
+
+/* integer registers */
+
+#define REG_RESULT 0 /* to deliver method results */
+#define REG_RESULT2 1 /* to deliver long method results */
+
+#define REG_D0 0 /* register may be trashed by callee */
+#define REG_D1 1
+
+
+
+#define REG_ITMP1 2 /* temporary register */
+#define REG_ITMP2 3 /* temporary register and method pointer */
+#define REG_ITMP3 4 /* temporary register */
+
+
+
+/* floating point registers */
+
+#define REG_F0 0 /* registers may be trashed by callee */
+#define REG_F1 1
+
+#define REG_FRESULT 0 /* to deliver floating point method results */
+#define REG_FTMP1 2 /* temporary floating point register */
+#define REG_FTMP2 3 /* temporary floating point register */
+#define REG_FTMP3 4 /* temporary floating point register */
+
+#define REG_IFTMP 2 /* temporary integer and floating point register */
+
+
+/* address registers */
+
+#define REG_A0 0 /* registers may be trashed by callee */
+#define REG_A1 1
+
+#define REG_ATMP1 2
+#define REG_ATMP2 3
+#define REG_METHODPTR REG_ATMP2 /* pointer to the place from where the procedure */
+#define REG_ATMP3 4
+
+#define REG_ATMP1_XPTR REG_ATMP1 /* exception pointer = temporary register 1 */
+#define REG_ATMP2_XPC REG_ATMP2 /* exception pc = temporary register 2 */
+
+#define REG_FP 6 /* frame pointer */
+#define REG_SP 7 /* stack pointer */
+
+/* number for the register allocator */
+
+#define INT_REG_CNT 8 /* number of integer registers */
+#define INT_SAV_CNT 3 /* number of int callee saved registers */
+#define INT_ARG_CNT 0 /* number of int argument registers */
+#define INT_TMP_CNT 2 /* number of integer temporary registers */
+#define INT_RES_CNT 3 /* number of integer reserved registers */
+
+#if !defined(ENABLE_SOFTFLOAT)
+ #define FLT_REG_CNT 8 /* number of float registers */
+ #define FLT_SAV_CNT 3 /* number of float callee saved registers */
+ #define FLT_ARG_CNT 0 /* number of float argument registers */
+ #define FLT_TMP_CNT 2 /* number of float temporary registers */
+ #define FLT_RES_CNT 3 /* number of float reserved registers */
+#else
+ #define FLT_REG_CNT 8 /* number of float registers */
+ #define FLT_SAV_CNT 0 /* number of float callee saved registers */
+ #define FLT_ARG_CNT 0 /* number of float argument registers */
+ #define FLT_TMP_CNT 0 /* number of float temporary registers */
+ #define FLT_RES_CNT 8 /* number of float reserved registers */
+#endif
+
+#define ADR_REG_CNT 8
+#define ADR_SAV_CNT 2
+#define ADR_ARG_CNT 0
+#define ADR_TMP_CNT 2
+#define ADR_RES_CNT 4
+
+
+/* packed register defines ***************************************************/
+
+#define REG_RESULT_PACKED PACK_REGS(REG_RESULT2, REG_RESULT)
+#define REG_ITMP12_PACKED PACK_REGS(REG_ITMP1, REG_ITMP2)
+#define REG_ITMP23_PACKED PACK_REGS(REG_ITMP2, REG_ITMP3)
+
+/* ABI defines ****************************************************************/
+
+/* TODO */
+
+#define LA_SIZE_IN_POINTERS 0
+#if 0
+#define LA_SIZE 48 /* linkage area size */
+#define LA_SIZE_ALIGNED 16 /* linkage area size aligned to 16-byte */
+#define LA_SIZE_IN_POINTERS (LA_SIZE / SIZEOF_VOID_P)
+#define LA_LR_OFFSET 16 /* link register offset in linkage area */
+#define PA_SIZE (PA_SIZE_IN_POINTERS*8)
+#define PA_SIZE_IN_POINTERS 8 /* linux/ppc64 has a minimun parameter save area size, XXX:darwin? */
+#endif
+/* #define ALIGN_FRAME_SIZE(sp) (sp) */
+
+#endif /* _MD_ABI_H */
+
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
/* handle replacement points */
-#if 0
- if (bptr->bitflags & BBFLAG_REPLACEMENT) {
- replacementpoint->pc = (u1*)(ptrint)bptr->mpc; /* will be resolved later */
-
- replacementpoint++;
- }
-#endif
+ REPLACEMENT_POINT_BLOCK_START(cd, bptr);
+
/* copy interface registers to their destination */
case ICMD_IRETURN: /* ..., retvalue ==> ... */
case ICMD_LRETURN:
+ REPLACEMENT_POINT_RETURN(cd, iptr);
+
s1 = emit_load_s1(jd, iptr, REG_RESULT_CALLEE);
M_INTMOVE(s1, REG_RESULT_CALLEE);
goto nowperformreturn;
case ICMD_ARETURN: /* ..., retvalue ==> ... */
+ REPLACEMENT_POINT_RETURN(cd, iptr);
+
s1 = emit_load_s1(jd, iptr, REG_RESULT_CALLEE);
M_INTMOVE(s1, REG_RESULT_CALLEE);
case ICMD_FRETURN: /* ..., retvalue ==> ... */
case ICMD_DRETURN:
+ REPLACEMENT_POINT_RETURN(cd, iptr);
+
s1 = emit_load_s1(jd, iptr, REG_FRESULT);
M_DBLMOVE(s1, REG_FRESULT);
goto nowperformreturn;
case ICMD_RETURN: /* ... ==> ... */
+
+ REPLACEMENT_POINT_RETURN(cd, iptr);
nowperformreturn:
{
case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */
+ REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr);
+
bte = iptr->sx.s23.s3.bte;
md = bte->md;
/* XXX: builtin calling with stack arguments not implemented */
- assert(md->paramcount <= 5 && md->argfltreguse <= 16);
+ assert(md->paramcount <= 4 && md->argfltreguse <= 16);
s3 = md->paramcount;
goto gen_method;
case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
-
case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */
case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */
case ICMD_INVOKEINTERFACE:
+ REPLACEMENT_POINT_INVOKE(cd, iptr);
+
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
lm = NULL;
um = iptr->sx.s23.s3.um;
switch (iptr->opc) {
case ICMD_BUILTIN:
- disp = dseg_add_functionptr(cd, bte->fp);
+ if (bte->stub == NULL) {
+ disp = dseg_add_functionptr(cd, bte->fp);
+ }
+ else {
+ disp = dseg_add_functionptr(cd, bte->stub);
+ }
M_ALD(REG_PV_CALLER, REG_PV, disp); /* built-in-function pointer */
M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO);
M_NOP;
+ REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
+ REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr);
disp = (s4) (cd->mcodeptr - cd->mcodebase);
/* REG_RA holds the value of the jmp instruction, therefore +8 */
M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8);
M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO);
M_NOP;
+ REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
disp = (s4) (cd->mcodeptr - cd->mcodebase);
/* REG_RA holds the value of the jmp instruction, therefore +8 */
M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8);
M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO);
M_NOP;
+ REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
disp = (s4) (cd->mcodeptr - cd->mcodebase);
/* REG_RA holds the value of the jmp instruction, therefore +8 */
M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8);
M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO);
M_NOP;
+ REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
disp = (s4) (cd->mcodeptr - cd->mcodebase);
/* REG_RA holds the value of the jmp instruction, therefore +8 */
M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8);
}
+/* codegen_emit_stub_builtin ***************************************************
+
+ Creates a stub routine which calls a builtin function.
+
+*******************************************************************************/
+
+void codegen_emit_stub_builtin(jitdata *jd, builtintable_entry *bte)
+{
+ codeinfo *code;
+ codegendata *cd;
+ methoddesc *md;
+ s4 i;
+ s4 disp;
+ s4 s1, s2;
+
+ /* get required compiler data */
+ code = jd->code;
+ cd = jd->cd;
+
+ /* set some variables */
+ md = bte->md;
+
+ /* calculate stack frame size */
+ cd->stackframesize =
+ WINSAVE_CNT +
+ ABIPARAMS_CNT +
+ FLT_ARG_CNT +
+ sizeof(stackframeinfo) / SIZEOF_VOID_P +
+ 4; /* 4 arguments or return value */
+
+
+ /* keep stack 16-byte aligned (ABI requirement) */
+
+ if (cd->stackframesize & 1)
+ cd->stackframesize++;
+
+ /* create method header */
+ (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
+ (void) dseg_add_unique_s4(cd, cd->stackframesize * 4); /* FrameSize */
+ (void) dseg_add_unique_s4(cd, 0); /* IsSync */
+ (void) dseg_add_unique_s4(cd, 0); /* IsLeaf */
+ (void) dseg_add_unique_s4(cd, 0); /* IntSave */
+ (void) dseg_add_unique_s4(cd, 0); /* FltSave */
+ (void) dseg_addlinenumbertablesize(cd);
+ (void) dseg_add_unique_s4(cd, 0); /* ExTableSize */
+
+
+ /* generate stub code */
+ M_SAVE(REG_SP, -cd->stackframesize * 8, REG_SP); /* build up stackframe */
+
+#if defined(ENABLE_GC_CACAO)
+ /* Save callee saved integer registers in stackframeinfo (GC may
+ need to recover them during a collection). */
+
+ disp = cd->stackframesize * 8 - sizeof(stackframeinfo) +
+ OFFSET(stackframeinfo, intregs) + BIAS;
+
+ for (i = 0; i < INT_SAV_CNT; i++)
+ M_AST(abi_registers_integer_saved[i], REG_SP, disp + i * 8);
+#endif
+
+ for (i = 0; i < md->paramcount; i++) {
+ s1 = md->params[i].regoff;
+
+ switch (md->paramtypes[i].type) {
+ case TYPE_INT:
+ case TYPE_LNG:
+ case TYPE_ADR:
+ break;
+ case TYPE_FLT:
+ case TYPE_DBL:
+ M_DST(s1, REG_SP, JITSTACK + i * 8);
+ break;
+ }
+ }
+
+ /* create dynamic stack info */
+
+ M_AADD_IMM(REG_SP, BIAS + cd->stackframesize * 8, REG_OUT0); /* data sp*/
+ M_MOV(REG_PV_CALLEE, REG_OUT1); /* PV */
+ M_MOV(REG_FP, REG_OUT2); /* java sp */
+ M_MOV(REG_RA_CALLEE, REG_OUT3); /* ra */
+
+ disp = dseg_add_functionptr(cd, codegen_stub_builtin_enter);
+ M_ALD(REG_ITMP3, REG_PV_CALLEE, disp);
+ M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO);
+ M_NOP; /* XXX fill me! */
+
+
+ /* builtins are allowed to have 5 arguments max */
+
+ assert(md->paramcount <= 5);
+
+ /* copy arguments into position */
+
+ for (i = 0; i < md->paramcount; i++) {
+ assert(!md->params[i].inmemory);
+
+ s1 = md->params[i].regoff;
+
+ switch (md->paramtypes[i].type) {
+ case TYPE_INT:
+ case TYPE_LNG:
+ case TYPE_ADR:
+ M_MOV(REG_WINDOW_TRANSPOSE(abi_registers_integer_argument[i]), s1);
+ break;
+ case TYPE_FLT:
+ case TYPE_DBL:
+ M_DLD(s1, REG_SP, JITSTACK + i * 8);
+ break;
+ }
+
+ }
+
+ /* call the builtin function */
+
+ disp = dseg_add_functionptr(cd, bte->fp);
+ M_ALD(REG_ITMP3, REG_PV_CALLEE, disp); /* load adress of builtin */
+ M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); /* call builtin */
+ M_NOP; /* delay slot */
+
+
+ /* save return value */
+
+ if (md->returntype.type != TYPE_VOID) {
+ if (IS_INT_LNG_TYPE(md->returntype.type))
+ M_MOV(REG_RESULT_CALLER, REG_RESULT_CALLEE);
+ else
+ M_DST(REG_FRESULT, REG_SP, CSTACK);
+ }
+
+
+ /* remove native stackframe info */
+
+ M_ADD_IMM(REG_FP, BIAS, REG_OUT0); /* datasp, like above */
+ disp = dseg_add_functionptr(cd, codegen_stub_builtin_exit);
+ M_ALD(REG_ITMP3, REG_PV_CALLEE, disp);
+ M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO);
+ M_NOP;
+
+ /* restore float return value, int return value already in our return reg */
+
+ if (md->returntype.type != TYPE_VOID) {
+ if (IS_FLT_DBL_TYPE(md->returntype.type)) {
+ if (IS_2_WORD_TYPE(md->returntype.type))
+ M_DLD(REG_FRESULT, REG_SP, CSTACK);
+ else
+ M_FLD(REG_FRESULT, REG_SP, CSTACK);
+ }
+ }
+
+
+#if defined(ENABLE_GC_CACAO)
+ /* Restore callee saved integer registers from stackframeinfo (GC
+ might have modified them during a collection). */
+
+ disp = cd->stackframesize * 8 - sizeof(stackframeinfo) +
+ OFFSET(stackframeinfo, intregs) + BIAS;
+
+ for (i = 0; i < INT_SAV_CNT; i++)
+ M_ALD(abi_registers_integer_saved[i], REG_SP, disp + i * 8);
+#endif
+
+ /* return */
+ M_RETURN(REG_RA_CALLEE, 8); /* implicit window restore */
+ M_NOP;
+
+ /* assert(0); */
+}
+
+
/* codegen_emit_stub_native ****************************************************
Emits a stub routine which calls a native method.