--- /dev/null
+/* src/vm/jit/alpha/codegen.c - machine code generator for Alpha
+
+ 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
+
+ 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., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Andreas Krall
+ Reinhard Grafl
+
+ Changes: Joseph Wenninger
+ Christian Thalinger
+ Christian Ullrich
+
+ $Id: codegen.c 3140 2005-09-02 15:17:20Z twisti $
+
+*/
+
+
+#include <stdio.h>
+
+#include "config.h"
+
+#include "machine-instr.h"
+
+#include "vm/jit/intrp/arch.h"
+#include "vm/jit/intrp/codegen.h"
+#include "vm/jit/intrp/types.h"
+
+#include "cacao/cacao.h"
+#include "native/native.h"
+#include "vm/builtin.h"
+#include "vm/global.h"
+#include "vm/loader.h"
+#include "vm/stringlocal.h"
+#include "vm/tables.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/codegen.inc"
+#include "vm/jit/jit.h"
+
+#include "vm/jit/parse.h"
+#include "vm/jit/patcher.h"
+
+#include "vm/jit/intrp/intrp.h"
+
+#define gen_branch(_inst) { \
+ gen_##_inst(&mcodeptr, 0); \
+ codegen_addreference(cd, (basicblock *) (iptr->target), mcodeptr); \
+}
+
+
+/* functions used by cacao-gen.i */
+
+void
+genarg_v(Inst ** ptr2current_threaded, Cell v)
+{
+ *((Cell *) *ptr2current_threaded) = v;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_i(Inst ** ptr2cur_threaded, s4 i)
+{
+ *((Cell *) *ptr2cur_threaded) = i;
+ (*ptr2cur_threaded)++;
+}
+
+void
+genarg_b(Inst ** ptr2cur_threaded, s4 i)
+{
+ genarg_i(ptr2cur_threaded, i);
+}
+
+void
+genarg_f(Inst ** ptr2cur_threaded, float f)
+{
+ s4 fi;
+
+ vm_f2Cell(f,fi);
+ genarg_i(ptr2cur_threaded, fi);
+}
+
+void
+genarg_l(Inst ** ptr2cur_threaded, s8 l)
+{
+ vm_l2twoCell(l, ((Cell*)*ptr2cur_threaded)[1], ((Cell*)*ptr2cur_threaded)[0]);
+ (*ptr2cur_threaded) +=2;
+}
+
+void
+genarg_aRef(Inst ** ptr2current_threaded, java_objectheader *a)
+{
+ *((java_objectheader **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_aArray(Inst ** ptr2current_threaded, java_arrayheader *a)
+{
+ *((java_arrayheader **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_aaTarget(Inst ** ptr2current_threaded, Inst **a)
+{
+ *((Inst ***) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_aClass(Inst ** ptr2current_threaded, classinfo *a)
+{
+ *((classinfo **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_acr(Inst ** ptr2current_threaded, constant_classref *a)
+{
+ *((constant_classref **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_addr(Inst ** ptr2current_threaded, u1 *a)
+{
+ *((u1 **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_af(Inst ** ptr2current_threaded, functionptr a)
+{
+ *((functionptr *) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_am(Inst ** ptr2current_threaded, methodinfo *a)
+{
+ *((methodinfo **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_acell(Inst ** ptr2current_threaded, Cell *a)
+{
+ *((Cell **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_ainst(Inst ** ptr2current_threaded, Inst *a)
+{
+ *((Inst **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_auf(Inst ** ptr2current_threaded, unresolved_field *a)
+{
+ *((unresolved_field **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_aum(Inst ** ptr2current_threaded, unresolved_method *a)
+{
+ *((unresolved_method **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+void
+genarg_avftbl(Inst ** ptr2current_threaded, vftbl_t *a)
+{
+ *((vftbl_t **) *ptr2current_threaded) = a;
+ (*ptr2current_threaded)++;
+}
+
+
+/* include the interpreter generation functions *******************************/
+
+#include "vm/jit/intrp/java-gen.i"
+
+
+typedef void (*genfunctionptr) (Inst **);
+
+typedef struct builtin_gen builtin_gen;
+
+struct builtin_gen {
+ functionptr builtin;
+ genfunctionptr gen;
+};
+
+struct builtin_gen builtin_gen_table[] = {
+ {BUILTIN_new, gen_NEW, },
+ {BUILTIN_newarray, gen_NEWARRAY, },
+ {BUILTIN_newarray_boolean, gen_NEWARRAY_BOOLEAN,},
+ {BUILTIN_newarray_byte, gen_NEWARRAY_BYTE, },
+ {BUILTIN_newarray_char, gen_NEWARRAY_CHAR, },
+ {BUILTIN_newarray_short, gen_NEWARRAY_SHORT, },
+ {BUILTIN_newarray_int, gen_NEWARRAY_INT, },
+ {BUILTIN_newarray_long, gen_NEWARRAY_LONG, },
+ {BUILTIN_newarray_float, gen_NEWARRAY_FLOAT, },
+ {BUILTIN_newarray_double, gen_NEWARRAY_DOUBLE, },
+ {BUILTIN_arrayinstanceof, gen_ARRAYINSTANCEOF, },
+#if defined(USE_THREADS)
+ {BUILTIN_monitorenter, gen_MONITORENTER, },
+ {BUILTIN_monitorexit, gen_MONITOREXIT, },
+#endif
+};
+
+/*
+ The following ones cannot use the BUILTIN mechanism, because they
+ need the class as immediate arguments of the patcher
+
+ PATCHER_builtin_new, gen_PATCHER_NEW,
+ PATCHER_builtin_newarray, gen_PATCHER_NEWARRAY,
+ PATCHER_builtin_arrayinstanceof, gen_PATCHER_ARRAYINSTANCEOF,
+*/
+
+
+
+
+/* codegen *********************************************************************
+
+ Generates machine code.
+
+*******************************************************************************/
+
+void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
+{
+ s4 i, len, s1, s2, d;
+ Inst *mcodeptr;
+ stackptr src;
+ basicblock *bptr;
+ instruction *iptr;
+ exceptiontable *ex;
+ u2 currentline;
+ methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */
+ unresolved_method *um;
+ builtintable_entry *bte;
+ methoddesc *md;
+
+ /* prevent compiler warnings */
+
+ d = 0;
+ currentline = 0;
+ lm = NULL;
+ bte = NULL;
+
+ /* create method header */
+
+ (void) dseg_addaddress(cd, m); /* MethodPointer */
+
+#if defined(USE_THREADS)
+ if (checksync && (m->flags & ACC_SYNCHRONIZED))
+ (void) dseg_adds4(cd, 1); /* IsSync */
+ else
+#endif
+ (void) dseg_adds4(cd, 0); /* IsSync */
+
+ dseg_addlinenumbertablesize(cd);
+
+ (void) dseg_adds4(cd, cd->exceptiontablelength); /* ExTableSize */
+
+ /* create exception table */
+
+ for (ex = cd->exceptiontable; ex != NULL; ex = ex->down) {
+ dseg_addtarget(cd, ex->start);
+ dseg_addtarget(cd, ex->end);
+ dseg_addtarget(cd, ex->handler);
+ (void) dseg_addaddress(cd, ex->catchtype.cls);
+ }
+
+ /* initialize mcode variables */
+
+ mcodeptr = (s4 *) cd->mcodebase;
+ cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
+
+ if (runverbose)
+ gen_TRACECALL(&mcodeptr);
+
+ /* walk through all basic blocks */
+
+ for (bptr = m->basicblocks; bptr != NULL; bptr = bptr->next) {
+
+ bptr->mpc = (s4) ((u1 *) mcodeptr - cd->mcodebase);
+
+ if (bptr->flags >= BBREACHED) {
+
+ /* walk through all instructions */
+
+ src = bptr->instack;
+ len = bptr->icount;
+
+ for (iptr = bptr->iinstr; len > 0; src = iptr->dst, len--, iptr++) {
+ if (iptr->line != currentline) {
+ dseg_addlinenumber(cd, iptr->line, (u1 *) mcodeptr);
+ currentline = iptr->line;
+ }
+
+ MCODECHECK(64); /* an instruction usually needs < 64 words */
+ switch (iptr->opc) {
+
+ case ICMD_INLINE_START:
+ case ICMD_INLINE_END:
+ break;
+
+ case ICMD_NOP: /* ... ==> ... */
+ break;
+
+ case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
+
+ gen_CHECKNULL(&mcodeptr);
+ break;
+
+ /* constant operations ************************************************/
+
+ case ICMD_ICONST: /* ... ==> ..., constant */
+ /* op1 = 0, val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ break;
+
+ case ICMD_LCONST: /* ... ==> ..., constant */
+ /* op1 = 0, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ break;
+
+ case ICMD_FCONST: /* ... ==> ..., constant */
+ /* op1 = 0, val.f = constant */
+ {
+ s4 fi;
+
+ vm_f2Cell(iptr->val.f, fi);
+ gen_ICONST(&mcodeptr, fi);
+ }
+ break;
+
+ case ICMD_DCONST: /* ... ==> ..., constant */
+ /* op1 = 0, val.d = constant */
+
+ gen_LCONST(&mcodeptr, *(s8 *)&(iptr->val.d));
+ break;
+
+ case ICMD_ACONST: /* ... ==> ..., constant */
+ /* op1 = 0, val.a = constant */
+
+ gen_ACONST(&mcodeptr, iptr->val.a);
+ break;
+
+
+ /* load/store operations **********************************************/
+
+ case ICMD_ILOAD: /* ... ==> ..., content of local variable */
+ /* op1 = local variable */
+
+ gen_ILOAD(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_LLOAD: /* ... ==> ..., content of local variable */
+ /* op1 = local variable */
+
+ gen_LLOAD(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_ALOAD: /* ... ==> ..., content of local variable */
+ /* op1 = local variable */
+
+ gen_ALOAD(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_FLOAD: /* ... ==> ..., content of local variable */
+ /* op1 = local variable */
+
+ gen_ILOAD(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_DLOAD: /* ... ==> ..., content of local variable */
+ /* op1 = local variable */
+
+ gen_LLOAD(&mcodeptr, iptr->op1);
+ break;
+
+
+ case ICMD_ISTORE: /* ..., value ==> ... */
+ /* op1 = local variable */
+
+ gen_ISTORE(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_LSTORE: /* ..., value ==> ... */
+ /* op1 = local variable */
+
+ gen_LSTORE(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_ASTORE: /* ..., value ==> ... */
+ /* op1 = local variable */
+
+ gen_ASTORE(&mcodeptr, iptr->op1);
+ break;
+
+
+ case ICMD_FSTORE: /* ..., value ==> ... */
+ /* op1 = local variable */
+
+ gen_ISTORE(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_DSTORE: /* ..., value ==> ... */
+ /* op1 = local variable */
+
+ gen_LSTORE(&mcodeptr, iptr->op1);
+ break;
+
+
+ /* pop/dup/swap operations ********************************************/
+
+ /* attention: double and longs are only one entry in CACAO ICMDs */
+
+ case ICMD_POP: /* ..., value ==> ... */
+
+ gen_POP(&mcodeptr);
+ break;
+
+ case ICMD_POP2: /* ..., value, value ==> ... */
+
+ gen_POP2(&mcodeptr);
+ break;
+
+ case ICMD_DUP: /* ..., a ==> ..., a, a */
+
+ gen_DUP(&mcodeptr);
+ break;
+
+ case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
+
+ gen_DUP_X1(&mcodeptr);
+ break;
+
+ case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
+
+ gen_DUP_X1(&mcodeptr);
+ break;
+
+ case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
+
+ gen_DUP2(&mcodeptr);
+ break;
+
+ case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
+
+ gen_DUP2_X1(&mcodeptr);
+ break;
+
+ case ICMD_DUP2_X2: /* ..., a, b, c, d ==> ..., c, d, a, b, c, d */
+
+ gen_DUP2_X2(&mcodeptr);
+ break;
+
+ case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
+
+ gen_SWAP(&mcodeptr);
+ break;
+
+
+ /* integer operations *************************************************/
+
+ case ICMD_INEG: /* ..., value ==> ..., - value */
+
+ gen_INEG(&mcodeptr);
+ break;
+
+ case ICMD_LNEG: /* ..., value ==> ..., - value */
+
+ gen_LNEG(&mcodeptr);
+ break;
+
+ case ICMD_I2L: /* ..., value ==> ..., value */
+
+ gen_I2L(&mcodeptr);
+ break;
+
+ case ICMD_L2I: /* ..., value ==> ..., value */
+
+ gen_L2I(&mcodeptr);
+ break;
+
+ case ICMD_INT2BYTE: /* ..., value ==> ..., value */
+
+ gen_INT2BYTE(&mcodeptr);
+ break;
+
+ case ICMD_INT2CHAR: /* ..., value ==> ..., value */
+
+ gen_INT2CHAR(&mcodeptr);
+ break;
+
+ case ICMD_INT2SHORT: /* ..., value ==> ..., value */
+
+ gen_INT2SHORT(&mcodeptr);
+ break;
+
+
+ case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+
+ gen_IADD(&mcodeptr);
+ break;
+
+ case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_IADD(&mcodeptr);
+ break;
+
+ case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+
+ gen_LADD(&mcodeptr);
+ break;
+
+ case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
+ /* val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_LADD(&mcodeptr);
+ break;
+
+ case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+
+ gen_ISUB(&mcodeptr);
+ break;
+
+ case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_ISUB(&mcodeptr);
+ break;
+
+ case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+
+ gen_LSUB(&mcodeptr);
+ break;
+
+ case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
+ /* val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_LSUB(&mcodeptr);
+ break;
+
+ case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+
+ gen_IMUL(&mcodeptr);
+ break;
+
+ case ICMD_IMULCONST: /* ..., val1, val2 ==> ..., val1 * val2 */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_IMUL(&mcodeptr);
+ break;
+
+ case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+
+ gen_LMUL(&mcodeptr);
+ break;
+
+ case ICMD_LMULCONST: /* ..., val1, val2 ==> ..., val1 * val2 */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_LMUL(&mcodeptr);
+ break;
+
+ case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+
+ gen_IDIV(&mcodeptr);
+ break;
+
+ case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */
+
+ gen_IREM(&mcodeptr);
+ break;
+
+ case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+
+ gen_LDIV(&mcodeptr);
+ break;
+
+ case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */
+
+ gen_LREM(&mcodeptr);
+ break;
+
+ case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
+ /* val.i = constant */
+
+ gen_IDIVPOW2(&mcodeptr, iptr->val.i);
+ break;
+
+ case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
+ /* val.i = constant */
+
+ gen_IREMPOW2(&mcodeptr, iptr->val.i);
+ break;
+
+ case ICMD_LDIVPOW2: /* ..., value ==> ..., value << constant */
+ /* val.i = constant */
+
+ gen_LDIVPOW2(&mcodeptr, iptr->val.i);
+ break;
+
+ case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
+ /* val.l = constant */
+
+ gen_LREMPOW2(&mcodeptr, iptr->val.i);
+ break;
+
+ case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
+
+ gen_ISHL(&mcodeptr);
+ break;
+
+ case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_ISHL(&mcodeptr);
+ break;
+
+ case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
+
+ gen_ISHR(&mcodeptr);
+ break;
+
+ case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_ISHR(&mcodeptr);
+ break;
+
+ case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
+
+ gen_IUSHR(&mcodeptr);
+ break;
+
+ case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_IUSHR(&mcodeptr);
+ break;
+
+ case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
+
+ gen_LSHL(&mcodeptr);
+ break;
+
+ case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_LSHL(&mcodeptr);
+ break;
+
+ case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
+
+ gen_LSHR(&mcodeptr);
+ break;
+
+ case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_LSHR(&mcodeptr);
+ break;
+
+ case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
+
+ gen_LUSHR(&mcodeptr);
+ break;
+
+ case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_LUSHR(&mcodeptr);
+ break;
+
+ case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
+
+ gen_IAND(&mcodeptr);
+ break;
+
+ case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_IAND(&mcodeptr);
+ break;
+
+ case ICMD_LAND: /* ..., val1, val2 ==> ..., val1 & val2 */
+
+ gen_LAND(&mcodeptr);
+ break;
+
+ case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
+ /* val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_LAND(&mcodeptr);
+ break;
+
+ case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
+
+ gen_IOR(&mcodeptr);
+ break;
+
+ case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_IOR(&mcodeptr);
+ break;
+
+ case ICMD_LOR: /* ..., val1, val2 ==> ..., val1 | val2 */
+
+ gen_LOR(&mcodeptr);
+ break;
+
+ case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
+ /* val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_LOR(&mcodeptr);
+ break;
+
+ case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
+
+ gen_IXOR(&mcodeptr);
+ break;
+
+ case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
+ /* val.i = constant */
+
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_IXOR(&mcodeptr);
+ break;
+
+ case ICMD_LXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
+
+ gen_LXOR(&mcodeptr);
+ break;
+
+ case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
+ /* val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_LXOR(&mcodeptr);
+ break;
+
+
+ case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
+
+ gen_LCMP(&mcodeptr);
+ break;
+
+
+ case ICMD_IINC: /* ..., value ==> ..., value + constant */
+ /* op1 = variable, val.i = constant */
+
+ gen_IINC(&mcodeptr, iptr->op1, iptr->val.i);
+ break;
+
+
+ /* floating operations ************************************************/
+
+ case ICMD_FNEG: /* ..., value ==> ..., - value */
+
+ gen_FNEG(&mcodeptr);
+ break;
+
+ case ICMD_DNEG: /* ..., value ==> ..., - value */
+
+ gen_DNEG(&mcodeptr);
+ break;
+
+ case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+
+ gen_FADD(&mcodeptr);
+ break;
+
+ case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+
+ gen_DADD(&mcodeptr);
+ break;
+
+ case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+
+ gen_FSUB(&mcodeptr);
+ break;
+
+ case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+
+ gen_DSUB(&mcodeptr);
+ break;
+
+ case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+
+ gen_FMUL(&mcodeptr);
+ break;
+
+ case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
+
+ gen_DMUL(&mcodeptr);
+ break;
+
+ case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+
+ gen_FDIV(&mcodeptr);
+ break;
+
+ case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+
+ gen_DDIV(&mcodeptr);
+ break;
+
+ case ICMD_I2F: /* ..., value ==> ..., (float) value */
+
+ gen_I2F(&mcodeptr);
+ break;
+
+ case ICMD_L2F: /* ..., value ==> ..., (float) value */
+
+ gen_L2F(&mcodeptr);
+ break;
+
+ case ICMD_I2D: /* ..., value ==> ..., (double) value */
+
+ gen_I2D(&mcodeptr);
+ break;
+
+ case ICMD_L2D: /* ..., value ==> ..., (double) value */
+
+ gen_L2D(&mcodeptr);
+ break;
+
+ case ICMD_F2I: /* ..., value ==> ..., (int) value */
+
+ gen_F2I(&mcodeptr);
+ break;
+
+ case ICMD_D2I: /* ..., value ==> ..., (int) value */
+
+ gen_D2I(&mcodeptr);
+ break;
+
+ case ICMD_F2L: /* ..., value ==> ..., (long) value */
+
+ gen_F2L(&mcodeptr);
+ break;
+
+ case ICMD_D2L: /* ..., value ==> ..., (long) value */
+
+ gen_D2L(&mcodeptr);
+ break;
+
+ case ICMD_F2D: /* ..., value ==> ..., (double) value */
+
+ gen_F2D(&mcodeptr);
+ break;
+
+ case ICMD_D2F: /* ..., value ==> ..., (float) value */
+
+ gen_D2F(&mcodeptr);
+ break;
+
+ case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */
+
+ gen_FCMPL(&mcodeptr);
+ break;
+
+ case ICMD_DCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */
+
+ gen_DCMPL(&mcodeptr);
+ break;
+
+ case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */
+
+ gen_FCMPG(&mcodeptr);
+ break;
+
+ case ICMD_DCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */
+
+ gen_DCMPG(&mcodeptr);
+ break;
+
+
+ /* memory operations **************************************************/
+
+ case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
+
+ gen_ARRAYLENGTH(&mcodeptr);
+ break;
+
+ case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
+
+ gen_BALOAD(&mcodeptr);
+ break;
+
+ case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
+
+ gen_CALOAD(&mcodeptr);
+ break;
+
+ case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
+
+ gen_SALOAD(&mcodeptr);
+ break;
+
+ case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
+ case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
+
+ gen_IALOAD(&mcodeptr);
+ break;
+
+ case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
+ case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
+
+ gen_LALOAD(&mcodeptr);
+ break;
+
+ case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
+
+ gen_AALOAD(&mcodeptr);
+ break;
+
+
+ case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
+
+ gen_BASTORE(&mcodeptr);
+ break;
+
+ case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
+ case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
+
+ gen_CASTORE(&mcodeptr);
+ break;
+
+ case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
+ case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
+
+ gen_IASTORE(&mcodeptr);
+ break;
+
+ case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
+ case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
+
+ gen_LASTORE(&mcodeptr);
+ break;
+
+ case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
+
+ gen_AASTORE(&mcodeptr);
+ break;
+
+
+ case ICMD_GETSTATIC: /* ... ==> ..., value */
+ /* op1 = type, val.a = field address */
+
+ {
+ fieldinfo *fi = iptr->val.a;
+ unresolved_field *uf = iptr->target;
+
+ switch (iptr->op1) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_GETSTATIC_INT(&mcodeptr, 0, uf);
+ } else {
+ gen_GETSTATIC_INT(&mcodeptr, (u1 *)&(fi->value.i), uf);
+ }
+ break;
+ case TYPE_LNG:
+ case TYPE_DBL:
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_GETSTATIC_LONG(&mcodeptr, 0, uf);
+ } else {
+ gen_GETSTATIC_LONG(&mcodeptr, (u1 *)&(fi->value.l), uf);
+ }
+ break;
+ case TYPE_ADR:
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_GETSTATIC_CELL(&mcodeptr, 0, uf);
+ } else {
+ gen_GETSTATIC_CELL(&mcodeptr, (u1 *)&(fi->value.a), uf);
+ }
+ break;
+ }
+ }
+ break;
+
+ case ICMD_PUTSTATIC: /* ..., value ==> ... */
+ /* op1 = type, val.a = field address */
+
+ {
+ fieldinfo *fi = iptr->val.a;
+ unresolved_field *uf = iptr->target;
+
+ switch (iptr->op1) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_PUTSTATIC_INT(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTSTATIC_INT(&mcodeptr, (u1 *)&(fi->value.i), uf);
+ }
+ break;
+ case TYPE_LNG:
+ case TYPE_DBL:
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_PUTSTATIC_LONG(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTSTATIC_LONG(&mcodeptr, (u1 *)&(fi->value.l), uf);
+ }
+ break;
+ case TYPE_ADR:
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_PUTSTATIC_CELL(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTSTATIC_CELL(&mcodeptr, (u1 *)&(fi->value.a), uf);
+ }
+ break;
+ }
+ }
+ break;
+
+ case ICMD_PUTSTATICCONST: /* ... ==> ... */
+ /* val = value (in current instruction) */
+ /* op1 = type, val.a = field address (in */
+ /* following NOP) */
+
+ {
+ fieldinfo *fi = iptr[1].val.a;
+ unresolved_field *uf = iptr[1].target;
+
+ switch (iptr->op1) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_PUTSTATIC_INT(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTSTATIC_INT(&mcodeptr, (u1 *)&(fi->value.i), uf);
+ }
+ break;
+ case TYPE_LNG:
+ case TYPE_DBL:
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_PUTSTATIC_LONG(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTSTATIC_LONG(&mcodeptr, (u1 *)&(fi->value.l), uf);
+ }
+ break;
+ case TYPE_ADR:
+ gen_ACONST(&mcodeptr, iptr->val.a);
+ if (fi == NULL || !fi->class->initialized) {
+ gen_PATCHER_PUTSTATIC_CELL(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTSTATIC_CELL(&mcodeptr, (u1 *)&(fi->value.a), uf);
+ }
+ break;
+ }
+ }
+ break;
+
+
+ case ICMD_GETFIELD: /* ... ==> ..., value */
+ /* op1 = type, val.a = field address */
+
+ {
+ fieldinfo *fi = iptr->val.a;
+ unresolved_field *uf = iptr->target;
+
+ switch (iptr->op1) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ if (fi == NULL) {
+ gen_PATCHER_GETFIELD_INT(&mcodeptr, 0, uf);
+ } else {
+ gen_GETFIELD_INT(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ case TYPE_LNG:
+ case TYPE_DBL:
+ if (fi == NULL) {
+ gen_PATCHER_GETFIELD_LONG(&mcodeptr, 0, uf);
+ } else {
+ gen_GETFIELD_LONG(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ case TYPE_ADR:
+ if (fi == NULL) {
+ gen_PATCHER_GETFIELD_CELL(&mcodeptr, 0, uf);
+ } else {
+ gen_GETFIELD_CELL(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ }
+ }
+ break;
+
+ case ICMD_PUTFIELD: /* ..., objectref, value ==> ... */
+ /* op1 = type, val.a = field address */
+
+ {
+ fieldinfo *fi = iptr->val.a;
+ unresolved_field *uf = iptr->target;
+
+ switch (iptr->op1) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ if (fi == NULL) {
+ gen_PATCHER_PUTFIELD_INT(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTFIELD_INT(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ case TYPE_LNG:
+ case TYPE_DBL:
+ if (fi == NULL) {
+ gen_PATCHER_PUTFIELD_LONG(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTFIELD_LONG(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ case TYPE_ADR:
+ if (fi == NULL) {
+ gen_PATCHER_PUTFIELD_CELL(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTFIELD_CELL(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ }
+ }
+ break;
+
+ case ICMD_PUTFIELDCONST: /* ..., objectref ==> ... */
+ /* val = value (in current instruction) */
+ /* op1 = type, val.a = field address (in */
+ /* following NOP) */
+
+ {
+ fieldinfo *fi = iptr[1].val.a;
+ unresolved_field *uf = iptr[1].target;
+
+ switch (iptr[1].op1) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ if (fi == NULL) {
+ gen_PATCHER_PUTFIELD_INT(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTFIELD_INT(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ case TYPE_LNG:
+ case TYPE_DBL:
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ if (fi == NULL) {
+ gen_PATCHER_PUTFIELD_LONG(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTFIELD_LONG(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ case TYPE_ADR:
+ gen_ACONST(&mcodeptr, iptr->val.a);
+ if (fi == NULL) {
+ gen_PATCHER_PUTFIELD_CELL(&mcodeptr, 0, uf);
+ } else {
+ gen_PUTFIELD_CELL(&mcodeptr, fi->offset, uf);
+ }
+ break;
+ }
+ }
+ break;
+
+
+ /* branch operations **************************************************/
+
+ case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */
+
+ gen_ATHROW(&mcodeptr);
+ break;
+
+ case ICMD_GOTO: /* ... ==> ... */
+ /* op1 = target JavaVM pc */
+ gen_branch(GOTO);
+ break;
+
+ case ICMD_JSR: /* ... ==> ... */
+ /* op1 = target JavaVM pc */
+ gen_branch(JSR);
+ break;
+
+ case ICMD_RET: /* ... ==> ... */
+ /* op1 = local variable */
+
+ gen_RET(&mcodeptr, iptr->op1);
+ break;
+
+ case ICMD_IFNULL: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IFNULL);
+ break;
+
+ case ICMD_IFNONNULL: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IFNONNULL);
+ break;
+
+ case ICMD_IFEQ: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.i = constant */
+
+ if (iptr->val.i == 0) {
+ gen_branch(IFEQ);
+ } else {
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_branch(IF_ICMPEQ);
+ }
+ break;
+
+ case ICMD_IFLT: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.i = constant */
+
+ if (iptr->val.i == 0) {
+ gen_branch(IFLT);
+ } else {
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_branch(IF_ICMPLT);
+ }
+ break;
+
+ case ICMD_IFLE: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.i = constant */
+
+ if (iptr->val.i == 0) {
+ gen_branch(IFLE);
+ } else {
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_branch(IF_ICMPLE);
+ }
+ break;
+
+ case ICMD_IFNE: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.i = constant */
+
+ if (iptr->val.i == 0) {
+ gen_branch(IFNE);
+ } else {
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_branch(IF_ICMPNE);
+ }
+ break;
+
+ case ICMD_IFGT: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.i = constant */
+
+ if (iptr->val.i == 0) {
+ gen_branch(IFGT);
+ } else {
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_branch(IF_ICMPGT);
+ }
+ break;
+
+ case ICMD_IFGE: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.i = constant */
+
+ if (iptr->val.i == 0) {
+ gen_branch(IFGE);
+ } else {
+ gen_ICONST(&mcodeptr, iptr->val.i);
+ gen_branch(IF_ICMPGE);
+ }
+ break;
+
+ case ICMD_IF_LEQ: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_branch(IF_LCMPEQ);
+ break;
+
+ case ICMD_IF_LLT: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_branch(IF_LCMPLT);
+ break;
+
+ case ICMD_IF_LLE: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_branch(IF_LCMPLE);
+ break;
+
+ case ICMD_IF_LNE: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_branch(IF_LCMPNE);
+ break;
+
+ case ICMD_IF_LGT: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_branch(IF_LCMPGT);
+ break;
+
+ case ICMD_IF_LGE: /* ..., value ==> ... */
+ /* op1 = target JavaVM pc, val.l = constant */
+
+ gen_LCONST(&mcodeptr, iptr->val.l);
+ gen_branch(IF_LCMPGE);
+ break;
+
+ case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ICMPEQ);
+ break;
+
+ case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_LCMPEQ);
+ break;
+
+ case ICMD_IF_ACMPEQ: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ACMPEQ);
+ break;
+
+ case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ICMPNE);
+ break;
+
+ case ICMD_IF_LCMPNE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_LCMPNE);
+ break;
+
+ case ICMD_IF_ACMPNE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ACMPNE);
+ break;
+
+ case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ICMPLT);
+ break;
+
+ case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_LCMPLT);
+ break;
+
+ case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ICMPGT);
+ break;
+
+ case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_LCMPGT);
+ break;
+
+ case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ICMPLE);
+ break;
+
+ case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_LCMPLE);
+ break;
+
+ case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_ICMPGE);
+ break;
+
+ case ICMD_IF_LCMPGE: /* ..., value, value ==> ... */
+ /* op1 = target JavaVM pc */
+
+ gen_branch(IF_LCMPGE);
+ break;
+
+
+ case ICMD_ARETURN: /* ..., retvalue ==> ... */
+ case ICMD_IRETURN: /* ..., retvalue ==> ... */
+ case ICMD_FRETURN: /* ..., retvalue ==> ... */
+
+#if defined(USE_THREADS)
+ if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ if (m->flags & ACC_STATIC) {
+ gen_ACONST(&mcodeptr, m->class);
+ } else {
+ gen_ALOAD(&mcodeptr, 0);
+ }
+ gen_MONITOREXIT(&mcodeptr);
+ }
+#endif
+ if (runverbose)
+ gen_TRACERETURN(&mcodeptr);
+
+ gen_IRETURN(&mcodeptr, cd->maxlocals);
+ break;
+
+ case ICMD_LRETURN: /* ..., retvalue ==> ... */
+ case ICMD_DRETURN: /* ..., retvalue ==> ... */
+
+#if defined(USE_THREADS)
+ if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ if (m->flags & ACC_STATIC) {
+ gen_ACONST(&mcodeptr, m->class);
+ } else {
+ gen_ALOAD(&mcodeptr, 0);
+ }
+ gen_MONITOREXIT(&mcodeptr);
+ }
+#endif
+ if (runverbose)
+ gen_TRACELRETURN(&mcodeptr);
+
+ gen_LRETURN(&mcodeptr, cd->maxlocals);
+ break;
+
+ case ICMD_RETURN: /* ... ==> ... */
+
+#if defined(USE_THREADS)
+ if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ if (m->flags & ACC_STATIC) {
+ gen_ACONST(&mcodeptr, m->class);
+ } else {
+ gen_ALOAD(&mcodeptr, 0);
+ }
+ gen_MONITOREXIT(&mcodeptr);
+ }
+#endif
+ if (runverbose)
+ gen_TRACERETURN(&mcodeptr);
+
+ gen_RETURN(&mcodeptr, cd->maxlocals);
+ break;
+
+
+ case ICMD_TABLESWITCH: /* ..., index ==> ... */
+ {
+ s4 i, l, *s4ptr;
+ void **tptr;
+
+ tptr = (void **) iptr->target;
+
+ s4ptr = iptr->val.a;
+ l = s4ptr[1]; /* low */
+ i = s4ptr[2]; /* high */
+
+ i = i - l + 1;
+
+ /* arguments: low, range, datasegment address, table offset in */
+ /* datasegment, default target */
+ gen_TABLESWITCH(&mcodeptr, l, i, NULL, 0, NULL);
+ dseg_adddata(cd, (u1 *) (mcodeptr - 2)); /* actually mcodeptr[-3] */
+ codegen_addreference(cd, (basicblock *) tptr[0], mcodeptr);
+
+ /* build jump table top down and use address of lowest entry */
+
+ tptr += i;
+
+ while (--i >= 0) {
+ dseg_addtarget(cd, (basicblock *) tptr[0]);
+ --tptr;
+ }
+ }
+
+ /* length of dataseg after last dseg_addtarget is used by load */
+ mcodeptr[-2] = (Inst) (ptrint) -(cd->dseglen);
+ break;
+
+
+ case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */
+ {
+ s4 i, *s4ptr;
+ void **tptr;
+
+ tptr = (void **) iptr->target;
+
+ s4ptr = iptr->val.a;
+
+ /* s4ptr[0] is equal to tptr[0] */
+ i = s4ptr[1]; /* count */
+
+ /* arguments: count, datasegment address, table offset in */
+ /* datasegment, default target */
+ gen_LOOKUPSWITCH(&mcodeptr, i, NULL, 0, NULL);
+ dseg_adddata(cd, (u1 *) (mcodeptr - 2)); /* actually mcodeptr[-3] */
+ codegen_addreference(cd, (basicblock *) tptr[0], mcodeptr);
+
+ /* build jump table top down and use address of lowest entry */
+
+ tptr += i;
+ s4ptr += i * 2;
+
+ while (--i >= 0) {
+ dseg_addtarget(cd, (basicblock *) tptr[0]);
+ dseg_addaddress(cd, s4ptr[0]);
+ --tptr;
+ s4ptr -= 2;
+ }
+ }
+
+ /* length of dataseg after last dseg_addtarget is used by load */
+ mcodeptr[-2] = (Inst) (ptrint) -(cd->dseglen);
+ break;
+
+
+ case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */
+ /* op1 = arg count val.a = builtintable entry */
+ bte = iptr->val.a;
+ if (bte->fp == PATCHER_builtin_new) {
+ gen_PATCHER_NEW(&mcodeptr, 0);
+ } else if (bte->fp == PATCHER_builtin_newarray) {
+ gen_PATCHER_NEWARRAY(&mcodeptr, 0);
+ } else if (bte->fp == PATCHER_builtin_arrayinstanceof) {
+ gen_PATCHER_ARRAYINSTANCEOF(&mcodeptr, 0);
+ } else {
+ for (i = 0; i < sizeof(builtin_gen_table)/sizeof(builtin_gen); i++) {
+ builtin_gen *bg = &builtin_gen_table[i];
+ if (bg->builtin == bte->fp) {
+ (bg->gen)(&mcodeptr);
+ break;
+ }
+ }
+ }
+ break;
+
+ case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
+ /* op1 = arg count, val.a = method pointer */
+
+ lm = iptr->val.a;
+ um = iptr->target;
+
+ if (lm == NULL) {
+ md = um->methodref->parseddesc.md;
+ gen_PATCHER_INVOKESTATIC(&mcodeptr, 0, md->paramslots, um);
+
+ } else {
+ md = lm->parseddesc;
+ gen_INVOKESTATIC(&mcodeptr, (Inst **)lm->stubroutine, md->paramslots, um);
+ }
+ break;
+
+ case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */
+
+ lm = iptr->val.a;
+ um = iptr->target;
+
+ if (lm == NULL) {
+ md = um->methodref->parseddesc.md;
+ gen_PATCHER_INVOKESPECIAL(&mcodeptr, 0, md->paramslots, um);
+
+ } else {
+ md = lm->parseddesc;
+ gen_INVOKESPECIAL(&mcodeptr, (Inst **)lm->stubroutine, md->paramslots, um);
+ }
+ break;
+
+ case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */
+
+ lm = iptr->val.a;
+ um = iptr->target;
+
+ if (lm == NULL) {
+ md = um->methodref->parseddesc.md;
+ gen_PATCHER_INVOKEVIRTUAL(&mcodeptr, 0, md->paramslots, um);
+
+ } else {
+ md = lm->parseddesc;
+
+ s1 = OFFSET(vftbl_t, table[0]) +
+ sizeof(methodptr) * lm->vftblindex;
+
+ gen_INVOKEVIRTUAL(&mcodeptr, s1, md->paramslots, um);
+ }
+ break;
+
+ case ICMD_INVOKEINTERFACE:/* op1 = arg count, val.a = method pointer */
+
+ lm = iptr->val.a;
+ um = iptr->target;
+
+ if (lm == NULL) {
+ md = um->methodref->parseddesc.md;
+ gen_PATCHER_INVOKEINTERFACE(&mcodeptr, 0, 0, md->paramslots, um);
+
+ } else {
+ md = lm->parseddesc;
+
+ s1 = OFFSET(vftbl_t, interfacetable[0]) -
+ sizeof(methodptr*) * lm->class->index;
+
+ s2 = sizeof(methodptr) * (lm - lm->class->methods);
+
+ gen_INVOKEINTERFACE(&mcodeptr, s1, s2, md->paramslots, um);
+ }
+ break;
+
+
+ case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
+ /* op1: 0 == array, 1 == class */
+ /* val.a: (classinfo *) superclass */
+
+ if (iptr->val.a == NULL) {
+ gen_PATCHER_CHECKCAST(&mcodeptr, 0, iptr->target);
+
+ } else {
+ gen_CHECKCAST(&mcodeptr, iptr->val.a, iptr->target);
+ }
+
+ break;
+
+ case ICMD_ARRAYCHECKCAST: /* ..., objectref ==> ..., objectref */
+ /* op1: 1... resolved, 0... not resolved */
+
+ if (iptr->op1 == 0) {
+ gen_PATCHER_ARRAYCHECKCAST(&mcodeptr, 0, iptr->target);
+ } else {
+ gen_ARRAYCHECKCAST(&mcodeptr, iptr->target, 0);
+ }
+ break;
+
+ case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
+ /* op1: 0 == array, 1 == class */
+ /* val.a: (classinfo *) superclass */
+
+ if (iptr->val.a == NULL) {
+ gen_PATCHER_INSTANCEOF(&mcodeptr, 0, iptr->target);
+ } else {
+ gen_INSTANCEOF(&mcodeptr, iptr->val.a, iptr->target);
+ }
+
+ break;
+
+
+ case ICMD_CHECKASIZE: /* ..., size ==> ..., size */
+
+ /* XXX remove me! */
+ break;
+
+ case ICMD_CHECKEXCEPTION: /* ..., objectref ==> ..., objectref */
+
+ gen_CHECKEXCEPTION(&mcodeptr);
+ break;
+
+ case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
+ /* op1 = dimension, val.a = array descriptor */
+
+ if (iptr->target) {
+ gen_PATCHER_MULTIANEWARRAY(&mcodeptr, 0, iptr->op1, iptr->val.a);
+ } else {
+ gen_MULTIANEWARRAY(&mcodeptr, iptr->val.a, iptr->op1, 0);
+ }
+ break;
+
+ default:
+ throw_cacao_exception_exit(string_java_lang_InternalError,
+ "Unknown ICMD %d", iptr->opc);
+ } /* switch */
+
+ } /* for instruction */
+
+ } /* if (bptr -> flags >= BBREACHED) */
+ } /* for basic block */
+
+ codegen_createlinenumbertable(cd);
+
+ codegen_finish(m, cd, (s4) ((u1 *) mcodeptr - cd->mcodebase));
+
+
+ /* branch resolving (walk through all basic blocks) */
+
+ for (bptr = m->basicblocks; bptr != NULL; bptr = bptr->next) {
+ branchref *brefs;
+
+ for (brefs = bptr->branchrefs; brefs != NULL; brefs = brefs->next) {
+ gen_resolveanybranch(((u1*) m->entrypoint) + brefs->branchpos,
+ ((u1 *)m->entrypoint) + bptr->mpc);
+ }
+ }
+}
+
+
+/* a stub consists of
+
++---------+
+|codeptr |
++---------+
+|maxlocals|
++---------+
+|TRANSLATE|
++---------+
+|methodinf|
++---------+
+
+codeptr points either to TRANSLATE or to the translated threaded code
+
+all methods are called indirectly through methodptr
+*/
+
+#define STUBSIZE 4
+
+functionptr createcompilerstub (methodinfo *m)
+{
+ Inst * t = CNEW(Inst, STUBSIZE);
+ Inst * codeptr=t;
+ genarg_ainst(&t, t+2);
+
+ if (m->flags & ACC_NATIVE) {
+ genarg_i(&t, m->parseddesc->paramslots);
+ } else {
+ genarg_i(&t, m->maxlocals);
+ }
+
+ gen_TRANSLATE(&t, m);
+ return (functionptr)codeptr;
+}
+
+
+/* native stub:
++---------+
+|NATIVECALL|
++---------+
+|methodinf|
++---------+
+|function |
++---------+
+
+where maxlocals==paramslots
+*/
+
+#define NATIVE_STUBSIZE 5
+
+functionptr createnativestub(functionptr f, methodinfo *m, codegendata *cd,
+ registerdata *rd, methoddesc *md)
+{
+ Inst *mcodeptr;
+
+ mcodeptr = (s4 *) cd->mcodebase;
+ cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
+
+ /* create method header */
+
+ (void) dseg_addaddress(cd, m); /* MethodPointer */
+ (void) dseg_adds4(cd, 0); /* IsSync */
+ dseg_addlinenumbertablesize(cd);
+ (void) dseg_adds4(cd, 0); /* ExTableSize */
+
+ if (runverbose)
+ gen_TRACECALL(&mcodeptr);
+
+ if (f == NULL) {
+ gen_PATCHER_NATIVECALL(&mcodeptr, m, f);
+ } else {
+ if (runverbose)
+ gen_TRACENATIVECALL(&mcodeptr, m, f);
+ else
+ gen_NATIVECALL(&mcodeptr, m, f);
+ }
+
+ codegen_finish(m, cd, (s4) ((u1 *) mcodeptr - cd->mcodebase));
+
+ return m->entrypoint;
+}
+
+
+/*
+ * 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:
+ */
--- /dev/null
+\
+\ JVM instruction specs
+\
+\ This file contains primitive specifications in the following format:
+\
+\ name ( stack effect ) [ number ]
+\ [""glossary entry""]
+\ C code
+\ [:
+\ Forth code]
+\
+\ Note: Fields in brackets are optional. Word specifications have to
+\ be separated by at least one empty line
+\
+\ Both name and stack items (in the stack effect) must
+\ conform to the C identifier syntax or the C compiler will complain.
+\ The branch field can be one of "branch", "cond", "indirect", or empty.
+\
+\ These specifications are automatically translated into C-code for the
+\ interpreter and into some other files. I hope that your C compiler has
+\ decent optimization, otherwise the automatically generated code will
+\ be somewhat slow. The Forth version of the code is included for manual
+\ compilers, so they will need to compile only the important words.
+\
+\ Note that stack pointer adjustment is performed according to stack
+\ effect by automatically generated code and NEXT is automatically
+\ appended to the C code. Also, you can use the names in the stack
+\ effect in the C code. Stack access is automatic. One exception: if
+\ your code does not fall through, the results are not stored into the
+\ stack. Use different names on both sides of the '--', if you change a
+\ value (some stores to the stack are optimized away).
+\
+
+\E stack data-stack sp Cell
+\E
+\E s" u4" single data-stack type-prefix ui
+\E s" Cell" single data-stack type-prefix v
+\E s" s4" single data-stack type-prefix b \ byte
+\E s" s4" single data-stack type-prefix s \ short
+\E s" s4" single data-stack type-prefix i
+\E s" s8" double data-stack type-prefix l
+\E s" float" single data-stack type-prefix f
+\E s" double" double data-stack type-prefix d
+
+\ we use a lot of types for the former "a" (address) type; this gives
+\ better typechecking in the C code, and allows better output from the
+\ disassembler and the tracer.
+
+\E s" java_objectheader *" single data-stack type-prefix aRef
+\E s" java_arrayheader *" single data-stack type-prefix aArray
+\E s" Inst **" single data-stack type-prefix aaTarget
+\E s" classinfo *" single data-stack type-prefix aClass
+\E s" constant_classref *" single data-stack type-prefix acr
+\E s" u1 *" single data-stack type-prefix addr
+\E s" functionptr" single data-stack type-prefix af
+\E s" methodinfo *" single data-stack type-prefix am
+\E s" Cell *" single data-stack type-prefix acell
+\E s" Inst *" single data-stack type-prefix ainst
+\E s" unresolved_field *" single data-stack type-prefix auf
+\E s" unresolved_method *" single data-stack type-prefix aum
+\E s" vftbl_t *" single data-stack type-prefix avftbl
+\E inst-stream stack-prefix #
+
+\ The stack variables have the following types:
+\
+\ name matches type
+\ i.* jint
+\ l.* jlong
+\ s.* Jshort
+\ b.* Jbyte
+\ c.* Jchar
+\ f.* jfloat
+\ d.* jdouble
+\ a.* jref
+\ r.* Jretaddr
+\
+\
+\ Starting a name with # indicates an inline argument instead of a stack
+\ argument; the rest of the name matches as usual.
+\
+\
+\ Questions:
+\ How does prims2x know the length of each instruction,
+\ where the instruction has immediate operands. We need
+\ some way to communicate this or compute it.
+\
+\ Some instructions don't care about the type of the
+\ values that they work with. For example, POP doesn't
+\ care what type the value on the top of the stack is.
+\ We need to communicate this.
+\ I'll add a type v (for void, or variable, whichever you
+\ prefer) which just means there's one element of the normal
+\ size on the stack, and we don't care what its type is.
+\
+\
+\ /*
+\ Define the following macros before including this file.
+\
+\ # define instr(name,opcode,label,len,syntax,body)
+\ # define undef(name,opcode,label,len,syntax,body)
+\ # define custm(name,opcode,label,len,syntax,body)
+\
+\
+\ To avoid race conditions, rewriting proceeds as follows:
+\ 1) the needed operands are fetched from the orignal byte code
+\ 2) the new operands are written
+\ 3) the new operator is written
+\ 4) the quick-version of the instruction is executed.
+\
+\ Note: the byte code remains unchanged.
+\
+\ */
+
+\ This is stub code for methods that we have not yet translated.
+\ Initially, the code for each method is set to this stub. The
+\ first time the method is called, the code in the stub runs, which
+\ translates the bytecode, and replaces the stub with the threaded code.
+
+\ instr(NOP, 0, nop, 1, op, {})
+
+ICONST ( #vConst -- vConst ) opt
+
+LCONST ( #l -- l ) opt
+
+ACONST ( #aRef -- aRef ) opt
+
+ILOAD ( #bLocal -- vResult ) 0x15
+{
+ vResult = access_local_int(bLocal);
+}
+
+LLOAD ( #bLocal -- lResult ) 0x16
+{
+ vm_twoCell2l(access_local_cell(bLocal), access_local_cell(bLocal+1), lResult);
+}
+
+ALOAD ( #bLocal -- aRef ) 0x19
+{
+ aRef = (java_objectheader *)access_local_cell(bLocal);
+}
+
+IALOAD ( aArray iIndex -- iResult ) 0x2e
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ iResult = access_array_int(aArray, iIndex);
+}
+
+LALOAD ( aArray iIndex -- lResult ) 0x2f
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ lResult = access_array_long(aArray, iIndex);
+}
+
+AALOAD ( aArray iIndex -- aRef ) 0x32
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ aRef = access_array_addr(aArray, iIndex);
+}
+
+BALOAD ( aArray iIndex -- iResult ) 0x33
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ iResult = access_array_byte(aArray, iIndex);
+}
+
+CALOAD ( aArray iIndex -- iResult ) 0x34
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ iResult = access_array_char(aArray, iIndex);
+}
+
+SALOAD ( aArray iIndex -- iResult ) 0x35
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ iResult = access_array_short(aArray, iIndex);
+}
+
+ISTORE ( #bLocal vValue -- ) 0x36
+{
+ access_local_int(bLocal) = vValue;
+}
+
+LSTORE ( #bLocal lValue -- ) 0x37
+{
+ vm_l2twoCell(lValue, access_local_cell(bLocal), access_local_cell(bLocal+1));
+}
+
+ASTORE ( #bLocal aRef -- ) 0x3a
+{
+ access_local_cell(bLocal) = (Cell)aRef;
+}
+
+IASTORE ( aArray iIndex iValue -- ) 0x4f
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ access_array_int(aArray, iIndex) = iValue;
+}
+
+LASTORE ( aArray iIndex lValue -- ) 0x50
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ access_array_long(aArray, iIndex) = lValue;
+}
+
+AASTORE ( aArray iIndex aRef -- ) 0x53
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ if (!builtin_canstore((java_objectarray *)aArray, aRef))
+ THROW(arraystoreexception);
+ access_array_addr(aArray, iIndex) = aRef;
+}
+
+BASTORE ( aArray iIndex iValue -- ) 0x54
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ access_array_byte(aArray, iIndex) = iValue;
+}
+
+CASTORE ( aArray iIndex iValue -- ) 0x55
+{
+ CHECK_NULL_PTR(aArray);
+ CHECK_OUT_OF_BOUNDS(aArray, iIndex);
+ ;
+ access_array_char(aArray, iIndex) = iValue;
+}
+
+POP ( vValue -- ) 0x57
+
+POP2 ( vValue vValue -- ) 0x58
+
+DUP ( vValue -- vValue vValue ) 0x59
+
+DUP_X1 ( vValue2 vValue1 -- vValue1 vValue2 vValue1 ) 0x5a
+
+DUP_X2 ( vValue3 vValue2 vValue1 -- vValue1 vValue3 vValue2 vValue1 ) 0x5b
+
+DUP2 ( vValue2 vValue1 -- vValue2 vValue1 vValue2 vValue1 ) 0x5c
+
+DUP2_X1 (vValue3 vValue2 vValue1 -- vValue2 vValue1 vValue3 vValue2 vValue1 ) 0x5d
+
+DUP2_X2 ( vValue4 vValue3 vValue2 vValue1 -- vValue2 vValue1 vValue4 vValue3 vValue2 vValue1 ) 0x5e
+
+SWAP ( vValue2 vValue1 -- vValue1 vValue2 ) 0x5f
+
+IADD ( iValue1 iValue2 -- iResult ) 0x60
+{
+ iResult = iValue1 + iValue2;
+}
+
+LADD ( lValue1 lValue2 -- lResult ) 0x61
+{
+ lResult = lValue1 + lValue2;
+}
+
+FADD ( fValue1 fValue2 -- fResult ) 0x62
+{
+ fResult = fValue1 + fValue2;
+}
+
+DADD ( dValue1 dValue2 -- dResult ) 0x63
+{
+ dResult = dValue1 + dValue2;
+}
+
+ISUB ( iValue1 iValue2 -- iResult ) 0x64
+{
+ iResult = iValue1 - iValue2;
+}
+
+LSUB ( lValue1 lValue2 -- lResult ) 0x65
+{
+ lResult = lValue1 - lValue2;
+}
+
+FSUB ( fValue1 fValue2 -- fResult ) 0x66
+{
+ fResult = fValue1 - fValue2;
+}
+
+DSUB ( dValue1 dValue2 -- dResult ) 0x67
+{
+ dResult = dValue1 - dValue2;
+}
+
+IMUL ( iValue1 iValue2 -- iResult ) 0x68
+{
+ iResult = iValue1 * iValue2;
+}
+
+LMUL ( lValue1 lValue2 -- lResult ) 0x69
+{
+ lResult = lValue1 * lValue2;
+}
+
+FMUL ( fValue1 fValue2 -- fResult ) 0x6a
+{
+ fResult = fValue1 * fValue2;
+}
+
+DMUL ( dValue1 dValue2 -- dResult ) 0x6b
+{
+ dResult = dValue1 * dValue2;
+}
+
+IDIV ( iValue1 iValue2 -- iResult ) 0x6c
+{
+ CHECK_ZERO_DIVISOR(iValue2);
+ ;
+ iResult = iValue1 / iValue2;
+}
+
+IDIVPOW2 ( i1 #ishift -- i2 ) opt
+{
+ u4 sign = i1>>31;
+ s4 offset = sign >> (32-ishift);
+ i2=(i1+offset)>>ishift;
+}
+
+LDIV ( lValue1 lValue2 -- lResult ) 0x6d
+{
+ CHECK_ZERO_DIVISOR(lValue2);
+ ;
+ lResult = lValue1 / lValue2;
+}
+
+LDIVPOW2 ( l1 #ishift -- l2 )
+{
+ u8 sign = l1>>63;
+ s8 offset = sign >> (64-ishift);
+ l2=(l1+offset)>>ishift;
+}
+
+FDIV ( fValue1 fValue2 -- fResult ) 0x6e
+{
+ fResult = fValue1 / fValue2;
+}
+
+DDIV ( dValue1 dValue2 -- dResult ) 0x6f
+{
+ dResult = dValue1 / dValue2;
+}
+
+
+IREM ( iValue1 iValue2 -- iResult ) 0x70
+{
+ CHECK_ZERO_DIVISOR(iValue2);
+ iResult = iValue1 % iValue2;
+}
+
+IREMPOW2 ( i1 #imask -- i2 )
+s4 x = i1;
+if (i1<0)
+ x += imask;
+x &= ~imask;
+i2 = i1-x;
+
+LREM ( lValue1 lValue2 -- lResult ) 0x71
+{
+ CHECK_ZERO_DIVISOR(lValue2);
+ lResult = lValue1 % lValue2;
+}
+
+LREMPOW2 ( l1 #lmask -- l2 )
+s8 x = l1;
+if (l1<0)
+ x += lmask;
+x &= ~lmask;
+l2 = l1-x;
+
+FREM ( fValue1 fValue2 -- fResult ) 0x72
+{
+ fResult = builtin_frem(fValue1, fValue2);
+}
+
+DREM ( dValue1 dValue2 -- dResult ) 0x73
+{
+ dResult = builtin_drem(dValue1, dValue2);
+}
+
+INEG ( iValue -- iResult ) 0x74
+{
+ iResult = -iValue;
+}
+
+LNEG ( lValue -- lResult ) 0x75
+{
+ lResult = -lValue;
+}
+
+FNEG ( fValue -- fResult ) 0x76
+{
+ fResult = -fValue;
+}
+
+DNEG ( dValue -- dResult ) 0x77
+{
+ dResult = -dValue;
+}
+
+ISHL ( iValue1 iValue2 -- iResult ) 0x78
+{
+ iResult = iValue1 << (iValue2 & 31);
+}
+
+LSHL ( lValue1 iValue2 -- lResult ) 0x79
+{
+ lResult = lValue1 << (iValue2 & 63);
+}
+
+ISHR ( iValue1 iValue2 -- iResult ) 0x7a
+{
+ iResult = iValue1 >> (iValue2 & 31);
+}
+
+LSHR ( lValue1 iValue2 -- lResult ) 0x7b
+{
+ lResult = lValue1 >> (iValue2 & 63);
+}
+
+IUSHR ( iValue1 iValue2 -- iResult ) 0x7c
+{
+ iResult = ((unsigned) iValue1) >> (iValue2 & 31);
+}
+
+LUSHR ( lValue1 iValue2 -- lResult ) 0x7d
+{
+ lResult = (unsigned long long) lValue1 >> (iValue2 & 63);
+}
+
+IAND ( iValue1 iValue2 -- iResult ) 0x7e
+{
+ iResult = iValue1 & iValue2;
+}
+
+LAND ( lValue1 lValue2 -- lResult ) 0x7f
+{
+ lResult = lValue1 & lValue2;
+}
+
+IOR ( iValue1 iValue2 -- iResult ) 0x80
+{
+ iResult = iValue1 | iValue2;
+}
+
+LOR ( lValue1 lValue2 -- lResult ) 0x81
+{
+ lResult = lValue1 | lValue2;
+}
+
+IXOR ( iValue1 iValue2 -- iResult ) 0x82
+{
+ iResult = iValue1 ^ iValue2;
+}
+
+LXOR ( lValue1 lValue2 -- lResult ) 0x83
+{
+ lResult = lValue1 ^ lValue2;
+}
+
+IINC ( #bIndex #iConst -- ) 0x84
+{
+ access_local_int((unsigned)bIndex) =
+ access_local_int((unsigned)bIndex) + iConst;
+}
+
+I2L ( iValue -- lValue ) 0x85
+{
+ lValue = iValue;
+}
+
+I2F ( iValue -- fValue ) 0x86
+{
+ fValue = (float) iValue;
+}
+
+I2D ( iValue -- dValue ) 0x87
+{
+ dValue = (double) iValue;
+}
+
+L2I ( lValue -- iValue ) 0x88
+{
+ iValue = lValue;
+}
+
+L2F ( lValue -- fValue ) 0x89
+{
+ fValue = (float) lValue;
+}
+
+L2D ( lValue -- dValue ) 0x8a
+{
+ dValue = (double) lValue;
+}
+
+F2I ( fValue -- iValue ) 0x8b
+{
+ iValue = builtin_f2i(fValue);
+}
+
+F2L ( fValue -- lValue ) 0x8c
+{
+ lValue = builtin_f2l(fValue);
+}
+
+F2D ( fValue -- dValue ) 0x8d
+{
+ dValue = fValue;
+}
+
+D2I ( dValue -- iValue ) 0x8e
+{
+ iValue = builtin_d2i(dValue);
+}
+
+D2L ( dValue -- lValue ) 0x8f
+{
+ lValue = builtin_d2l(dValue);
+}
+
+D2F ( dValue -- fValue ) 0x90
+{
+ fValue = dValue;
+}
+
+INT2BYTE ( iValue -- iResult ) 0x91
+{
+ iResult = (iValue << 24) >> 24; /* XXX: try "(s1)iValue" */
+}
+
+
+INT2CHAR ( iValue -- iResult ) 0x92
+{
+ iResult = iValue & 0xFFFF;
+}
+
+INT2SHORT ( iValue -- iResult ) 0x93
+{
+ iResult = (iValue << 16) >> 16; /* XXX: try "(s2)iValue" */
+}
+
+LCMP ( lValue1 lValue2 -- iResult ) 0x94
+{
+ iResult = lValue1 < lValue2 ? -1 : lValue1 > lValue2 ? 1 : 0;
+}
+
+FCMPL ( fValue1 fValue2 -- iResult ) 0x95
+{
+ iResult = builtin_fcmpl(fValue1, fValue2);
+}
+
+FCMPG ( fValue1 fValue2 -- iResult ) 0x96
+{
+ iResult = builtin_fcmpg(fValue1, fValue2);
+}
+
+DCMPL ( dValue1 dValue2 -- iResult ) 0x97
+{
+ iResult = builtin_dcmpl(dValue1, dValue2);
+}
+
+DCMPG ( dValue1 dValue2 -- iResult ) 0x98
+{
+ iResult = builtin_dcmpg(dValue1, dValue2);
+}
+
+IFEQ ( #ainstTarget iValue -- ) 0x99
+{
+ if ( iValue == 0 ) {
+ SET_IP(ainstTarget); INST_TAIL;
+ }
+}
+
+IFNE ( #ainstTarget iValue -- ) 0x9a
+{
+ if ( iValue != 0 ) {
+ SET_IP(ainstTarget); INST_TAIL;
+ }
+}
+
+IFLT ( #ainstTarget iValue -- ) 0x9b
+{
+ if ( iValue < 0 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IFGE ( #ainstTarget iValue -- ) 0x9c
+{
+ if ( iValue >= 0 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IFGT ( #ainstTarget iValue -- ) 0x9d
+{
+ if ( iValue > 0 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IFLE ( #ainstTarget iValue -- ) 0x9e
+{
+ if ( iValue <= 0 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ICMPEQ ( #ainstTarget iValue1 iValue2 -- ) 0x9f
+{
+ if ( iValue1 == iValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ICMPNE ( #ainstTarget iValue1 iValue2 -- ) 0xa0
+{
+ if ( iValue1 != iValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ICMPLT ( #ainstTarget iValue1 iValue2 -- ) 0xa1
+{
+ if ( iValue1 < iValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ICMPGE ( #ainstTarget iValue1 iValue2 -- ) 0xa2
+{
+ if ( iValue1 >= iValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ICMPGT ( #ainstTarget iValue1 iValue2 -- ) 0xa3
+{
+ if ( iValue1 > iValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ICMPLE ( #ainstTarget iValue1 iValue2 -- ) 0xa4
+{
+ if ( iValue1 <= iValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_LCMPEQ ( #ainstTarget lValue1 lValue2 -- ) opt
+{
+ if ( lValue1 == lValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_LCMPNE ( #ainstTarget lValue1 lValue2 -- ) opt
+{
+ if ( lValue1 != lValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_LCMPLT ( #ainstTarget lValue1 lValue2 -- ) opt
+{
+ if ( lValue1 < lValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_LCMPGE ( #ainstTarget lValue1 lValue2 -- ) opt
+{
+ if ( lValue1 >= lValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_LCMPGT ( #ainstTarget lValue1 lValue2 -- ) opt
+{
+ if ( lValue1 > lValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_LCMPLE ( #ainstTarget lValue1 lValue2 -- ) opt
+{
+ if ( lValue1 <= lValue2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ACMPEQ ( #ainstTarget aRef1 aRef2 -- ) 0xa5
+{
+ if ( aRef1 == aRef2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+IF_ACMPNE ( #ainstTarget aRef1 aRef2 -- ) 0xa6
+{
+ if ( aRef1 != aRef2 )
+ SET_IP(ainstTarget); INST_TAIL;
+}
+
+GOTO ( #ainstTarget -- ) 0xa7
+{
+ SET_IP(ainstTarget);
+}
+
+JSR ( #ainstTarget -- ainstRA ) 0xa8
+{
+ /* Warning: The generator already adds 1 to the IP
+ because there is an inline parameter. Thus, instead
+ of writing IP + 1, we write...*/
+ ainstRA = IP;
+ SET_IP(ainstTarget);
+}
+
+RET ( #bIndex -- ) 0xa9
+{
+ Inst * saved_ip;
+ saved_ip = access_local_ref((unsigned) bIndex);
+ SET_IP(saved_ip);
+}
+
+TABLESWITCH ( #iLow #iRange #addrSegment #iOffset #ainstDefault iIndex -- ) 0xaa
+{
+ s4 idx = iIndex - iLow;
+ if ( ((u4) idx) >= iRange ) {
+ SET_IP(ainstDefault); INST_TAIL;
+ }
+ else {
+ SET_IP(((Inst **)(addrSegment+iOffset))[idx]); INST_TAIL;
+ }
+}
+
+LOOKUPSWITCH ( #iNpairs #addrSegment #iOffset #ainstDefault iKey -- ) 0xab
+{
+ /* Note: This code should use a binary search, as
+ the table is sorted. Note also, we reversed the order
+ of the parms */
+ unsigned i;
+ for ( i = 0; i < iNpairs; i++ ) {
+ Cell *table = (Cell *)(addrSegment+iOffset);
+ if ( iKey == (s4)(table[2 * i]) ) {
+ SET_IP((Inst *)(table[2 * i + 1])); INST_TAIL;
+ }
+ }
+ /* falls through if no match */
+ SET_IP(ainstDefault);
+}
+
+
+\ Our stack works like this:
+\ The stack holds locals, the operand stack and the return address stack.
+\ When we invoke a method, the paramaters are the top N elements
+\ on the stack. These become the first N local variables.
+\ Next we have space for the rest of the local variables.
+\ Next comes a single position on the stack which holds
+\ the value of the frame pointer for the calling function.
+\ Another position holds the instruction pointer of the caller.
+\ Finally, we have space for the elements of the operand stack.
+
+\ fp points to the bottom local; since the stack grows downwards, the
+\ upper end of the frame is fp+1, not fp. That's why the sp updates
+\ in the returns look like they are off by one.
+
+\ fp -> local0
+\ local1
+\ ...
+\ oldfp
+\ sp -> oldip ; at the start, empty stack
+\ stack0 ;once there is something on the stack
+\ ...
+
+IRETURN ( #iIndexFP vValue -- vResult ) 0xac
+{
+ Inst *new_ip;
+ new_ip = (Inst *)access_local_cell(iIndexFP + 1);
+ sp = fp;
+ fp = (Cell *)access_local_cell(iIndexFP);
+ vResult = vValue;
+ SET_IP(new_ip);
+}
+
+LRETURN ( #iIndexFP lValue -- lResult ) 0xad
+{
+ Inst *new_ip = (Inst *)access_local_cell(iIndexFP + 1);
+ sp = fp - 1;
+ fp = (Cell *)access_local_cell(iIndexFP);
+ lResult = lValue;
+ SET_IP(new_ip);
+}
+
+RETURN ( #iIndexFP -- ) 0xb1
+{
+ Inst *new_ip;
+ IF_spTOS(sp[0] = spTOS);
+ new_ip = (Inst *)access_local_cell(iIndexFP + 1);
+ sp = fp+1;
+ fp = (Cell *)access_local_cell(iIndexFP);
+ SET_IP(new_ip);
+ IF_spTOS(spTOS = sp[0]);
+}
+
+GETSTATIC_CELL ( #addr #auf -- vResult ) opt
+{
+ vResult = *(Cell *)addr;
+}
+
+GETSTATIC_INT ( #addr #auf -- iResult ) opt
+{
+ iResult = *(s4 *)addr;
+}
+
+GETSTATIC_LONG ( #addr #auf -- lResult ) opt
+{
+ lResult = *((s8 *) addr);
+}
+
+PUTSTATIC_CELL ( #addr #auf vValue -- ) opt
+{
+ *((Cell *) addr) = vValue;
+}
+
+PUTSTATIC_INT ( #addr #auf iValue -- ) opt
+{
+ *((s4 *) addr) = iValue;
+}
+
+PUTSTATIC_LONG ( #addr #auf lValue -- ) opt
+{
+ *((s8 *) addr) = lValue;
+}
+
+GETFIELD_CELL ( #iOffset #auf aRef -- vResult ) opt
+{
+ CHECK_NULL_PTR(aRef);
+ vResult = *((Cell *) (((u1 *)aRef) + iOffset));
+}
+
+GETFIELD_INT ( #iOffset #auf aRef -- iResult ) opt
+{
+ CHECK_NULL_PTR(aRef);
+ iResult = *((s4 *) (((u1 *)aRef) + iOffset));
+}
+
+GETFIELD_LONG ( #iOffset #auf aRef -- lResult ) opt
+{
+ CHECK_NULL_PTR(aRef);
+ lResult = *((s8 *) (((u1 *)aRef) + iOffset));
+}
+
+
+PUTFIELD_CELL ( #iOffset #auf aRef vValue -- ) opt
+{
+ CHECK_NULL_PTR(aRef);
+ *((Cell *) (((u1 *)aRef) + iOffset)) = vValue;
+}
+
+PUTFIELD_INT ( #iOffset #auf aRef iValue -- ) opt
+{
+ CHECK_NULL_PTR(aRef);
+ *((s4 *) (((u1 *)aRef) + iOffset)) = iValue;
+}
+
+PUTFIELD_LONG ( #iOffset #auf aRef lValue -- ) opt
+{
+ CHECK_NULL_PTR(aRef);
+ *((s8 *) (((u1 *)aRef) + iOffset)) = lValue;
+}
+
+\ !! called methods have the number of locals at offset -1.
+\ methods are always called indirectly through the codeptr in the stub
+\ (see createcompilerstub and TRANSLATE).
+
+INVOKEVIRTUAL ( #iOffset #iNargs #aum -- acelloldfp ainstoldip ) 0xd8
+{
+ java_objectheader *aRef = (java_objectheader *)(sp[iNargs + 1]); /* corrected for sp change by vmg */
+ char *v;
+ Inst **stub;
+ Inst *target;
+ CHECK_NULL_PTR(aRef);
+ v = (char *)(aRef->vftbl);
+ stub = *(Inst ***)(v+iOffset);
+ target = *stub;
+ acelloldfp = fp;
+ ainstoldip = IP;
+ fp = sp + 1 + iNargs;
+ sp = fp - MAXLOCALS(stub) - 1;
+ SET_IP(target);
+}
+
+INVOKESTATIC ( #aaTarget #iNargs #aum -- acelloldfp ainstoldip ) 0xb8
+/* an indirect pointer to target is passed to avoid references to uncompiled code */
+{
+ Inst *target = *aaTarget;
+ acelloldfp = fp;
+ ainstoldip = IP;
+ /* sp is already updated by the generator, so we have to compensate for that */
+ fp = sp + 1 + iNargs; /* !! scale nargs at translation time */
+ sp = fp - MAXLOCALS(aaTarget) - 1;
+ SET_IP(target);
+}
+
+INVOKESPECIAL ( #aaTarget #iNargs #aum -- acelloldfp ainstoldip ) 0xb7
+/* an indirect pointer to target is passed to avoid references to uncompiled code */
+{
+ java_objectheader *aRef = (java_objectheader *)(sp[iNargs + 1]); /* corrected for sp change by vmg */
+ Inst *target = *aaTarget;
+ CHECK_NULL_PTR(aRef);
+ acelloldfp = fp;
+ ainstoldip = IP;
+ /* sp is already updated by the generator, so we have to compensate for that */
+ fp = sp + 1 + iNargs; /* !! scale nargs at translation time */
+ sp = fp - MAXLOCALS(aaTarget) - 1;
+ SET_IP(target);
+}
+
+INVOKEINTERFACE ( #iInterfaceOffset #iOffset #iNargs #aum -- acelloldfp ainstoldip ) 0xd8
+{
+ java_objectheader *aRef;
+ char *v, *t;
+ Inst **stub;
+ Inst *target;
+ ;
+ aRef = (java_objectheader *)sp[iNargs + 1];
+ CHECK_NULL_PTR(aRef);
+ v = (char *)(aRef->vftbl);
+ t = *(char **)(v + iInterfaceOffset);
+ stub = *(Inst ***)(t+iOffset);
+ target = *stub;
+ acelloldfp = fp;
+ ainstoldip = IP;
+ fp = sp + 1 + iNargs;
+ sp = fp - MAXLOCALS(stub) - 1;
+ SET_IP(target);
+}
+
+\ the BUILTIN functions like NEW get their parameters on the stack
+\ instead of through immediate arguments.
+
+NEW ( aClass -- aRef ) 0xbb
+{
+ /* fprintf(stderr,"new: class %lx, class-state=%d\n",(long)aClass,((Hjava_lang_Class*)aClass)->state); */
+ global_sp=sp;
+ aRef = builtin_new((classinfo *)aClass);
+ CLEAR_global_sp;
+}
+
+\ !! use a macro
+
+NEWARRAY_BOOLEAN ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_boolean(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_CHAR ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_char(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_FLOAT ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_float(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_DOUBLE ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_double(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_BYTE ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_byte(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_SHORT ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_short(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_INT ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_int(iSize);
+CLEAR_global_sp;
+
+NEWARRAY_LONG ( iSize -- aArray )
+global_sp=sp;
+aArray = (java_arrayheader *)builtin_newarray_long(iSize);
+CLEAR_global_sp;
+
+NEWARRAY ( iSize avftbl -- aArray ) 0xbd
+{
+ global_sp=sp;
+ aArray = (java_arrayheader *)builtin_newarray(iSize, (vftbl_t *)avftbl);
+ CLEAR_global_sp;
+}
+
+ARRAYLENGTH ( aArray -- iResult ) 0xbe
+{
+ CHECK_NULL_PTR(aArray);
+ iResult = length_array(aArray);
+}
+
+ATHROW ( aRef -- aRef1 ) 0xbf
+{
+ Cell *new_sp, *new_fp;
+ Inst *new_ip;
+ CHECK_NULL_PTR(aRef);
+ goto athrow;
+throw:
+ CLEAR_global_sp;
+ /* IF_spTOS(sp[0] = spTOS); */
+ aRef = *exceptionptr;
+ *exceptionptr = NULL;
+athrow:
+ new_ip = builtin_throw(IP,aRef,fp,&new_sp,&new_fp);
+ if (new_ip==NULL) {
+ /* !! sp = new_sp; ? */
+ IF_spTOS(sp[0] = spTOS); /* !! correct? even for superinstructions? */
+ global_sp = sp;
+ SUPER_END; /* ATHROW may end a basic block */
+ return aRef;
+ }
+ SET_IP(new_ip);
+ aRef1 = aRef;
+ sp=new_sp-1;
+ fp=new_fp;
+ /* IF_spTOS(spTOS = sp[0]); */
+}
+
+CHECKCAST ( #aClass #acr aRef -- aRef ) 0xc0
+{
+ if (!builtin_checkcast((java_objectheader *)aRef, (classinfo *)aClass))
+ THROW(classcastexception);
+}
+
+ARRAYCHECKCAST ( #avftbl #acr aRef -- aRef ) 0xc0
+{
+ if (!builtin_arraycheckcast(aRef, avftbl))
+ THROW(classcastexception);
+}
+
+INSTANCEOF ( #aClass #acr aRef -- iResult ) 0xc1
+{
+ iResult = builtin_instanceof(aRef, aClass);
+}
+
+ARRAYINSTANCEOF ( aRef avftbl -- iResult ) 0xc1
+{
+ iResult = builtin_arrayinstanceof(aRef, avftbl);
+}
+
+MONITORENTER ( aRef -- ) 0xc2
+{
+#if defined(USE_THREADS)
+ /* CHECK_NULL_PTR(aRef); is now done explicitly */
+ builtin_monitorenter(aRef);
+#endif
+}
+
+MONITOREXIT ( aRef -- ) 0xc3
+{
+#if defined(USE_THREADS)
+ /* CHECK_NULL_PTR(aRef); cannot happen */
+ builtin_monitorexit(aRef);
+#endif
+}
+
+CHECKNULL ( aRef -- aRef ) 0xc3
+{
+ CHECK_NULL_PTR(aRef);
+}
+
+MULTIANEWARRAY ( #avftbl #iSize #acr -- aRef ) 197
+{
+ long dims[iSize];
+ int i;
+ IF_spTOS(sp[0] = spTOS);
+ for (i=0; i<iSize; i++) {
+ dims[i]=sp[iSize-i-1];
+ }
+ global_sp=sp;
+ aRef = (java_objectheader *)builtin_multianewarray(iSize, avftbl, dims);
+ CLEAR_global_sp;
+ sp += iSize;
+ IF_spTOS(spTOS = sp[0]);
+}
+
+IFNULL ( #ainstTarget aRef -- ) 0xc6
+{
+ if ( aRef == NULL ) {
+ SET_IP(ainstTarget); INST_TAIL;
+ }
+}
+
+IFNONNULL ( #ainstTarget aRef -- ) 0xc7
+{
+ if ( aRef != NULL ) {
+ SET_IP(ainstTarget); INST_TAIL;
+ }
+}
+
+\ patchers for stuff that is unknown at compile time (unloaded classes)
+
+PATCHER_GETSTATIC_INT ( #aRef #auf -- )
+global_sp = sp;
+if (!patcher_get_putstatic((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(GETSTATIC_INT);
+SET_IP(IP-3);
+
+PATCHER_GETSTATIC_LONG ( #aRef #auf -- )
+global_sp = sp;
+if (!patcher_get_putstatic((u1 *)(IP-3)))
+ THROW0;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(GETSTATIC_LONG);
+SET_IP(IP-3);
+
+PATCHER_GETSTATIC_CELL ( #aRef #auf -- )
+global_sp = sp;
+if (!patcher_get_putstatic((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(GETSTATIC_CELL);
+SET_IP(IP-3);
+
+PATCHER_PUTSTATIC_INT ( #aRef #auf -- )
+global_sp = sp;
+if (!patcher_get_putstatic((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(PUTSTATIC_INT);
+SET_IP(IP-3);
+
+PATCHER_PUTSTATIC_LONG ( #aRef #auf -- )
+global_sp = sp;
+if (!patcher_get_putstatic((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(PUTSTATIC_LONG);
+SET_IP(IP-3);
+
+PATCHER_PUTSTATIC_CELL ( #aRef #auf -- )
+global_sp = sp;
+if (!patcher_get_putstatic((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(PUTSTATIC_CELL);
+SET_IP(IP-3);
+
+PATCHER_GETFIELD_INT ( #iOffset #auf -- )
+global_sp = sp;
+if (!patcher_get_putfield((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(GETFIELD_INT);
+SET_IP(IP-3);
+
+PATCHER_GETFIELD_LONG ( #iOffset #auf -- )
+global_sp = sp;
+if (!patcher_get_putfield((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(GETFIELD_LONG);
+SET_IP(IP-3);
+
+PATCHER_GETFIELD_CELL ( #iOffset #auf -- )
+global_sp = sp;
+if (!patcher_get_putfield((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(GETFIELD_CELL);
+SET_IP(IP-3);
+
+PATCHER_PUTFIELD_INT ( #iOffset #auf -- )
+global_sp = sp;
+if (!patcher_get_putfield((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(PUTFIELD_INT);
+SET_IP(IP-3);
+
+PATCHER_PUTFIELD_LONG ( #iOffset #auf -- )
+global_sp = sp;
+if (!patcher_get_putfield((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(PUTFIELD_LONG);
+SET_IP(IP-3);
+
+PATCHER_PUTFIELD_CELL ( #iOffset #auf -- )
+global_sp = sp;
+if (!patcher_get_putfield((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(PUTFIELD_CELL);
+SET_IP(IP-3);
+
+NEW1 ( #aClass acrUnused -- aRef ) 0xbb
+{
+ /* fprintf(stderr,"new: class %lx, class-state=%d\n",(long)aClass,((Hjava_lang_Class*)aClass)->state); */
+ global_sp=sp;
+ aRef = builtin_new((classinfo *)aClass);
+ CLEAR_global_sp;
+}
+
+PATCHER_NEW ( #aClass -- )
+/* the unresolved class is in the cell right before this VM instruction;
+ our code generator guarantees thus */
+global_sp = sp;
+if (!patcher_builtin_new((u1 *)(IP-2)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-2] = INST_ADDR(NEW1);
+SET_IP(IP-2);
+
+NEWARRAY1 ( iSize #avftbl avftblUnused -- aRef ) 0xbd
+{
+ global_sp=sp;
+ aRef = (java_objectheader *)builtin_newarray(iSize, (vftbl_t *)avftbl);
+ CLEAR_global_sp;
+}
+
+PATCHER_NEWARRAY ( #avftbl -- )
+/* the unresolved class is in the cell right before this VM instruction;
+ our code generator guarantees thus */
+global_sp = sp;
+if (!patcher_builtin_newarray((u1 *)(IP-2)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-2] = INST_ADDR(NEWARRAY1);
+SET_IP(IP-2);
+
+PATCHER_MULTIANEWARRAY ( #avftbl #iSize #acr -- )
+global_sp = sp;
+if (!patcher_builtin_multianewarray((u1 *)(IP-4)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-4] = INST_ADDR(MULTIANEWARRAY);
+SET_IP(IP-4);
+
+ARRAYINSTANCEOF1 ( aRef #avftbl avftblUnused -- iResult ) 0xc1
+{
+ iResult = builtin_arrayinstanceof(aRef, avftbl);
+}
+
+PATCHER_ARRAYINSTANCEOF ( #avftbl -- )
+/* the unresolved class is in the cell right before this VM instruction;
+ our code generator guarantees thus */
+global_sp = sp;
+if (!patcher_builtin_newarray((u1 *)(IP-2)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-2] = INST_ADDR(ARRAYINSTANCEOF1);
+SET_IP(IP-2);
+
+PATCHER_INVOKESTATIC ( #aaTarget #iNargs #aum -- ) 0xd8
+global_sp = sp;
+if (!patcher_invokestatic_special((u1 *)(IP-4)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-4] = INST_ADDR(INVOKESTATIC);
+SET_IP(IP-4);
+
+PATCHER_INVOKESPECIAL ( #aaTarget #iNargs #aum -- ) 0xd8
+global_sp = sp;
+if (!patcher_invokestatic_special((u1 *)(IP-4)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-4] = INST_ADDR(INVOKESPECIAL);
+SET_IP(IP-4);
+
+PATCHER_INVOKEVIRTUAL ( #iOffset #iNargs #aum -- ) 0xd8
+global_sp = sp;
+if (!patcher_invokevirtual((u1 *)(IP-4)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-4] = INST_ADDR(INVOKEVIRTUAL);
+SET_IP(IP-4);
+
+PATCHER_INVOKEINTERFACE ( #iInterfaceoffset #iOffset #iNargs #aum -- ) 0xd8
+global_sp = sp;
+if (!patcher_invokeinterface((u1 *)(IP-5)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-5] = INST_ADDR(INVOKEINTERFACE);
+SET_IP(IP-5);
+
+PATCHER_CHECKCAST ( #aClass #acr -- ) 0xc
+global_sp = sp;
+if (!patcher_checkcast_instanceof((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(CHECKCAST);
+SET_IP(IP-3);
+
+PATCHER_ARRAYCHECKCAST ( #avftbl #acr -- ) 0xc0
+global_sp = sp;
+if (!patcher_builtin_arraycheckcast((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(ARRAYCHECKCAST);
+SET_IP(IP-3);
+
+PATCHER_INSTANCEOF ( #aClass #acr -- ) 0xc1
+global_sp = sp;
+if (!patcher_checkcast_instanceof((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = INST_ADDR(INSTANCEOF);
+SET_IP(IP-3);
+
+\ CHECKEXCEPTION could be integrated into NEW etc., but that's not as
+\ nice to maintain.
+
+CHECKEXCEPTION ( aRef -- aRef )
+if (aRef==NULL)
+ THROW0;
+
+\ This is stub code for methods that we have not yet translated.
+\ Initially, the code for each method is set to this stub. The
+\ first time the method is called, the code in the stub runs, which
+\ translates the bytecode, and replaces the stub with the threaded code.
+
+TRANSLATE ( #am -- )
+{
+ Inst *codeptr;
+ ;
+ IF_spTOS(sp[0] = spTOS);
+ global_sp = sp;
+ codeptr = (Inst *)jit_compile(am);
+ CLEAR_global_sp;
+ IP[-4] = codeptr;
+ SET_IP(codeptr);
+}
+
+NATIVECALL ( #am #af acelloldfp ainstoldip -- )
+sp = nativecall(af, am, sp);
+IF_spTOS(spTOS = sp[0]);
+fp = acelloldfp;
+SET_IP(ainstoldip);
+
+TRACENATIVECALL ( #am #af acelloldfp ainstoldip -- )
+sp = nativecall(af, am, sp);
+IF_spTOS(spTOS = sp[0]);
+fp = acelloldfp;
+SET_IP(ainstoldip);
+{
+Cell v = spTOS;
+functionptr fp = codegen_findmethod((functionptr)(IP-1));
+methodinfo *m = ((methodinfo **) fp)[-1];
+float f;
+vm_Cell2f(v,f);
+builtin_displaymethodstop(m, (s8)v, f, f);
+}
+
+PATCHER_NATIVECALL ( #am #af -- )
+#if !defined(ENABLE_STATICVM)
+global_sp = sp;
+if (!patcher_resolve_native((u1 *)(IP-3)))
+ THROW0;
+CLEAR_global_sp;
+STORE_ORDER_BARRIER();
+IP[-3] = runverbose ? INST_ADDR(TRACENATIVECALL) : INST_ADDR(NATIVECALL);
+SET_IP(IP-3);
+#else
+assert(false);
+#endif
+
+TRACECALL ( -- )
+functionptr f = codegen_findmethod((functionptr)(IP-1));
+methodinfo *m = ((methodinfo **) f)[-1];
+builtin_trace_args(
+ access_local_cell(0),
+ access_local_cell(1),
+ access_local_cell(2),
+ access_local_cell(3),
+#if TRACE_ARGS_NUM > 4
+ access_local_cell(4),
+ access_local_cell(5),
+#endif
+#if TRACE_ARGS_NUM == 8
+ access_local_cell(6),
+ access_local_cell(7),
+#endif
+ m);
+
+TRACERETURN ( v -- v )
+functionptr fp = codegen_findmethod((functionptr)(IP-1));
+methodinfo *m = ((methodinfo **) fp)[-1];
+float f;
+vm_Cell2f(v,f);
+builtin_displaymethodstop(m, (s8)v, f, f);
+
+TRACELRETURN ( l -- l )
+functionptr fp = codegen_findmethod((functionptr)(IP-1));
+methodinfo *m = ((methodinfo **) fp)[-1];
+Double_Store ds;
+ds.l = l;
+builtin_displaymethodstop(m, l, ds.d, ds.d);
+
+END ( -- )
+IF_spTOS(sp[0] = spTOS);
+global_sp = sp;
+SUPER_END;
+vm_uncount_block(IP); /* undo the count part of SUPER_END,
+ because there is no fallthrough */
+return NULL;
+
+ICONST_ISTORE = ICONST ISTORE