X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Fpatcher.c;h=b7fcccb633ab59b995b90525b61df249ce37ee48;hb=c414f560a7e0b7636a780e6b933e91e441f80503;hp=976cdcdac93716423d31ed8942d83c7986c9e9b7;hpb=45da15062404c21c3ab5cef99a8facc3c5ff7034;p=cacao.git diff --git a/src/vm/jit/x86_64/patcher.c b/src/vm/jit/x86_64/patcher.c index 976cdcdac..b7fcccb63 100644 --- a/src/vm/jit/x86_64/patcher.c +++ b/src/vm/jit/x86_64/patcher.c @@ -1,6 +1,6 @@ /* src/vm/jit/x86_64/patcher.c - x86_64 code patching functions - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2011 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -32,24 +32,19 @@ #include "vm/jit/x86_64/codegen.h" #include "vm/jit/x86_64/md.h" -#include "mm/memory.h" +#include "mm/memory.hpp" -#include "native/native.h" +#include "native/native.hpp" -#include "vm/builtin.h" -#include "vm/class.h" -#include "vm/field.h" -#include "vm/initialize.h" +#include "vm/jit/builtin.hpp" +#include "vm/class.hpp" +#include "vm/field.hpp" +#include "vm/initialize.hpp" #include "vm/options.h" #include "vm/references.h" -#include "vm/resolve.h" +#include "vm/resolve.hpp" -#include "vm/jit/patcher-common.h" - - -#define PATCH_BACK_ORIGINAL_MCODE \ - do { \ - } while (0) +#include "vm/jit/patcher-common.hpp" /* patcher_patch_code ********************************************************** @@ -64,6 +59,55 @@ void patcher_patch_code(patchref_t *pr) md_icacheflush((void*) pr->mpc, PATCHER_CALL_SIZE); } +static int32_t *patch_checked_location(int32_t *p, int32_t val) +{ + assert(*p == 0); + // verify that it's aligned + assert((((uintptr_t) p) & (4-1)) == 0); + *p = val; + return p; +} + +static void checked_icache_flush(int32_t *addr, int nbytes, int32_t *check_loc) +{ + assert((int8_t*) addr + nbytes - sizeof(int32_t) >= (int8_t*) check_loc); + md_icacheflush(addr, nbytes); +} + +/** + * Check if the trap instruction at the given PC is valid. + * + * @param pc Program counter. + * + * @return true if valid, false otherwise. + */ +bool patcher_is_valid_trap_instruction_at(void* pc) +{ + uint16_t mcode = *((uint16_t*) pc); + + // Check for the undefined instruction we use. + return (mcode == 0x0b0f); +} + +/** + * Overwrites the MFENCE instruction at the indicated address with a 3-byte + * NOP. The MFENCE instruction is not allowed to cross a (4-byte) word + * boundary. + * + * @param pc Program counter. + */ +static void patch_out_mfence(void *pc) +{ + uint32_t *p = (uint32_t*) (((uintptr_t) pc) & ~3); + + assert((((uintptr_t) pc) & 3) < 2); + if (((uintptr_t) pc) & 1) + *p = (*p & 0x000000ff) | 0x001f0f00; + else + *p = (*p & 0xff000000) | 0x00001f0f; + + md_icacheflush(p, 4); +} /* patcher_resolve_classref_to_classinfo *************************************** @@ -104,7 +148,7 @@ bool patcher_resolve_classref_to_classinfo(patchref_t *pr) *datap = (uintptr_t) c; // Synchronize data cache. - md_dcacheflush(pr->datap, SIZEOF_VOID_P); + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); // Patch back the original code. patcher_patch_code(pr); @@ -137,7 +181,7 @@ bool patcher_resolve_classref_to_vftbl(patchref_t *pr) *datap = (uintptr_t) c->vftbl; // Synchronize data cache. - md_dcacheflush(pr->datap, SIZEOF_VOID_P); + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); // Patch back the original code. patcher_patch_code(pr); @@ -166,9 +210,12 @@ bool patcher_resolve_classref_to_flags(patchref_t *pr) if (c == NULL) return false; + ra += PATCHER_CALL_SIZE; + ra += PATCH_ALIGNMENT((uintptr_t) ra, 2, sizeof(int32_t)); + // Patch class flags. /* *datap = c->flags; */ - *((int32_t*) (ra + 2)) = c->flags; + patch_checked_location((int32_t*) (ra + 2), c->flags); // Synchronize data cache. /* md_dcacheflush(datap, sizeof(int32_t)); */ @@ -195,6 +242,7 @@ bool patcher_get_putstatic(patchref_t *pr) { unresolved_field* uf = (unresolved_field*) pr->ref; uintptr_t* datap = (uintptr_t*) pr->datap; + uint8_t* ra = (uint8_t*) pr->mpc; // Resolve the field. fieldinfo* fi = resolve_field_eager(uf); @@ -202,6 +250,8 @@ bool patcher_get_putstatic(patchref_t *pr) if (fi == NULL) return false; + ra += PATCHER_CALL_SIZE; + // Check if the field's class is initialized/ if (!(fi->clazz->state & CLASS_INITIALIZED)) if (!initialize_class(fi->clazz)) @@ -210,8 +260,11 @@ bool patcher_get_putstatic(patchref_t *pr) // Patch the field value's address. *datap = (uintptr_t) fi->value; + if (pr->disp_mb && !(fi->flags & ACC_VOLATILE)) + patch_out_mfence(ra + pr->disp_mb - 2); + // Synchronize data cache. - md_dcacheflush(pr->datap, SIZEOF_VOID_P); + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); // Patch back the original code. patcher_patch_code(pr); @@ -240,25 +293,16 @@ bool patcher_get_putfield(patchref_t *pr) if (fi == NULL) return false; - // Patch the field's offset: we check for the field type, because - // the instructions have different lengths. - if (IS_INT_LNG_TYPE(fi->type)) { - // Check for special case: %rsp or %r12 as base register. - if (pc[3] == 0x24) - *((int32_t*) (pc + 4)) = fi->offset; - else - *((int32_t*) (pc + 3)) = fi->offset; - } - else { - // Check for special case: %rsp or %r12 as base register. - if (pc[5] == 0x24) - *((int32_t*) (pc + 6)) = fi->offset; - else - *((int32_t*) (pc + 5)) = fi->offset; - } + pc += PATCHER_CALL_SIZE; + + int disp = -sizeof(int32_t) + pr->patch_align; + patch_checked_location((int32_t*) (pc + disp), fi->offset); + + if (pr->disp_mb && !(fi->flags & ACC_VOLATILE)) + patch_out_mfence(pc + pr->disp_mb - 2); // Synchronize instruction cache. - md_icacheflush(pc, 6 + sizeof(int32_t)); + md_icacheflush(pc, disp + sizeof(int32_t)); // Patch back the original code. patcher_patch_code(pr); @@ -287,24 +331,16 @@ bool patcher_putfieldconst(patchref_t *pr) if (fi == NULL) return false; - // Patch the field's offset. - if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) { - // Handle special case when the base register is %r12. - if (pc[12] == 0x94) - *((uint32_t*) (pc + 14)) = fi->offset; - else - *((uint32_t*) (pc + 13)) = fi->offset; - } - else { - // Handle special case when the base register is %r12. - if (pc[2] == 0x84) - *((uint32_t*) (pc + 4)) = fi->offset; - else - *((uint32_t*) (pc + 3)) = fi->offset; - } + pc += PATCHER_CALL_SIZE; + + int disp = -2*sizeof(int32_t) + pr->patch_align; + patch_checked_location((int32_t*) (pc + disp), fi->offset); + + if (pr->disp_mb && !(fi->flags & ACC_VOLATILE)) + patch_out_mfence(pc + pr->disp_mb - 2); // Synchronize instruction cache. - md_icacheflush(pc, 14 + sizeof(int32_t)); + md_icacheflush(pc, disp + sizeof(int32_t)); // Patch back the original code. patcher_patch_code(pr); @@ -338,7 +374,7 @@ bool patcher_invokestatic_special(patchref_t *pr) *datap = (uintptr_t) m->stubroutine; // Synchronize data cache. - md_dcacheflush(pr->datap, SIZEOF_VOID_P); + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); // Patch back the original code. patcher_patch_code(pr); @@ -369,8 +405,11 @@ bool patcher_invokevirtual(patchref_t *pr) if (m == NULL) return false; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t)); + // Patch vftbl index. - *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex); + patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex)); // Synchronize instruction cache. md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P); @@ -405,14 +444,19 @@ bool patcher_invokeinterface(patchref_t *pr) if (m == NULL) return false; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t)); + // Patch interfacetable index. - *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index); + patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index)); + int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 3 + 7), 3, sizeof(int32_t)); + pc += disp; // Patch method offset. - *((int32_t*) (pc + 3 + 7 + 3)) = (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)); + int32_t *loc = patch_checked_location((int32_t*) (pc + 3 + 7 + 3), (int32_t) (sizeof(methodptr) * (m - m->clazz->methods))); // Synchronize instruction cache. - md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P); + checked_icache_flush(pc + 6, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P + disp, loc); // Patch back the original code. patcher_patch_code(pr); @@ -445,13 +489,18 @@ bool patcher_checkcast_interface(patchref_t *pr) if (c == NULL) return false; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t)); + // Patch super class index. - *((int32_t*) (pc + 7 + 3)) = c->index; + patch_checked_location((int32_t*) (pc + 10), c->index); - *((int32_t*) (pc + 7 + 7 + 6 + 8 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)); + int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 7 + 7 + 6 + 8), 3, sizeof(int32_t)); + pc += disp; + int32_t *loc = patch_checked_location((int32_t*) (pc + 7 + 7 + 6 + 8 + 3), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*))); // Synchronize instruction cache. - md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t)); + checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t) + disp, loc); // Patch back the original code. patcher_patch_code(pr); @@ -483,13 +532,18 @@ bool patcher_instanceof_interface(patchref_t *pr) if (c == NULL) return false; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t)); + // Patch super class index. - *((int32_t*) (pc + 7 + 3)) = c->index; + patch_checked_location((int32_t*) (pc + 10), c->index); - *((int32_t*) (pc + 7 + 7 + 6 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)); + int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 7 + 7 + 6), 3, sizeof(int32_t)); + pc += disp; + int32_t *loc = patch_checked_location((int32_t*) (pc + 7 + 7 + 6 + 3), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*))); // Synchronize instruction cache. - md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 3 + sizeof(int32_t)); + checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 3 + sizeof(int32_t) + disp, loc); // Patch back the original code. patcher_patch_code(pr);