From: Robert Schuster Date: Fri, 27 Jun 2008 11:35:14 +0000 (+0200) Subject: - created jitcache-arm-x86 branch X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=cacao.git;a=commitdiff_plain;h=69d7ab699b50b7e24e74d13ffd9d50e8dc62e8a7 - created jitcache-arm-x86 branch - initial import of the jitcache work to this branch --HG-- branch : jitcache-arm-x86 --- diff --git a/configure.ac b/configure.ac index 45fcc80a7..61b3bffe7 100644 --- a/configure.ac +++ b/configure.ac @@ -306,6 +306,7 @@ AC_CHECK_FUNCS([fopen]) AC_CHECK_FUNCS([fprintf]) AC_CHECK_FUNCS([fread]) AC_CHECK_FUNCS([free]) +AC_CHECK_FUNCS([fseek]) AC_CHECK_FUNCS([fstat]) AC_CHECK_FUNCS([fsync]) AC_CHECK_FUNCS([ftruncate]) @@ -406,6 +407,7 @@ AC_CHECK_ENABLE_STATISTICS AC_CHECK_ENABLE_VERIFIER AC_CHECK_ENABLE_RT_TIMING AC_CHECK_ENABLE_CYCLE_STATS +AC_CHECK_ENABLE_JITCACHE AC_CHECK_ENABLE_JVMTI AC_CHECK_ENABLE_THREADS AC_CHECK_ENABLE_IFCONV diff --git a/m4/jitcache.m4 b/m4/jitcache.m4 new file mode 100644 index 000000000..d873f30bb --- /dev/null +++ b/m4/jitcache.m4 @@ -0,0 +1,40 @@ +dnl m4/jitcache.m4 +dnl +dnl Copyright (C) 2008 +dnl CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO +dnl +dnl This file is part of CACAO. +dnl +dnl This program is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU General Public License as +dnl published by the Free Software Foundation; either version 2, or (at +dnl your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. + + +dnl check for jitcache support +AC_DEFUN([AC_CHECK_ENABLE_JITCACHE],[ +AC_MSG_CHECKING(whether JIT compiler output caching should be enabled) +AC_ARG_ENABLE([jitcache], + [AS_HELP_STRING(--enable-jitcache,enable caching of JIT compiler output [[default=no]])], + [case "${enableval}" in + yes) ENABLE_JITCACHE=yes;; + *) ENABLE_JITCACHE=no;; + esac], + [ENABLE_JITCACHE=no]) +AC_MSG_RESULT(${ENABLE_JITCACHE}) +AM_CONDITIONAL([ENABLE_JITCACHE], test x"${ENABLE_JITCACHE}" = "xyes") + +if test x"${ENABLE_JITCACHE}" = "xyes"; then + AC_DEFINE([ENABLE_JITCACHE], 1, [store and load JIT compiler output]) +fi +]) diff --git a/src/vm/builtin.c b/src/vm/builtin.c index 417aced8f..dab69a171 100644 --- a/src/vm/builtin.c +++ b/src/vm/builtin.c @@ -281,6 +281,81 @@ bool builtin_init(void) } +/* builtintable_get_by_key ***************************************************** + + Returns a key for the given builtintable_entry object which is suitable + for retrieving the instance again by calling builtintable_get_by_key. + + The key can be regarded fixed between multiple runs of the JVM. + +*******************************************************************************/ + +s4 builtintable_get_key(builtintable_entry *bte) +{ + s4 entries; +/* + int i; + entries = sizeof(builtintable_internal) / sizeof(builtintable_entry) - 1; + for (i = 0; i < entries; i++) + if (&builtintable_internal[i] == bte) + return i + 1; + + entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1; + for (i = 0; i < entries; i++) + if (&builtintable_automatic[i] == bte) + return -i; + + entries = sizeof(builtintable_function) / sizeof(builtintable_entry) - 1; + for (i = 0; i < entries; i++) + if (&builtintable_function[i] == bte) + return -1000 - i; +*/ + + entries = sizeof(builtintable_internal) / sizeof(builtintable_entry) - 1; + if (&builtintable_internal[0] <= bte + && &builtintable_internal[entries - 1] >= bte) + { + return (s4) (bte - &builtintable_internal[0]) + 1; + } + + entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1; + if (&builtintable_automatic[0] <= bte + && &builtintable_automatic[entries - 1] >= bte) + { + return -(s4) (bte - &builtintable_automatic[0]); + } + + entries = sizeof(builtintable_function) / sizeof(builtintable_entry) - 1; + if (&builtintable_function[0] <= bte + && &builtintable_function[entries - 1] >= bte) + { + return -1000 - (s4) (bte - &builtintable_function[0]); + } + + /* builtintable_entry is not in our tables. */ + assert (0); + + return 0; +} + +/* builtintable_get_by_key ***************************************************** + + Retrieves an entry in the internal and automatic builtin functions tables + using a key that was retrived previously with builtintable_get_key() + +*******************************************************************************/ + +builtintable_entry *builtintable_get_by_key(s4 key) +{ + /* If key is positive it is the index into builtintable_internal. If it is + * negative it is the index into builtintable_automatic. If it is <= -1000 + * it is the index into builtintable_function. + */ + return (key > 0) + ? &builtintable_internal[key - 1] + : (key > -1000 ? &builtintable_automatic[-key] : &builtintable_function[-(1000 + key)]); +} + /* builtintable_get_internal *************************************************** Finds an entry in the builtintable for internal functions and diff --git a/src/vm/builtin.h b/src/vm/builtin.h index 9177c32e4..af6c51eb8 100644 --- a/src/vm/builtin.h +++ b/src/vm/builtin.h @@ -89,6 +89,8 @@ struct builtintable_entry { bool builtin_init(void); +s4 builtintable_get_key(builtintable_entry *); +builtintable_entry *builtintable_get_by_key(s4 key); builtintable_entry *builtintable_get_internal(functionptr fp); builtintable_entry *builtintable_get_automatic(s4 opcode); @@ -110,7 +112,7 @@ bool builtintable_replace_function(void *iptr); * * IMPORTANT: * For each builtin function which is used in a BUILTIN* opcode there - * must be an entry in the builtin_desc table in jit/jit.c. + * must be an entry in the tables in vm/builtintable.inc. * * Below each prototype is either the BUILTIN_ macro definition or a * comment specifiying that this function is not used in BUILTIN* diff --git a/src/vm/jit/Makefile.am b/src/vm/jit/Makefile.am index 015a917ce..5c2aada1d 100644 --- a/src/vm/jit/Makefile.am +++ b/src/vm/jit/Makefile.am @@ -114,6 +114,14 @@ TRAP_SOURCES = \ trap.h endif +if ENABLE_JITCACHE +JITCACHE_SOURCES = \ + jitcache.c \ + jitcache.h + +endif + + if ENABLE_REPLACEMENT REPLACE_SOURCES += \ replace.c @@ -170,6 +178,7 @@ libjit_la_SOURCES = \ patcher-common.h \ $(RECOMPILE_SOURCES) \ $(REG_SOURCES) \ + $(JITCACHE_SOURCES) \ $(REPLACE_SOURCES) \ show.c \ show.h \ diff --git a/src/vm/jit/arm/codegen.c b/src/vm/jit/arm/codegen.c index 00a37a242..41bccef1b 100644 --- a/src/vm/jit/arm/codegen.c +++ b/src/vm/jit/arm/codegen.c @@ -53,6 +53,7 @@ #include "vm/jit/dseg.h" #include "vm/jit/emit-common.h" #include "vm/jit/jit.h" +#include "vm/jit/jitcache.h" #include "vm/jit/linenumbertable.h" #include "vm/jit/methodheader.h" #include "vm/jit/parse.h" @@ -141,7 +142,13 @@ bool codegen_emit(jitdata *jd) /* SECTION: Method Header */ /* create method header */ +#if defined(ENABLE_JITCACHE) + disp = dseg_add_unique_address(cd, code); /* CodeinfoPointer */ + jitcache_add_cached_ref(code, CRT_CODEINFO, 0, disp); +#else (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ +#endif + (void) dseg_add_unique_s4(cd, cd->stackframesize); /* FrameSize */ code->synchronizedoffset = rd->memuse * 8; @@ -279,6 +286,7 @@ bool codegen_emit(jitdata *jd) if (m->flags & ACC_STATIC) { disp = dseg_add_address(cd, &m->clazz->object.header); + JITCACHE_ADD_CACHED_REF(code, CRT_OBJECT_HEADER, m->clazz, disp); M_DSEG_LOAD(REG_A0, disp); } else { @@ -287,6 +295,8 @@ bool codegen_emit(jitdata *jd) M_STR(REG_A0, REG_SP, s1); disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + JITCACHE_ADD_CACHED_REF(code, + CRT_BUILTIN_FP, builtintable_get_internal(LOCK_monitor_enter), disp); M_DSEG_BRANCH(disp); s1 = (s4) (cd->mcodeptr - cd->mcodebase); M_RECOMPUTE_PV(s1); @@ -410,7 +420,33 @@ bool codegen_emit(jitdata *jd) M_DSEG_LOAD(d, disp); } else { +#if defined(ENABLE_JITCACHE) + /* Dealing with ICONST and the JIT cache is tricky because + * ICONST generates different code depending on the value of the + * number. We therefore go the slightly less optimal way and + * generate an entry in the data segment. + * For the null constant however we use the plain integer load. + */ + if (iptr->sx.val.anyptr) + { + disp = dseg_add_unique_address(cd, iptr->sx.val.anyptr); + + jitcache_add_cached_ref(code, + (iptr->flags.bits & INS_FLAG_CLASS) ? CRT_CLASSINFO + : CRT_STRING, + (iptr->flags.bits & INS_FLAG_CLASS) ? iptr->sx.val.c.cls + : iptr->sx.val.stringconst, + disp); + + M_DSEG_LOAD(d, disp); + } + else { + ICONST(d, (u4) 0); + } + +#else ICONST(d, (u4) iptr->sx.val.anyptr); +#endif } emit_store_dst(jd, iptr, d); break; @@ -679,6 +715,7 @@ bool codegen_emit(jitdata *jd) /* call builtin function */ bte = iptr->sx.s23.s3.bte; disp = dseg_add_functionptr(cd, bte->fp); + JITCACHE_ADD_CACHED_REF(code, CRT_BUILTIN_FP, bte, disp); M_DSEG_BRANCH(disp); /* recompute pv */ @@ -708,6 +745,7 @@ bool codegen_emit(jitdata *jd) /* call builtin function */ bte = iptr->sx.s23.s3.bte; disp = dseg_add_functionptr(cd, bte->fp); + JITCACHE_ADD_CACHED_REF(code, CRT_BUILTIN_FP, bte, disp); M_DSEG_BRANCH(disp); /* recompute pv */ @@ -1352,6 +1390,10 @@ bool codegen_emit(jitdata *jd) /* call builtin function */ disp = dseg_add_functionptr(cd, BUILTIN_FAST_canstore); + JITCACHE_ADD_CACHED_REF( + code, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_FAST_canstore), disp); + M_DSEG_BRANCH(disp); /* recompute pv */ @@ -1382,7 +1424,7 @@ bool codegen_emit(jitdata *jd) fi = iptr->sx.s23.s3.fmiref->p.field; fieldtype = fi->type; disp = dseg_add_address(cd, fi->value); - + JITCACHE_ADD_CACHED_REF(code, CRT_FIELDINFO_VALUE, fi, disp); if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) { patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); @@ -1435,7 +1477,7 @@ bool codegen_emit(jitdata *jd) fi = iptr->sx.s23.s3.fmiref->p.field; fieldtype = fi->type; disp = dseg_add_address(cd, fi->value); - + JITCACHE_ADD_CACHED_REF(code, CRT_FIELDINFO_VALUE, fi, disp); if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) { patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); @@ -1628,6 +1670,7 @@ bool codegen_emit(jitdata *jd) iptr->sx.s23.s2.uc, 0); } disp = dseg_add_functionptr(cd, asm_handle_exception); + JITCACHE_ADD_CACHED_REF(code, CRT_ASM_HANDLE_EXCEPTION, NULL, disp); M_DSEG_LOAD(REG_ITMP3, disp); M_MOV(REG_ITMP2_XPC, REG_PC); M_MOV(REG_PC, REG_ITMP3); @@ -2116,6 +2159,10 @@ bool codegen_emit(jitdata *jd) M_LDR(REG_A0, REG_SP, s1); disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + JITCACHE_ADD_CACHED_REF(code, + CRT_BUILTIN_FP, builtintable_get_internal(LOCK_monitor_exit), + disp); + M_DSEG_BRANCH(disp); /* we no longer need PV here, no more loading */ @@ -2245,6 +2292,8 @@ bool codegen_emit(jitdata *jd) disp = dseg_add_functionptr(cd, bte->stub); } + JITCACHE_ADD_CACHED_REF(code, CRT_BUILTIN, bte, disp); + M_DSEG_LOAD(REG_PV, disp); /* pointer to built-in-function */ /* generate the actual call */ @@ -2267,7 +2316,10 @@ bool codegen_emit(jitdata *jd) um, disp); } else + { disp = dseg_add_address(cd, lm->stubroutine); + JITCACHE_ADD_CACHED_REF(code, CRT_METHODINFO_STUBROUTINE, lm, disp); + } M_DSEG_LOAD(REG_PV, disp); /* Pointer to method */ @@ -2281,6 +2333,7 @@ bool codegen_emit(jitdata *jd) case ICMD_INVOKEVIRTUAL: if (lm == NULL) { + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); s1 = 0; @@ -2288,12 +2341,12 @@ bool codegen_emit(jitdata *jd) else s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex; + /* implicit null-pointer check */ M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); M_LDR_INTERN(REG_PV, REG_METHODPTR, s1); - /* generate the actual call */ M_MOV(REG_LR, REG_PC); @@ -2319,7 +2372,9 @@ bool codegen_emit(jitdata *jd) M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); M_LDR_INTERN(REG_METHODPTR, REG_METHODPTR, s1); + M_LDR_INTERN(REG_PV, REG_METHODPTR, s2); + JITCACHE_ADD_CACHED_REF_MD_JD(jd, CRT_METHODINFO_METHODOFFSET, 1, lm); /* generate the actual call */ @@ -2435,6 +2490,9 @@ bool codegen_emit(jitdata *jd) iptr->sx.s23.s3.c.ref, disp); } else { +/* + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_INDEX, super, disp); +*/ M_TST(s1, s1); emit_label_beq(cd, BRANCH_LABEL_3); } @@ -2500,7 +2558,7 @@ bool codegen_emit(jitdata *jd) } else { disp = dseg_add_address(cd, super->vftbl); - + JITCACHE_ADD_CACHED_REF(code, CRT_CLASSINFO_VFTBL, super, disp); M_TST(s1, s1); emit_label_beq(cd, BRANCH_LABEL_5); } @@ -2546,10 +2604,14 @@ bool codegen_emit(jitdata *jd) disp); } else + { disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls); + JITCACHE_ADD_CACHED_REF(code, CRT_CLASSINFO, iptr->sx.s23.s3.c.cls, disp); + } M_DSEG_LOAD(REG_A1, disp); disp = dseg_add_functionptr(cd, BUILTIN_arraycheckcast); + JITCACHE_ADD_CACHED_REF(code, CRT_BUILTIN, builtintable_get_internal(BUILTIN_arraycheckcast), disp); M_DSEG_BRANCH(disp); /* recompute pv */ @@ -2628,6 +2690,9 @@ bool codegen_emit(jitdata *jd) iptr->sx.s23.s3.c.ref, disp); } else { +/* TODO: Not needed? + JITCACHE_ADD_CACHED_REF(code, CRT_CLASSINFO_INDEX, super, disp); +*/ M_EOR(d, d, d); M_TST(s1, s1); emit_label_beq(cd, BRANCH_LABEL_3); @@ -2698,6 +2763,7 @@ bool codegen_emit(jitdata *jd) } else { disp = dseg_add_address(cd, super->vftbl); + JITCACHE_ADD_CACHED_REF(code, CRT_CLASSINFO_VFTBL, super, disp); M_EOR(d, d, d); M_TST(s1, s1); @@ -2768,7 +2834,10 @@ bool codegen_emit(jitdata *jd) iptr->sx.s23.s3.c.ref, disp); } else + { disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls); + JITCACHE_ADD_CACHED_REF(code, CRT_CLASSINFO, iptr->sx.s23.s3.c.cls, disp); + } /* a1 = arraydescriptor */ @@ -2781,6 +2850,11 @@ bool codegen_emit(jitdata *jd) /* call builtin_multianewarray here */ disp = dseg_add_functionptr(cd, BUILTIN_multianewarray); + /* + * For some unknown reason this causes an illegal instruction. + * JITCACHE_ADD_CACHED_REF(code, CRT_BUILTIN, builtintable_get_internal(BUILTIN_multianewarray), disp); + */ + M_DSEG_BRANCH(disp); /* recompute pv */ diff --git a/src/vm/jit/arm/patcher.c b/src/vm/jit/arm/patcher.c index 84e8287c5..4c3ad2805 100644 --- a/src/vm/jit/arm/patcher.c +++ b/src/vm/jit/arm/patcher.c @@ -64,6 +64,28 @@ /*(inst) |= (1 << 23);*/ \ } +/* This is the same as gen_resolveload but does not check whether the opcode + * is 'clean' (= current offset is zero). + */ +#define gen_resolveload_unchecked(inst,offset) \ + assert((offset) >= -0x0fff && (offset) <= 0x0fff); \ + if ((offset) < 0) { \ + (inst) = ((inst) & 0xff7ff000) | ((-(offset)) & 0x0fff); \ + /*(inst) &= ~(1 << 23);*/ \ + } else { \ + (inst) = ((inst) & 0xfffff000) | ((offset) & 0x0fff); \ + /*(inst) |= (1 << 23);*/ \ + } + +/* patch_md ******************************************************************** + + Patch back address in a machine dependent way + +*******************************************************************************/ +void patch_md(s4 md_patch, ptrint dest, voidptr ref) +{ + gen_resolveload_unchecked(*((s4 *) dest), (s4) ref); +} /* patcher_patch_code ********************************************************** diff --git a/src/vm/jit/code.c b/src/vm/jit/code.c index 3bdc4678f..0a7e70cc5 100644 --- a/src/vm/jit/code.c +++ b/src/vm/jit/code.c @@ -36,8 +36,9 @@ #include "vm/jit/code.h" #include "vm/jit/codegen-common.h" -#include "vm/jit/patcher-common.h" +#include "vm/jit/jitcache.h" #include "vm/jit/methodtree.h" +#include "vm/jit/patcher-common.h" #include "vmcore/options.h" @@ -67,6 +68,7 @@ void code_init(void) The following fields are set in codeinfo: m patchers + cachedrefs RETURN VALUE: a new, initialized codeinfo, or @@ -84,7 +86,11 @@ codeinfo *code_codeinfo_new(methodinfo *m) patcher_list_create(code); -#if defined(ENABLE_STATISTICS) +#if defined (ENABLE_JITCACHE) + jitcache_list_create(code); +#endif + +#if defined (ENABLE_STATISTICS) if (opt_stat) size_codeinfo += sizeof(codeinfo); #endif @@ -241,6 +247,10 @@ void code_codeinfo_free(codeinfo *code) patcher_list_free(code); +#if defined(ENABLE_JITCACHE) + jitcache_list_free(code); +#endif + #if defined(ENABLE_REPLACEMENT) replace_free_replacement_points(code); #endif diff --git a/src/vm/jit/code.h b/src/vm/jit/code.h index adff257fe..b2f9fcdf5 100644 --- a/src/vm/jit/code.h +++ b/src/vm/jit/code.h @@ -85,6 +85,10 @@ struct codeinfo { /* patcher list */ list_t *patchers; +#if defined (ENABLE_JITCACHE) + list_t *cachedrefs; +#endif + /* replacement */ s4 stackframesize; /* size of the stackframe in slots */ diff --git a/src/vm/jit/codegen-common.c b/src/vm/jit/codegen-common.c index 045a44c86..6f9cb4039 100644 --- a/src/vm/jit/codegen-common.c +++ b/src/vm/jit/codegen-common.c @@ -45,6 +45,8 @@ #include #include +#include "vm/jit/jitcache.h" + #include "vm/types.h" #include "codegen.h" @@ -831,9 +833,13 @@ void codegen_finish(jitdata *jd) /* jump table resolving */ for (jr = cd->jumpreferences; jr != NULL; jr = jr->next) + { *((functionptr *) ((ptrint) epoint + jr->tablepos)) = (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc); + JITCACHE_ADD_CACHED_REF(code, CRT_JUMPREFERENCE, jr->target->mpc, jr->tablepos); + } + /* patcher resolving */ patcher_resolve(jd); diff --git a/src/vm/jit/i386/codegen.c b/src/vm/jit/i386/codegen.c index 5123b4b23..6c08b9cfb 100644 --- a/src/vm/jit/i386/codegen.c +++ b/src/vm/jit/i386/codegen.c @@ -62,6 +62,8 @@ #include "vm/jit/reg.h" #include "vm/jit/replace.h" #include "vm/jit/stacktrace.h" + +#include "vm/jit/jitcache.h" #include "vm/jit/trap.h" #if defined(ENABLE_SSA) @@ -136,7 +138,6 @@ bool codegen_emit(jitdata *jd) savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); cd->stackframesize = rd->memuse + savedregs_num; - #if defined(ENABLE_THREADS) /* space to save argument of monitor_enter */ @@ -155,7 +156,12 @@ bool codegen_emit(jitdata *jd) align_off = cd->stackframesize ? 4 : 0; +#if defined(ENABLE_JITCACHE) + disp = dseg_add_unique_address(cd, code); /* CodeinfoPointer */ + jitcache_add_cached_ref(code, CRT_CODEINFO, 0, disp); +#else (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ +#endif (void) dseg_add_unique_s4( cd, cd->stackframesize * 8 + align_off); /* FrameSize */ @@ -178,6 +184,8 @@ bool codegen_emit(jitdata *jd) /* count frequency */ M_MOV_IMM(code, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CODEINFO, NULL); + M_IADD_IMM_MEMBASE(1, REG_ITMP3, OFFSET(codeinfo, frequency)); } #endif @@ -356,6 +364,7 @@ bool codegen_emit(jitdata *jd) if (m->flags & ACC_STATIC) { M_MOV_IMM(&m->clazz->object.header, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_OBJECT_HEADER, m->clazz); } else { M_ALD(REG_ITMP1, REG_SP, cd->stackframesize * 8 + 4 + align_off); @@ -367,6 +376,8 @@ bool codegen_emit(jitdata *jd) M_AST(REG_ITMP1, REG_SP, s1 * 8); M_AST(REG_ITMP1, REG_SP, 0 * 4); M_MOV_IMM(LOCK_monitor_enter, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(LOCK_monitor_enter)); M_CALL(REG_ITMP3); } #endif @@ -570,6 +581,7 @@ bool codegen_emit(jitdata *jd) disp = dseg_add_float(cd, iptr->sx.val.f); emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); emit_flds_membase(cd, REG_ITMP1, disp); } emit_store_dst(jd, iptr, d); @@ -598,6 +610,7 @@ bool codegen_emit(jitdata *jd) disp = dseg_add_double(cd, iptr->sx.val.d); emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); emit_fldl_membase(cd, REG_ITMP1, disp); } emit_store_dst(jd, iptr, d); @@ -617,7 +630,15 @@ bool codegen_emit(jitdata *jd) if (iptr->sx.val.anyptr == NULL) M_CLR(d); else + { M_MOV_IMM(iptr->sx.val.anyptr, d); + JITCACHE_ADD_CACHED_REF_JD( + jd, + (iptr->flags.bits & INS_FLAG_CLASS) ? CRT_CLASSINFO + : CRT_STRING, + (iptr->flags.bits & INS_FLAG_CLASS) ? iptr->sx.val.c.cls + : iptr->sx.val.stringconst); + } } emit_store_dst(jd, iptr, d); break; @@ -999,6 +1020,7 @@ bool codegen_emit(jitdata *jd) M_LST(s1, REG_SP, 0 * 4); M_MOV_IMM(bte->fp, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, bte); M_CALL(REG_ITMP3); emit_store_dst(jd, iptr, d); break; @@ -1566,6 +1588,7 @@ bool codegen_emit(jitdata *jd) disp = dseg_add_unique_s4(cd, 0); emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); emit_mov_reg_membase(cd, var->vv.regoff, REG_ITMP1, disp); emit_fildl_membase(cd, REG_ITMP1, disp); } @@ -1595,6 +1618,7 @@ bool codegen_emit(jitdata *jd) emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); /* Round to zero, 53-bit mode, exception masked */ disp = dseg_add_s4(cd, 0x0e7f); @@ -1640,6 +1664,8 @@ bool codegen_emit(jitdata *jd) /* XXX: change this when we use registers */ emit_flds_membase(cd, REG_SP, var1->vv.regoff); emit_mov_imm_reg(cd, (ptrint) asm_builtin_f2i, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_f2i)); emit_call_reg(cd, REG_ITMP1); if (var->flags & INMEMORY) { @@ -1657,6 +1683,7 @@ bool codegen_emit(jitdata *jd) emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); /* Round to zero, 53-bit mode, exception masked */ disp = dseg_add_s4(cd, 0x0e7f); @@ -1702,6 +1729,8 @@ bool codegen_emit(jitdata *jd) /* XXX: change this when we use registers */ emit_fldl_membase(cd, REG_SP, var1->vv.regoff); emit_mov_imm_reg(cd, (ptrint) asm_builtin_d2i, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_d2i)); emit_call_reg(cd, REG_ITMP1); if (var->flags & INMEMORY) { @@ -1718,6 +1747,7 @@ bool codegen_emit(jitdata *jd) emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); /* Round to zero, 53-bit mode, exception masked */ disp = dseg_add_s4(cd, 0x0e7f); @@ -1761,6 +1791,8 @@ bool codegen_emit(jitdata *jd) /* XXX: change this when we use registers */ emit_flds_membase(cd, REG_SP, var1->vv.regoff); emit_mov_imm_reg(cd, (ptrint) asm_builtin_f2l, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_f2l)); emit_call_reg(cd, REG_ITMP1); emit_mov_reg_membase(cd, REG_RESULT, REG_SP, var->vv.regoff); emit_mov_reg_membase(cd, REG_RESULT2, @@ -1779,6 +1811,7 @@ bool codegen_emit(jitdata *jd) emit_mov_imm_reg(cd, 0, REG_ITMP1); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); /* Round to zero, 53-bit mode, exception masked */ disp = dseg_add_s4(cd, 0x0e7f); @@ -1821,6 +1854,8 @@ bool codegen_emit(jitdata *jd) /* XXX: change this when we use registers */ emit_fldl_membase(cd, REG_SP, var1->vv.regoff); emit_mov_imm_reg(cd, (ptrint) asm_builtin_d2l, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_d2l)); emit_call_reg(cd, REG_ITMP1); emit_mov_reg_membase(cd, REG_RESULT, REG_SP, var->vv.regoff); emit_mov_reg_membase(cd, REG_RESULT2, @@ -2107,6 +2142,8 @@ bool codegen_emit(jitdata *jd) M_AST(s1, REG_SP, 0 * 4); M_AST(s3, REG_SP, 1 * 4); M_MOV_IMM(BUILTIN_FAST_canstore, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_FAST_canstore)); M_CALL(REG_ITMP1); emit_arraystore_check(cd, iptr); @@ -2195,6 +2232,7 @@ bool codegen_emit(jitdata *jd) else { fi = iptr->sx.s23.s3.fmiref->p.field; fieldtype = fi->type; + disp = (intptr_t) fi->value; if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) @@ -2202,6 +2240,7 @@ bool codegen_emit(jitdata *jd) } M_MOV_IMM(disp, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD_COND(jd, CRT_FIELDINFO_VALUE, fi, disp); switch (fieldtype) { case TYPE_INT: case TYPE_ADR: @@ -2236,13 +2275,14 @@ bool codegen_emit(jitdata *jd) else { fi = iptr->sx.s23.s3.fmiref->p.field; fieldtype = fi->type; + disp = (intptr_t) fi->value; if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); } - M_MOV_IMM(disp, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD_COND(jd, CRT_FIELDINFO_VALUE, fi, disp); switch (fieldtype) { case TYPE_INT: case TYPE_ADR: @@ -2278,6 +2318,7 @@ bool codegen_emit(jitdata *jd) else { fi = iptr->sx.s23.s3.fmiref->p.field; fieldtype = fi->type; + disp = (intptr_t) fi->value; if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) @@ -2285,6 +2326,7 @@ bool codegen_emit(jitdata *jd) } M_MOV_IMM(disp, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD_COND(jd, CRT_FIELDINFO_VALUE, fi, disp); switch (fieldtype) { case TYPE_INT: case TYPE_ADR: @@ -2319,7 +2361,9 @@ bool codegen_emit(jitdata *jd) else { fi = iptr->sx.s23.s3.fmiref->p.field; fieldtype = fi->type; + disp = fi->offset; + } switch (fieldtype) { @@ -2453,6 +2497,7 @@ bool codegen_emit(jitdata *jd) M_POP(REG_ITMP2_XPC); M_MOV_IMM(asm_handle_exception, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ASM_HANDLE_EXCEPTION, 1); M_JMP(REG_ITMP3); break; @@ -2767,6 +2812,8 @@ nowperformreturn: M_AST(REG_ITMP2, REG_SP, 0); M_MOV_IMM(LOCK_monitor_exit, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(LOCK_monitor_exit)); M_CALL(REG_ITMP3); /* and now restore the proper return value */ @@ -2856,6 +2903,7 @@ nowperformreturn: M_MOV_IMM(0, REG_ITMP2); dseg_adddata(cd); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_ENTRYPOINT, NULL); emit_mov_memindex_reg(cd, -(cd->dseglen), REG_ITMP2, REG_ITMP1, 2, REG_ITMP1); M_JMP(REG_ITMP1); } @@ -2964,6 +3012,7 @@ gen_method: else { M_MOV_IMM(bte->stub, REG_ITMP1); } + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN, bte); M_CALL(REG_ITMP1); #if defined(ENABLE_ESCAPE_CHECK) @@ -2990,10 +3039,11 @@ gen_method: } else { disp = (ptrint) lm->stubroutine; + d = lm->parseddesc->returntype.type; } - M_MOV_IMM(disp, REG_ITMP2); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_METHODINFO_STUBROUTINE, lm); M_CALL(REG_ITMP2); break; @@ -3012,12 +3062,14 @@ gen_method: else { s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex; + d = md->returntype.type; } M_ALD(REG_METHODPTR, REG_ITMP1, OFFSET(java_object_t, vftbl)); M_ALD32(REG_ITMP3, REG_METHODPTR, s1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_METHODINFO_TABLE, lm); M_CALL(REG_ITMP3); break; @@ -3046,7 +3098,9 @@ gen_method: M_ALD(REG_METHODPTR, REG_ITMP1, OFFSET(java_object_t, vftbl)); M_ALD32(REG_METHODPTR, REG_METHODPTR, s1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_METHODINFO_INTERFACETABLE, lm); M_ALD32(REG_ITMP3, REG_METHODPTR, s2); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_METHODINFO_METHODOFFSET, lm); M_CALL(REG_ITMP3); break; } @@ -3103,14 +3157,13 @@ gen_method: superindex = super->index; supervftbl = super->vftbl; } - + if ((super == NULL) || !(super->flags & ACC_INTERFACE)) CODEGEN_CRITICAL_SECTION_NEW; s1 = emit_load_s1(jd, iptr, REG_ITMP1); /* if class is not resolved, check which code to call */ - if (super == NULL) { M_TEST(s1); emit_label_beq(cd, BRANCH_LABEL_1); @@ -3142,6 +3195,7 @@ gen_method: M_ILD32(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, interfacetablelength)); M_ISUB_IMM32(superindex, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_INDEX, super); /* XXX do we need this one? */ M_TEST(REG_ITMP3); emit_classcast_check(cd, iptr, BRANCH_LE, REG_ITMP3, s1); @@ -3149,6 +3203,7 @@ gen_method: M_ALD32(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, interfacetable[0]) - superindex * sizeof(methodptr*)); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_INTERFACETABLE, super); M_TEST(REG_ITMP3); emit_classcast_check(cd, iptr, BRANCH_EQ, REG_ITMP3, s1); @@ -3178,6 +3233,7 @@ gen_method: } M_MOV_IMM(supervftbl, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super); CODEGEN_CRITICAL_SECTION_START; @@ -3195,6 +3251,7 @@ gen_method: M_ILD32(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval)); M_ISUB(REG_ITMP3, REG_ITMP2); M_MOV_IMM(supervftbl, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super); M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval)); CODEGEN_CRITICAL_SECTION_END; @@ -3224,10 +3281,18 @@ gen_method: if (INSTRUCTION_IS_UNRESOLVED(iptr)) { patcher_add_patch_ref(jd, PATCHER_builtin_arraycheckcast, iptr->sx.s23.s3.c.ref, 0); + disp = 0; } + else { + disp = iptr->sx.s23.s3.c.cls; + } + + M_AST_IMM(disp, REG_SP, 1 * 4); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO, disp); - M_AST_IMM(iptr->sx.s23.s3.c.cls, REG_SP, 1 * 4); M_MOV_IMM(BUILTIN_arraycheckcast, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_arraycheckcast)); M_CALL(REG_ITMP3); s1 = emit_load_s1(jd, iptr, REG_ITMP2); @@ -3294,6 +3359,7 @@ gen_method: emit_label_beq(cd, BRANCH_LABEL_3); } + M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl)); if (super == NULL) { @@ -3304,6 +3370,8 @@ gen_method: M_ILD32(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, interfacetablelength)); M_ISUB_IMM32(superindex, REG_ITMP3); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_INDEX, super); + M_TEST(REG_ITMP3); disp = (2 + 4 /* mov_membase32_reg */ + 2 /* test */ + @@ -3313,6 +3381,7 @@ gen_method: M_ALD32(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, interfacetable[0]) - superindex * sizeof(methodptr*)); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_INTERFACETABLE, super); M_TEST(REG_ITMP1); /* emit_setcc_reg(cd, CC_A, d); */ /* emit_jcc(cd, CC_BE, 5); */ @@ -3344,7 +3413,7 @@ gen_method: } M_MOV_IMM(supervftbl, REG_ITMP2); - + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super); CODEGEN_CRITICAL_SECTION_START; M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval)); @@ -3412,6 +3481,7 @@ gen_method: /* a1 = arraydescriptor */ M_IST_IMM(disp, REG_SP, 1 * 4); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO, disp); /* a2 = pointer to dimensions = stack pointer */ @@ -3420,6 +3490,8 @@ gen_method: M_AST(REG_ITMP1, REG_SP, 2 * 4); M_MOV_IMM(BUILTIN_multianewarray, REG_ITMP1); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_BUILTIN_FP, + builtintable_get_internal(BUILTIN_multianewarray)); M_CALL(REG_ITMP1); /* check for exception before result assignment */ @@ -3541,6 +3613,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s M_MOV_IMM(code, REG_ITMP1); M_IADD_IMM_MEMBASE(1, REG_ITMP1, OFFSET(codeinfo, frequency)); + JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CODEINFO, 0); } #endif diff --git a/src/vm/jit/i386/patcher.c b/src/vm/jit/i386/patcher.c index 661c245e4..4aa86f6e2 100644 --- a/src/vm/jit/i386/patcher.c +++ b/src/vm/jit/i386/patcher.c @@ -263,7 +263,7 @@ bool patcher_putfieldconst(patchref_t *pr) Machine code: - + c7 04 24 00 00 00 00 movl $0x0000000,(%esp) b8 00 00 00 00 mov $0x0000000,%eax @@ -413,7 +413,7 @@ bool patcher_invokestatic_special(patchref_t *pr) ra = (u1 *) pr->mpc; um = (unresolved_method *) pr->ref; - /* get the fieldinfo */ + /* get the methodinfo */ if (!(m = resolve_method_eager(um))) return false; diff --git a/src/vm/jit/jit.c b/src/vm/jit/jit.c index e6f17c2d8..4225c66c6 100644 --- a/src/vm/jit/jit.c +++ b/src/vm/jit/jit.c @@ -57,6 +57,10 @@ #include "vm/jit/show.h" #include "vm/jit/stack.h" +#if defined(ENABLE_JITCACHE) +# include "vm/jit/jitcache.h" +#endif + #include "vm/jit/allocator/simplereg.h" #if defined(ENABLE_LSRA) && !defined(ENABLE_SSA) # include "vm/jit/allocator/lsra.h" @@ -341,6 +345,17 @@ u1 *jit_compile(methodinfo *m) STATISTICS(count_methods++); +#if defined (ENABLE_JITCACHE) + + if (jitcache_load (m)) + { + LOCK_MONITOR_EXIT(m); + + return m->code->entrypoint; + } + +#endif + #if defined(ENABLE_STATISTICS) /* measure time */ @@ -431,6 +446,10 @@ u1 *jit_compile(methodinfo *m) DEBUG_JIT_COMPILEVERBOSE("Running: "); } +#if defined (ENABLE_JITCACHE) + jitcache_store(m); +#endif + /* release dump area */ DRELEASE; diff --git a/src/vm/jit/jitcache.c b/src/vm/jit/jitcache.c new file mode 100644 index 000000000..0028b225f --- /dev/null +++ b/src/vm/jit/jitcache.c @@ -0,0 +1,2410 @@ +/* src/vm/jit/jitcache.c - JIT caching stuff + + Copyright (C) 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + +*/ + +#include "config.h" + +#if defined(ENABLE_JITCACHE) + +/* for mkdir() */ +#include + +#include +#include + +#include "md.h" + +#include "toolbox/list.h" +#include "toolbox/logging.h" + +#include "mm/memory.h" +#include "mm/codememory.h" + +#include "vm/types.h" +#include "vm/resolve.h" +#include "vm/builtin.h" +#include "vm/stringlocal.h" + +#include "vm/jit/asmpart.h" +#include "vm/jit/jit.h" +#include "vm/jit/code.h" +#include "vm/jit/patcher-common.h" +#include "vm/jit/codegen-common.h" +#include "vm/jit/linenumbertable.h" +#include "vm/jit/exceptiontable.h" +#include "vm/jit/methodtree.h" + +#include "vmcore/references.h" +#include "vmcore/method.h" +#include "vmcore/system.h" +#include "vmcore/field.h" +#include "vmcore/utf8.h" +#include "vmcore/options.h" + +#include "vm/jit/jitcache.h" + +#include "threads/mutex.h" + +/* TODO: Wrap this in vm/system.h" */ +#include "unistd.h" + +#define CACHEROOT "/tmp/cacao-jitcache/" + +/* small grained helper functions */ +char *get_dest_dir(methodinfo *); +char *get_dest_file(methodinfo *); + +int mkdir_hier(char *, mode_t); +int open_to_read(char *); +int open_to_write(char *); + +u1 *to_abs(u1 *, u1 *); +u1 *to_offset(u1 *, u1 *); + +void store_utf(int, utf *); +void store_classinfo(int, classinfo *); +void store_builtin(int, builtintable_entry *); +void store_string(int, java_object_t *); +void store_methodinfo(int, methodinfo *); +void store_fieldinfo(int, fieldinfo *); +void store_cachedref(int, cachedref_t *); + +void load_utf(utf **, int); +void load_classinfo(classinfo **, int, methodinfo *); +void load_builtin(builtintable_entry **, int); +void load_string(java_object_t **, int); +void load_methodinfo(methodinfo **, int, methodinfo *); +void load_fieldinfo(fieldinfo **, int, methodinfo *); +void load_cachedref(cachedref_t **, int, codeinfo *); + +/* medium grained helper functions */ +void load_from_file_patchers(codeinfo *, int); +void load_from_file_cachedrefs(codeinfo *, int); +void load_from_file_exceptiontable(codeinfo *, int); +void load_from_file_linenumbertable(codeinfo *, int); + +void store_to_file_patchers(int, codeinfo *); +void store_to_file_cachedrefs(int, codeinfo *); +void store_to_file_linenumbertable(int, codeinfo *); +void store_to_file_exceptiontable(int, codeinfo *); + +/* file handling functions */ +void update_method_table(methodinfo *, int); +int seek_method_table(methodinfo *, int); +int get_cache_file_readable(methodinfo *); +int get_cache_file_writable(methodinfo *); + +/* serializer forward declarations */ +void s_dummy(int, patchref_t *, methodinfo *); +void s_unresolved_class(int, patchref_t *, methodinfo *); +void s_unresolved_field(int, patchref_t *, methodinfo *); +void s_unresolved_method(int, patchref_t *, methodinfo *); +void s_constant_classref(int, patchref_t *, methodinfo *); +void s_classinfo(int, patchref_t *, methodinfo *); +void s_methodinfo(int, patchref_t *, methodinfo *); +void s_fieldinfo(int, patchref_t *, methodinfo *); +void s_string(int, patchref_t *, methodinfo *); + +/* deserializer forward declarations */ +void d_dummy(patchref_t *, int, methodinfo *); +void d_unresolved_class(patchref_t *, int, methodinfo *); +void d_unresolved_field(patchref_t *, int, methodinfo *); +void d_unresolved_method(patchref_t *, int, methodinfo *); +void d_constant_classref(patchref_t *, int, methodinfo *); +void d_classinfo(patchref_t *, int, methodinfo *); +void d_methodinfo(patchref_t *, int, methodinfo *); +void d_fieldinfo(patchref_t *, int, methodinfo *); +void d_string(patchref_t *, int, methodinfo *); + +/* The order of entries follows the order of + * declarations in patcher-common.h + */ + +static jitcache_patcher_function_list_t patcher_functions[] = { + { PATCHER_resolve_class, s_unresolved_class, d_unresolved_class }, + { PATCHER_initialize_class, s_classinfo, d_classinfo }, + { PATCHER_resolve_classref_to_classinfo, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_classref_to_vftbl, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_classref_to_index, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_classref_to_flags, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_native_function, s_methodinfo, d_methodinfo }, + + /* old patcher functions */ + { PATCHER_get_putstatic, s_unresolved_field, d_unresolved_field }, + +#if defined(__I386__) + { PATCHER_getfield, s_unresolved_field, d_unresolved_field }, + { PATCHER_putfield, s_unresolved_field, d_unresolved_field }, +#else + { PATCHER_get_putfield, s_unresolved_field, d_unresolved_field }, +#endif + +#if defined(__I386__) || defined(__X86_64__) + { PATCHER_putfieldconst, s_unresolved_field, d_unresolved_field }, /* 10 */ +#endif + + { PATCHER_invokestatic_special, s_unresolved_method, d_unresolved_method }, + { PATCHER_invokevirtual, s_unresolved_method, d_unresolved_method }, + { PATCHER_invokeinterface, s_unresolved_method, d_unresolved_method }, + +#if defined(__ALPHA__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) || defined(__M68K__) + { PATCHER_checkcast_interface, s_constant_classref, d_constant_classref }, + { PATCHER_instanceof_interface, s_constant_classref, d_constant_classref }, +#endif + +#if defined(__S390__) + { PATCHER_checkcast_instanceof_interface, s_dummy, d_dummy }, +#endif + +#if defined(__I386__) + { PATCHER_aconst, s_constant_classref, d_constant_classref }, /* 16 */ + { PATCHER_builtin_multianewarray, s_constant_classref, d_constant_classref }, + { PATCHER_builtin_arraycheckcast, s_constant_classref, d_constant_classref }, + { PATCHER_checkcast_instanceof_flags, s_constant_classref, d_constant_classref }, + { PATCHER_checkcast_class, s_constant_classref, d_constant_classref }, + { PATCHER_instanceof_class, s_constant_classref, d_constant_classref }, +#endif + + { NULL, s_dummy, d_dummy } +}; + +#define JC_MRU_SIZE 100 +static classinfo *jc_mru_list[JC_MRU_SIZE]; +int mru_last_free = 0; +int mru_start = 0; + +/* jitcache_mru_add ************************************************************ + + Adds a classinfo to the most recently used (MRU) list. The MRU uses a simple + strategy: it will store entries until it is full, further candidates replace + the + +*******************************************************************************/ + +void jitcache_mru_add(classinfo *c, int fd) +{ + classinfo *old_c; + assert(!c->cache_file_fd); + + c->cache_file_fd = fd; + + if (mru_last_free < JC_MRU_SIZE) { + jc_mru_list[mru_last_free] = c; + + mru_last_free++; + + return; + } + else { + mru_start--; + if (mru_start < 0) + mru_start = JC_MRU_SIZE - 1; + + old_c = jc_mru_list[mru_start]; + + assert (old_c); + assert (old_c->cache_file_fd); + system_close(old_c->cache_file_fd); + old_c->cache_file_fd = 0; + + jc_mru_list[mru_start] = c; + } + +} + +void jitcache_mru_remove(classinfo *c) +{ + int i, j; + + for (i = 0; i < JC_MRU_SIZE; i++) + if (jc_mru_list[i] == c) { + jc_mru_list[j] = NULL; + + for (j = i; i < mru_last_free - 1; j++) + jc_mru_list[j] = jc_mru_list[j+1]; + + mru_last_free--; + } + + assert (0); +} + +/* jitcache_list_create ******************************************************** + + Creates an empty cached reference list for the given codeinfo. + +*******************************************************************************/ + +void jitcache_list_create(codeinfo *code) +{ + code->cachedrefs = list_create(OFFSET(cachedref_t, linkage)); +} + + +/* jitcache_list_reset ********************************************************** + + Resets the cached reference list inside a codeinfo. + +*******************************************************************************/ + +void jitcache_list_reset(codeinfo *code) +{ + cachedref_t *pr; + + /* free all elements of the list */ + + while((pr = list_first(code->cachedrefs)) != NULL) { + list_remove(code->cachedrefs, pr); + + FREE(pr, cachedref_t); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + size_cachedref -= sizeof(cachedref_t); +#endif + } +} + + +/* jitcache_list_free *********************************************************** + + Frees the cached reference list and all its entries for the given codeinfo. + +*******************************************************************************/ + +void jitcache_list_free(codeinfo *code) +{ + /* free all elements of the list */ + + jitcache_list_reset(code); + + /* free the list itself */ + + FREE(code->cachedrefs, list_t); +} + + +/* jitcache_list_find *********************************************************** + + Find an entry inside the cached reference list for the given codeinfo + by specifying the displacement in the code/data segment. + + NOTE: Caller should hold the patcher list lock or maintain + exclusive access otherwise. + +*******************************************************************************/ + +static cachedref_t *jitcache_list_find(codeinfo *code, s4 disp) +{ + cachedref_t *cr; + + /* walk through all cached references for the given codeinfo */ + + cr = list_first(code->cachedrefs); + while (cr) { + + if (cr->disp == disp) + return cr; + + cr = list_next(code->cachedrefs, cr); + } + + return NULL; +} + + +/* jitcache_new_cachedref ****************************************************** + + Creates and initializes a new cachedref + +*******************************************************************************/ + +cachedref_t *jitcache_new_cached_ref(cachedreftype type, s4 md_patch, voidptr ref, s4 disp) +{ + cachedref_t *cr; + + /* allocate cachedref on heap (at least freed together with codeinfo) */ + + cr = NEW(cachedref_t); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + size_cachedref += sizeof(cachedref_t); +#endif + + /* set reference information */ + + cr->type = type; + cr->md_patch= md_patch; + cr->disp = disp; + cr->ref = ref; + + return cr; +} +/* jitcache_add_cachedref_jd *************************************************** + + Creates a new cached ref appends it to the list in the codeinfo structure + *or* attaches it to the *last* patchref_t if it overlaps with the address + of the cached reference. + +*******************************************************************************/ + +void jitcache_add_cached_ref_intern(codeinfo *code, cachedref_t *cachedref) +{ + cachedref_t *list_cr; + + list_cr = (cachedref_t *) list_first(code->cachedrefs); + + while (list_cr) + { + if (list_cr->disp == cachedref->disp) + { + assert(list_cr->type == cachedref->type); + assert(list_cr->ref == cachedref->ref); + + /* Cachedref for already existing object found. No need to store + * it. + */ + return; + } + + list_cr = list_next(code->cachedrefs, list_cr); + } + + list_add_first(code->cachedrefs, cachedref); +} + +/* jitcache_add_cachedref_jd *************************************************** + + Creates a new cached ref appends it to the list in the codeinfo structure + *or* attaches it to the *last* patchref_t if it overlaps with the address + of the cached reference. + +*******************************************************************************/ + +void jitcache_add_cached_ref_jd(jitdata *jd, cachedreftype type, voidptr ref) +{ + jitcache_add_cached_ref_md_jd(jd, type, 0, ref); +} + + +/* jitcache_add_cachedref_md_jd ************************************************ + + Creates a new cached ref appends it to the list in the codeinfo structure + *or* attaches it to the *last* patchref_t if it overlaps with the address + of the cached reference. + +*******************************************************************************/ + +void jitcache_add_cached_ref_md_jd(jitdata *jd, cachedreftype type, s4 md_patch, voidptr ref) +{ + patchref_t *patchref; + codegendata *cd; + s4 disp; + cachedref_t *cachedref; + + if (type >= CRT_OBJECT_HEADER && !ref) + return; + + cd = jd->cd; + + disp = (s4) (cd->mcodeptr - cd->mcodebase) - SIZEOF_VOID_P; + cachedref = jitcache_new_cached_ref(type, md_patch, ref, disp); + + patchref = (patchref_t *) list_first(jd->code->patchers); + + if (patchref + && (patchref->mpc) <= disp + && (patchref->mpc + sizeof(patchref->mcode)) >= disp) + { + /* patchers and cachedref overlap: cached ref must + * be handled after the patcher. + */ + + if (opt_DebugJitCache) + { + log_message_method("cached ref overlaps with patchref: ", jd->m); + } + + /* There can be only one cached ref per patcher currently. + * If the need arises to handle more cached refs a list can + * be used. + */ + assert(!patchref->attached_ref); + + patchref->attached_ref = cachedref; + } + else + jitcache_add_cached_ref_intern(jd->code, cachedref); +} + + +/* jitcache_add_cachedref ****************************************************** + + Creates a new cached references and appends it to the list. + +*******************************************************************************/ + +void jitcache_add_cached_ref(codeinfo *code, cachedreftype type, voidptr ref, s4 disp) +{ + cachedref_t *cr; + + /* allocate cachedref on heap (at least freed together with codeinfo) */ + cr = jitcache_new_cached_ref(type, 0, ref,disp); + + jitcache_add_cached_ref_intern(code, cr); +} + + + +/* jitcache_handle_cached_ref ************************************************** + + Creates a new cached references and appends it to the list. + +*******************************************************************************/ + +void jitcache_handle_cached_ref(cachedref_t *cr, codeinfo *code) +{ + u1 **location; + + location = (u1 **) (code->entrypoint + cr->disp); + + /* Write the restored reference into the code. */ + if (cr->md_patch) + patch_md(cr->md_patch, (ptrint) location, cr->ref); + else + *location = cr->ref; + + md_cacheflush(location, SIZEOF_VOID_P); + + FREE(cr, cachedref_t); +} + +#include +#include + +bool filter(utf *classname) +{ + static bool printed = false; + char *buf = NULL; + int i = 0; + int max_index = 30000; + const char *classes[] = { + "Test$FooBar", + "Test", + "FieldTest", + "UnresolvedClass", + "java/lang/ThreadGroup", + "java/lang/Object", + "java/util/Vector", + "java/util/Vector$1", + "java/util/AbstractList", + "java/util/AbstractCollection", + "java/lang/Thread", + "java/lang/String", + "java/lang/ClassLoader", + "java/lang/VMClassLoader", + "java/util/HashMap", + "java/util/HashSet", + "java/util/AbstractSet", + "gnu/classpath/SystemProperties", + "java/util/Properties", + "java/util/Hashtable", + "java/util/Dictionary", + "java/util/Hashtable$HashEntry", + "java/util/AbstractMap$SimpleEntry", + "java/lang/StringBuilder", + "java/lang/AbstractStringBuffer", + "java/util/Collections$SynchronizedSet", + "java/util/Collections$SynchronizedCollection", + "java/util/Hashtable$3", + "java/util/Hashtable$EntryIterator", + "java/util/Collections$SynchronizedIterator", + "java/lang/Boolean", + "java/util/Collections", + "java/util/Collections$EmptySet", + "java/util/Collections$EmptyList", + "java/util/Collections$EmptyMap", + "java/util/Collections$ReverseComparator", + "java/util/Collections$UnmodifiableMap", + "java/io/File", + "java/util/StringTokenizer", + "java/util/ArrayList", + "java/io/VMFile", + "java/lang/System", + "java/lang/VMSystem", + "java/io/FileDescriptor", + "gnu/java/io/FileChannelImpl", + "java/lang/Runtime", + "gnu/classpath/VMStackWalker", + "gnu/java/io/VMChannel", + "gnu/java/io/VMChannel$State", + "gnu/java/io/VMChannel$Kind", + "java/nio/channels/FileChannelImpl", + "java/nio/channels/spi/AbstractInterruptibleChannel", + "java/lang/Number", + "java/io/FileInputStream", + "java/io/InputStream", + "java/io/BufferedInputStream", + "java/io/FilterInputStream", + "java/io/PrintStream", + "java/io/OutputStream", + "java/io/BufferedOutputStream", + "java/io/FilterOutputStream", + "java/net/URL", + "java/util/Locale", + "java/lang/Math", + "gnu/java/lang/CharData", + "java/lang/Character", + "java/net/URL$1", + "java/security/VMAccessController", + "java/lang/ThreadLocal", + "java/security/CodeSource", + "**placeholder**", + "java/security/PermissionCollection", + "Test$1", + "java/security/ProtectionDomain", + "java/security/AccessControlContext", + "gnu/java/util/WeakIdentityHashMap", + "gnu/java/util/WeakIdentityHashMap$WeakEntrySet", + "java/lang/ref/ReferenceQueue", + "java/util/LinkedList", + "java/util/AbstractSequentialList", + "gnu/java/util/WeakIdentityHashMap$WeakBucket$WeakEntry", + "java/util/LinkedList$Entry", + "java/lang/Class", + "java/lang/reflect/VMConstructor", + "java/lang/reflect/Constructor", + "java/lang/reflect/Modifier", + "gnu/java/net/protocol/file/Handler", + "java/net/URLStreamHandler", + "java/util/ArrayList", + "java/security/SecureClassLoader", + "java/lang/Exception", + "java/lang/Throwable", + "java/lang/VMThrowable", + "gnu/java/net/loader/FileURLLoader", + "gnu/java/net/loader/URLLoader", + "java/security/Policy", + "gnu/java/security/provider/DefaultPolicy", + "gnu/java/net/loader/Resource", + "gnu/java/net/loader/FileResource", + "java/io/FileInputStream", + "gnu/java/nio/FileChannelImpl", + "java/nio/ByteBuffer", + "java/nio/Buffer", + "java/nio/ByteOrder", + "java/security/Permissions$PermissionsHash", + "java/nio/charset/Charset", + "gnu/java/nio/charset/Provider", + "gnu/java/nio/charset/Provider$1", + "gnu/java/nio/charset/US_ASCII", + "java/util/Collections$UnmodifiableSet/", + "java/util/Collections$UnmodifiableCollection", + "java/util/Collections$UnmodifiableIterator", + "gnu/java/nio/charset/ISO_8859_1", + "gnu/java/nio/charset/UTF_8", + "gnu/java/nio/charset/UTF_16BE", + "gnu/java/nio/charset/UTF_16LE", + "gnu/java/nio/charset/UTF_16", + "gnu/java/nio/charset/UnicodeLittle", + "gnu/java/nio/charset/Windows1250", + "gnu/java/nio/charset/Windows1250", + "gnu/java/nio/charset/ByteCharset", + "gnu/java/nio/charset/Windows1251", + "gnu/java/nio/charset/Windows1252", + "gnu/java/nio/charset/Windows1253", + "gnu/java/nio/charset/Windows1254", + "gnu/java/nio/charset/Windows1257", + "gnu/java/nio/charset/ISO_8859_2", + "gnu/java/nio/charset/ISO_8859_4", + "gnu/java/nio/charset/ISO_8859_5", + "gnu/java/nio/charset/ISO_8859_7", + "gnu/java/nio/charset/ISO_8859_9", + "gnu/java/nio/charset/ISO_8859_13", + "gnu/java/nio/charset/ISO_8859_15", + "gnu/java/nio/charset/KOI_8", + "gnu/java/nio/charset/ISO_8859_1$Encoder", + "java/nio/charset/CharsetEncoder", + "gnu/java/nio/charset/ByteEncodeLoopHelper", + "java/nio/charset/CodingErrorAction", + "java/nio/CharBuffer", + "java/nio/CharBufferImpl", + "gnu/java/nio/charset/ByteEncodeLoopHelper", + "java/nio/charset/CoderResult", + "java/nio/charset/CoderResult$1", + "java/nio/charset/CoderResult$2", + "java/nio/charset/CoderResult$Cache", + "java/awt/Toolkit", + "gnu/java/awt/peer/gtk/GtkToolkit", + "gnu/java/awt/peer/gtk/GtkGenericPeer", + "java/util/WeakHashMap", + "java/util/WeakHashMap$1", + "java/util/WeakHashMap$WeakEntrySet", + "gnu/java/awt/peer/gtk/GtkWindowPeer", + "gnu/java/awt/peer/gtk/GtkCheckboxPeer", + "gnu/java/awt/peer/gtk/GtkFileDialogPeer", + "gnu/java/awt/peer/gtk/GtkMainThread", + "java/security/AccessController", + "java/security/Permission", + "java/lang/ClassLoader$StaticData", + "java/lang/VMString", + "gnu/java/lang/CPStringBuilder", + "gnu/java/lang/VMCPStringBuilder", + "java/io/FileOutputStream", + "gnu/java/nio/VMChannel", + "gnu/java/nio/VMChannel$State", + "gnu/java/nio/VMChannel$Kind", + "java/nio/channels/FileChannel", + "gnu/classpath/VMSystemProperties", + "java/lang/StringBuffer", + "java/lang/VMRuntime", + "java/lang/VMObject", + "java/lang/VMThread", + "java/lang/VMClass", + "java/lang/InheritableThreadLocal", + "java/lang/ClassNotFoundException", + "java/net/URLClassLoader", + "java/lang/ClassLoader$1", + "java/nio/ByteBufferImpl", + "java/io/FilePermission", + "gnu/java/nio/charset/ISO_8859_1$Encoder$1", + "java/nio/charset/spi/CharsetProvider", + "gnu/java/net/loader/URLStreamHandlerCache", + "java/util/HashMap$HashIterator", + "java/util/HashMap$HashEntry", + "java/util/AbstractMap", + "java/util/AbstractMap$1", + "java/lang/RuntimeException", + "java/util/Collections$UnmodifiableSet", + "java/lang/ref/Reference", + "java/lang/ref/WeakReference", + "gnu/java/util/WeakIdentityHashMap$WeakBucket", + "gnu/java/util/WeakIdentityHashMap$WeakEntrySet$1", + "java/lang/String$CaseInsensitiveComparator", + "java/lang/Throwable$StaticData", + "java/lang/StackTraceElement", + "java/lang/VMMath", + "java/lang/Double", + "java/lang/VMDouble", + "java/lang/Long", + "java/lang/Float", + "java/lang/VMFloat", + "java/security/Permissions", /* 200 */ + "java/security/AllPermission", + "java/security/AllPermission$AllPermissionCollection", + "java/util/AbstractMap$1$1", /* 203 */ + "java/lang/Integer", + + NULL }; + + if (getenv("FILTER_VERBOSE") && !printed) + { + i = 0; + while (classes[i]) + { + log_println("[%d] - %s", i, classes[i]); + i++; + } + + printed = true; + } + + buf = getenv("INDEX"); + if (buf) + sscanf(buf, "%d", &max_index); + + i = 0; + while (classes[i] && i <= max_index) + { + + if (!strcmp(classes[i], classname->text)) + return true; + + i++; + } + + if ((buf = getenv("FILTER_VERBOSE"))) + { + log_println("filtered: %s", classname->text); + } + + return false; +} + +void filter_match() +{ + /* Wohoo! */ +} + +/** + * Causes filter_match() on which one can set a breakpoint in the debugger + * in the following conditions: + * + * If the environment variable NO_FILTER is set, then filter_match() is not + * called at all. This disables filter capabilities. + * + * If environment variable TEST_CLASS is set and the method belong to this + * class and there is no variable TEST_METHOD then filter_match() is called. + * + * If TEST_CLASS and TEST_METHOD match the methodinfo and TEST_DESCRIPTOR is + * not set. + * + * If TEST_CLASS, TEST_METHOD and TEST_DESCRIPTOR match the methodinfo's values. + */ +void filter_single(methodinfo *m) +{ + char *buf = NULL; + + buf = getenv("NO_FILTER"); + if (buf) + return; + + buf = getenv("TEST_CLASS"); + if (!buf || strcmp(m->clazz->name->text, buf)) + return; + + buf = getenv("TEST_METHOD"); + if (!buf) + { + filter_match(); + return; + } + else if (strcmp(m->name->text, buf)) + return; + + buf = getenv("TEST_DESCRIPTOR"); + if (!buf) + { + filter_match(); + return; + } + else if (strcmp(m->descriptor->text, buf)) + return; + + filter_match(); +} + +mutex_t jitcache_lock; + +/* jitcache_store ************************************************************** + + Saves the generated machine code to disk. + +*******************************************************************************/ +void jitcache_store (methodinfo *m) +{ + static int init_lock = true; + u1 *temp; + int fd; + + if (init_lock) + { + mutex_init(&jitcache_lock); + init_lock = false; + } + +/* + filter_single(m); + + if (!filter(m->clazz->name)) + return; +*/ + + /* Never try to store native method stubs because those include a reference + * a dynamically resolved function. + * + * TODO: Handle those, too. + */ + if (m->flags & ACC_NATIVE) + return; + + fd = get_cache_file_writable(m); + if (!fd) + { + if (opt_DebugJitCache) + log_message_method("[jitcache] store: got no file descriptor for ", m); + + return; + } + + /* Write (and some read) file operations beyond this point. + * Acquire lock first because another thread may try to load a different + * method from this class. + */ +/* mutex_lock(&m->clazz->cache_file_lock);*/ + mutex_lock(&jitcache_lock); + + if (opt_DebugJitCache) + log_message_method("[jitcache] store: ", m); + + update_method_table(m, fd); + + /* flags, optlevel, basicblockcount, synchronizedoffset, stackframesize, entrypoint, mcodelength, mcode + */ + system_write(fd, (const void *) &m->code->flags, sizeof(m->code->flags)); + + system_write(fd, (const void *) &m->code->optlevel, sizeof(m->code->optlevel)); + system_write(fd, (const void *) &m->code->basicblockcount, sizeof(m->code->basicblockcount)); + + system_write(fd, (const void *) &m->code->synchronizedoffset, sizeof(m->code->synchronizedoffset)); + + system_write(fd, (const void *) &m->code->stackframesize, sizeof(m->code->stackframesize)); + + temp = to_offset(m->code->mcode, m->code->entrypoint); + system_write(fd, (const void *) &temp, sizeof(temp)); + + system_write(fd, (const void *) &m->code->mcodelength, sizeof(m->code->mcodelength)); + + system_write(fd, (const void *) m->code->mcode, m->code->mcodelength); + + store_to_file_exceptiontable(fd, m->code); + + store_to_file_linenumbertable(fd, m->code); + + store_to_file_patchers(fd, m->code); + + store_to_file_cachedrefs(fd, m->code); + +/* mutex_unlock(&m->clazz->cache_file_lock);*/ + mutex_unlock(&jitcache_lock); + +} + +/* jitcache_load *************************************************************** + + Try to load previously generated machine code from disk. + + Returns non-zero if successfull. + +*******************************************************************************/ + +u1 jitcache_load (methodinfo *m) +{ + codeinfo *code; + u1 *endpc; + int fd; + +/* + if (!filter(m->clazz->name)) + return false; +*/ + + /* Never try to store native method stubs because those include a reference + * a dynamically resolved function. + */ + if (m->flags & ACC_NATIVE) + return false; + + fd = get_cache_file_readable(m); + if (fd <= 0) + { + if (opt_DebugJitCache) + log_message_method("[jitcache] load: got no file descriptor for ", m); + + return false; + } + + if(!seek_method_table(m, fd)) + { + system_close(fd); + + return false; + } + + if (opt_DebugJitCache) + log_message_method("[jitcache] load: ", m); + + code = code_codeinfo_new(m); + m->code = code; + + /* flags, optlevel, basicblockcount, synchronizedoffset, stackframesize, entrypoint, mcodelength, mcode + */ + system_read(fd, (void *) &code->flags, sizeof(code->flags)); + + system_read(fd, (void *) &code->optlevel, sizeof(code->optlevel)); + system_read(fd, (void *) &code->basicblockcount, sizeof(code->basicblockcount)); + + system_read(fd, (void *) &code->synchronizedoffset, sizeof(code->synchronizedoffset)); + + system_read(fd, (void *) &code->stackframesize, sizeof(code->stackframesize)); + + system_read(fd, (void *) &code->entrypoint, sizeof(code->entrypoint)); + + system_read(fd, (void *) &code->mcodelength, sizeof(code->mcodelength)); + + code->mcode = CNEW(u1, code->mcodelength); + system_read(fd, (void *) code->mcode, code->mcodelength); + code->entrypoint = to_abs(code->mcode, code->entrypoint); + + load_from_file_exceptiontable(code, fd); + + load_from_file_linenumbertable(code, fd); + + load_from_file_patchers(code, fd); + + load_from_file_cachedrefs(code, fd); + + system_close(fd); + + endpc = (u1 *) ((ptrint) code->mcode) + code->mcodelength; + + /* Insert method into methodtree to find the entrypoint. */ + + methodtree_insert(code->entrypoint, endpc); + + /* flush the instruction and data caches */ + + md_cacheflush(code->mcode, code->mcodelength); + + if (opt_DebugJitCache) + { + log_println("[jitcache] load - registered method: %x -> %x", code->entrypoint, endpc); + } + + return true; +} + +void jitcache_quit() +{ + int i; + + for (i = 0; i < mru_last_free; i++) + { + system_close(jc_mru_list[i]->cache_file_fd); + jc_mru_list[i]->cache_file_fd = 0; + jc_mru_list[i] = 0; + } + + mru_last_free = 0; + + /* Closes all open file descriptors. */ +} + +void jitcache_freeclass(classinfo *c) +{ + if (c->cache_file_fd) + jitcache_mru_remove(c); +} + +/* Helper functions */ +void update_method_table(methodinfo *m, int fd) +{ + int state = 0, i, temp, offset = 0; + + system_lseek(fd, 0, SEEK_SET); + + system_read(fd, (void *) &state, sizeof(state)); + + /* table does not exist yet and needs to be created first */ + if (state != 1) + { + system_lseek(fd, 0, SEEK_SET); + state = 1; + system_write(fd, &state, sizeof(state)); + + temp = -1; + for (i = 0; i < m->clazz->methodscount; i++) + system_write(fd, &temp, sizeof(temp)); + } + + /* get last offset in file */ + offset = system_lseek(fd, 0, SEEK_END); + + /* find out the index in the methods array */ + temp = -1; + for (i = 0; i < m->clazz->methodscount; i++) + if (&m->clazz->methods[i] == m) + { + temp = i; + break; + } + assert(temp != -1); + + /* seek to the method's entry in the table */ + system_lseek(fd, temp * sizeof(int) + sizeof(int), SEEK_SET); + + /* enter the location */ + system_write(fd, &offset, sizeof(offset)); + + system_lseek(fd, offset, SEEK_SET); +} + +int seek_method_table(methodinfo *m, int fd) +{ + int state = 0, i, temp, offset; + + system_lseek(fd, 0, SEEK_SET); + + system_read(fd, (void *) &state, sizeof(state)); + + /* if table does not exist, we cannot load any machine code from this file */ + if (state != 1) + return 0; + + /* find out the index in the methods array */ + temp = -1; + for (i = 0; i < m->clazz->methodscount; i++) + if (&m->clazz->methods[i] == m) + { + temp = i; + break; + } + assert(temp != -1); + + /* seek to the method's entry in the table */ + system_lseek(fd, temp * sizeof(int) + sizeof(int), SEEK_SET); + + /* get the location */ + system_read(fd, &offset, sizeof(offset)); + + if (offset > 0) + { + system_lseek(fd, offset, SEEK_SET); + return offset; + } + + return 0; +} + +int get_cache_file_readable(methodinfo *m) +{ + char *dest_file; + int fd; + + if (m->clazz->cache_file_fd) + return dup(m->clazz->cache_file_fd); + + + /* load from filesystem */ + dest_file = get_dest_file(m); + + if (system_access(dest_file, F_OK) != 0) + { + if (opt_DebugJitCache) + log_message_method("[jitcache] no cache file found for ", m); + + system_free(dest_file); + + return 0; + } + +/* + filter_single(m); +*/ + + fd = open_to_read(dest_file); + + system_free(dest_file); + +/* + if (fd > 0) + jitcache_mru_add(m->clazz, fd); +*/ + return fd; +} + +int get_cache_file_writable(methodinfo *m) +{ + char *dest_file, *dest_dir; + int fd; + + if (m->clazz->cache_file_fd) + return m->clazz->cache_file_fd; + + /* try to get the file first */ + dest_file = get_dest_file(m); + fd = open_to_write(dest_file); + + /* file does not exist. We need to create it and possibly + * the directory hierarchy as well. + */ + if (fd <= 0) { + dest_dir = get_dest_dir(m); + + if (system_access(dest_dir, F_OK) != 0) + { + if (mkdir_hier(dest_dir, S_IRWXU | S_IRWXG) != 0) + { + if (opt_DebugJitCache) + log_println("[jitcache] unable to create cache directory: %s", dest_dir); + + system_free(dest_dir); + system_free(dest_file); + + return 0; + } + } + + system_free(dest_dir); + + /* try to open the file again. */ + fd = open_to_write(dest_file); + system_free(dest_file); + + if (fd <= 0) + return 0; + } + + system_free(dest_file); + + jitcache_mru_add(m->clazz, fd); + + return fd; +} + +/* mkdir_hier ****************************************************************** + + Creates a directory hierarchy on the filesystem. + +*******************************************************************************/ +int mkdir_hier(char *path, mode_t mode) +{ + int index; + int length = system_strlen(path); + + for (index = 0; index < length; index++) + { + if (path[index] == '/') + { + path[index] = 0; + mkdir(path, mode); + + path[index] = '/'; + } + } + + return mkdir(path, mode); +} + +/* get_dest_file **************************************************************** + + Returns a string denoting the file in which the method's machine code + (along with the other data) is stored. + +*******************************************************************************/ + +char *get_dest_file(methodinfo *m) +{ + int len_cacheroot = system_strlen(CACHEROOT); + int len_classname = utf_bytes(m->clazz->name); + + char *dest_file = system_calloc(sizeof(u1), + len_cacheroot + + len_classname + + 2); + + strcat(dest_file, CACHEROOT); + utf_cat(dest_file, m->clazz->name); + + return dest_file; +} + +/* get_dest_dir **************************************************************** + + Returns a string denoting the directory in which the method's machine code + (along with the other data) is stored. + +*******************************************************************************/ + +char *get_dest_dir(methodinfo *m) +{ + int len_cacheroot = system_strlen(CACHEROOT); + int len_packagename = utf_bytes(m->clazz->packagename); + + char *dest_dir = system_calloc(sizeof(u1), + len_cacheroot + + len_packagename + 2); + + strcat(dest_dir, CACHEROOT); + utf_cat(dest_dir, m->clazz->packagename); + + /* Make trailing slash from package name to 0 */ + dest_dir[len_cacheroot + len_packagename + 2 - 1] = 0; + + return dest_dir; +} + +/* to_abs ********************************************************************** + + Generates an absolute pointer from an offset. You need this after loading + a value from the disk which is absolute at runtime. + +*******************************************************************************/ + +u1 *to_abs(u1 *base, u1 *offset) +{ + return (u1 *) ((ptrint) base + (ptrint) offset); +} + +/* to_offset ******************************************************************* + + Generates an offset from an absolute pointer. This has to be done to each + absolute pointer before storing it to disk. + +*******************************************************************************/ + +u1 *to_offset(u1 *base, u1 *abs) +{ + return (u1 *) ((ptrint) abs - (ptrint) base); +} + +/* open_to_read **************************************************************** + + Open a file for reading. + +*******************************************************************************/ + +int open_to_read(char *dest_file) +{ + int fd; +/* + fd = system_open(dest_file, O_RDONLY, 0); +*/ + fd = system_open(dest_file, + O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + return fd; +} + +/* open_to_write *************************************************************** + + Open a file for writing. + +*******************************************************************************/ + +int open_to_write(char *dest_file) +{ + int fd; + +/* fd = system_open(filename, + O_CREAT | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +*/ + fd = system_open(dest_file, + O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + return fd; +} + +/* store_utf ******************************************************************* + + Writes a utf object to disk (via filedescriptor). + +*******************************************************************************/ +void store_utf(int fd, utf *s) +{ + int len; + + if (!s) + { + len = -1; + system_write(fd, (const void *) &len, sizeof(len)); + } + else + { + len = utf_bytes(s); + system_write(fd, (const void *) &len, sizeof(len)); + system_write(fd, s->text, len); + } +} + +/* load_utf ******************************************************************** + + Loads a UTF8 constant from the given filedescriptor and initializes + the given pointer with it. + In case the stored constant's length is -1 the returned string is NULL. + +*******************************************************************************/ +void load_utf(utf **s, int fd) +{ + int len = 0; + char *tmp; + + system_read(fd, (void *) &len, sizeof(len)); + + if (len == -1) + *s = NULL; + else + { + tmp = system_calloc(sizeof(char), len); + + system_read(fd, tmp, len); + + *s = utf_new(tmp, len); + +/* system_free(tmp);*/ + } +} + + +/* store_to_file_patchers ****************************************************** + + Writes the patchers structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_patchers(int fd, codeinfo *code) +{ + int temp = 0; + u1 *temp_ptr; + patchref_t *pr; + int j; + + list_t *patchers = code->patchers; + + /* serialize patchers list */ + system_write(fd, (const void *) &patchers->size, sizeof(patchers->size)); + if (opt_DebugJitCache) + log_println("store_to_file_patchers - patchers size %d", patchers->size); + + for (pr = (patchref_t *) list_first(patchers); pr != NULL; pr = (patchref_t *) list_next(patchers, pr)) + { + temp_ptr = to_offset(code->mcode, (u1 *) pr->mpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + temp_ptr = to_offset(code->mcode, (u1 *) pr->datap); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + system_write(fd, (const void *) &pr->disp, sizeof(pr->disp)); + + temp = -1; + j = 0; + while (patcher_functions[j].patcher) + { + if (patcher_functions[j].patcher == pr->patcher) + { + temp = j; + system_write(fd, (const void *) &j, sizeof(j)); + + (*patcher_functions[j].serializer)(fd, pr, code->m); + + if (patcher_functions[j].serializer == s_dummy) + log_println("store_to_file_patchers: unhandled patcher function for %d", j); + break; + } + j++; + } + + if (temp == -1) + { + log_println("warning! unknown patcher function stored!"); + system_write(fd, (const void *) &temp, sizeof(temp)); + } + + system_write(fd, (const void *) &pr->attached_ref, sizeof(pr->attached_ref)); + + if (pr->attached_ref) + { + store_cachedref(fd, pr->attached_ref); + + /* Release the cached reference now because it should not be used + * in the current Cacao process. + */ + FREE(pr->attached_ref, cachedref_t); + pr->attached_ref = NULL; + } + + system_write(fd, (const void *) &pr->mcode, sizeof(pr->mcode)); + } +} + + +/* store_to_file_cachedrefs ***************************************************** + + Writes the cachedrefs structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_cachedrefs(int fd, codeinfo *code) +{ + cachedref_t *cr; + + list_t *cachedrefs = code->cachedrefs; + if (opt_DebugJitCache) + log_println("store_to_file_cachedrefs - cachedrefs size %d", cachedrefs->size); + + /* serialize cachedrefs list */ + system_write(fd, (const void *) &cachedrefs->size, sizeof(cachedrefs->size)); + + for (cr = (cachedref_t *) list_first(cachedrefs); + cr != NULL; + cr = (cachedref_t *) list_next(cachedrefs, cr)) + store_cachedref(fd, cr); +} + +/* store_cachedref ************************************************************* + + Stores a single cachedref_t instance to disk. + +*******************************************************************************/ + +void store_cachedref(int fd, cachedref_t *cr) +{ + system_write(fd, (const void *) &cr->type, sizeof(cr->type)); + system_write(fd, (const void *) &cr->md_patch, sizeof(cr->md_patch)); + system_write(fd, (const void *) &cr->disp, sizeof(cr->disp)); + + switch (cr->type) { + case CRT_CODEINFO: + case CRT_ENTRYPOINT: + case CRT_CODEGEN_FINISH_NATIVE_CALL: + case CRT_ASM_HANDLE_EXCEPTION: + case CRT_ASM_HANDLE_NAT_EXCEPTION: + /* Nothing to store. */ + break; + case CRT_NUM: + system_write(fd, (const void *) &cr->ref, sizeof(s4)); + break; + case CRT_OBJECT_HEADER: + case CRT_CLASSINFO: + case CRT_CLASSINFO_INDEX: + case CRT_CLASSINFO_INTERFACETABLE: + case CRT_CLASSINFO_VFTBL: + /* Store classinfo */ + store_classinfo(fd, (classinfo *) cr->ref); + break; + case CRT_BUILTIN: + case CRT_BUILTIN_FP: + store_builtin(fd, (builtintable_entry *) cr->ref); + break; + case CRT_STRING: + store_string(fd, (java_object_t *) cr->ref); + break; + case CRT_METHODINFO_STUBROUTINE: + case CRT_METHODINFO_TABLE: + case CRT_METHODINFO_INTERFACETABLE: + case CRT_METHODINFO_METHODOFFSET: + store_methodinfo(fd, (methodinfo *) cr->ref); + break; + case CRT_FIELDINFO_VALUE: + case CRT_FIELDINFO_OFFSET: + case CRT_FIELDINFO_OFFSET_HIGH: + store_fieldinfo(fd, (fieldinfo *) cr->ref); + break; + case CRT_JUMPREFERENCE: + system_write(fd, (const void *) &cr->ref, sizeof(cr->ref)); + + break; + default: + log_println("store_cachedref: Invalid cachedref type: %d", cr->type); + assert(0); + } +} + + +/* store_to_file_exceptiontable ************************************************ + + Writes the exceptiontable structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_exceptiontable(int fd, codeinfo *code) +{ + int count = 0; + u1 *temp_ptr; + int i; + utf *name; + + /* serialize exceptiontable */ + + /* temp will contain the amount of exceptiontable entries or zero + * if none exists. + */ + if (code->exceptiontable) + count = code->exceptiontable->length; + + system_write(fd, (const void *) &count, sizeof(count)); + if (opt_DebugJitCache) + log_println("store_exceptiontable - exceptiontable size %d", count); + + for (i = 0; i < count; i++) + { + exceptiontable_entry_t *entry = &code->exceptiontable->entries[i]; + + temp_ptr = to_offset(code->mcode, entry->endpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + temp_ptr = to_offset(code->mcode, entry->startpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + temp_ptr = to_offset(code->mcode, entry->handlerpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + /* store class name of entry->catchtype */ + if (entry->catchtype.any) + { + name = CLASSREF_OR_CLASSINFO_NAME(entry->catchtype); + store_utf(fd, name); + } + else + store_utf(fd, NULL); + + } + +} + + +/* store_to_file_linenumbertable *********************************************** + + Writes the linenumbertable structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_linenumbertable(int fd, codeinfo *code) +{ + void *temp_ptr; + linenumbertable_entry_t *lte; + int count = 0; + int i; + linenumbertable_t *linenumbertable; + + linenumbertable = code->linenumbertable; + + if (code->linenumbertable) + count = code->linenumbertable->length; + + /* serialize patchers list */ + system_write(fd, (const void *) &count, sizeof(count)); + + if (opt_DebugJitCache) + log_println("store_to_file_linenumbertable - linenumbertable size %d", count); + + if (count) + { + lte = linenumbertable->entries; + for (i = 0; i < count; i++) + { + system_write(fd, (const void *) <e->linenumber, sizeof(lte->linenumber)); + + temp_ptr = to_offset(code->entrypoint, lte->pc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + lte++; + } + } + +} + + +/* load_from_file_patchers ***************************************************** + + Loads the patchers structure of codeinfo from a file. + +*******************************************************************************/ +void load_from_file_patchers(codeinfo *code, int fd) +{ + int temp = 0; + u1 *temp_ptr; + int count = 0; + int i; + + /* serialize patchers list */ + system_read(fd, (void *) &count, sizeof(count)); + + if (opt_DebugJitCache /* Insert method into methodtree to find the entrypoint. */ +) + log_println("load_from_file_patchers - patcher size %d", count); + + patcher_list_create(code); + + for (i = 0;i < count; i++) + { + patchref_t *pr = NEW(patchref_t); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + pr->mpc = (ptrint) to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + pr->datap = (ptrint) to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &pr->disp, sizeof(pr->disp)); + + system_read(fd, (void *) &temp, sizeof(temp)); + if (temp == -1) + { + vm_abort("Invalid patcher function index loaded!"); + temp = 0; + } + pr->patcher = patcher_functions[temp].patcher; + + (*patcher_functions[temp].deserializer)(pr, fd, code->m); + + /* Load the pointer value to decide whether a cached reference must + * be loaded or not. */ + system_read(fd, (void *) &pr->attached_ref, sizeof(pr->attached_ref)); + + if (pr->attached_ref) + { + pr->attached_ref = NULL; + load_cachedref(&pr->attached_ref, fd, code); + } + + system_read(fd, (void *) &pr->mcode, sizeof(pr->mcode)); + + pr->done = false; + + list_add_first(code->patchers, pr); + } +} + +/* load_from_file_cachedrefs *************************************************** + + Loads the cachedrefs structure of codeinfo from a file. + + Note: code->entrypoint *must* be valid at this point! + + Binary format: + int - number of cachedref_t instances in the file + cachedref_t - see load_cachedref + +*******************************************************************************/ +void load_from_file_cachedrefs(codeinfo *code, int fd) +{ + cachedref_t *cr; + int count = 0; + int i; + + /* serialize cachedrefs list */ + system_read(fd, (void *) &count, sizeof(count)); + + if (opt_DebugJitCache) + log_println("load_from_file_cachedrefs - cachedrefs size %d", count); + + jitcache_list_reset(code); + + cr = NEW(cachedref_t); + + for (i = 0;i < count; i++) + { + load_cachedref(&cr, fd, code); + + /* Write the restored reference into the code. */ + if (cr->md_patch) + patch_md(cr->md_patch, ((ptrint) code->entrypoint) + cr->disp, cr->ref); + else + { + *((u1 **) (code->entrypoint + cr->disp)) = cr->ref; + } + + } + + FREE(cr, cachedref_t); +} + + +/* load_cachedref ************************************************************** + + Loads a cached reference from disk and + + Binary format: + s4 - disp value + cachedreftype - type value + * - cached ref specific (depends on type) + +*******************************************************************************/ + +void load_cachedref(cachedref_t **result_cr, int fd, codeinfo *code) +{ + cachedref_t *cr; + classinfo *ci; + methodinfo *mi; + fieldinfo *fi; + builtintable_entry *bte; + java_object_t *h; + + if (*result_cr) + cr = *result_cr; + else + *result_cr = cr = NEW(cachedref_t); + + system_read(fd, (void *) &cr->type, sizeof(cr->type)); + system_read(fd, (void *) &cr->md_patch, sizeof(cr->md_patch)); + system_read(fd, (void *) &cr->disp, sizeof(cr->disp)); + + switch (cr->type) { + case CRT_CODEINFO: + /* Just set the current codeinfo. */ + cr->ref = (voidptr) code; + break; + case CRT_NUM: + system_read(fd, (void *) &cr->ref, sizeof(s4)); + break; + case CRT_ENTRYPOINT: + /* Just set the current entrypoint. */ + cr->ref = (voidptr) code->entrypoint; + break; + case CRT_CODEGEN_FINISH_NATIVE_CALL: + /* Just set the pointer to codegen_finish_native_call. */ + cr->ref = (voidptr) (ptrint) codegen_finish_native_call; + break; + case CRT_ASM_HANDLE_EXCEPTION: + /* Just set the pointer to asm_handle_exception. */ + cr->ref = (voidptr) (ptrint) asm_handle_exception; + break; + case CRT_ASM_HANDLE_NAT_EXCEPTION: + /* Just put the pointer to asm_handle_nat_exception. */ + cr->ref = (voidptr) (ptrint) asm_handle_nat_exception; + break; + case CRT_OBJECT_HEADER: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = &ci->object.header; + break; + case CRT_BUILTIN: + load_builtin(&bte, fd); + /* TODO: For the time being prefer the stub if it exists, otherwise + * use the function pointer directlty. + * This should go away with a moving garbage collector. + */ + cr->ref = (voidptr) (bte->stub == NULL ? (ptrint) bte->fp : (ptrint) bte->stub); + + break; + case CRT_BUILTIN_FP: + load_builtin(&bte, fd); + cr->ref = (voidptr) (ptrint) bte->fp; + + break; + case CRT_STRING: + load_string(&h, fd); + cr->ref = (voidptr) h; + break; + case CRT_CLASSINFO: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (voidptr) ci; + + break; + case CRT_CLASSINFO_INDEX: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (voidptr) ci->index; + break; + case CRT_CLASSINFO_INTERFACETABLE: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (voidptr) (OFFSET(vftbl_t, interfacetable[0]) - + ci->index * sizeof(methodptr*)); + break; + case CRT_CLASSINFO_VFTBL: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (voidptr) ci->vftbl; + break; + case CRT_METHODINFO_STUBROUTINE: + load_methodinfo(&mi, fd, code->m); + cr->ref = (voidptr) mi->stubroutine; + break; + case CRT_METHODINFO_TABLE: + load_methodinfo(&mi, fd, code->m); + cr->ref = (voidptr) ((OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * mi->vftblindex)); + break; + case CRT_METHODINFO_INTERFACETABLE: + load_methodinfo(&mi, fd, code->m); + cr->ref = (voidptr) (OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr) * mi->clazz->index); + break; + case CRT_METHODINFO_METHODOFFSET: + load_methodinfo(&mi, fd, code->m); + cr->ref = (voidptr) ((sizeof(methodptr) * (mi - mi->clazz->methods))); + break; + case CRT_FIELDINFO_VALUE: + load_fieldinfo(&fi, fd, code->m); + + cr->ref = (voidptr) fi->value; + break; + case CRT_FIELDINFO_OFFSET: + load_fieldinfo(&fi, fd, code->m); + + cr->ref = (voidptr) fi->offset; + break; + case CRT_FIELDINFO_OFFSET_HIGH: + /* Should be used on 32 bit archs only. */ + load_fieldinfo(&fi, fd, code->m); + + cr->ref = (voidptr) fi->offset + 4; + break; + case CRT_JUMPREFERENCE: + system_read(fd, (void *) &cr->ref, sizeof(cr->ref)); + + cr->ref = (voidptr) ((ptrint) cr->ref + (ptrint) code->entrypoint); + break; + default: + log_println("Invalid (or unhandled) cachedreference type: %d", cr->type); + assert(0); + break; + } + + + if (opt_DebugJitCache) + { + if (cr->md_patch) + log_println("[%X, %d]: replace (md) %X with %X", code->entrypoint + cr->disp, cr->type, 0xFFF & (u4) (*(u1 **) (code->entrypoint + cr->disp)), cr->ref); + else + { + log_println("[%X, %d]: replace %X with %X", code->entrypoint + cr->disp, cr->type, *((u1 **) (code->entrypoint + cr->disp)), cr->ref); + if ((cr->type == CRT_BUILTIN || cr->type == CRT_BUILTIN_FP) && (voidptr) (*((u1 **) (code->entrypoint + cr->disp))) != cr->ref) + log_println("[!!!] differing builtin function pointer: %s", bte->cname); + } + } + + +} + +/* load_from_file_exceptiontable *********************************************** + + Loads the exceptiontable structure of codeinfo from a file. + +*******************************************************************************/ +void load_from_file_exceptiontable(codeinfo *code, int fd) +{ + int i; + u1 *temp_ptr; + utf *classname; + constant_classref *classref; + exceptiontable_entry_t *ete; + + code->exceptiontable = NEW(exceptiontable_t); + + system_read(fd, (void *) &code->exceptiontable->length, sizeof(code->exceptiontable->length)); + + if (opt_DebugJitCache) + log_println("load_exceptiontable - exceptiontable size %d", code->exceptiontable->length); + + + ete = MNEW(exceptiontable_entry_t, code->exceptiontable->length); + code->exceptiontable->entries = ete; + + for (i = 0; i < code->exceptiontable->length; i++) + { + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + ete->endpc = to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + ete->startpc = to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + ete->handlerpc = to_abs(code->mcode, temp_ptr); + + /* load class name of entry->catchtype */ + load_utf(&classname, fd); + + if (classname) + { + classref = NEW(constant_classref); + CLASSREF_INIT(*classref, code->m->clazz, classname); + + ete->catchtype = CLASSREF_OR_CLASSINFO(classref); + } + else + ete->catchtype.any = NULL; + + ete++; + } + +} + + +/* load_from_file_linenumbertable ********************************************** + + Loads the linenumbertable structure of codeinfo from a file. + +*******************************************************************************/ +void load_from_file_linenumbertable(codeinfo *code, int fd) +{ + linenumbertable_entry_t *lte; + void *temp_ptr; + int i; + + code->linenumbertable = NEW(linenumbertable_t); + + system_read(fd, (void *) &code->linenumbertable->length, sizeof(code->linenumbertable->length)); + + if (opt_DebugJitCache) + log_println("load_linenumbertable - linenumbertable size %d", code->linenumbertable->length); + + lte = MNEW(linenumbertable_entry_t, code->linenumbertable->length); + code->linenumbertable->entries = lte; + + for (i = 0;i < code->linenumbertable->length; i++) + { + system_read(fd, (void *) <e->linenumber, sizeof(lte->linenumber)); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + lte->pc = to_abs(code->entrypoint, temp_ptr); + + lte++; + } +} + + +/* s_dummy ********************************************************************* + + Patcher serialization function which does nothing and can therefore be used + as a placeholder for not yet written serializers. + +*******************************************************************************/ +void s_dummy(int fd, patchref_t *pr, methodinfo *m) +{ + /* Intentionally does nothing. */ +} + +/* s_unresolved_class ********************************************************** + + Serializes a unresolved_class reference. + + Binary format: + - utf string - classname + +*******************************************************************************/ +void s_unresolved_class(int fd, patchref_t *pr, methodinfo *m) +{ + unresolved_class *uc; + + uc = (unresolved_class *) pr->ref; + + /* Store the class name ... */ + store_utf(fd, uc->classref->name); + +/* + log_println("s_unresolved_class:"); + log_message_utf("class:", uc->classref->name); +*/ +} + +/* s_unresolved_field ********************************************************** + + Serializes a unresolved_field reference. + + Binary format: + s4 - unresolved_field.flags + int - index into class' cpinfo that denotes the unresolved_field's + constant_FMIref + +*******************************************************************************/ +void s_unresolved_field(int fd, patchref_t *pr, methodinfo *m) +{ + int i; + + unresolved_field *ref = (unresolved_field *) pr->ref; + +/* + log_println("s_unresolved_field:"); + log_message_utf("field name: ", ref->fieldref->name); + log_message_utf("field desc: ", ref->fieldref->descriptor); + log_message_utf("field's class: ", FIELDREF_CLASSNAME(ref->fieldref)); +*/ + system_write(fd, (const void *) &ref->flags, sizeof(ref->flags)); + + for (i = 0; i < m->clazz->cpcount; i++) + { + if (m->clazz->cpinfos[i] == (voidptr) ref->fieldref) + { + system_write(fd, (const void *) &i, sizeof(i)); + + return; + } + } + /* We should be out at this point. */ + + vm_abort("fieldref not found"); +} + +/* s_unresolved_method ********************************************************** + + Serializes a unresolved_method reference. + + Binary format: + undecided + +*******************************************************************************/ +void s_unresolved_method(int fd, patchref_t *pr, methodinfo *m) +{ + int i; + + unresolved_method *ref = (unresolved_method *) pr->ref; + + system_write(fd, (const void *) &ref->flags, sizeof(ref->flags)); + + for (i = 0; i < m->clazz->cpcount; i++) + { + if (m->clazz->cpinfos[i] == (voidptr) ref->methodref) + { + system_write(fd, (const void *) &i, sizeof(i)); + + return; + } + } + /* We should be out at this point. */ + + vm_abort("methodref not found"); +} + +/* s_classinfo ***************************************************************** + + Serializes a classinfo reference. + +*******************************************************************************/ +void s_classinfo(int fd, patchref_t *pr, methodinfo *m) +{ + classinfo *ci; + + ci = (classinfo *) pr->ref; + + store_classinfo(fd, ci); +} + +/* s_methodinfo **************************************************************** + + Serializes a methodinfo reference. + +*******************************************************************************/ +void s_methodinfo(int fd, patchref_t *pr, methodinfo *m) +{ + methodinfo *mi; + + mi = (methodinfo *) pr->ref; + + store_methodinfo(fd, mi); +} + +/* store_methodinfo ************************************************************ + + Serializes a methodinfo reference. + + Binary format: + utf - method name + utf - method descriptor + utf - class to which method belongs + +*******************************************************************************/ +void store_methodinfo(int fd, methodinfo *mi) +{ + store_utf(fd, mi->name); + store_utf(fd, mi->descriptor); + store_utf(fd, mi->clazz->name); +} + +/* s_fieldinfo **************************************************************** + + Serializes a fieldinfo reference. + + Binary format: + utf - field name + utf - field descriptor + utf - class to which field belongs + +*******************************************************************************/ +void s_fieldinfo(int fd, patchref_t *pr, methodinfo *m) +{ + fieldinfo *fi; + + fi = (fieldinfo *) pr->ref; + + store_fieldinfo(fd, fi); +} + +void store_fieldinfo(int fd, fieldinfo *fi) +{ + store_utf(fd, fi->name); + store_utf(fd, fi->descriptor); + store_utf(fd, fi->clazz->name); +} + +/* s_constant_classref ********************************************************* + + Serializes a constant_classref reference. + + Binary format: + - utf string - constant_classref's classname + +*******************************************************************************/ +void s_constant_classref(int fd, patchref_t *pr, methodinfo *m) +{ + constant_classref *cr = (constant_classref *) pr->ref; + + store_utf(fd, cr->name); +} + + +/* store_builtin ******************************************************************* + + Serializes a constant_classref reference. + + Binary format: + - s4 - key from builtintable_get_key() + +*******************************************************************************/ +void store_builtin(int fd, builtintable_entry *bte) +{ + s4 key; + + key = builtintable_get_key(bte); + + system_write(fd, (const void *) &key, sizeof(key)); +} + +/* store_string **************************************************************** + + Serializes a java_object_t reference which denotes a string. + + Binary format: + - utf - utf bytes of the string instance + +*******************************************************************************/ +void store_string(int fd, java_object_t *h) +{ + utf *string; + + string = javastring_toutf((java_handle_t *) h, false); + + store_utf(fd, string); +} + + +/* d_dummy ********************************************************************* + + Patcher deserialization function which does nothing and can therefore be used + as a placeholder for not yet written deserializers. + +*******************************************************************************/ +void d_dummy(patchref_t *pr, int fd, methodinfo *m) +{ + /* Intentionally do nothing. */ +} + +/* + * Loads UTF8 classname and creates an unresolved_class for it + * using the class to which the patchref_t belongs as the referer. + */ +void d_unresolved_class(patchref_t *pr, int fd, methodinfo *m) +{ + utf *classname; + constant_classref *classref; + unresolved_class *uc; + + classref = NEW(constant_classref); + + load_utf(&classname, fd); + + CLASSREF_INIT(*classref, m->clazz, classname); + + uc = create_unresolved_class(m, classref, NULL); + + pr->ref = (voidptr) uc; + +/* FREE(classref, constant_classref);*/ + +/* system_free(classname); */ +} + +void d_unresolved_field(patchref_t *pr, int fd, methodinfo *m) +{ + int i; + + unresolved_field *ref = NEW(unresolved_field); + + system_read(fd, (void *) &ref->flags, sizeof(ref->flags)); + + system_read(fd, (void *) &i, sizeof(i)); + ref->fieldref = (constant_FMIref *) m->clazz->cpinfos[i]; + + ref->referermethod = m; + + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); + + pr->ref = (voidptr) ref; +} + +void d_unresolved_method(patchref_t *pr, int fd, methodinfo *m) +{ + int i; + + unresolved_method *ref = NEW(unresolved_method); + + system_read(fd, (void *) &ref->flags, sizeof(ref->flags)); + + system_read(fd, (void *) &i, sizeof(i)); + ref->methodref = (constant_FMIref *) m->clazz->cpinfos[i]; + + ref->referermethod = m; + ref->paramconstraints = NULL; + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); + + pr->ref = (voidptr) ref; +} + +void d_classinfo(patchref_t *pr, int fd, methodinfo *m) +{ + classinfo *ci; + + load_classinfo(&ci, fd, m); + + pr->ref = (voidptr) ci; +} + +void d_methodinfo(patchref_t *pr, int fd, methodinfo *m) +{ + methodinfo *lm; + + load_methodinfo(&lm, fd, m); + + pr->ref = (voidptr) lm; +} + +void load_methodinfo(methodinfo **lm, int fd, methodinfo *m) +{ + utf *m_name; + utf *m_desc; + utf *classname; + classinfo *class; + constant_classref ref; + + load_utf(&m_name, fd); + load_utf(&m_desc, fd); + load_utf(&classname, fd); + + CLASSREF_INIT(ref, m->clazz, classname); + + class = resolve_classref_eager(&ref); + + *lm = class_findmethod(class, m_name, m_desc); +} + +void d_fieldinfo(patchref_t *pr, int fd, methodinfo *m) +{ + fieldinfo *fi; + + load_fieldinfo(&fi, fd, m); + + pr->ref = (voidptr) fi; +} + +void load_fieldinfo(fieldinfo **fi, int fd, methodinfo *m) +{ + utf *f_name; + utf *f_desc; + utf *classname; + classinfo *class; + constant_classref ref; + + load_utf(&f_name, fd); + load_utf(&f_desc, fd); + load_utf(&classname, fd); + + CLASSREF_INIT(ref, m->clazz, classname); + + class = resolve_classref_eager(&ref); +/* + if (!(class->state & CLASS_INITIALIZED)) + if (!initialize_class(class)) +*/ + *fi = class_findfield(class, f_name, f_desc); +} + +/* + * Loads UTF8 classname and initializes a constant_classref for it + * using the class to which the patchref_t belongs as the referer. + */ +void d_constant_classref(patchref_t *pr, int fd, methodinfo *m) +{ + utf *classname; + constant_classref *cr = NEW(constant_classref); + + load_utf(&classname, fd); + + CLASSREF_INIT(*cr, m->clazz, classname); + + pr->ref = (voidptr) cr; + +/* system_free(classname);*/ +} + +void load_builtin(builtintable_entry **bte, int fd) +{ + s4 key; + + system_read(fd, (void *) &key, sizeof(key)); + + *bte = builtintable_get_by_key(key); +} + +void load_string(java_object_t **h, int fd) +{ + utf *string; + + load_utf(&string, fd); + +/* *h = javastring_new(string);*/ + *h = literalstring_new(string); +} + +/* store_classinfo ************************************************************* + + Serializes a classinfo reference. + + Binary format: + - utf string - classinfo's classname + +*******************************************************************************/ +void store_classinfo(int fd, classinfo *ci) +{ + /* Store the class name ... */ + store_utf(fd, ci->name); +} + + +/* load_classinfo ************************************************************* + + Deserializes a classinfo reference. + + Binary format: see store_classinfo + +*******************************************************************************/ +void load_classinfo(classinfo **ci, int fd, methodinfo *m) +{ + utf *classname; + constant_classref *classref; + + classref = NEW(constant_classref); + + load_utf(&classname, fd); + + CLASSREF_INIT(*classref, m->clazz, classname); + + *ci = resolve_classref_eager(classref); +} +#endif + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/jitcache.h b/src/vm/jit/jitcache.h new file mode 100644 index 000000000..f80f7d5dd --- /dev/null +++ b/src/vm/jit/jitcache.h @@ -0,0 +1,174 @@ +/* src/vm/jit/jitcache.h - jit compiler output caching + + Copyright (C) 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + +*/ + +#ifndef _JITCACHE_H +#define _JITCACHE_H + +#if defined(ENABLE_JITCACHE) + +#include "config.h" + +#include + +#include "vm/jit/patcher-common.h" + +#include "vmcore/class.h" +#include "vmcore/method.h" + +typedef enum cachedreftype { + CRT_CODEINFO, + CRT_NUM, + CRT_ENTRYPOINT, + CRT_CODEGEN_FINISH_NATIVE_CALL, + CRT_ASM_HANDLE_EXCEPTION, /* 4 */ + CRT_ASM_HANDLE_NAT_EXCEPTION, + CRT_OBJECT_HEADER, + CRT_BUILTIN, /* 7 */ + CRT_BUILTIN_FP, + CRT_STRING, + CRT_CLASSINFO, /* 10 */ + CRT_CLASSINFO_INDEX, + CRT_CLASSINFO_INTERFACETABLE, + CRT_CLASSINFO_VFTBL, + CRT_METHODINFO_STUBROUTINE, /* 14 */ + CRT_METHODINFO_TABLE, + CRT_METHODINFO_INTERFACETABLE, + CRT_METHODINFO_METHODOFFSET, + CRT_FIELDINFO_VALUE, /* 18 */ + CRT_FIELDINFO_OFFSET, + CRT_FIELDINFO_OFFSET_HIGH, + CRT_JUMPREFERENCE /* 21 */ +} cachedreftype; + +/* cachedref_t ***************************************************************** + + A cached reference contains information about a code or data position + which needs patching after restoring the it from disk. + +*******************************************************************************/ + +typedef struct cachedref_t { + cachedreftype type; /* type of the cached reference */ + s4 md_patch; /* machine dependent back patching */ + s4 disp; /* displacement of ref in the data segment */ + voidptr ref; /* reference passed */ + listnode_t linkage; +} cachedref_t; + +/* +typedef struct mru_entry_t { + classinfo *clazz; + mutex_t lock; +} +*/ + +/* typedefs *******************************************************************/ + +typedef void (*serializerfptr) (int, patchref_t *, methodinfo *); +typedef void (*deserializerfptr) (patchref_t *, int, methodinfo *); + +/* jitcache_patcher_function_list_t typedef ***********************************/ + +typedef struct jitcache_patcher_function_list_t { + functionptr patcher; + serializerfptr serializer; + deserializerfptr deserializer; +} jitcache_patcher_function_list_t; + +/* function prototypes ********************************************************/ + +void jitcache_list_create(codeinfo *code); + +void jitcache_list_reset(codeinfo *code); + +void jitcache_list_free(codeinfo *code); + +void jitcache_add_cached_ref_jd(jitdata *jd, cachedreftype type, voidptr ref); + +void jitcache_add_cached_ref_md_jd(jitdata *jd, cachedreftype type, s4 md_patch, voidptr ref); + +void jitcache_add_cached_ref(codeinfo *code, cachedreftype type, voidptr ref, s4 disp); + +void jitcache_store(methodinfo *m); + +u1 jitcache_load(methodinfo *m); + +void jitcache_handle_cached_ref(cachedref_t *cr, codeinfo *code); + +void jitcache_quit(); + +void jitcache_freeclass(classinfo *); + +#define JITCACHE_ADD_CACHED_REF_JD(jd, type, ref) \ + (jitcache_add_cached_ref_jd(jd, type, ref)) + +#define JITCACHE_ADD_CACHED_REF_JD_COND(jd, type, ref, COND) \ + if (COND) \ + (jitcache_add_cached_ref_jd(jd, type, ref)) + +#define JITCACHE_ADD_CACHED_REF_MD_JD(jd, type, md_patch, ref) \ + (jitcache_add_cached_ref_md_jd(jd, type, md_patch, ref)) + +#define JITCACHE_ADD_CACHED_REF(code, type, ref, disp) \ + (jitcache_add_cached_ref(code, type, ref, disp)) + +#define JITCACHE_ADD_CACHED_REF_COND(code, type, ref, disp, COND) \ + if (COND) \ + jitcache_add_cached_ref(code, type, ref, disp) + +#else + +#define JITCACHE_ADD_CACHED_REF_JD(jd, type, ref) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF_JD_COND(jd, type, ref, COND) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF_MD_JD(jd, type, md_patch, ref) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF(code, type, ref, disp) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF_COND(code, type, ref, disp, COND) \ + while (0) { } + +#endif /* ENABLE_JITCACHE */ + +#endif /* _LINENUMBERTABLE_H */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/patcher-common.c b/src/vm/jit/patcher-common.c index b3fbe3042..dee3d3de5 100644 --- a/src/vm/jit/patcher-common.c +++ b/src/vm/jit/patcher-common.c @@ -211,6 +211,10 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref, pr->mcode = 0; pr->done = false; +#if defined(ENABLE_JITCACHE) + pr->attached_ref = NULL; +#endif + /* Generate NOPs for opt_shownops. */ if (opt_shownops) @@ -366,6 +370,15 @@ java_handle_t *patcher_handler(u1 *pc) } #endif +#if defined(ENABLE_JITCACHE) + /* Put cached reference into the code and remove it from the patcher */ + if (pr->attached_ref) + { + jitcache_handle_cached_ref(pr->attached_ref, code); + pr->attached_ref = NULL; + } +#endif + /* check for return value and exit accordingly */ if (result == false) { @@ -481,6 +494,28 @@ bool patcher_resolve_native_function(patchref_t *pr) return true; } +/** Placeholder functions to calm down linker */ +#if defined(__I386__) +bool patcher_resolve_classref_to_classinfo(patchref_t *pr) +{ + return true; +} + +bool patcher_resolve_classref_to_vftbl(patchref_t *pr) +{ + return true; +} + +bool patcher_resolve_classref_to_index(patchref_t *pr) +{ + return true; +} + +bool patcher_resolve_classref_to_flags(patchref_t *pr) +{ + return true; +} +#endif /* * These are local overrides for various environment variables in Emacs. diff --git a/src/vm/jit/patcher-common.h b/src/vm/jit/patcher-common.h index a10344797..f4cf9a507 100644 --- a/src/vm/jit/patcher-common.h +++ b/src/vm/jit/patcher-common.h @@ -39,6 +39,9 @@ #include "vm/jit/jit.h" +#if defined (ENABLE_JITCACHE) +struct cached_ref_t; +#endif /* patchref_t ****************************************************************** @@ -55,6 +58,11 @@ typedef struct patchref_t { voidptr ref; /* reference passed */ u8 mcode; /* machine code to be patched back in */ bool done; /* XXX preliminary: patch already applied? */ +#if defined (ENABLE_JITCACHE) + struct cachedref_t *attached_ref; + /* cached reference which must be resolved * + * patcher has been run. */ +#endif listnode_t linkage; } patchref_t; @@ -181,6 +189,7 @@ bool patcher_instanceof_class(patchref_t *pr); #endif /* defined(__I386__) */ +void patch_md(s4 md_patch, ptrint dest, voidptr ref); #endif /* _PATCHER_COMMON_H */ diff --git a/src/vm/resolve.c b/src/vm/resolve.c index b125bdefc..a98388550 100644 --- a/src/vm/resolve.c +++ b/src/vm/resolve.c @@ -2241,7 +2241,7 @@ resolved_the_method: /* check subtype constraints for TYPE_ADR parameters */ - assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); + assert(mi == ref->methodref->p.method || mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); paramtypes = mi->parseddesc->paramtypes; for (i = 0; i < mi->parseddesc->paramcount-instancecount; i++) { diff --git a/src/vm/vm.c b/src/vm/vm.c index 5fa1f57a1..84a9a7351 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -86,6 +86,7 @@ #include "vm/jit/argument.h" #include "vm/jit/asmpart.h" #include "vm/jit/code.h" +#include "vm/jit/jitcache.h" #if defined(ENABLE_DISASSEMBLER) # include "vm/jit/disass.h" @@ -1937,6 +1938,10 @@ void vm_shutdown(s4 status) } #endif +#if defined (ENABLE_JITCACHE) + jitcache_quit(); +#endif + exit(status); } diff --git a/src/vmcore/class.c b/src/vmcore/class.c index ec8432278..51470abf8 100644 --- a/src/vmcore/class.c +++ b/src/vmcore/class.c @@ -49,6 +49,7 @@ #include "vm/resolve.h" #include "vm/jit/asmpart.h" +#include "vm/jit/jitcache.h" #include "vmcore/class.h" #include "vmcore/classcache.h" @@ -265,6 +266,9 @@ classinfo *class_create_classinfo(utf *classname) if (classname != utf_not_named_yet) class_set_packagename(c); +#if defined (ENABLE_JITCACHE) + c->cache_file_fd = 0; +#endif LOCK_INIT_OBJECT_LOCK(&c->object.header); @@ -809,6 +813,11 @@ void class_free(classinfo *c) s4 i; vftbl_t *v; +#if defined(ENABLE_JITCACHE) +/* TODO: Find a way around the linker problem */ +/* jitcache_freeclass(c);*/ +#endif + class_freecpool(c); if (c->interfaces != NULL) diff --git a/src/vmcore/class.h b/src/vmcore/class.h index 59d56fd56..4b8be1be5 100644 --- a/src/vmcore/class.h +++ b/src/vmcore/class.h @@ -56,7 +56,6 @@ typedef struct castinfo castinfo; #include "vmcore/references.h" #include "vmcore/utf8.h" - /* class state defines ********************************************************/ #define CLASS_LOADING 0x0001 @@ -166,6 +165,9 @@ struct classinfo { /* class structure */ java_objectarray_t *signers; # endif #endif +#if defined(ENABLE_JITCACHE) + int cache_file_fd; +#endif }; diff --git a/src/vmcore/options.c b/src/vmcore/options.c index e9ae46fbc..a5494ba56 100644 --- a/src/vmcore/options.c +++ b/src/vmcore/options.c @@ -113,6 +113,10 @@ bool opt_prof = false; bool opt_prof_bb = false; #endif +#if defined(ENABLE_JITCACHE) +bool opt_jitcache = false; +bool opt_jitcache_details = false; +#endif /* optimization options *******************************************************/ @@ -164,6 +168,9 @@ int opt_ThreadStackSize = 0; int opt_DebugExceptions = 0; int opt_DebugFinalizer = 0; +#if defined(ENABLE_JITCACHE) +int opt_DebugJitCache = 0; +#endif int opt_DebugLocalReferences = 0; int opt_DebugLocks = 0; int opt_DebugPackage = 0; @@ -231,6 +238,7 @@ enum { OPT_DebugExceptions, OPT_DebugFinalizer, + OPT_DebugJitCache, OPT_DebugLocalReferences, OPT_DebugLocks, OPT_DebugPackage, @@ -283,6 +291,9 @@ option_t options_XX[] = { { "DebugExceptions", OPT_DebugExceptions, OPT_TYPE_BOOLEAN, "debug exceptions" }, { "DebugFinalizer", OPT_DebugFinalizer, OPT_TYPE_BOOLEAN, "debug finalizer thread" }, +#if defined (ENABLE_JITCACHE) + { "DebugJitCache", OPT_DebugJitCache, OPT_TYPE_BOOLEAN, "debug JIT cache actions" }, +#endif { "DebugLocalReferences", OPT_DebugLocalReferences, OPT_TYPE_BOOLEAN, "print debug information for local reference tables" }, { "DebugLocks", OPT_DebugLocks, OPT_TYPE_BOOLEAN, "print debug information for locks" }, { "DebugPackage", OPT_DebugPackage, OPT_TYPE_BOOLEAN, "debug Java boot-packages" }, @@ -618,6 +629,12 @@ void options_xx(JavaVMInitArgs *vm_args) opt_DebugFinalizer = enable; break; +#if defined(ENABLE_JITCACHE) + case OPT_DebugJitCache: + opt_DebugJitCache = enable; + break; +#endif + case OPT_DebugLocalReferences: opt_DebugLocalReferences = enable; break; diff --git a/src/vmcore/options.h b/src/vmcore/options.h index ca4e09666..6bc04c841 100644 --- a/src/vmcore/options.h +++ b/src/vmcore/options.h @@ -183,6 +183,9 @@ extern int opt_ThreadStackSize; extern int opt_DebugExceptions; extern int opt_DebugFinalizer; +#if defined(ENABLE_JITCACHE) +extern int opt_DebugJitCache; +#endif extern int opt_DebugLocalReferences; extern int opt_DebugLocks; extern int opt_DebugPatcher; diff --git a/src/vmcore/references.h b/src/vmcore/references.h index 6ac233618..9fa790c34 100644 --- a/src/vmcore/references.h +++ b/src/vmcore/references.h @@ -136,7 +136,7 @@ struct constant_FMIref{ /* Fieldref, Methodref and InterfaceMethodref */ (IS_FMIREF_RESOLVED(fmiref) ? (fmiref)->p.method->clazz->name \ : (fmiref)->p.classref->name) -/* macro for accessing the class name of a method reference */ +/* macro for accessing the class name of a field reference */ #define FIELDREF_CLASSNAME(fmiref) \ (IS_FMIREF_RESOLVED(fmiref) ? (fmiref)->p.field->clazz->name \ : (fmiref)->p.classref->name) diff --git a/src/vmcore/statistics.c b/src/vmcore/statistics.c index 99781e8c6..dbffc1173 100644 --- a/src/vmcore/statistics.c +++ b/src/vmcore/statistics.c @@ -109,6 +109,8 @@ int32_t size_linenumbertable = 0; s4 size_patchref = 0; +s4 size_cachedref = 0; + u8 count_calls_java_to_native = 0; u8 count_calls_native_to_java = 0; @@ -695,12 +697,14 @@ void statistics_print_memory_usage(void) log_println("linenumber tables (%5d): %10d", count_linenumbertable, size_linenumbertable); log_println("exception tables: %10d", count_extable_len); log_println("patcher references: %10d", size_patchref); + log_println("cached references: %10d", size_cachedref); log_println(" ----------"); sum = size_linenumbertable + count_extable_len + - size_patchref; + size_patchref + + size_cachedref; log_println(" %10d", sum); diff --git a/src/vmcore/statistics.h b/src/vmcore/statistics.h index 62730ce93..3bae33bd8 100644 --- a/src/vmcore/statistics.h +++ b/src/vmcore/statistics.h @@ -114,6 +114,8 @@ extern int32_t size_linenumbertable; extern s4 size_patchref; +extern s4 size_cachedref; + extern u8 count_calls_java_to_native; extern u8 count_calls_native_to_java; diff --git a/src/vmcore/system.h b/src/vmcore/system.h index f927ab1b0..8a052aedc 100644 --- a/src/vmcore/system.h +++ b/src/vmcore/system.h @@ -225,6 +225,15 @@ inline static size_t system_fread(void *ptr, size_t size, size_t nmemb, FILE *st #endif } +inline static int system_fseek(FILE *stream, off_t offset, int whence) +{ +#if defined(HAVE_FSEEK) + return fseek(stream, offset, whence); +#else +# error fseek not available +#endif +} + inline static void system_free(void *ptr) { #if defined(HAVE_FREE)