X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Fpatcher.c;h=b7fcccb633ab59b995b90525b61df249ce37ee48;hb=c414f560a7e0b7636a780e6b933e91e441f80503;hp=d4cc235ead539a31a803eb94e46c261ff3c7e6e5;hpb=9c9a05ccb626e70e2affe0dc6edb8561cc17ec5d;p=cacao.git diff --git a/src/vm/jit/x86_64/patcher.c b/src/vm/jit/x86_64/patcher.c index d4cc235ea..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. @@ -30,27 +30,21 @@ #include "vm/types.h" #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/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.hpp" -#include "vm/jit/patcher-common.h" - -#include "vmcore/class.h" -#include "vmcore/field.h" -#include "vmcore/options.h" -#include "vmcore/references.h" -#include "vm/resolve.h" - - -#define PATCH_BACK_ORIGINAL_MCODE \ - do { \ - *((uint16_t *) pr->mpc) = (uint16_t) pr->mcode; \ - } while (0) +#include "vm/jit/patcher-common.hpp" /* patcher_patch_code ********************************************************** @@ -61,9 +55,59 @@ void patcher_patch_code(patchref_t *pr) { - PATCH_BACK_ORIGINAL_MCODE; + *((uint16_t*) pr->mpc) = (uint16_t) pr->mcode; + 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 *************************************** @@ -91,23 +135,23 @@ void patcher_patch_code(patchref_t *pr) bool patcher_resolve_classref_to_classinfo(patchref_t *pr) { - constant_classref *cr; - intptr_t *datap; - classinfo *c; + constant_classref* cr = (constant_classref*) pr->ref; + uintptr_t* datap = (uintptr_t*) pr->datap; - cr = (constant_classref *) pr->ref; - datap = (intptr_t *) pr->datap; + // Resolve the class. + classinfo* c = resolve_classref_eager(cr); - /* get the classinfo */ - - if (!(c = resolve_classref_eager(cr))) + if (c == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; + // Patch the class. + *datap = (uintptr_t) c; - /* patch the classinfo pointer */ + // Synchronize data cache. + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); - *datap = (intptr_t) c; + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -124,25 +168,23 @@ bool patcher_resolve_classref_to_classinfo(patchref_t *pr) bool patcher_resolve_classref_to_vftbl(patchref_t *pr) { - constant_classref *cr; - intptr_t *datap; - classinfo *c; - - /* get stuff from the stack */ - - cr = (constant_classref *) pr->ref; - datap = (intptr_t *) pr->datap; + constant_classref* cr = (constant_classref*) pr->ref; + uintptr_t* datap = (uintptr_t*) pr->datap; - /* get the fieldinfo */ + // Resolve the field. + classinfo* c = resolve_classref_eager(cr); - if (!(c = resolve_classref_eager(cr))) + if (c == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; + // Patch super class' vftbl. + *datap = (uintptr_t) c->vftbl; - /* patch super class' vftbl */ + // Synchronize data cache. + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); - *datap = (intptr_t) c->vftbl; + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -158,31 +200,29 @@ bool patcher_resolve_classref_to_vftbl(patchref_t *pr) bool patcher_resolve_classref_to_flags(patchref_t *pr) { - constant_classref *cr; - int32_t *datap; - classinfo *c; - uint8_t *ra; + constant_classref* cr = (constant_classref*) pr->ref; +/* int32_t* datap = (int32_t*) pr->datap; */ + uint8_t* ra = (uint8_t*) pr->mpc; - cr = (constant_classref *) pr->ref; - datap = (int32_t *) pr->datap; - ra = (uint8_t *) pr->mpc; + // Resolve the field. + classinfo* c = resolve_classref_eager(cr); - /* get the fieldinfo */ - - if (!(c = resolve_classref_eager(cr))) + if (c == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; - - /* if we show disassembly, we have to skip the nop's */ + ra += PATCHER_CALL_SIZE; + ra += PATCH_ALIGNMENT((uintptr_t) ra, 2, sizeof(int32_t)); - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + // Patch class flags. +/* *datap = c->flags; */ + patch_checked_location((int32_t*) (ra + 2), c->flags); - /* patch class flags */ + // Synchronize data cache. +/* md_dcacheflush(datap, sizeof(int32_t)); */ + md_icacheflush(ra + 2, sizeof(int32_t)); -/* *datap = c->flags; */ - *((int32_t *) (ra + 2)) = c->flags; + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -200,29 +240,34 @@ bool patcher_resolve_classref_to_flags(patchref_t *pr) bool patcher_get_putstatic(patchref_t *pr) { - unresolved_field *uf; - intptr_t *datap; - fieldinfo *fi; - - uf = (unresolved_field *) pr->ref; - datap = (intptr_t *) pr->datap; + unresolved_field* uf = (unresolved_field*) pr->ref; + uintptr_t* datap = (uintptr_t*) pr->datap; + uint8_t* ra = (uint8_t*) pr->mpc; - /* get the fieldinfo */ + // Resolve the field. + fieldinfo* fi = resolve_field_eager(uf); - if (!(fi = resolve_field_eager(uf))) + if (fi == NULL) return false; - /* check if the field's class is initialized */ + ra += PATCHER_CALL_SIZE; + // Check if the field's class is initialized/ if (!(fi->clazz->state & CLASS_INITIALIZED)) if (!initialize_class(fi->clazz)) return false; - PATCH_BACK_ORIGINAL_MCODE; + // Patch the field value's address. + *datap = (uintptr_t) fi->value; - /* patch the field value's address */ + if (pr->disp_mb && !(fi->flags & ACC_VOLATILE)) + patch_out_mfence(ra + pr->disp_mb - 2); - *datap = (intptr_t) fi->value; + // Synchronize data cache. + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); + + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -239,49 +284,28 @@ bool patcher_get_putstatic(patchref_t *pr) bool patcher_get_putfield(patchref_t *pr) { - uint8_t *ra; - unresolved_field *uf; - fieldinfo *fi; - uint8_t byte; - - ra = (uint8_t *) pr->mpc; - uf = (unresolved_field *) pr->ref; + uint8_t* pc = (uint8_t*) pr->mpc; + unresolved_field* uf = (unresolved_field*) pr->ref; - /* get the fieldinfo */ + // Resolve the field. + fieldinfo* fi = resolve_field_eager(uf); - if (!(fi = resolve_field_eager(uf))) + if (fi == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; - - /* if we show disassembly, we have to skip the nop's */ - - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; - - /* Patch the field's offset: we check for the field type, because - the instructions have different lengths. */ + pc += PATCHER_CALL_SIZE; - if (IS_INT_LNG_TYPE(fi->type)) { - /* Check for special case: %rsp or %r12 as base register. */ + int disp = -sizeof(int32_t) + pr->patch_align; + patch_checked_location((int32_t*) (pc + disp), fi->offset); - byte = *(ra + 3); + if (pr->disp_mb && !(fi->flags & ACC_VOLATILE)) + patch_out_mfence(pc + pr->disp_mb - 2); - if (byte == 0x24) - *((int32_t *) (ra + 4)) = fi->offset; - else - *((int32_t *) (ra + 3)) = fi->offset; - } - else { - /* Check for special case: %rsp or %r12 as base register. */ + // Synchronize instruction cache. + md_icacheflush(pc, disp + sizeof(int32_t)); - byte = *(ra + 5); - - if (byte == 0x24) - *((int32_t *) (ra + 6)) = fi->offset; - else - *((int32_t *) (ra + 5)) = fi->offset; - } + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -298,50 +322,28 @@ bool patcher_get_putfield(patchref_t *pr) bool patcher_putfieldconst(patchref_t *pr) { - uint8_t *ra; - unresolved_field *uf; - fieldinfo *fi; - uint8_t byte; - - ra = (uint8_t *) pr->mpc; - uf = (unresolved_field *) pr->ref; + uint8_t* pc = (uint8_t*) pr->mpc; + unresolved_field* uf = (unresolved_field*) pr->ref; - /* get the fieldinfo */ + // Resolve the field. + fieldinfo* fi = resolve_field_eager(uf); - if (!(fi = resolve_field_eager(uf))) + if (fi == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; - - /* if we show disassembly, we have to skip the nop's */ - - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; - - /* 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 */ + pc += PATCHER_CALL_SIZE; - byte = *(ra + 12); + int disp = -2*sizeof(int32_t) + pr->patch_align; + patch_checked_location((int32_t*) (pc + disp), fi->offset); - if (byte == 0x94) { - *((uint32_t *) (ra + 14)) = fi->offset; - } - else { - *((uint32_t *) (ra + 13)) = fi->offset; - } - } - else { - /* handle special case when the base register is %r12 */ + if (pr->disp_mb && !(fi->flags & ACC_VOLATILE)) + patch_out_mfence(pc + pr->disp_mb - 2); - byte = *(ra + 2); + // Synchronize instruction cache. + md_icacheflush(pc, disp + sizeof(int32_t)); - if (byte == 0x84) - *((uint32_t *) (ra + 4)) = fi->offset; - else - *((uint32_t *) (ra + 3)) = fi->offset; - } + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -359,25 +361,23 @@ bool patcher_putfieldconst(patchref_t *pr) bool patcher_invokestatic_special(patchref_t *pr) { - unresolved_method *um; - intptr_t *datap; - methodinfo *m; + unresolved_method* um = (unresolved_method*) pr->ref; + uintptr_t* datap = (uintptr_t*) pr->datap; - /* get stuff from the stack */ + // Resolve the method. + methodinfo* m = resolve_method_eager(um); - um = (unresolved_method *) pr->ref; - datap = (intptr_t *) pr->datap; - - /* get the fieldinfo */ - - if (!(m = resolve_method_eager(um))) + if (m == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; + // Patch stubroutine. + *datap = (uintptr_t) m->stubroutine; - /* patch stubroutine */ + // Synchronize data cache. + md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P); - *datap = (intptr_t) m->stubroutine; + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -396,30 +396,26 @@ bool patcher_invokestatic_special(patchref_t *pr) bool patcher_invokevirtual(patchref_t *pr) { - uint8_t *ra; - unresolved_method *um; - methodinfo *m; - - ra = (uint8_t *) pr->mpc; - um = (unresolved_method *) pr->ref; + uint8_t* pc = (uint8_t*) pr->mpc; + unresolved_method* um = (unresolved_method*) pr->ref; - /* get the methodinfo */ + // Resovlve the method. + methodinfo* m = resolve_method_eager(um); - if (!(m = resolve_method_eager(um))) + if (m == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t)); - /* if we show disassembly, we have to skip the nop's */ + // Patch vftbl index. + patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex)); - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + // Synchronize instruction cache. + md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P); - /* patch vftbl index */ - - *((int32_t *) (ra + 3 + 3)) = - (int32_t) (OFFSET(vftbl_t, table[0]) + - sizeof(methodptr) * m->vftblindex); + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -439,37 +435,31 @@ bool patcher_invokevirtual(patchref_t *pr) bool patcher_invokeinterface(patchref_t *pr) { - uint8_t *ra; - unresolved_method *um; - methodinfo *m; - - /* get stuff from the stack */ - - ra = (uint8_t *) pr->mpc; - um = (unresolved_method *) pr->ref; + uint8_t* pc = (uint8_t*) pr->mpc; + unresolved_method* um = (unresolved_method*) pr->ref; - /* get the fieldinfo */ + // Resolve the method. + methodinfo* m = resolve_method_eager(um); - if (!(m = resolve_method_eager(um))) + if (m == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t)); - /* if we show disassembly, we have to skip the nop's */ + // Patch interfacetable index. + patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index)); - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 3 + 7), 3, sizeof(int32_t)); + pc += disp; + // Patch method offset. + int32_t *loc = patch_checked_location((int32_t*) (pc + 3 + 7 + 3), (int32_t) (sizeof(methodptr) * (m - m->clazz->methods))); - /* patch interfacetable index */ + // Synchronize instruction cache. + checked_icache_flush(pc + 6, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P + disp, loc); - *((int32_t *) (ra + 3 + 3)) = - (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr) * m->clazz->index); - - /* patch method offset */ - - *((int32_t *) (ra + 3 + 7 + 3)) = - (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)); + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -490,32 +480,30 @@ bool patcher_invokeinterface(patchref_t *pr) bool patcher_checkcast_interface(patchref_t *pr) { - uint8_t *ra; - constant_classref *cr; - classinfo *c; - - ra = (uint8_t *) pr->mpc; - cr = (constant_classref *) pr->ref; + uint8_t* pc = (uint8_t*) pr->mpc; + constant_classref* cr = (constant_classref*) pr->ref; - /* get the fieldinfo */ + // Resolve the class. + classinfo* c = resolve_classref_eager(cr); - if (!(c = resolve_classref_eager(cr))) + if (c == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t)); - /* if we show disassembly, we have to skip the nop's */ + // Patch super class index. + patch_checked_location((int32_t*) (pc + 10), c->index); - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + 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*))); - /* patch super class index */ + // Synchronize instruction cache. + checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t) + disp, loc); - *((int32_t *) (ra + 7 + 3)) = c->index; - - *((int32_t *) (ra + 7 + 7 + 6 + 8 + 3)) = - (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - - c->index * sizeof(methodptr*)); + // Patch back the original code. + patcher_patch_code(pr); return true; } @@ -535,32 +523,30 @@ bool patcher_checkcast_interface(patchref_t *pr) bool patcher_instanceof_interface(patchref_t *pr) { - uint8_t *ra; - constant_classref *cr; - classinfo *c; - - ra = (uint8_t *) pr->mpc; - cr = (constant_classref *) pr->ref; + uint8_t* pc = (uint8_t*) pr->mpc; + constant_classref* cr = (constant_classref*) pr->ref; - /* get the fieldinfo */ + // Resolve the class. + classinfo* c = resolve_classref_eager(cr); - if (!(c = resolve_classref_eager(cr))) + if (c == NULL) return false; - PATCH_BACK_ORIGINAL_MCODE; - - /* if we show disassembly, we have to skip the nop's */ + pc += PATCHER_CALL_SIZE; + pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t)); - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + // Patch super class index. + patch_checked_location((int32_t*) (pc + 10), c->index); - /* patch super class index */ + 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*))); - *((int32_t *) (ra + 7 + 3)) = c->index; + // Synchronize instruction cache. + checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 3 + sizeof(int32_t) + disp, loc); - *((int32_t *) (ra + 7 + 7 + 6 + 3)) = - (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - - c->index * sizeof(methodptr*)); + // Patch back the original code. + patcher_patch_code(pr); return true; }