#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)
savedregs_num += (FLT_SAV_CNT - rd->savfltreguse);
cd->stackframesize = rd->memuse + savedregs_num;
-
#if defined(ENABLE_THREADS)
/* space to save argument of monitor_enter */
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 */
/* 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
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);
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
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);
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);
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;
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;
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);
}
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);
/* 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) {
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);
/* 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) {
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);
/* 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,
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);
/* 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,
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);
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))
}
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:
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:
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))
}
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:
else {
fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
+
disp = fi->offset;
+
}
switch (fieldtype) {
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;
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 */
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);
}
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)
}
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;
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;
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;
}
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);
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);
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);
}
M_MOV_IMM(supervftbl, REG_ITMP3);
+ JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super);
CODEGEN_CRITICAL_SECTION_START;
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;
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);
emit_label_beq(cd, BRANCH_LABEL_3);
}
+
M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
if (super == NULL) {
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 */ +
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); */
}
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));
/* 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 */
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 */
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
--- /dev/null
+/* 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 <sys/stat.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#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 <stdlib.h>
+#include <stdio.h>
+
+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:
+ */