Merged trunk and subtype.
[cacao.git] / src / vm / jit / x86_64 / codegen.c
index 07c71c78ad6a20438392ca18a70b239765b9ca2a..dc42a9a966075f1b9cb7a297edadb8102c9785d2 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/x86_64/codegen.c - machine code generator for x86_64
 
-   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
 
 #include "mm/memory.h"
 
-#include "native/jni.h"
 #include "native/localref.h"
 #include "native/native.h"
 
 #include "threads/lock-common.h"
 
-#include "vm/builtin.h"
-#include "vm/exceptions.h"
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
 #include "vm/global.h"
-#include "vm/stringlocal.h"
-#include "vm/vm.h"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/statistics.h"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
 
 #include "vm/jit/abi.h"
 #include "vm/jit/asmpart.h"
-#include "vm/jit/code.h"
-#include "vm/jit/codegen-common.h"
+#include "vm/jit/code.hpp"
+#include "vm/jit/codegen-common.hpp"
 #include "vm/jit/dseg.h"
-#include "vm/jit/emit-common.h"
-#include "vm/jit/jit.h"
+#include "vm/jit/emit-common.hpp"
+#include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.h"
 #include "vm/jit/methodheader.h"
 #include "vm/jit/parse.h"
-#include "vm/jit/patcher-common.h"
+#include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
-#include "vm/jit/replace.h"
-#include "vm/jit/stacktrace.h"
+#include "vm/jit/replace.hpp"
+#include "vm/jit/stacktrace.hpp"
 #include "vm/jit/trap.h"
 
 #if defined(ENABLE_LSRA)
 # include "vm/jit/allocator/lsra.h"
 #endif
 
-#include "vmcore/loader.h"
-#include "vmcore/options.h"
-#include "vmcore/statistics.h"
-
 
 /* codegen_emit ****************************************************************
 
@@ -1888,8 +1885,8 @@ bool codegen_emit(jitdata *jd)
                                if (IS_IMM32(iptr->sx.s23.s2.constval))
                                        M_LST_IMM32(iptr->sx.s23.s2.constval, REG_ITMP1, 0);
                                else {
-                                       M_IST_IMM(iptr->sx.s23.s2.constval, REG_ITMP1, 0);
-                                       M_IST_IMM(iptr->sx.s23.s2.constval >> 32, REG_ITMP1, 4);
+                                       M_MOV_IMM(iptr->sx.s23.s2.constval, REG_ITMP2);
+                                       M_LST(REG_ITMP2, REG_ITMP1, 0);
                                }
                                break;
                        }
@@ -2011,9 +2008,12 @@ bool codegen_emit(jitdata *jd)
                        case TYPE_LNG:
                        case TYPE_ADR:
                        case TYPE_DBL:
-                               /* XXX why no check for IS_IMM32? */
-                               M_IST32_IMM(iptr->sx.s23.s2.constval, s1, disp);
-                               M_IST32_IMM(iptr->sx.s23.s2.constval >> 32, s1, disp + 4);
+                               /* XXX why no check for IS_IMM32? -- probably because of the patcher */
+                               M_MOV_IMM(iptr->sx.s23.s2.constval, REG_ITMP2);
+                               if (disp)  /* resolved, disp can never be 0 */
+                                       M_LST(REG_ITMP2, s1, disp);
+                               else       /* unresolved */
+                                       M_LST32(REG_ITMP2, s1, disp);
                                break;
                        }
                        break;
@@ -2486,8 +2486,6 @@ gen_method:
                                classinfo *super;
                                s4         superindex;
 
-                               s4 looptarget;
-
                                if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                        super      = NULL;
                                        superindex = 0;
@@ -2566,67 +2564,45 @@ gen_method:
                                                disp = dseg_add_address(cd, super->vftbl);
                                        }
 
-                                       if (s1 == REG_ITMP1)
-                                               M_AST(REG_ITMP1, REG_SP, -8); /* store in red zone */
-
-                                       M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
-                                       M_ALD(REG_ITMP2, RIP, disp);
+                                       M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+                                       M_ALD(REG_ITMP3, RIP, disp);
 
                                        if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
-                                       M_ALD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_offset));
-
-                                       *(cd->mcodeptr++) = 0x4e;
-                                       *(cd->mcodeptr++) = 0x3b;
-                                       *(cd->mcodeptr++) = 0x14;
-                                       *(cd->mcodeptr++) = 0x18;
-                                       /* cmp (ITMP1, ITMP3, 1), ITMP2 */
-
-                                       emit_label_beq(cd, BRANCH_LABEL_6); /* good */
-
-                                       M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP3);
-                                       emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
-
-                                       /* use red zone */
-                                       M_AST(REG_ITMP2, REG_SP, -16);
-                                       M_AST_IMM32(0, REG_SP, -24);
-                                       M_ALD(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, subtype_overflow));
-                                       looptarget = cd->mcodeptr - cd->mcodebase;
-
-                                       M_ALD(REG_ITMP2, REG_SP, -24);
-                                       M_ICMP_MEMBASE(REG_ITMP1, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP2);
-
-                                       emit_classcast_check(cd, iptr, BRANCH_GE, REG_ITMP3, s1);
-
-                                       *(cd->mcodeptr++) = 0x4f;
-                                       *(cd->mcodeptr++) = 0x8b;
-                                       *(cd->mcodeptr++) = 0x14;
-                                       *(cd->mcodeptr++) = 0xd3;
-                                       /* movq (ITMP3, ITMP2, 8), ITMP2 */
-
-                                       M_LCMP_MEMBASE(REG_SP, -16, REG_ITMP2);
-                                       emit_label_beq(cd, BRANCH_LABEL_7); /* good, pop */
-
-                                       M_LINC_MEMBASE(REG_SP, -24);
-                                       M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
-
-                                       emit_label(cd, BRANCH_LABEL_7);
-
-                                       emit_label(cd, BRANCH_LABEL_6);
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                               M_LCMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+                                               emit_label_beq(cd, BRANCH_LABEL_6);  /* good */
+
+                                               if (super == NULL) {
+                                                       M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                                       emit_label_bne(cd, BRANCH_LABEL_10);  /* throw */
+                                               }
+
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                               M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+                                               emit_label_bgt(cd, BRANCH_LABEL_9);  /* throw */
+
+                                               M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                               M_LCMP_MEMINDEX(REG_ITMP2, -8*DISPLAY_SIZE, REG_ITMP1, 3, REG_ITMP3);
+                                               emit_label_beq(cd, BRANCH_LABEL_7);  /* good */
+
+                                               emit_label(cd, BRANCH_LABEL_9);
+                                               if (super == NULL)
+                                                       emit_label(cd, BRANCH_LABEL_10);
+
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                               M_ALD_MEM(s1, TRAP_ClassCastException);
+
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                               emit_label(cd, BRANCH_LABEL_6);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
                                        }
                                        else {
-                                               assert(super->vftbl->subtype_offset < 0x80);
-                                               *(cd->mcodeptr++) = 0x4c;
-                                               *(cd->mcodeptr++) = 0x3b;
-                                               *(cd->mcodeptr++) = 0x50;
-                                               *(cd->mcodeptr++) = super->vftbl->subtype_offset;
-                                               /* cmp off(ITMP1), ITMP2 */
-
+                                               M_LCMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
                                                emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
                                        }
 
-                                       if (s1 == REG_ITMP1)
-                                               M_ALD(REG_ITMP1, REG_SP, -8);
-
                                        if (super != NULL)
                                                emit_label(cd, BRANCH_LABEL_5);
                                }
@@ -2678,8 +2654,6 @@ gen_method:
                        classinfo *super;
                        s4         superindex;
 
-                       s4 looptarget;
-
                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                super      = NULL;
                                superindex = 0;
@@ -2767,69 +2741,54 @@ gen_method:
                                        disp = dseg_add_address(cd, super->vftbl);
                                }
 
-                               M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
-                               M_ALD(REG_ITMP2, RIP, disp);
+                               M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+                               M_ALD(REG_ITMP3, RIP, disp);
 
                                if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
-                               M_ALD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_offset));
-
-                               *(cd->mcodeptr++) = 0x4e;
-                               *(cd->mcodeptr++) = 0x3b;
-                               *(cd->mcodeptr++) = 0x14;
-                               *(cd->mcodeptr++) = 0x18;
-                               /* cmp (ITMP1, ITMP3, 1), ITMP2 */
-
-                               emit_label_bne(cd, BRANCH_LABEL_6);
-                               M_LINC(d);
-                               emit_label_br(cd, BRANCH_LABEL_7); /* ende */
-
-                               emit_label(cd, BRANCH_LABEL_6);
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                       M_LCMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+                                       emit_label_bne(cd, BRANCH_LABEL_8); /* jump over INC/SETE */
+                                       if (d == REG_ITMP2) {
+                                               M_SETE(d);
+                                               M_BSEXT(d, d);
+                                       } else
+                                               M_LINC(d);
+                                       emit_label_br(cd, BRANCH_LABEL_6);  /* true */
+                                       emit_label(cd, BRANCH_LABEL_8);
 
-                               M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP3);
-                               emit_label_bne(cd, BRANCH_LABEL_6); /* ende */
-
-                               /* use the red zone */
-                               M_AST(REG_ITMP2, REG_SP, -16);
-                               M_AST_IMM32(0, REG_SP, -24);
-                               M_ALD(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, subtype_overflow));
-                               looptarget = cd->mcodeptr - cd->mcodebase;
-
-                               M_ALD(REG_ITMP2, REG_SP, -24);
-                               M_ICMP_MEMBASE(REG_ITMP1, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP2);
-                               emit_label_bge(cd, BRANCH_LABEL_8); /* ende pop */
+                                       if (super == NULL) {
+                                               M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                               emit_label_bne(cd, BRANCH_LABEL_10);  /* false */
+                                       }
 
-                               *(cd->mcodeptr++) = 0x4f;
-                               *(cd->mcodeptr++) = 0x8b;
-                               *(cd->mcodeptr++) = 0x14;
-                               *(cd->mcodeptr++) = 0xd3;
-                               /* movq (ITMP3, ITMP2, 8), ITMP2 */
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                       M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+                                       emit_label_bgt(cd, BRANCH_LABEL_9);  /* false */
 
-                               M_LCMP_MEMBASE(REG_SP, -16, REG_ITMP2);
-                               emit_label_bne(cd, BRANCH_LABEL_9);
-                               M_LINC(d);
-                               emit_label_br(cd, BRANCH_LABEL_10); /* ende pop */
-                               emit_label(cd, BRANCH_LABEL_9);
+                                       M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                       M_LCMP_MEMINDEX(REG_ITMP2, -8*DISPLAY_SIZE, REG_ITMP1, 3, REG_ITMP3);
+                                       M_SETE(d);
+                                       if (d == REG_ITMP2) {
+                                               M_BSEXT(d, d);
 
-                               M_LINC_MEMBASE(REG_SP, -24);
-                               M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
+                                               emit_label_br(cd, BRANCH_LABEL_7); /* jump over M_CLR */
+                                       }
 
-                               emit_label(cd, BRANCH_LABEL_8);
-                               emit_label(cd, BRANCH_LABEL_10);
+                                       emit_label(cd, BRANCH_LABEL_9);
+                                       if (super == NULL)
+                                               emit_label(cd, BRANCH_LABEL_10);
+                                       if (d == REG_ITMP2) {
+                                               M_CLR(d);
 
-                               emit_label(cd, BRANCH_LABEL_6);
-                               emit_label(cd, BRANCH_LABEL_7);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                       }
+                                       emit_label(cd, BRANCH_LABEL_6);
                                }
                                else {
-                                       assert(super->vftbl->subtype_offset < 0x80);
-                                       *(cd->mcodeptr++) = 0x4c;
-                                       *(cd->mcodeptr++) = 0x3b;
-                                       *(cd->mcodeptr++) = 0x50;
-                                       *(cd->mcodeptr++) = super->vftbl->subtype_offset;
-                                       /* cmp off(ITMP1), ITMP2 */
-
-                                       emit_label_bne(cd, BRANCH_LABEL_6);
-                                       M_LINC(d);
-                                       emit_label(cd, BRANCH_LABEL_6);
+                                       M_LCMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+                                       M_SETE(d);
+                                       if (d == REG_ITMP2)
+                                               M_BSEXT(d, d);
                                }
 
                                if (super != NULL)
@@ -3115,7 +3074,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s
 
                /* put env into first argument register */
 
-               M_MOV_IMM(_Jv_env, REG_A0);
+               M_MOV_IMM(VM_get_jnienv(), REG_A0);
        }
 
        /* Call the native function. */
@@ -3130,6 +3089,20 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s
        case TYPE_INT:
        case TYPE_LNG:
        case TYPE_ADR:
+               switch (md->returntype.primitivetype) {
+               case PRIMITIVETYPE_BOOLEAN:
+                       M_BZEXT(REG_RESULT, REG_RESULT);
+                       break;
+               case PRIMITIVETYPE_BYTE:
+                       M_BSEXT(REG_RESULT, REG_RESULT);
+                       break;
+               case PRIMITIVETYPE_CHAR:
+                       M_CZEXT(REG_RESULT, REG_RESULT);
+                       break;
+               case PRIMITIVETYPE_SHORT:
+                       M_SSEXT(REG_RESULT, REG_RESULT);
+                       break;
+               }
                M_LST(REG_RESULT, REG_SP, 0 * 8);
                break;
        case TYPE_FLT: