* src/vm/jit/md.h: Removed.
[cacao.git] / src / vm / jit / jit.c
index b18279e22e85e547a07f402e760676f5776b939e..488103b81a61cd416cb1b26687df5944538065c2 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/jit.c - calls the code generation functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
    J. Wenninger, Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Andreas Krall
-            Reinhard Grafl
-
-   Changes: Edwin Steiner
-            Christian Thalinger
-            Christian Ullrich
-
-   $Id: jit.c 5924 2006-11-05 22:47:23Z edwin $
-
 */
 
 
 #include "config.h"
-#include "vm/types.h"
 
 #include <assert.h>
+#include <stdint.h>
+
+#include "vm/types.h"
+
+#include "md.h"
 
 #include "mm/memory.h"
+
 #include "native/native.h"
+
 #include "toolbox/logging.h"
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/lock.h"
-#else
-# include "threads/none/lock.h"
-#endif
+#include "threads/lock-common.h"
+#include "threads/threads-common.h"
 
-#include "vm/class.h"
 #include "vm/global.h"
 #include "vm/initialize.h"
-#include "vm/loader.h"
-#include "vm/method.h"
-#include "vm/options.h"
-#include "vm/statistics.h"
+
 #include "vm/jit/asmpart.h"
 
 # include "vm/jit/cfg.h"
 # include "vm/jit/optimizing/ssa.h"
 #endif
 
+#if defined(ENABLE_INLINING)
+# include "vm/jit/inline/inline.h"
+#endif
+
 #include "vm/jit/loop/analyze.h"
 #include "vm/jit/loop/graph.h"
 #include "vm/jit/loop/loop.h"
 #include "vm/jit/optimizing/reorder.h"
 
 #include "vm/jit/verify/typecheck.h"
-#include "vm/rt-timing.h"
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/threads.h"
-#endif
+#include "vmcore/class.h"
+#include "vmcore/loader.h"
+#include "vmcore/method.h"
+#include "vmcore/options.h"
+#include "vmcore/rt-timing.h"
+#include "vmcore/statistics.h"
 
 
 /* debug macros ***************************************************************/
 
 #if !defined(NDEBUG)
-#define DEBUG_JIT_COMPILEVERBOSE(x) \
-    do { \
-        if (compileverbose) { \
-            log_message_method(x, m); \
-        } \
+#define DEBUG_JIT_COMPILEVERBOSE(x)                            \
+    do {                                                                               \
+        if (compileverbose) {                                  \
+            log_message_method(x, m);                  \
+        }                                                                              \
     } while (0)
 #else
 #define DEBUG_JIT_COMPILEVERBOSE(x)    /* nothing */
 #endif
 
+#if !defined(NDEBUG)
+# define TRACECOMPILERCALLS()                                                          \
+       do {                                                                                                    \
+               if (opt_TraceCompilerCalls) {                                           \
+                       log_start();                                                                    \
+                       log_print("[JIT compiler started: method=");    \
+                       method_print(m);                                                                \
+                       log_print("]");                                                                 \
+                       log_finish();                                                                   \
+               }                                                                                                       \
+       } while (0)
+#else
+# define TRACECOMPILERCALLS()
+#endif
+
+
 /* the ICMD table ************************************************************/
 
 #if !defined(NDEBUG)
@@ -908,6 +917,23 @@ void jit_init(void)
        /* initialize codegen subsystem */
 
        codegen_init();
+
+       /* initialize code subsystem */
+
+       (void) code_init();
+
+       /* Machine dependent initialization. */
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (opt_intrp)
+               intrp_md_init();
+       else
+# endif
+               md_init();
+#else
+       intrp_md_init();
+#endif
 }
 
 
@@ -939,7 +965,8 @@ static u1 *do_nothing_function(void)
 
 jitdata *jit_jitdata_new(methodinfo *m)
 {
-       jitdata *jd;
+       jitdata  *jd;
+       codeinfo *code;
 
        /* allocate jitdata structure and fill it */
 
@@ -954,26 +981,32 @@ jitdata *jit_jitdata_new(methodinfo *m)
 
        /* Allocate codeinfo memory from the heap as we need to keep them. */
 
-       jd->code  = code_codeinfo_new(m);
-
-       /* initialize variables */
+       code = code_codeinfo_new(m);
 
-       jd->flags = 0;
-       jd->exceptiontable = NULL;
-       jd->exceptiontablelength = 0;
-       jd->returncount = 0;
-       jd->branchtoentry = false;
-       jd->branchtoend = false;
-       jd->returncount = 0;
-       jd->returnblock = NULL;
-       jd->maxlocals = m->maxlocals;
+       /* Set codeinfo flags. */
 
 #if defined(ENABLE_THREADS)
        if (checksync && (m->flags & ACC_SYNCHRONIZED))
-               jd->isleafmethod = false;
+               code_flag_synchronized(code);
+
+       if (checksync && (m->flags & ACC_SYNCHRONIZED))
+               code_unflag_leafmethod(code);
        else
 #endif
-               jd->isleafmethod = true;
+               code_flag_leafmethod(code);
+
+       /* initialize variables */
+
+       jd->code                 = code;
+       jd->flags                = 0;
+       jd->exceptiontable       = NULL;
+       jd->exceptiontablelength = 0;
+       jd->returncount          = 0;
+       jd->branchtoentry        = false;
+       jd->branchtoend          = false;
+       jd->returncount          = 0;
+       jd->returnblock          = NULL;
+       jd->maxlocals            = m->maxlocals;
 
        return jd;
 }
@@ -1029,6 +1062,8 @@ u1 *jit_compile(methodinfo *m)
                return m->code->entrypoint;
        }
 
+       TRACECOMPILERCALLS();
+
        STATISTICS(count_methods++);
 
 #if defined(ENABLE_STATISTICS)
@@ -1065,6 +1100,11 @@ u1 *jit_compile(methodinfo *m)
                jd->flags |= JITDATA_FLAG_IFCONV;
 #endif
 
+#if defined(ENABLE_INLINING) && defined(ENABLE_INLINING_DEBUG)
+       if (opt_inlining && opt_inline_debug_all)
+               jd->flags |= JITDATA_FLAG_INLINE;
+#endif
+
        if (opt_showintermediate)
                jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE;
 
@@ -1074,6 +1114,11 @@ u1 *jit_compile(methodinfo *m)
        if (opt_verbosecall)
                jd->flags |= JITDATA_FLAG_VERBOSECALL;
 
+#if defined(ENABLE_REPLACEMENT) && defined(ENABLE_INLINING)
+       if (opt_inlining)
+               jd->flags |= JITDATA_FLAG_COUNTDOWN;
+#endif
+
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
        if (!opt_intrp)
@@ -1099,11 +1144,13 @@ u1 *jit_compile(methodinfo *m)
 
                code_codeinfo_free(jd->code);
 
+#if defined(ENABLE_PROFILING)
                /* Release memory for basic block profiling information. */
 
                if (JITDATA_HAS_FLAG_INSTRUMENT(jd))
                        if (jd->code->bbfrequency != NULL)
                                MFREE(jd->code->bbfrequency, u4, jd->code->basicblockcount);
+#endif
        }
        else {
                DEBUG_JIT_COMPILEVERBOSE("Running: ");
@@ -1145,14 +1192,16 @@ u1 *jit_recompile(methodinfo *m)
 
        /* check for max. optimization level */
 
-       optlevel = m->code->optlevel;
+       optlevel = (m->code) ? m->code->optlevel : 0;
 
+#if 0
        if (optlevel == 1) {
 /*             log_message_method("not recompiling: ", m); */
                return NULL;
        }
+#endif
 
-       log_message_method("Recompiling start: ", m);
+       DEBUG_JIT_COMPILEVERBOSE("Recompiling start: ");
 
        STATISTICS(count_jit_calls++);
 
@@ -1181,10 +1230,18 @@ u1 *jit_recompile(methodinfo *m)
        jd->flags |= JITDATA_FLAG_VERIFY;
 #endif
 
-       jd->flags |= JITDATA_FLAG_REORDER;
-       jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE;
-       jd->flags |= JITDATA_FLAG_SHOWDISASSEMBLE;
-/*     jd->flags |= JITDATA_FLAG_VERBOSECALL; */
+       /* jd->flags |= JITDATA_FLAG_REORDER; */
+       if (opt_showintermediate)
+               jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE;
+       if (opt_showdisassemble)
+               jd->flags |= JITDATA_FLAG_SHOWDISASSEMBLE;
+       if (opt_verbosecall)
+               jd->flags |= JITDATA_FLAG_VERBOSECALL;
+
+#if defined(ENABLE_INLINING)
+       if (opt_inlining)
+               jd->flags |= JITDATA_FLAG_INLINE;
+#endif
 
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
@@ -1222,7 +1279,7 @@ u1 *jit_recompile(methodinfo *m)
                compilingtime_stop();
 #endif
 
-       log_message_method("Recompiling done: ", m);
+       DEBUG_JIT_COMPILEVERBOSE("Recompiling done: ");
 
        /* return pointer to the methods entry point */
 
@@ -1245,7 +1302,7 @@ static u1 *jit_compile_intern(jitdata *jd)
 #if defined(ENABLE_RT_TIMING)
        struct timespec time_start,time_checks,time_parse,time_stack,
                                        time_typecheck,time_loop,time_ifconv,time_alloc,
-                                       time_rplpoints,time_codegen;
+                                       time_codegen;
 #endif
        
        RT_TIMING_GET_TIME(time_start);
@@ -1259,27 +1316,26 @@ static u1 *jit_compile_intern(jitdata *jd)
        code = jd->code;
        cd   = jd->cd;
        
-       /* print log message for compiled method */
-
-       DEBUG_JIT_COMPILEVERBOSE("Compiling: ");
+#if defined(ENABLE_DEBUG_FILTER)
+       show_filters_apply(jd->m);
+#endif
 
        /* handle native methods and create a native stub */
 
        if (m->flags & ACC_NATIVE) {
                functionptr f;
 
-#if defined(WITH_STATIC_CLASSPATH)
-               f = native_findfunction(m->class->name, m->name, m->descriptor,
-                                                               (m->flags & ACC_STATIC));
+               f = native_method_resolve(m);
+
                if (f == NULL)
                        return NULL;
-#else
-               f = NULL;
-#endif
 
-               code = codegen_createnativestub(f, m);
+               code = codegen_generate_stub_native(m, f);
+
+               /* Native methods are never recompiled. */
+               
+               assert(!m->code);
 
-               assert(!m->code); /* native methods are never recompiled */
                m->code = code;
                
                return code->entrypoint;
@@ -1306,6 +1362,18 @@ static u1 *jit_compile_intern(jitdata *jd)
 
        RT_TIMING_GET_TIME(time_checks);
 
+#if defined(WITH_CLASSPATH_SUN)
+       /* Code for Sun's OpenJDK (see
+          hotspot/src/share/vm/classfile/verifier.cpp
+          (Verifier::is_eligible_for_verification)): Don't verify
+          dynamically-generated bytecodes. */
+
+# if defined(ENABLE_VERIFIER)
+       if (class_issubclass(m->class, class_sun_reflect_MagicAccessorImpl))
+               jd->flags &= ~JITDATA_FLAG_VERIFY;
+# endif
+#endif
+
        /* call the compiler passes ***********************************************/
 
        DEBUG_JIT_COMPILEVERBOSE("Parsing: ");
@@ -1379,6 +1447,16 @@ static u1 *jit_compile_intern(jitdata *jd)
 #endif
                RT_TIMING_GET_TIME(time_ifconv);
 
+               /* inlining */
+
+#if defined(ENABLE_INLINING)
+               if (JITDATA_HAS_FLAG_INLINE(jd)) {
+                       if (!inline_inline(jd))
+                               return NULL;
+               }
+#endif
+
+#if defined(ENABLE_PROFILING)
                /* Basic block reordering.  I think this should be done after
                   if-conversion, as we could lose the ability to do the
                   if-conversion. */
@@ -1388,6 +1466,7 @@ static u1 *jit_compile_intern(jitdata *jd)
                                return NULL;
                        jit_renumber_basicblocks(jd);
                }
+#endif
 
                DEBUG_JIT_COMPILEVERBOSE("Allocating registers: ");
 
@@ -1412,7 +1491,7 @@ static u1 *jit_compile_intern(jitdata *jd)
                } else
 # endif /* defined(ENABLE_SSA) */
                {
-                       STATISTICS(count_locals_conflicts += (cd->maxlocals - 1) * (cd->maxlocals));
+                       STATISTICS(count_locals_conflicts += (jd->maxlocals - 1) * (jd->maxlocals));
 
                        regalloc(jd);
                }
@@ -1426,20 +1505,17 @@ static u1 *jit_compile_intern(jitdata *jd)
 #endif /* defined(ENABLE_JIT) */
        RT_TIMING_GET_TIME(time_alloc);
 
+#if defined(ENABLE_PROFILING)
        /* Allocate memory for basic block profiling information. This
           _must_ be done after loop optimization and register allocation,
           since they can change the basic block count. */
 
        if (JITDATA_HAS_FLAG_INSTRUMENT(jd))
                code->bbfrequency = MNEW(u4, jd->basicblockcount);
+#endif
 
        DEBUG_JIT_COMPILEVERBOSE("Generating code: ");
 
-       /* create the replacement points */
-       if (!replace_create_replacement_points(jd))
-               return NULL;
-       RT_TIMING_GET_TIME(time_rplpoints);
-
        /* now generate the machine code */
 
 #if defined(ENABLE_JIT)
@@ -1463,7 +1539,7 @@ static u1 *jit_compile_intern(jitdata *jd)
        } else
 # endif
                {
-                       if (!codegen(jd)) {
+                       if (!codegen_generate(jd)) {
                                DEBUG_JIT_COMPILEVERBOSE("Exception while generating code: ");
 
                                return NULL;
@@ -1480,25 +1556,35 @@ static u1 *jit_compile_intern(jitdata *jd)
 
        DEBUG_JIT_COMPILEVERBOSE("Generating code done: ");
 
+#if !defined(NDEBUG) && defined(ENABLE_REPLACEMENT)
+       /* activate replacement points inside newly created code */
+
+       if (opt_TestReplacement)
+               replace_activate_replacement_points(code, false);
+#endif
+
 #if !defined(NDEBUG)
-       /* intermediate and assembly code listings */
+#if defined(ENABLE_DEBUG_FILTER)
+       if (jd->m->filtermatches & SHOW_FILTER_FLAG_SHOW_METHOD)
+#endif
+       {
+               /* intermediate and assembly code listings */
                
-       if (JITDATA_HAS_FLAG_SHOWINTERMEDIATE(jd)) {
-               show_method(jd, SHOW_CODE);
-       }
-       else if (JITDATA_HAS_FLAG_SHOWDISASSEMBLE(jd)) {
+               if (JITDATA_HAS_FLAG_SHOWINTERMEDIATE(jd)) {
+                       show_method(jd, SHOW_CODE);
+               }
+               else if (JITDATA_HAS_FLAG_SHOWDISASSEMBLE(jd)) {
 # if defined(ENABLE_DISASSEMBLER)
-               DISASSEMBLE(code->entrypoint,
-                                       code->entrypoint + (code->mcodelength - cd->dseglen));
+                       DISASSEMBLE(code->entrypoint,
+                                               code->entrypoint + (code->mcodelength - cd->dseglen));
 # endif
-       }
+               }
 
-       if (opt_showddatasegment)
-               dseg_display(jd);
+               if (opt_showddatasegment)
+                       dseg_display(jd);
+       }
 #endif
 
-       DEBUG_JIT_COMPILEVERBOSE("Compiling done: ");
-
        /* switch to the newly generated code */
 
        assert(code);
@@ -1515,8 +1601,7 @@ static u1 *jit_compile_intern(jitdata *jd)
        RT_TIMING_TIME_DIFF(time_stack,time_typecheck,RT_TIMING_JIT_TYPECHECK);
        RT_TIMING_TIME_DIFF(time_typecheck,time_loop,RT_TIMING_JIT_LOOP);
        RT_TIMING_TIME_DIFF(time_loop,time_alloc,RT_TIMING_JIT_ALLOC);
-       RT_TIMING_TIME_DIFF(time_alloc,time_rplpoints,RT_TIMING_JIT_RPLPOINTS);
-       RT_TIMING_TIME_DIFF(time_rplpoints,time_codegen,RT_TIMING_JIT_CODEGEN);
+       RT_TIMING_TIME_DIFF(time_alloc,time_codegen,RT_TIMING_JIT_CODEGEN);
        RT_TIMING_TIME_DIFF(time_start,time_codegen,RT_TIMING_JIT_TOTAL);
 
        /* return pointer to the methods entry point */
@@ -1525,6 +1610,93 @@ static u1 *jit_compile_intern(jitdata *jd)
 } 
 
 
+/* jit_invalidate_code *********************************************************
+
+   Mark the compiled code of the given method as invalid and take care that
+   it is replaced if necessary.
+
+   XXX Not fully implemented, yet.
+
+*******************************************************************************/
+
+void jit_invalidate_code(methodinfo *m)
+{
+       codeinfo *code;
+
+       code = m->code;
+
+       if (code == NULL || code_is_invalid(code))
+               return;
+
+       code_flag_invalid(code);
+
+       /* activate mappable replacement points */
+
+#if defined(ENABLE_REPLACEMENT)
+       replace_activate_replacement_points(code, true);
+#else
+       vm_abort("invalidating code only works with ENABLE_REPLACEMENT");
+#endif
+}
+
+
+/* jit_request_optimization ****************************************************
+
+   Request optimization of the given method. If the code of the method is
+   unoptimized, it will be invalidated, so the next jit_get_current_code(m)
+   triggers an optimized recompilation.
+   If the method is already optimized, this function does nothing.
+
+   IN:
+       m................the method
+
+*******************************************************************************/
+
+void jit_request_optimization(methodinfo *m)
+{
+       codeinfo *code;
+
+       code = m->code;
+
+       if (code && code->optlevel == 0)
+               jit_invalidate_code(m);
+}
+
+
+/* jit_get_current_code ********************************************************
+
+   Get the currently valid code for the given method. If there is no valid
+   code, (re)compile the method.
+
+   IN:
+       m................the method
+
+   RETURN VALUE:
+       the codeinfo* for the current code, or
+          NULL if an exception has been thrown during recompilation.
+
+*******************************************************************************/
+
+codeinfo *jit_get_current_code(methodinfo *m)
+{
+       assert(m);
+
+       /* if we have valid code, return it */
+
+       if (m->code && !code_is_invalid(m->code))
+               return m->code;
+
+       /* otherwise: recompile */
+
+       if (!jit_recompile(m))
+               return NULL;
+
+       assert(m->code);
+
+       return m->code;
+}
+
+
 /* jit_asm_compile *************************************************************
 
    This method is called from asm_vm_call_method and does:
@@ -1538,17 +1710,18 @@ static u1 *jit_compile_intern(jitdata *jd)
 *******************************************************************************/
 
 #if defined(ENABLE_JIT)
+#if !defined(JIT_COMPILER_VIA_SIGNAL)
 u1 *jit_asm_compile(methodinfo *m, u1 *mptr, u1 *sp, u1 *ra)
 {
-       stackframeinfo  sfi;
-       u1             *entrypoint;
-       u1             *pa;
-       ptrint         *p;
+       stackframeinfo_t  sfi;
+       u1               *entrypoint;
+       u1               *pa;
+       ptrint           *p;
 
        /* create the stackframeinfo (subtract 1 from RA as it points to the */
        /* instruction after the call)                                       */
 
-       stacktrace_create_extern_stackframeinfo(&sfi, NULL, sp, ra, ra-1);
+       stacktrace_stackframeinfo_add(&sfi, NULL, sp, ra, ra-1);
 
        /* actually compile the method */
 
@@ -1556,7 +1729,7 @@ u1 *jit_asm_compile(methodinfo *m, u1 *mptr, u1 *sp, u1 *ra)
 
        /* remove the stackframeinfo */
 
-       stacktrace_remove_stackframeinfo(&sfi);
+       stacktrace_stackframeinfo_remove(&sfi);
 
        /* there was a problem during compilation */
 
@@ -1565,7 +1738,7 @@ u1 *jit_asm_compile(methodinfo *m, u1 *mptr, u1 *sp, u1 *ra)
 
        /* get the method patch address */
 
-       pa = md_get_method_patch_address(ra, &sfi, mptr);
+       pa = md_jit_method_patch_address(sfi.pv, (void *) ra, mptr);
 
        /* patch the method entry point */
 
@@ -1579,6 +1752,51 @@ u1 *jit_asm_compile(methodinfo *m, u1 *mptr, u1 *sp, u1 *ra)
 
        return entrypoint;
 }
+#endif
+
+/* jit_compile_handle **********************************************************
+
+   This method is called from the appropriate signal handler which
+   handles compiler-traps and does the following:
+
+     - compile the method
+     - patch the entrypoint of the method into the calculated address in
+       the JIT code
+     - flush the instruction cache
+
+*******************************************************************************/
+
+void *jit_compile_handle(methodinfo *m, void *pv, void *ra, void *mptr)
+{
+       void      *newpv;                               /* new compiled method PV */
+       void      *pa;                                           /* patch address */
+       uintptr_t *p;                                      /* convenience pointer */
+
+       /* Compile the method. */
+
+       newpv = jit_compile(m);
+
+       /* There was a problem during compilation. */
+
+       if (newpv == NULL)
+               return NULL;
+
+       /* Get the method patch address. */
+
+       pa = md_jit_method_patch_address(pv, ra, mptr);
+
+       /* Patch the method entry point. */
+
+       p = (uintptr_t *) pa;
+
+       *p = (uintptr_t) newpv;
+
+       /* Flush both caches. */
+
+       md_cacheflush(pa, SIZEOF_VOID_P);
+
+       return newpv;
+}
 #endif /* defined(ENABLE_JIT) */