X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Fpatcher.c;h=2d394fff212ef8392a6c6dd7c30878fab9f9af03;hb=67702ed5605e84f33724aeee9ccf5f82ea774084;hp=2ab929aaf413c546d722f315c9e416adf84140df;hpb=b76e356b0af200d2568e6fc55e82e233f1808eb9;p=cacao.git diff --git a/src/vm/jit/x86_64/patcher.c b/src/vm/jit/x86_64/patcher.c index 2ab929aaf..2d394fff2 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-2005, 2006, 2007, 2008, 2009, 2010 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -30,29 +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/exceptions.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 "vm/jit/stacktrace.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 ********************************************************** @@ -63,9 +55,44 @@ 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); +} + +/** + * 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 *************************************** @@ -93,23 +120,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; - - 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 classinfo */ + // Resolve the class. + classinfo* c = resolve_classref_eager(cr); - 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; } @@ -126,25 +153,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; + constant_classref* cr = (constant_classref*) pr->ref; + uintptr_t* datap = (uintptr_t*) pr->datap; - /* get stuff from the stack */ + // Resolve the field. + classinfo* c = resolve_classref_eager(cr); - cr = (constant_classref *) pr->ref; - datap = (intptr_t *) pr->datap; - - /* get the fieldinfo */ - - 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; } @@ -160,31 +185,28 @@ 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; - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + // Patch class flags. +/* *datap = c->flags; */ + *((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; } @@ -202,29 +224,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; } @@ -241,50 +268,43 @@ 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; + // 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. */ - - byte = *(ra + 3); - - if (byte == 0x24) - *((int32_t *) (ra + 4)) = fi->offset; + // Check for special case: %rsp or %r12 as base register. + if (pc[3] == 0x24) + *((int32_t*) (pc + 4)) = fi->offset; else - *((int32_t *) (ra + 3)) = fi->offset; + *((int32_t*) (pc + 3)) = fi->offset; } else { - /* Check for special case: %rsp or %r12 as base register. */ - - byte = *(ra + 5); - - if (byte == 0x24) - *((int32_t *) (ra + 6)) = fi->offset; + // Check for special case: %rsp or %r12 as base register. + if (pc[5] == 0x24) + *((int32_t*) (pc + 6)) = fi->offset; else - *((int32_t *) (ra + 5)) = fi->offset; + *((int32_t*) (pc + 5)) = 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)); + + // Patch back the original code. + patcher_patch_code(pr); + return true; } @@ -300,53 +320,42 @@ 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 */ + pc += 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 */ - - byte = *(ra + 2); - - if (byte == 0x84) { - *((uint32_t *) (ra + 4)) = fi->offset; - *((uint32_t *) (ra + 12 + 4)) = fi->offset + 4; - } - else { - *((uint32_t *) (ra + 3)) = fi->offset; - *((uint32_t *) (ra + 11 + 3)) = fi->offset + 4; - } + // 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 */ - - byte = *(ra + 2); - - if (byte == 0x84) - *((uint32_t *) (ra + 4)) = fi->offset; + // Handle special case when the base register is %r12. + if (pc[2] == 0x84) + *((uint32_t*) (pc + 4)) = fi->offset; else - *((uint32_t *) (ra + 3)) = fi->offset; + *((uint32_t*) (pc + 3)) = 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)); + + // Patch back the original code. + patcher_patch_code(pr); + return true; } @@ -363,25 +372,23 @@ bool patcher_putfieldconst(patchref_t *pr) bool patcher_invokestatic_special(patchref_t *pr) { - unresolved_method *um; - intptr_t *datap; - methodinfo *m; - - /* get stuff from the stack */ + unresolved_method* um = (unresolved_method*) pr->ref; + uintptr_t* datap = (uintptr_t*) pr->datap; - um = (unresolved_method *) pr->ref; - datap = (intptr_t *) pr->datap; + // Resolve the method. + methodinfo* m = resolve_method_eager(um); - /* 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; } @@ -400,30 +407,25 @@ 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; - /* if we show disassembly, we have to skip the nop's */ + // Patch vftbl index. + *((int32_t*) (pc + 3 + 3)) = (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; } @@ -443,37 +445,28 @@ 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; - /* if we show disassembly, we have to skip the nop's */ + // Patch interfacetable index. + *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index); - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + // Patch method offset. + *((int32_t*) (pc + 3 + 7 + 3)) = (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)); - /* patch interfacetable index */ + // Synchronize instruction cache. + md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P); - *((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; } @@ -494,32 +487,27 @@ 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; - /* if we show disassembly, we have to skip the nop's */ + // Patch super class index. + *((int32_t*) (pc + 7 + 3)) = c->index; - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + *((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. + md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t)); - *((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; } @@ -539,32 +527,27 @@ 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; - if (opt_shownops) - ra = ra + PATCHER_CALL_SIZE; + // Patch super class index. + *((int32_t*) (pc + 7 + 3)) = c->index; - /* patch super class index */ + *((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. + md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 3 + sizeof(int32_t)); - *((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; }