- created jitcache-arm-x86 branch
authorRobert Schuster <robertschuster@fsfe.org>
Fri, 27 Jun 2008 11:35:14 +0000 (13:35 +0200)
committerRobert Schuster <robertschuster@fsfe.org>
Fri, 27 Jun 2008 11:35:14 +0000 (13:35 +0200)
 - initial import of the jitcache work to this branch

--HG--
branch : jitcache-arm-x86

27 files changed:
configure.ac
m4/jitcache.m4 [new file with mode: 0644]
src/vm/builtin.c
src/vm/builtin.h
src/vm/jit/Makefile.am
src/vm/jit/arm/codegen.c
src/vm/jit/arm/patcher.c
src/vm/jit/code.c
src/vm/jit/code.h
src/vm/jit/codegen-common.c
src/vm/jit/i386/codegen.c
src/vm/jit/i386/patcher.c
src/vm/jit/jit.c
src/vm/jit/jitcache.c [new file with mode: 0644]
src/vm/jit/jitcache.h [new file with mode: 0644]
src/vm/jit/patcher-common.c
src/vm/jit/patcher-common.h
src/vm/resolve.c
src/vm/vm.c
src/vmcore/class.c
src/vmcore/class.h
src/vmcore/options.c
src/vmcore/options.h
src/vmcore/references.h
src/vmcore/statistics.c
src/vmcore/statistics.h
src/vmcore/system.h

index 45fcc80a753ca153bf4adaa8bb7e15e622aec5cc..61b3bffe77268cc9d8d442d5ea83c56b1464ba33 100644 (file)
@@ -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 (file)
index 0000000..d873f30
--- /dev/null
@@ -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
+])
index 417aced8f73eb33e5ca0c143979a29e8bc0e4322..dab69a171795b276ccd7fce46e18907bed463f75 100644 (file)
@@ -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
index 9177c32e427d6649e0cca5a8730c98410e835b60..af6c51eb8bd855d49ebee528ddefafbc53839163 100644 (file)
@@ -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*
index 015a917ce6cc392c394ac03c84dfd99e8638e1cd..5c2aada1d2d70c77921b87dd4b2d6102fb562626 100644 (file)
@@ -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 \
index 00a37a24206fb919ebe14e382dd6f2a6148977ae..41bccef1bb0553be650dcb28762542b76b7e637a 100644 (file)
@@ -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 */
index 84e8287c502cb4a1b5f509a1e77f70daa1462aef..4c3ad2805bcf1472709253dd17f5d51a5637579a 100644 (file)
                /*(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 **********************************************************
 
index 3bdc4678f5e4467ae9d329bd1f6e7e1c50fe9684..0a7e70cc589b0f975f1821a26f64c0762595d8a5 100644 (file)
@@ -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
index adff257fe0262c85398d156effa7bb900144a240..b2f9fcdf505fae5f84388397fc668f92f43c0f25 100644 (file)
@@ -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    */
 
index 045a44c86123ca17d057f1fd734cfc1e887ac31a..6f9cb4039fa26d680d27206ff9a5bc63b8f9a5a7 100644 (file)
@@ -45,6 +45,8 @@
 #include <assert.h>
 #include <string.h>
 
+#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);
index 5123b4b230140158ad270b3b14e9ebf5b36493d2..6c08b9cfb756126d328766c526eda5546a7468ee 100644 (file)
@@ -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
 
index 661c245e4ad0851dac5d088a938b982937d924aa..4aa86f6e23afe739d0c23bc521f2a1cd807140ca 100644 (file)
@@ -263,7 +263,7 @@ bool patcher_putfieldconst(patchref_t *pr)
 
    Machine code:
 
-   <patched call postition>
+   <patched call position>
    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;
index e6f17c2d83f5266996607b181bd4b0c5b4682654..4225c66c66da01876cf354b5915ddb11b26d2dbb 100644 (file)
 #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 (file)
index 0000000..0028b22
--- /dev/null
@@ -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 <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 *) &lte->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 *) &lte->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 (file)
index 0000000..f80f7d5
--- /dev/null
@@ -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 <stdint.h>
+
+#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:
+ */
index b3fbe3042570bdce3ca4e330c5c29420e9cf20b9..dee3d3de592714dc863fe3a2d66db4a9dde01a56 100644 (file)
@@ -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.
index a103447976fe3f2bbc01f32f26343b180755e116..f4cf9a50745fa90ea1fba843596488f836d1ee15 100644 (file)
@@ -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 */
 
index b125bdefc2d4e590d608cb88be502d0419186a2d..a98388550e533d90431e95ef0b5bd482492122a2 100644 (file)
@@ -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++) {
index 5fa1f57a1db303de45b7fe3d55459255e5654268..84a9a7351b553a4f3f67a16d78660fbf1f33d0ca 100644 (file)
@@ -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);
 }
 
index ec8432278550d6e33f5e891ddb9c62c6088d9716..51470abf8e3cad71b388021467b976a91fda35eb 100644 (file)
@@ -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)
index 59d56fd56cc0c7341fb20cec26ca431966dcf435..4b8be1be518b80facab19da89b63c5eda1bda154 100644 (file)
@@ -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
 };
 
 
index e9ae46fbcd763f25f93db60501fea452229bb28d..a5494ba5696192de279fe417cf78eadd0c4d4208 100644 (file)
@@ -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;
index ca4e09666c6ab77c0eab2078ee93a508260f1a72..6bc04c8411faef05ead51730389f499d7310ac6e 100644 (file)
@@ -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;
index 6ac233618293bbebde516c81cc4574a9df1fe234..9fa790c342fe15c2ce872b511fa8f6ab88fb4910 100644 (file)
@@ -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)
index 99781e8c682ae17d329d217d30cf11161e108ec1..dbffc11731ff9d1618e945ae4ad89bf41f409012 100644 (file)
@@ -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);
 
index 62730ce9335ef156be0721f9ad04140604c73b2c..3bae33bd877b42eb0ed25e99bef091cc6188304c 100644 (file)
@@ -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;
 
index f927ab1b0067e054af5f5e15b1be43bd5bc44276..8a052aedc9a06a06b041c28345eda1086299c7d1 100644 (file)
@@ -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)