PR144 (aligned patchers on x86_64)
[cacao.git] / src / vm / jit / x86_64 / codegen.c
index 61c86520adac4c06c365ecc0f722c52b250af9f2..c28050b843e65de52e5e27e262750b7dee414af4 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/x86_64/codegen.c - machine code generator for x86_64
 
-   Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
+   Copyright (C) 1996-2011
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
@@ -187,6 +187,37 @@ void codegen_emit_epilog(jitdata* jd)
        M_RET;
 }
 
+/**
+ * Generates a memory barrier to be used after volatile writes. It can be
+ * patched out later if the field turns out not to be volatile.
+ */
+void codegen_emit_patchable_barrier(instruction *iptr, codegendata *cd, patchref_t *pr, fieldinfo *fi)
+{
+       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+               /* Align on word boundary */
+               if ((((intptr_t) cd->mcodeptr) & 3) >= 2)
+                       emit_nop(cd, 4 - (((intptr_t) cd->mcodeptr) & 3));
+               /* Displacement for patching out MFENCE */
+               pr->disp_mb = (cd->mcodeptr - cd->mcodebase - pr->mpc);
+       }
+       if (INSTRUCTION_IS_UNRESOLVED(iptr) || fi->flags & ACC_VOLATILE)
+               M_MFENCE;
+}
+
+/**
+ * Ensures that the patched location (an int32_t) is aligned.
+ */
+static void codegen_fixup_alignment(codegendata *cd, patchref_t *pr, u1 *mcodeptr_save)
+{
+       u1 *codeptr = cd->mcodeptr;
+       int disp = PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 0, sizeof(int32_t));
+       memmove(mcodeptr_save + disp, mcodeptr_save, cd->mcodeptr - mcodeptr_save);
+       pr->patch_align += cd->mcodeptr - mcodeptr_save + disp;
+
+       cd->mcodeptr = mcodeptr_save;
+       emit_arbitrary_nop(cd, disp);
+       cd->mcodeptr = codeptr + disp;
+}
 
 /**
  * Generates machine code for one ICMD.
@@ -200,9 +231,11 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
        unresolved_method*  um;
        fieldinfo*          fi;
        unresolved_field*   uf;
+       patchref_t*         pr;
        int32_t             fieldtype;
        int32_t             s1, s2, s3, d;
        int32_t             disp;
+       u1*                 mcodeptr_save;
 
        // Get required compiler data.
        codegendata*  cd = jd->cd;
@@ -1487,9 +1520,11 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
 
 /*                             PROFILE_CYCLE_STOP; */
 
-                               patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
+                               pr = patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
 
 /*                             PROFILE_CYCLE_START; */
+
+                               fi = NULL;              /* Silence compiler warning */
                        }
                        else {
                                fi        = iptr->sx.s23.s3.fmiref->p.field;
@@ -1504,6 +1539,8 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
 
                                        //PROFILE_CYCLE_START;
                                }
+
+                               pr = NULL;              /* Silence compiler warning */
                        }
 
                        /* This approach is much faster than moving the field
@@ -1527,6 +1564,7 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                }
                                break;
                        }
+                       codegen_emit_patchable_barrier(iptr, cd, pr, fi);
                        break;
 
                case ICMD_GETFIELD:   /* ...  ==> ..., value                          */
@@ -1540,14 +1578,19 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
 
 /*                             PROFILE_CYCLE_STOP; */
 
-                               patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+                               pr = patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+                               mcodeptr_save = cd->mcodeptr;
 
 /*                             PROFILE_CYCLE_START; */
+
+                               fi = NULL;              /* Silence compiler warning */
                        }
                        else {
                                fi        = iptr->sx.s23.s3.fmiref->p.field;
                                fieldtype = fi->type;
                                disp      = fi->offset;
+
+                               pr = 0;
                        }
 
                        /* implicit null-pointer check */
@@ -1569,7 +1612,12 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
                                M_DLD32(d, s1, disp);
                                break;
+                       default:
+                               // Silence compiler warning.
+                               d = 0;
                        }
+                       if (pr)
+                               codegen_fixup_alignment(cd, pr, mcodeptr_save);
                        emit_store_dst(jd, iptr, d);
                        break;
 
@@ -1585,14 +1633,19 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
 
 /*                             PROFILE_CYCLE_STOP; */
 
-                               patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+                               pr = patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+                               mcodeptr_save = cd->mcodeptr;
 
 /*                             PROFILE_CYCLE_START; */
+
+                               fi = NULL;              /* Silence compiler warning */
                        } 
                        else {
                                fi        = iptr->sx.s23.s3.fmiref->p.field;
                                fieldtype = fi->type;
                                disp      = fi->offset;
+
+                               pr = NULL;              /* Silence compiler warning */
                        }
 
                        /* implicit null-pointer check */
@@ -1611,6 +1664,9 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                M_DST32(s2, s1, disp);
                                break;
                        }
+                       if (pr)
+                               codegen_fixup_alignment(cd, pr, mcodeptr_save);
+                       codegen_emit_patchable_barrier(iptr, cd, pr, fi);
                        break;
 
                case ICMD_PUTFIELDCONST:  /* ..., objectref, value  ==> ...           */
@@ -1626,14 +1682,19 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
 
 /*                             PROFILE_CYCLE_STOP; */
 
-                               patcher_add_patch_ref(jd, PATCHER_putfieldconst, uf, 0);
+                               pr = patcher_add_patch_ref(jd, PATCHER_putfieldconst, uf, 0);
+                               mcodeptr_save = cd->mcodeptr;
 
 /*                             PROFILE_CYCLE_START; */
+
+                               fi = NULL;              /* Silence compiler warning */
                        } 
                        else {
                                fi        = iptr->sx.s23.s3.fmiref->p.field;
                                fieldtype = fi->type;
                                disp      = fi->offset;
+
+                               pr = NULL;              /* Silence compiler warning */
                        }
 
                        /* implicit null-pointer check */
@@ -1649,10 +1710,15 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                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 */
+                               else {     /* unresolved */
                                        M_LST32(REG_ITMP2, s1, disp);
+                                       pr->patch_align = 4;
+                               }
                                break;
                        }
+                       if (pr)
+                               codegen_fixup_alignment(cd, pr, mcodeptr_save);
+                       codegen_emit_patchable_barrier(iptr, cd, pr, fi);
                        break;
 
 
@@ -1776,6 +1842,7 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                um = iptr->sx.s23.s3.um;
                                patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0);
+                               emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 6, sizeof(int32_t)));
 
                                s1 = 0;
                        }
@@ -1795,6 +1862,7 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                um = iptr->sx.s23.s3.um;
                                patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0);
+                               emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 6, sizeof(int32_t)));
 
                                s1 = 0;
                                s2 = 0;
@@ -1810,6 +1878,8 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                        /* implicit null-pointer check */
                        M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl));
                        M_ALD32(REG_METHODPTR, REG_METHODPTR, s1);
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr))
+                               emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 3, sizeof(int32_t)));
                        M_ALD32(REG_ITMP3, REG_METHODPTR, s2);
                        M_CALL(REG_ITMP3);
                        break;
@@ -1842,6 +1912,8 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                        patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags,
                                                                                  iptr->sx.s23.s3.c.ref, 0);
 
+                                       emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 2, sizeof(int32_t)));
+
                                        M_IMOV_IMM(0, REG_ITMP2);                 /* super->flags */
                                        M_IAND_IMM(ACC_INTERFACE, REG_ITMP2);
                                        emit_label_beq(cd, BRANCH_LABEL_2);
@@ -1861,6 +1933,7 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                                patcher_add_patch_ref(jd, PATCHER_checkcast_interface,
                                                                                          iptr->sx.s23.s3.c.ref,
                                                                                          0);
+                                               emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 10, sizeof(int32_t)));
                                        }
 
                                        M_ILD32(REG_ITMP3,
@@ -1868,6 +1941,8 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                        M_ICMP_IMM32(superindex, REG_ITMP3);
                                        emit_classcast_check(cd, iptr, BRANCH_LE, REG_ITMP3, s1);
 
+                                       if (super == NULL)
+                                               emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 3, sizeof(int32_t)));
                                        M_ALD32(REG_ITMP3, REG_ITMP2, 
                                                        OFFSET(vftbl_t, interfacetable[0]) -
                                                        superindex * sizeof(methodptr*));
@@ -2018,6 +2093,8 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags,
                                                                          iptr->sx.s23.s3.c.ref, 0);
 
+                               emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 2, sizeof(int32_t)));
+
                                M_IMOV_IMM(0, REG_ITMP3);                     /* super->flags */
                                M_IAND_IMM(ACC_INTERFACE, REG_ITMP3);
                                emit_label_beq(cd, BRANCH_LABEL_2);
@@ -2026,6 +2103,7 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                        /* interface instanceof code */
 
                        if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
+                               int nops;
                                if (super != NULL) {
                                        M_TEST(s1);
                                        emit_label_beq(cd, BRANCH_LABEL_3);
@@ -2036,15 +2114,19 @@ void codegen_emit_instruction(jitdata* jd, instruction* iptr)
                                if (super == NULL) {
                                        patcher_add_patch_ref(jd, PATCHER_instanceof_interface,
                                                                                  iptr->sx.s23.s3.c.ref, 0);
+                                       emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 10, sizeof(int32_t)));
                                }
 
                                M_ILD32(REG_ITMP3,
                                                REG_ITMP1, OFFSET(vftbl_t, interfacetablelength));
                                M_ICMP_IMM32(superindex, REG_ITMP3);
 
-                               int a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */;
+                               nops = super == NULL ? PATCH_ALIGNMENT((uintptr_t) (cd->mcodeptr + 6), 3, sizeof(int32_t)) : 0;
+
+                               int a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */ + nops;
 
                                M_BLE(a);
+                               emit_arbitrary_nop(cd, nops);
                                M_ALD32(REG_ITMP1, REG_ITMP1,
                                                OFFSET(vftbl_t, interfacetable[0]) -
                                                superindex * sizeof(methodptr*));