* merged default branch into jitcache-arm-x86 branch
authorRobert Schuster <robertschuster@fsfe.org>
Fri, 10 Oct 2008 14:18:16 +0000 (16:18 +0200)
committerRobert Schuster <robertschuster@fsfe.org>
Fri, 10 Oct 2008 14:18:16 +0000 (16:18 +0200)
--HG--
branch : jitcache-arm-x86
rename : src/vm/class.c => src/vm/class.cpp
rename : src/vm/class.h => src/vm/class.hpp
rename : src/vm/resolve.c => src/vm/resolve.cpp

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

index bfd698fb5f3836f4518e87e5fa041527e27c454d..a9572aad24d93a69bb131314587dec47abcbd850 100644 (file)
@@ -331,6 +331,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])
@@ -437,6 +438,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 6444cbb6750449a5b869fa7416a54b6dd12311c1..1e479529b61ce124f11a7ff33fa9b02a83a24cfe 100644 (file)
@@ -51,6 +51,7 @@
 #include "vm/global.h"
 #include "vm/globals.hpp"
 #include "vm/javaobjects.hpp"
+#include "vm/jit/jitcache.hpp"
 #include "vm/linker.h"
 #include "vm/loader.hpp"
 #include "vm/options.h"
@@ -176,6 +177,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
 
        c->object.header.lockword.init();
 
@@ -720,6 +724,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 c82e4bf244092e56f767483fe2c2715f29f0b559..f643fd357850d1398b12e49b132475afa0b220e7 100644 (file)
@@ -52,7 +52,6 @@ typedef struct extra_classref extra_classref;
 #include "vm/string.hpp"
 #include "vm/utf8.h"
 
-
 /* class state defines ********************************************************/
 
 #define CLASS_LOADING         0x0001
@@ -162,6 +161,9 @@ struct classinfo {                /* class structure                          */
        java_objectarray_t *signers;
 # endif
 #endif
+#if defined(ENABLE_JITCACHE)
+       int         cache_file_fd;
+#endif
 };
 
 
index ce48bfff76f1f82a75b9aca5e1209cc6f3469d3c..c8d27ba749d5334d83230a0ae1d4c9c6e27790f8 100644 (file)
@@ -114,6 +114,14 @@ TRAP_SOURCES = \
        trap.h
 endif
 
+if ENABLE_JITCACHE
+JITCACHE_SOURCES = \
+       jitcache.cpp \
+       jitcache.hpp
+
+endif
+
+
 if ENABLE_REPLACEMENT
 REPLACE_SOURCES += \
        replace.cpp
@@ -179,6 +187,7 @@ libjit_la_SOURCES = \
        patcher-common.hpp \
        $(RECOMPILE_SOURCES) \
        $(REG_SOURCES) \
+       $(JITCACHE_SOURCES) \
        $(REPLACE_SOURCES) \
        show.cpp \
        show.hpp \
index 09f3d0b5f2cb5c0d260d06faa7a807b5963748db..efe6d3d746eac7d775dae8bc56eb9495294cb972 100644 (file)
@@ -55,6 +55,7 @@
 #include "vm/jit/dseg.h"
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
+#include "vm/jit/jitcache.hpp"
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/methodheader.h"
 #include "vm/jit/parse.h"
@@ -140,7 +141,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;
@@ -278,6 +285,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 {
@@ -286,6 +294,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);
@@ -409,7 +419,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;
@@ -678,6 +714,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 */
@@ -707,6 +744,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 */
@@ -1367,6 +1405,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 */
@@ -1397,7 +1439,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);
@@ -1450,7 +1492,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);
@@ -1643,6 +1685,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);
@@ -2131,6 +2174,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 */
@@ -2260,6 +2307,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 */
@@ -2282,7 +2331,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 */
 
@@ -2296,6 +2348,7 @@ bool codegen_emit(jitdata *jd)
 
                        case ICMD_INVOKEVIRTUAL:
                                if (lm == NULL) {
+
                                        patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0);
 
                                        s1 = 0;
@@ -2303,12 +2356,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);
@@ -2334,7 +2387,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 */
 
@@ -2447,6 +2502,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);
                                }
@@ -2512,7 +2570,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);
                                }
@@ -2554,10 +2612,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 */
@@ -2633,6 +2695,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);
@@ -2703,6 +2768,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);
@@ -2769,7 +2835,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 */
 
@@ -2782,6 +2851,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 36f0adfc328d561a9f6fbfa6b313d002f982011b..da037dd68934f2f38f59cb768d6a80a7a02763c8 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, void* ref)
+{
+       gen_resolveload_unchecked(*((s4 *) dest), (s4) ref);
+}
 
 /* patcher_patch_code **********************************************************
 
index 39448913e38f885b47bcac9de6aea6312fc837ce..f3ebf0ad7c96900f5821b47c8f770c9885a6300e 100644 (file)
@@ -267,6 +267,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 2a03455299c52069529db48f81d0e9b410789cb4..3a7747dc291bf6702747dfd5b0ffec69f1615a05 100644 (file)
@@ -94,6 +94,8 @@ extern "C" {
 
 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);
 
@@ -115,7 +117,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 b39852d2ed7a8f20024421d435153fc70bb2bb25..a991de2895c9938070b835979e3b0d4f39c9430f 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "vm/jit/code.hpp"
 #include "vm/jit/codegen-common.hpp"
+#include "vm/jit/jitcache.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/methodtree.h"
 
@@ -66,6 +67,7 @@ void code_init(void)
    The following fields are set in codeinfo:
        m
        patchers
+          cachedrefs
 
    RETURN VALUE:
        a new, initialized codeinfo, or
@@ -83,7 +85,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
@@ -234,6 +240,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 cd082dd19f93b2963be4985037c6e11e7f771da1..fcdb08c686b06ecaf75b4e3a0973751e32e24dfb 100644 (file)
@@ -39,6 +39,9 @@
 #include "vm/method.h"
 
 #include "vm/jit/exceptiontable.h"
+#if defined (ENABLE_JITCACHE)
+#include "vm/jit/jitcache.hpp"
+#endif
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/methodheader.h"
 #include "vm/jit/patcher-common.hpp"
@@ -90,6 +93,14 @@ struct codeinfo {
        List*         patchers;
 #endif
 
+#if defined (ENABLE_JITCACHE)
+#ifdef __cplusplus
+       List<cachedref_t>* cachedrefs;
+#else
+       List*         cachedrefs;
+#endif
+#endif
+
        /* replacement */                                   
        s4            stackframesize;       /* size of the stackframe in slots    */
 
index 173c272c5b5d6eac1b21355ca05501e61a31d3fc..47ad041c746bba5c21f8d237ba258fea267d6ee2 100644 (file)
@@ -45,6 +45,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include "vm/jit/jitcache.hpp"
+
 #include "vm/types.h"
 
 #include "codegen.h"
@@ -652,9 +654,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 1252e136ac09e7e1c89e22669df606846d4db23e..b7e808cabc8f7ecaa927bb0ea5b0bb89c9e6e26a 100644 (file)
@@ -58,6 +58,7 @@
 #include "vm/jit/dseg.h"
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
+#include "vm/jit/jitcache.hpp"
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/parse.h"
 #include "vm/jit/patcher-common.hpp"
@@ -134,7 +135,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 */
@@ -153,7 +153,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       */
 
@@ -176,6 +181,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
@@ -354,6 +361,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);
@@ -365,6 +373,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
@@ -566,6 +576,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);
@@ -594,6 +605,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);
@@ -613,7 +625,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) ? (void*) iptr->sx.val.c.cls
+                                                                                                                       : (void*) iptr->sx.val.stringconst);
+                               }
                        }
                        emit_store_dst(jd, iptr, d);
                        break;
@@ -995,6 +1015,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;
@@ -1562,6 +1583,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);
                        }
@@ -1591,6 +1613,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);
@@ -1636,6 +1659,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) {
@@ -1653,6 +1678,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);
@@ -1698,6 +1724,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) {
@@ -1714,6 +1742,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);
@@ -1757,6 +1786,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, 
@@ -1775,6 +1806,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);
@@ -1817,6 +1849,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, 
@@ -2103,6 +2137,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);
 
@@ -2191,6 +2227,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))
@@ -2198,6 +2235,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:
@@ -2232,13 +2270,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:
@@ -2274,6 +2313,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))
@@ -2281,6 +2321,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:
@@ -2315,7 +2356,9 @@ bool codegen_emit(jitdata *jd)
                        else {
                                fi        = iptr->sx.s23.s3.fmiref->p.field;
                                fieldtype = fi->type;
+
                                disp      = fi->offset;
+
                        }
 
                        switch (fieldtype) {
@@ -2449,6 +2492,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;
 
@@ -2763,6 +2807,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 */
@@ -2852,6 +2898,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);
                        }
@@ -2975,6 +3022,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)
@@ -3001,10 +3049,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;
 
@@ -3023,12 +3072,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;
 
@@ -3057,7 +3108,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;
                        }
@@ -3114,11 +3167,9 @@ gen_method:
                                        superindex = super->index;
                                        supervftbl = super->vftbl;
                                }
-                       
                                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);
@@ -3150,6 +3201,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);
@@ -3157,6 +3209,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);
 
@@ -3186,6 +3239,7 @@ gen_method:
                                        }
 
                                        M_MOV_IMM(supervftbl, REG_ITMP3);
+                                       JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super);
 
                                        M_ILD32(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
 
@@ -3201,6 +3255,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));
 
                                        /*                              } */
@@ -3228,10 +3283,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 = (ptrint) 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);
@@ -3295,6 +3358,7 @@ gen_method:
                                        emit_label_beq(cd, BRANCH_LABEL_3);
                                }
 
+
                                M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
 
                                if (super == NULL) {
@@ -3305,6 +3369,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 */ +
@@ -3314,6 +3380,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); */
@@ -3345,7 +3412,7 @@ gen_method:
                                }
 
                                M_MOV_IMM(supervftbl, REG_ITMP2);
-
+                               JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super);
                                M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
                                M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, diffval));
                                M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
@@ -3409,6 +3476,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 */
 
@@ -3417,6 +3485,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 */
@@ -3538,6 +3608,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 fa55465e22c61bb36e6f079f164f252b34c418bc..b2297fcd2cf0b801bb941b9d32a1b43fef024b5b 100644 (file)
@@ -245,7 +245,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
 
@@ -380,7 +380,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 095e9840155dba245ac7ec97a0a07909feaa1efb..09c9e862eb6798d7cdffc17aa234b89e7b861da2 100644 (file)
 #include "vm/jit/stack.h"
 #include "vm/jit/stubs.hpp"
 
+#if defined(ENABLE_JITCACHE)
+# include "vm/jit/jitcache.hpp"
+#endif
+
 #if defined(ENABLE_OPAGENT)
 #include "vm/jit/oprofile-agent.hpp"
 #endif
@@ -312,6 +316,17 @@ u1 *jit_compile(methodinfo *m)
 
        STATISTICS(count_methods++);
 
+#if defined (ENABLE_JITCACHE)
+
+       if (jitcache_load (m))
+       {
+               m->mutex->unlock();
+
+               return m->code->entrypoint;
+       }
+
+#endif
+
 #if defined(ENABLE_STATISTICS)
        /* measure time */
 
@@ -402,6 +417,10 @@ u1 *jit_compile(methodinfo *m)
                DEBUG_JIT_COMPILEVERBOSE("Running: ");
        }
 
+#if defined (ENABLE_JITCACHE)
+       jitcache_store(m);
+#endif
+
 #if defined(ENABLE_STATISTICS)
        /* measure time */
 
diff --git a/src/vm/jit/jitcache.cpp b/src/vm/jit/jitcache.cpp
new file mode 100644 (file)
index 0000000..2cd93a2
--- /dev/null
@@ -0,0 +1,2393 @@
+/* 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)
+
+#include "threads/thread.hpp"
+
+#include "toolbox/list.hpp"
+
+#include "vm/field.hpp"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/jit/code.hpp"
+#include "vm/jit/codegen-common.hpp"
+#include "vm/jit/jit.hpp"
+#include "vm/jit/jitcache.hpp"
+#include "vm/jit/linenumbertable.hpp"
+#include "vm/jit/patcher-common.hpp"
+
+#include "vm/os.hpp"
+#include "vm/string.hpp"
+
+extern "C" {
+
+/* for mkdir() */
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "md.h"
+
+#include "toolbox/logging.h"
+
+#include "mm/memory.h"
+#include "mm/codememory.h"
+
+#include "vm/method.h"
+#include "vm/options.h"
+#include "vm/resolve.h"
+#include "vm/types.h"
+
+#include "vm/jit/asmpart.h"
+#include "vm/jit/exceptiontable.h"
+#include "vm/jit/methodtree.h"
+
+#include "vm/references.h"
+#include "vm/utf8.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 *);
+
+void *to_abs(void *, void *);
+void *to_offset(void *, void *);
+
+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);
+               os::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 = new List<cachedref_t>();
+}
+
+
+/* jitcache_list_reset **********************************************************
+
+   Resets the cached reference list inside a codeinfo.
+
+*******************************************************************************/
+
+void jitcache_list_reset(codeinfo *code)
+{
+       code->cachedrefs->clear();
+}
+
+
+/* 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 */
+
+       delete code->cachedrefs;
+       code->cachedrefs = 0;
+}
+
+
+/* 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)
+{
+       /* walk through all cached references for the given codeinfo */
+
+       for (List<cachedref_t>::iterator it = code->cachedrefs->begin();
+                       it != code->cachedrefs->end(); it++)
+       {
+
+               if (it->disp == disp)
+                       return &(*it);
+       }
+
+       return NULL;
+}
+
+
+/* jitcache_new_cachedref ******************************************************
+
+   Creates and initializes a new cachedref
+
+*******************************************************************************/
+
+cachedref_t jitcache_new_cached_ref(cachedreftype type, s4 md_patch, void* ref, s4 disp)
+{
+       cachedref_t cr;
+
+       /* set reference information */
+
+       cr.type    = type;
+       cr.md_patch= md_patch;
+       cr.disp    = disp;
+       cr.ref     = ref;
+
+       return cr;
+}
+/* jitcache_add_cachedref_intern ***********************************************
+
+   Creates a new cached ref appends it to the list in the codeinfo structure.
+
+*******************************************************************************/
+
+void jitcache_add_cached_ref_intern(codeinfo *code, cachedref_t cachedref)
+{
+       List<cachedref_t>::iterator it = code->cachedrefs->begin();
+
+       while (it != code->cachedrefs->end())
+       {
+               if (it->disp == cachedref.disp)
+               {
+                       assert(it->type == cachedref.type);
+                       assert(it->ref == cachedref.ref);
+
+                       /* Cachedref for already existing object found. No need to store
+                        * it.
+             */
+                       return;
+               }
+
+               it++;
+       }
+
+       code->cachedrefs->push_front(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, void* 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, void* ref)
+{
+       patchref_t       patchref;
+       codegendata      *cd;
+       ptrint                   disp;
+       cachedref_t  cachedref;
+
+       if (type >= CRT_OBJECT_HEADER && !ref)
+               return;
+
+       cd = jd->cd;
+
+       disp = (ptrint) (cd->mcodeptr - cd->mcodebase) - SIZEOF_VOID_P;
+       cachedref = jitcache_new_cached_ref(type, md_patch, ref, disp);
+
+       patchref = jd->code->patchers->front();
+
+       if ((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, void* 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 defined (__ARM__)
+       if (cr->md_patch)
+               patch_md(cr->md_patch, (ptrint) location, cr->ref);
+       else
+#endif
+               *location = (u1 *) 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 *jitcache_lock;
+
+/* jitcache_store **************************************************************
+
+   Saves the generated machine code to disk.
+
+*******************************************************************************/
+void jitcache_store (methodinfo *m)
+{
+       static int init_lock = true;
+       void *temp;
+       int fd;
+
+       if (init_lock)
+       {
+               jitcache_lock = new Mutex();
+               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);*/
+       jitcache_lock->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);*/
+       jitcache_lock->unlock();
+
+}
+
+/* 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))
+       {
+               os::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 = (u1 *) 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);
+
+       os::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++)
+       {
+               os::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 (os::access(dest_file, F_OK) != 0)
+       {
+               if (opt_DebugJitCache)
+                       log_message_method("[jitcache] no cache file found for ", m);
+
+               perror("get_cache_file_writable: ");
+
+               os::free(dest_file);
+
+               return 0;
+       }
+
+/*
+       filter_single(m);
+*/
+
+       fd = open_to_read(dest_file);
+
+       os::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 (os::access(dest_dir, F_OK) != 0)
+               {
+                       if (mkdir_hier(dest_dir, S_IRWXU | S_IRWXG) != 0)
+                       {
+                               perror("get_cache_file_writable: ");
+
+                               if (opt_DebugJitCache)
+                                       log_println("[jitcache] unable to create cache directory: %s", dest_dir);
+
+                               os::free(dest_dir);
+                               os::free(dest_file);
+
+                               return 0;
+                       }
+               }
+
+               os::free(dest_dir);
+
+               /* try to open the file again. */
+               fd = open_to_write(dest_file);
+               os::free(dest_file);
+
+               if (fd <= 0)
+               {
+                       perror("get_cache_file_writable2: ");
+                       return 0;
+               }
+       }
+
+       os::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 = os::strlen(path);
+
+       for (index = 0; index < length; index++)
+       {
+               if (path[index] == '/')
+               {
+                       path[index] = 0;
+                       mkdir(path, mode);
+
+                       path[index] = '/';
+               }
+       }
+
+       if (!mkdir(path, mode) || errno == EEXIST)
+               return 0;
+}
+
+/* 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 = os::strlen(CACHEROOT);
+       int len_classname = utf_bytes(m->clazz->name);
+
+       char *dest_file = (char *) os::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 = os::strlen(CACHEROOT);
+       int len_packagename = utf_bytes(m->clazz->packagename);
+
+       char *dest_dir = (char *) os::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.
+
+*******************************************************************************/
+
+void *to_abs(void *base, void *offset)
+{
+       return (void *) ((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.
+
+*******************************************************************************/
+
+void *to_offset(void *base, void *abs)
+{
+       return (void *) ((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 = (char *) os::calloc(sizeof(char), len);
+
+               system_read(fd, tmp, len);
+
+               *s = utf_new(tmp, len);
+
+/*             os::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;
+       void *temp_ptr;
+       int j;
+
+       int size = code->patchers->size();
+
+       /* serialize patchers list */
+       system_write(fd, (const void *) &size, sizeof(size));
+       if (opt_DebugJitCache)
+               log_println("store_to_file_patchers - patchers size %d", size);
+
+       for (List<patchref_t>::iterator it = code->patchers->begin();
+                       it != code->patchers->end(); it++)
+       {
+               temp_ptr = to_offset(code->mcode, (u1 *) it->mpc);
+               system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr));
+
+               temp_ptr = to_offset(code->mcode, (u1 *) it->datap);
+               system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr));
+
+               system_write(fd, (const void *) &it->disp, sizeof(it->disp));
+
+               temp = -1;
+               j = 0;
+               while (patcher_functions[j].patcher)
+               {
+                       if (patcher_functions[j].patcher == it->patcher)
+                       {
+                               temp = j;
+                               system_write(fd, (const void *) &j, sizeof(j));
+
+                               (*patcher_functions[j].serializer)(fd, &(*it), 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));
+               }
+
+               if (it->attached_ref)
+                       temp = 1;
+               
+               system_write(fd, (const void *) &temp, sizeof(temp));
+
+               if (it->attached_ref)
+               {
+                       store_cachedref(fd, it->attached_ref);
+
+                       /* Release the cached reference now because it should not be used
+                        * in the current Cacao process.
+                        */
+                       FREE(it->attached_ref, cachedref_t);
+                       it->attached_ref = NULL;
+               }
+
+               system_write(fd, (const void *) &it->mcode, sizeof(it->mcode));
+       }
+}
+
+
+/* store_to_file_cachedrefs *****************************************************
+
+   Writes the cachedrefs structure of a codeinfo to disk.
+
+*******************************************************************************/
+void store_to_file_cachedrefs(int fd, codeinfo *code)
+{
+       int size = code->cachedrefs->size();
+       if (opt_DebugJitCache)
+               log_println("store_to_file_cachedrefs - cachedrefs size %d", size);
+
+       /* serialize cachedrefs list */
+       system_write(fd, (const void *) &size, sizeof(size));
+
+       for (List<cachedref_t>::iterator it = code->cachedrefs->begin();
+                       it != code->cachedrefs->end(); it++)
+               store_cachedref(fd, &(*it));
+}
+
+/* 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;
+       void *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;
+       int count = 0;
+
+       if (code->linenumbertable)
+               count = code->linenumbertable->_linenumbers.size();
+
+       /* 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)
+       {
+               for (std::vector<Linenumber>::iterator it = code->linenumbertable->_linenumbers.begin();
+                       it != code->linenumbertable->_linenumbers.end(); it++)
+               {
+                       int temp = it->get_linenumber();
+                       system_write(fd, (const void *) &temp, sizeof(temp));
+       
+                       temp_ptr = to_offset(code->entrypoint, it->get_pc());
+                       system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr));
+               }
+       }
+
+}
+
+
+/* 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;
+
+               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 *) &temp, sizeof(temp));
+
+               if (temp)
+               {
+                       pr.attached_ref = 0;
+                       load_cachedref(&pr.attached_ref, fd, code);
+               }
+
+               system_read(fd, (void *) &pr.mcode, sizeof(pr.mcode));
+
+               pr.done = false;
+
+               code->patchers->push_front(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 defined (__ARM__)
+               if (cr->md_patch)
+                       patch_md(cr->md_patch, ((ptrint) code->entrypoint) + cr->disp, cr->ref);
+               else
+#endif
+               {
+                 *((u1 **) (code->entrypoint + cr->disp)) = (u1 *) 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 = (void*) code;
+                       break;
+               case CRT_NUM:
+                       system_read(fd, (void *) &cr->ref, sizeof(s4));
+                       break;
+               case CRT_ENTRYPOINT:
+                       /* Just set the current entrypoint. */
+                       cr->ref = (void*) code->entrypoint;
+                       break;
+               case CRT_CODEGEN_FINISH_NATIVE_CALL:
+                       /* Just set the pointer to codegen_finish_native_call. */
+                       cr->ref = (void*) (ptrint) codegen_finish_native_call;
+                       break;
+               case CRT_ASM_HANDLE_EXCEPTION:
+                       /* Just set the pointer to asm_handle_exception. */
+                       cr->ref = (void*) (ptrint) asm_handle_exception;
+                       break;
+               case CRT_ASM_HANDLE_NAT_EXCEPTION:
+                       /* Just put the pointer to asm_handle_nat_exception. */
+                       cr->ref = (void*) (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 = (void*) (bte->stub == NULL ? (ptrint) bte->fp : (ptrint) bte->stub);
+
+                       break;
+               case CRT_BUILTIN_FP:
+                       load_builtin(&bte, fd);
+                       cr->ref = (void*) (ptrint) bte->fp;
+
+                       break;
+               case CRT_STRING:
+                       load_string(&h, fd);
+                       cr->ref = (void*) h;
+                       break;
+               case CRT_CLASSINFO:
+                       /* Load classinfo */
+                       load_classinfo(&ci, fd, code->m);
+                       cr->ref = (void*) ci;
+
+                       break;
+               case CRT_CLASSINFO_INDEX:
+                       /* Load classinfo */
+                       load_classinfo(&ci, fd, code->m);
+                       cr->ref = (void*) ci->index;
+                       break;
+               case CRT_CLASSINFO_INTERFACETABLE:
+                       /* Load classinfo */
+                       load_classinfo(&ci, fd, code->m);
+                       cr->ref = (void*) (OFFSET(vftbl_t, interfacetable[0]) -
+                                               ci->index * sizeof(methodptr*));
+                       break;
+               case CRT_CLASSINFO_VFTBL:
+                       /* Load classinfo */
+                       load_classinfo(&ci, fd, code->m);
+                       cr->ref = (void*) ci->vftbl;
+                       break;
+               case CRT_METHODINFO_STUBROUTINE:
+                       load_methodinfo(&mi, fd, code->m);
+                       cr->ref = (void*) mi->stubroutine;
+                       break;
+               case CRT_METHODINFO_TABLE:
+                       load_methodinfo(&mi, fd, code->m);
+                       cr->ref = (void*) ((OFFSET(vftbl_t, table[0]) +
+                                                          sizeof(methodptr) * mi->vftblindex));
+                       break;
+               case CRT_METHODINFO_INTERFACETABLE:
+                       load_methodinfo(&mi, fd, code->m);
+                       cr->ref = (void*) (OFFSET(vftbl_t, interfacetable[0]) -
+                                       sizeof(methodptr) * mi->clazz->index);
+                       break;
+               case CRT_METHODINFO_METHODOFFSET:
+                       load_methodinfo(&mi, fd, code->m);
+                       cr->ref = (void*) ((sizeof(methodptr) * (mi - mi->clazz->methods)));
+                       break;
+               case CRT_FIELDINFO_VALUE:
+                       load_fieldinfo(&fi, fd, code->m);
+
+                       cr->ref = (void*) fi->value;
+                       break;
+               case CRT_FIELDINFO_OFFSET:
+                       load_fieldinfo(&fi, fd, code->m);
+
+                       cr->ref = (void*) fi->offset;
+                       break;
+               case CRT_FIELDINFO_OFFSET_HIGH:
+                       /* Should be used on 32 bit archs only. */
+                       load_fieldinfo(&fi, fd, code->m);
+
+                       cr->ref = (void*) (fi->offset + 4);
+                       break;
+               case CRT_JUMPREFERENCE:
+                       system_read(fd, (void *) &cr->ref, sizeof(cr->ref));
+
+                       cr->ref = (void*) ((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) && (void*) (*((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)
+{
+       void *temp_ptr;
+       int i;
+
+       code->linenumbertable = new LinenumberTable();
+
+       int size;
+       system_read(fd, (void *) &size, sizeof(size));
+
+       if (opt_DebugJitCache)
+               log_println("load_linenumbertable - linenumbertable size %d", size);
+
+       for (i = 0;i < size; i++)
+       {
+               int linenumber;
+               system_read(fd, (void *) &linenumber, sizeof(linenumber));
+
+               system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr));
+
+               code->linenumbertable->_linenumbers.push_back(
+                       Linenumber(linenumber, to_abs(code->entrypoint, temp_ptr)));
+       }
+}
+
+
+/* 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] == (void*) 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] == (void*) 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 = (void*) uc;
+
+/*     FREE(classref, constant_classref);*/
+
+/*     os::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 = (void*) 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 = (void*) ref;
+}
+
+void d_classinfo(patchref_t *pr, int fd, methodinfo *m)
+{
+       classinfo *ci;
+
+       load_classinfo(&ci, fd, m);
+
+       pr->ref = (void*) ci;
+}
+
+void d_methodinfo(patchref_t *pr, int fd, methodinfo *m)
+{
+       methodinfo *lm;
+
+       load_methodinfo(&lm, fd, m);
+
+       pr->ref = (void*) lm;
+}
+
+void load_methodinfo(methodinfo **lm, int fd, methodinfo *m)
+{
+       utf *m_name;
+       utf *m_desc;
+       utf *classname;
+       classinfo *clazz;
+       constant_classref ref;
+
+       load_utf(&m_name, fd);
+       load_utf(&m_desc, fd);
+       load_utf(&classname, fd);
+
+       CLASSREF_INIT(ref, m->clazz, classname);
+
+       clazz = resolve_classref_eager(&ref);
+
+       *lm = class_findmethod(clazz, m_name, m_desc);
+}
+
+void d_fieldinfo(patchref_t *pr, int fd, methodinfo *m)
+{
+       fieldinfo *fi;
+
+       load_fieldinfo(&fi, fd, m);
+       
+       pr->ref = (void*) fi;
+}
+
+void load_fieldinfo(fieldinfo **fi, int fd, methodinfo *m)
+{
+       utf *f_name;
+       utf *f_desc;
+       utf *classname;
+       classinfo *clazz;
+       constant_classref ref;
+
+       load_utf(&f_name, fd);
+       load_utf(&f_desc, fd);
+       load_utf(&classname, fd);
+
+       CLASSREF_INIT(ref, m->clazz, classname);
+
+       clazz = resolve_classref_eager(&ref);
+/*
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+*/
+       *fi = class_findfield(clazz, 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 = (void*) cr;
+
+/*     os::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.hpp b/src/vm/jit/jitcache.hpp
new file mode 100644 (file)
index 0000000..250b046
--- /dev/null
@@ -0,0 +1,182 @@
+/* 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
+
+#include "vm/jit/patcher-common.hpp"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(ENABLE_JITCACHE)
+
+#include "config.h"
+
+#include <stdint.h>
+
+#include "vm/class.h"
+#include "vm/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.
+
+*******************************************************************************/
+
+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    */
+       void*       ref;          /* reference passed                           */
+};
+
+/*
+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 ***********************************/
+
+struct jitcache_patcher_function_list_t {
+       functionptr patcher;
+       serializerfptr serializer;
+       deserializerfptr deserializer;
+};
+
+/* 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, void* ref);
+
+void   jitcache_add_cached_ref_md_jd(jitdata *jd, cachedreftype type, s4 md_patch, void* ref);
+
+void   jitcache_add_cached_ref(codeinfo *code, cachedreftype type, void* 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, (void*) ref))
+
+#define JITCACHE_ADD_CACHED_REF_JD_COND(jd, type, ref, COND) \
+       if (COND) \
+       (jitcache_add_cached_ref_jd(jd, type, (void*) ref))
+
+#define JITCACHE_ADD_CACHED_REF_MD_JD(jd, type, md_patch, ref) \
+       (jitcache_add_cached_ref_md_jd(jd, type, md_patch, (void*) ref))
+
+#define JITCACHE_ADD_CACHED_REF(code, type, ref, disp) \
+       (jitcache_add_cached_ref(code, type, (void*) ref, disp))
+
+#define JITCACHE_ADD_CACHED_REF_COND(code, type, ref, disp, COND) \
+       if (COND) \
+               jitcache_add_cached_ref(code, type, (void*) 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 */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _JITCACHE_HPP */
+
+
+/*
+ * 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 620cc1a3112b0cb1e3d9661d85c3d52262343d5b..0d6143e171f21f36ab484a76a66004ba2d5d90ce 100644 (file)
@@ -88,8 +88,9 @@ public:
  * Linenumber table of a Java method.
  */
 class LinenumberTable {
-private:
+public:
        std::vector<Linenumber> _linenumbers;
+private:
 
        // Comparator class.
        class comparator : public std::binary_function<Linenumber, void*, bool> {
@@ -102,6 +103,7 @@ private:
 
 public:
        LinenumberTable(jitdata* jd);
+       LinenumberTable() { }
        ~LinenumberTable();
 
        int32_t find(methodinfo **pm, void* pc);
index b4799b3138184ab603afefb94ae348f42dab2a79..2bcf973ba8b43bbcd714f433e3bae8dc1c90c977 100644 (file)
@@ -189,6 +189,10 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
        pr.mcode   = 0;
        pr.done    = false;
 
+#if defined(ENABLE_JITCACHE)
+       pr.attached_ref = NULL;
+#endif
+
        // Store patcher in the list (NOTE: structure is copied).
        code->patchers->push_back(pr);
 
@@ -387,6 +391,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) {
@@ -504,6 +517,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 72ed1ec0bf5a9948d0af08ef9de861bd9f633492..7a10d4d22cf278dadb0fb84425ab15672169308f 100644 (file)
@@ -28,6 +28,7 @@
 
 /* forward typedefs ***********************************************************/
 
+typedef struct cachedref_t cachedref_t;
 typedef struct patchref_t patchref_t;
 
 #include "config.h"
@@ -39,6 +40,9 @@ typedef struct patchref_t patchref_t;
 
 #include "vm/jit/jit.hpp"
 
+#if defined (ENABLE_JITCACHE)
+struct cached_ref_t;
+#endif
 
 /* patchref_t ******************************************************************
 
@@ -55,6 +59,11 @@ struct patchref_t {
        void*        ref;           /* reference passed                           */
        uint32_t     mcode;         /* machine code to be patched back in         */
        bool         done;          /* XXX preliminary: patch already applied?    */
+#if defined (ENABLE_JITCACHE)
+       cachedref_t  *attached_ref;
+                                                               /* cached reference which must be resolved    *
+                                                                * patcher has been run.                      */
+#endif
 };
 
 
@@ -189,6 +198,10 @@ bool patcher_instanceof_class(patchref_t *pr);
 
 #endif /* defined(__I386__) */
 
+#if defined (__ARM__)
+void patch_md(s4 md_patch, ptrint dest, void* ref);
+#endif /* defined(__ARM__) */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 3c3bace7016621d07fa95fe0ddd201a9e4549b13..962e98f4b04efc6773cae37d814ac99e5d683e55 100644 (file)
@@ -163,6 +163,9 @@ int      opt_ThreadStackSize              = 0;
 bool     opt_AlwaysEmitLongBranches       = false;
 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;
@@ -234,6 +237,7 @@ enum {
        OPT_AlwaysEmitLongBranches,
        OPT_DebugExceptions,
        OPT_DebugFinalizer,
+  OPT_DebugJitCache,
        OPT_DebugLocalReferences,
        OPT_DebugLocks,
        OPT_DebugPackage,
@@ -288,6 +292,9 @@ option_t options_XX[] = {
        { "AlwaysEmitLongBranches",       OPT_AlwaysEmitLongBranches,       OPT_TYPE_BOOLEAN, "Always emit long-branches." },
        { "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" },
@@ -630,6 +637,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 1758add5c3a757ba8858a35ad51f1177f1d29667..460f595dc7a513b3b5f16ce390e558da6e3ba527 100644 (file)
@@ -185,6 +185,9 @@ extern int      opt_ThreadStackSize;
 extern bool     opt_AlwaysEmitLongBranches;
 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 66de93d5155630e879a91ecd66cb3e81a2b945bb..6a18dd71ddbda4d06b10735611f669a41a170e99 100644 (file)
@@ -341,6 +341,15 @@ inline size_t os::fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
 #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 void os::free(void* ptr)
 {
 #if defined(HAVE_FREE)
index b81c2ffb56edd6a9feff279176db6e94f6d38dfc..f29d69fc594483a64a47f3b2676918f8e75beafe 100644 (file)
@@ -135,7 +135,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 1d1173a87d4bca833f37cb6b09aa926f02ea596f..cdd42a733ef852c8ec3cb955bc0695fdcbcf00a5 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 c23a737cc2d2127a7c7bb73d8971659959dc5971..8ab2f6fd509fee91404cca97fe80ad1577e98f24 100644 (file)
@@ -46,6 +46,8 @@
 
 #include "toolbox/logging.h"
 
+#include "threads/thread.hpp"
+
 #include "vm/class.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
@@ -106,6 +108,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;
 
@@ -302,12 +306,25 @@ s8 getcputime(void)
 
 *******************************************************************************/
 
+Mutex *loadingtime_lock = Mutex_new();
+
 void loadingtime_start(void)
 {
+       Mutex_lock(loadingtime_lock);
+
        loadingtime_recursion++;
 
        if (loadingtime_recursion == 1)
                loadingstarttime = getcputime();
+       else {
+               int end = getcputime();
+               loadingtime += (end - loadingstarttime);
+
+               loadingstarttime = loadingstoptime = end;
+       }
+       
+
+       Mutex_unlock(loadingtime_lock);
 }
 
 
@@ -319,12 +336,18 @@ void loadingtime_start(void)
 
 void loadingtime_stop(void)
 {
-       if (loadingtime_recursion == 1) {
-               loadingstoptime = getcputime();
-               loadingtime += (loadingstoptime - loadingstarttime);
+       Mutex_lock(loadingtime_lock);
+
+       loadingstoptime = getcputime();
+       loadingtime += (loadingstoptime - loadingstarttime);
+
+       if (loadingtime_recursion > 1) {
+               loadingstarttime = loadingstoptime;
        }
 
        loadingtime_recursion--;
+
+       Mutex_unlock(loadingtime_lock);
 }
 
 
@@ -692,12 +715,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 484fba15c27fd800151b073896b17f50f093b4d4..d84cf4da89777c765130d8f4b311530dce8c3de4 100644 (file)
@@ -112,6 +112,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 d05bef1af2d23e69526681cadf2f2987bb03ac0c..f50e37732d3b5b91cfa91b46d7a23e9cdbc0f859 100644 (file)
@@ -88,7 +88,7 @@
 # include "vm/jit/disass.h"
 #endif
 
-#include "vm/jit/jit.hpp"
+#include "vm/jit/jitcache.hpp"
 #include "vm/jit/methodtree.h"
 
 #if defined(ENABLE_PROFILING)
@@ -1915,6 +1915,10 @@ void vm_shutdown(s4 status)
        }       
 #endif
 
+#if defined (ENABLE_JITCACHE)
+  jitcache_quit();
+#endif
+
        exit(status);
 }