Merged with tip.
authorPeter Molnar <pm@complang.tuwien.ac.at>
Wed, 9 Jul 2008 18:00:49 +0000 (20:00 +0200)
committerPeter Molnar <pm@complang.tuwien.ac.at>
Wed, 9 Jul 2008 18:00:49 +0000 (20:00 +0200)
32 files changed:
configure.ac
src/mm/Makefile.am
src/mm/tlh.c [new file with mode: 0644]
src/mm/tlh.h [new file with mode: 0644]
src/threads/posix/thread-posix.c
src/threads/posix/thread-posix.h
src/vm/builtin.c
src/vm/builtin.h
src/vm/builtintable.inc
src/vm/global.h
src/vm/jit/cfg.c
src/vm/jit/code.h
src/vm/jit/emit-common.h
src/vm/jit/i386/codegen.c
src/vm/jit/i386/emit.c
src/vm/jit/i386/linux/md-os.c
src/vm/jit/i386/md-trap.h
src/vm/jit/jit.c
src/vm/jit/jit.h
src/vm/jit/optimizing/bytecode_escape.c
src/vm/jit/optimizing/escape.c
src/vm/jit/optimizing/escape.h
src/vm/jit/optimizing/ssa.c
src/vm/jit/optimizing/ssa3.c
src/vm/jit/reg.h
src/vm/jit/replace.c
src/vm/jit/show.c
src/vm/jit/trap.c
src/vmcore/linker.c
src/vmcore/method.c
src/vmcore/rt-timing.c
src/vmcore/rt-timing.h

index c8ddf37b8f6824f4b1127bd584f8e11ad5d32cd2..1dbd15e1f8afc1490c9d154ec80a75e7f6d86415 100644 (file)
@@ -449,11 +449,13 @@ AC_MSG_RESULT(${ENABLE_SSA})
 AM_CONDITIONAL([ENABLE_SSA], test x"${ENABLE_SSA}" = "xyes")
 AM_CONDITIONAL([ENABLE_ESCAPE], test x"${ENABLE_SSA}" = "xyes")
 AM_CONDITIONAL([ENABLE_ESCAPE_CHECK], test x"${ENABLE_SSA}" = "xyes")
+AM_CONDITIONAL([ENABLE_TLH], test x"${ENABLE_SSA}" = "xyes")
 
 if test x"${ENABLE_SSA}" = "xyes"; then
     AC_DEFINE([ENABLE_SSA], 1, [enable lsra with ssa])
     AC_DEFINE([ENABLE_ESCAPE], 1, [enable escape analysis with ssa])
     AC_DEFINE([ENABLE_ESCAPE_CHECK], 1, [enable generating code to validate escape analysis results])
+    AC_DEFINE([ENABLE_TLH], 1, [enable thread local heap])
     ENABLE_LSRA="no"
 fi
 
index 22c39cec2ed77c989a22004cbf4b07976c250b7f..afd9feef0301c0ed095e05f36c7dec2f1c5c92ca 100644 (file)
@@ -69,6 +69,11 @@ libmm_la_SOURCES = \
 libmm_la_LIBADD = \
        $(GC_LIB)
 
+if ENABLE_TLH
+libmm_la_SOURCES += \
+       tlh.h \
+       tlh.c
+endif
 
 ## Local variables:
 ## mode: Makefile
diff --git a/src/mm/tlh.c b/src/mm/tlh.c
new file mode 100644 (file)
index 0000000..e46cf87
--- /dev/null
@@ -0,0 +1,128 @@
+/* src/mm/tlh.c
+
+   Copyright (C) 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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"
+
+#include "mm/memory.h"
+#include "mm/tlh.h"
+
+#include "vm/global.h"
+
+#include <assert.h>
+#include <sys/mman.h>
+
+static const int TLH_MAX_SIZE = (20 * 1024 * 1024);
+
+static inline bool tlh_avail(tlh_t *tlh, unsigned n) {
+       /*
+    ---  --- --- ---
+                    ^ end
+            ^ top
+                    ^ top + 2
+       */
+       return (tlh->top + n) <= tlh->end;
+}
+
+void tlh_init(tlh_t *tlh) {
+
+       void *heap = mmap(
+               NULL, 
+               TLH_MAX_SIZE, 
+               PROT_READ|PROT_WRITE, 
+               MAP_ANONYMOUS|MAP_PRIVATE, 
+               -1, 
+               0
+       );
+       
+       if (heap == MAP_FAILED) {
+               /* The top pointer points to end, so all allocations will fail. */
+               tlh->start = NULL;
+               tlh->end = NULL;
+               tlh->top = NULL;
+               tlh->base = NULL;
+       } else {
+               tlh->start = (uint8_t *)heap;
+               tlh->top = tlh->start;
+               tlh->base = tlh->start;
+               tlh->end = tlh->start + TLH_MAX_SIZE;
+       }
+
+       tlh->overflows = 0;
+}
+
+void tlh_destroy(tlh_t *tlh) {
+       int res = munmap(tlh->start, TLH_MAX_SIZE);
+       if (res == -1) {
+               /* TODO */
+               assert(0);
+       }
+       tlh->start = NULL;
+       tlh->end = NULL;
+       tlh->top = NULL;
+       tlh->base = NULL;
+}
+
+void tlh_add_frame(tlh_t *tlh) {
+       if (tlh_avail(tlh, SIZEOF_VOID_P)) {
+               *(uint8_t **)tlh->top = tlh->base;
+               tlh->base = tlh->top;
+               tlh->top += SIZEOF_VOID_P;
+       } else {
+               tlh->overflows += 1;
+       }
+}
+
+void tlh_remove_frame(tlh_t *tlh) {
+       if (tlh->overflows > 0) {
+               tlh->overflows -= 1;
+       } else {
+               tlh->top = tlh->base;
+               tlh->base = *(uint8_t **)tlh->top;
+       }
+}
+
+void *tlh_alloc(tlh_t *tlh, size_t size) {
+       void *ret;
+       if (tlh_avail(tlh, size)) {
+               ret = tlh->top;
+               tlh->top += size;
+               MZERO(ret, char, size);
+       } else {
+               ret = NULL;
+       }
+       return ret;
+}
+
+/*
+ * 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/mm/tlh.h b/src/mm/tlh.h
new file mode 100644 (file)
index 0000000..48b40e3
--- /dev/null
@@ -0,0 +1,62 @@
+/* src/mm/tlh.h
+
+   Copyright (C) 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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 _MM_TLH_H
+#define _MM_TLH_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+       uint8_t *start;
+       uint8_t *end;
+       uint8_t *top;
+       uint8_t *base;
+       unsigned overflows;
+} tlh_t;
+
+void tlh_init(tlh_t *tlh);
+
+void tlh_destroy(tlh_t *tlh);
+
+void tlh_add_frame(tlh_t *tlh);
+
+void tlh_remove_frame(tlh_t *tlh);
+
+void *tlh_alloc(tlh_t *tlh, size_t size);
+
+#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:
+ */
index bfcdc58a7c37ac9a54196457e05b455b117897e6..defe4220e711761f2d8aad96266ddc0c50bd6428 100644 (file)
@@ -475,6 +475,10 @@ void threads_impl_thread_init(threadobject *t)
 
        t->suspendmutex = Mutex_new();
        t->suspendcond = Condition_new();
+
+#if defined(ENABLE_TLH)
+       tlh_init(&(t->tlh));
+#endif
 }
 
 /* threads_impl_thread_clear ***************************************************
@@ -563,6 +567,11 @@ void threads_impl_thread_reuse(threadobject *t)
 
 /*     not really needed */
        t->flc_object = NULL;
+
+#if defined(ENABLE_TLH)
+       tlh_destroy(&(t->tlh));
+       tlh_init(&(t->tlh));
+#endif
 }
 
 
@@ -1617,6 +1626,17 @@ void threads_yield(void)
        sched_yield();
 }
 
+#if defined(ENABLE_TLH)
+
+void threads_tlh_add_frame() {
+       tlh_add_frame(&(THREADOBJECT->tlh));
+}
+
+void threads_tlh_remove_frame() {
+       tlh_remove_frame(&(THREADOBJECT->tlh));
+}
+
+#endif
 
 /*
  * These are local overrides for various environment variables in Emacs.
index 5c107f86372897e8c42410d06ea12f11817b83b0..bb8b4206d9efdf30553678d0d6785b34d0e58e1e 100644 (file)
@@ -40,6 +40,10 @@ typedef struct threadobject threadobject;
 
 #include "mm/memory.h"
 
+#if defined(ENABLE_TLH)
+#include "mm/tlh.h"
+#endif
+
 #include "native/localref.h"
 
 #include "threads/condition.hpp"
@@ -74,6 +78,7 @@ typedef struct {
 #endif
 
 
+
 /* current threadobject *******************************************************/
 
 #if defined(HAVE___THREAD)
@@ -171,6 +176,14 @@ struct threadobject {
        u4                    tracejavacallcount;
 #endif
 
+#if defined(ENABLE_TLH)
+       tlh_t                 tlh;
+#endif
+
+#if defined(ENABLE_ESCAPE_REASON)
+       void *escape_reasons;
+#endif
+
        listnode_t            linkage;      /* threads-list                       */
        listnode_t            linkage_free; /* free-list                          */
 };
@@ -285,6 +298,11 @@ void threads_wait_with_timeout_relative(threadobject *t, s8 millis, s4 nanos);
 
 void threads_thread_interrupt(threadobject *thread);
 
+#if defined(ENABLE_TLH)
+void threads_tlh_add_frame();
+void threads_tlh_remove_frame();
+#endif
+
 #endif /* _THREAD_POSIX_H */
 
 
index 62099a7b807a589e800399eba0268e0b233d610f..377bad8830fd3370390200d55b26348f91e13fd7 100644 (file)
@@ -904,6 +904,90 @@ java_handle_t *builtin_new(classinfo *c)
        return o;
 }
 
+#if defined(ENABLE_ESCAPE_REASON)
+java_handle_t *builtin_escape_reason_new(classinfo *c) {
+       print_escape_reasons();
+       return builtin_java_new(c);
+}
+#endif
+
+#if defined(ENABLE_TLH)
+java_handle_t *builtin_tlh_new(classinfo *c)
+{
+       java_handle_t *o;
+#if defined(ENABLE_RT_TIMING)
+       struct timespec time_start, time_end;
+#endif
+#if defined(ENABLE_CYCLES_STATS)
+       u8 cycles_start, cycles_end;
+#endif
+
+       RT_TIMING_GET_TIME(time_start);
+       CYCLES_STATS_GET(cycles_start);
+
+       /* is the class loaded */
+
+       assert(c->state & CLASS_LOADED);
+
+       /* check if we can instantiate this class */
+
+       if (c->flags & ACC_ABSTRACT) {
+               exceptions_throw_instantiationerror(c);
+               return NULL;
+       }
+
+       /* is the class linked */
+
+       if (!(c->state & CLASS_LINKED))
+               if (!link_class(c))
+                       return NULL;
+
+       if (!(c->state & CLASS_INITIALIZED)) {
+#if !defined(NDEBUG)
+               if (initverbose)
+                       log_message_class("Initialize class (from builtin_new): ", c);
+#endif
+
+               if (!initialize_class(c))
+                       return NULL;
+       }
+
+       /*
+       o = tlh_alloc(&(THREADOBJECT->tlh), c->instancesize);
+       */
+       o = NULL;
+
+       if (o == NULL) {
+               o = heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
+                                          c->finalizer, true);
+       }
+
+       if (!o)
+               return NULL;
+
+#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
+       /* XXX this is only a dirty hack to make Boehm work with handles */
+
+       o = LLNI_WRAP((java_object_t *) o);
+#endif
+
+       LLNI_vftbl_direct(o) = c->vftbl;
+
+#if defined(ENABLE_THREADS)
+       lock_init_object_lock(LLNI_DIRECT(o));
+#endif
+
+       CYCLES_STATS_GET(cycles_end);
+       RT_TIMING_GET_TIME(time_end);
+
+/*
+       CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
+       RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
+*/
+
+       return o;
+#endif
+}
 
 /* builtin_java_new ************************************************************
 
index 769d5426720a7b54be54b97ea7c60c14216197d0..f898706b83525c3a4026b4282e62933a503ff0d7 100644 (file)
@@ -149,6 +149,17 @@ java_handle_t *builtin_new(classinfo *c);
 /* NOT AN OP */
 java_handle_t *builtin_java_new(java_handle_t *c);
 #define BUILTIN_new (functionptr) builtin_java_new
+
+#if defined(ENABLE_TLH)
+#define BUILTIN_tlh_new (functionptr) builtin_tlh_new
+java_handle_t *builtin_tlh_new(classinfo *c);
+#endif
+
+#if defined(ENABLE_ESCAPE_REASON)
+#define BUILTIN_escape_reason_new (functionptr)builtin_escape_reason_new
+java_handle_t *builtin_escape_reason_new(classinfo *c);
+#endif
+
 java_object_t *builtin_fast_new(classinfo *c);
 #define BUILTIN_FAST_new (functionptr) builtin_fast_new
 
index 735c1de70776c296d1113670634222df52a2526e..3f5781fe261a27bff1c1cd70173e64ea41011157 100644 (file)
@@ -194,6 +194,39 @@ static builtintable_entry builtintable_internal[] = {
                NULL,
                NULL
        },
+
+#if defined(ENABLE_TLH)
+       {
+               ICMD_NEW,
+               BUILTINTABLE_FLAG_STUB,
+               BUILTIN_tlh_new,
+               NULL,
+               NULL,
+               "tlh_new",
+               "(Ljava/lang/Class;)Ljava/lang/Object;",
+               NULL,
+               NULL,
+               NULL,
+               NULL
+       },
+#endif
+
+#if defined(ENABLE_ESCAPE_REASON)
+       {
+               ICMD_NEW,
+               BUILTINTABLE_FLAG_STUB,
+               BUILTIN_escape_reason_new,
+               NULL,
+               NULL,
+               "escape_reason_new",
+               "(Ljava/lang/Class;)Ljava/lang/Object;",
+               NULL,
+               NULL,
+               NULL,
+               NULL
+       },
+#endif
+
        {
                ICMD_NEW,
                0,
index 5d1e65bf82de057e4202d673a9baa8d102717735..2a09e47c1fdafb958d9fedf361c010c83051c87d 100644 (file)
@@ -207,6 +207,10 @@ typedef struct java_objectarray_t java_objectarray_t;
 #define ACC_METHOD_IMPLEMENTED 0x00020000     /* there is an implementation   */
 #define ACC_METHOD_MONOMORPHIC 0x00040000     /* currently monomorphic method */
 #define ACC_METHOD_EA          0x00080000     /* method being escape analyzed */
+#define ACC_METHOD_MONOMORPHY_USED \
+                               0x00100000
+#define ACC_METHOD_PARENT_MONOMORPHY_USED \
+                               0x00200000
 
 
 /* data structures of the runtime system **************************************/
index 652e200970461fc6d6531c460f30a62cd6935182..da46ee966b02b3beadb2ee23c3391c9a4e7f89dc 100644 (file)
@@ -501,6 +501,21 @@ void cfg_add_root(jitdata *jd) {
        }
 }
 
+void cfg_remove_root(jitdata *jd) {
+       basicblock *root, *zero, *it;
+
+       root = jd->basicblocks;
+       zero = root->next;
+
+       zero->predecessorcount -= 1;
+
+       jd->basicblocks = zero;
+
+       for (it = zero; it; it = it->next) {
+               it->nr -= 1;
+       }
+}
+
 #if defined(ENABLE_SSA)
 
 static void cfg_eliminate_edges_to_unreachable(jitdata *jd);
index adff257fe0262c85398d156effa7bb900144a240..375379725984bfcec636ae7f6c9d29591a1a7de4 100644 (file)
@@ -50,6 +50,7 @@
 #define CODE_FLAG_INVALID         0x0001
 #define CODE_FLAG_LEAFMETHOD      0x0002
 #define CODE_FLAG_SYNCHRONIZED    0x0004
+#define CODE_FLAG_TLH             0x0008
 
 
 /* codeinfo *******************************************************************
index 34fa5ada147f7abe820421a611c2390f2e544e8d..f0f854a03b92cac66d76eef33413c4257f5f9369 100644 (file)
@@ -178,6 +178,7 @@ void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg);
 void emit_exception_check(codegendata *cd, instruction *iptr);
 
 void emit_trap_compiler(codegendata *cd);
+void emit_trap_countdown(codegendata *cd, s4 *counter);
 uint32_t emit_trap(codegendata *cd);
 
 void emit_patcher_traps(jitdata *jd);
index b384f45a7095da670b374caba06a92a589db65c2..7d64347c3844b519b1f46b5d949d8867680fdc6a 100644 (file)
@@ -408,9 +408,7 @@ bool codegen_emit(jitdata *jd)
                if (bptr->bitflags & BBFLAG_REPLACEMENT) {
                        if (cd->replacementpoint[-1].flags & RPLPOINT_FLAG_COUNTDOWN) {
                                MCODECHECK(32);
-                               disp = (s4) &(m->hitcountdown);
-                               M_ISUB_IMM_MEMABS(1, disp);
-                               M_BS(0);
+                               emit_trap_countdown(cd, &(m->hitcountdown));
                        }
                }
 #endif
@@ -2225,7 +2223,7 @@ bool codegen_emit(jitdata *jd)
                        break;
 
                case ICMD_PUTSTATIC:  /* ..., value  ==> ...                          */
-
+                       
                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                uf        = iptr->sx.s23.s3.uf;
                                fieldtype = uf->fieldref->parseddesc.fd->type;
@@ -2891,6 +2889,21 @@ nowperformreturn:
 
                        bte = iptr->sx.s23.s3.bte;
                        md = bte->md;
+
+#if defined(ENABLE_ESCAPE_REASON)
+                       if (bte->fp == BUILTIN_escape_reason_new) {
+                               void set_escape_reasons(void *);
+                               M_ASUB_IMM(8, REG_SP);
+                               M_MOV_IMM(iptr->escape_reasons, REG_ITMP1);
+                               M_AST(EDX, REG_SP, 4);
+                               M_AST(REG_ITMP1, REG_SP, 0);
+                               M_MOV_IMM(set_escape_reasons, REG_ITMP1);
+                               M_CALL(REG_ITMP1);
+                               M_ALD(EDX, REG_SP, 4);
+                               M_AADD_IMM(8, REG_SP);
+                       }
+#endif
+
                        goto gen_method;
 
                case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ...            */
index 74e7f493f4868c06c0bf437314c13f48d0dfca88..7c61037afcaf40aa14b4b3befe25e6f81290c25b 100644 (file)
@@ -517,6 +517,20 @@ void emit_trap_compiler(codegendata *cd)
        M_ALD_MEM(REG_METHODPTR, TRAP_COMPILER);
 }
 
+/* emit_trap_countdown *********************************************************
+
+   Emit a countdown trap.
+
+   counter....absolute address of the counter variable
+
+*******************************************************************************/
+
+void emit_trap_countdown(codegendata *cd, s4 *counter)
+{
+       M_ISUB_IMM_MEMABS(1, (s4) counter);
+       M_BNS(6);
+       M_ALD_MEM(REG_METHODPTR, TRAP_COUNTDOWN);
+}
 
 /* emit_trap *******************************************************************
 
index d445e4798ab28104bddb46508060f89caafbfb55..77a88c63b3efdf8b3245d8359ac6dc25b7f07a32 100644 (file)
@@ -151,6 +151,11 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
                        _mc->gregs[REG_EIP] = (uintptr_t) p;
                }
        }
+#if defined(ENABLE_REPLACEMENT)
+       else if (type == TRAP_COUNTDOWN) {
+               /* context has been written by md_replace_executionstate_write */
+       }
+#endif
        else {
                _mc->gregs[REG_EAX] = (uintptr_t) p;
                _mc->gregs[REG_ECX] = (uintptr_t) xpc;               /* REG_ITMP2_XPC */
index 0c39650967eae2db07d0c9449b5e361b9cdae55f..3d30a6fc89363658e8b893bd05c74ab39f28ccd1 100644 (file)
@@ -58,6 +58,7 @@ enum {
        /* Don't use 8 (could be a normal load offset). */
 
        TRAP_COMPILER                       = 9,
+       TRAP_COUNTDOWN                      = 10,
        TRAP_END
 };
 
index e6f17c2d83f5266996607b181bd4b0c5b4682654..971a9dd752b937a6d9554b44dbd5b81d24d0bcc1 100644 (file)
@@ -390,8 +390,9 @@ u1 *jit_compile(methodinfo *m)
                jd->flags |= JITDATA_FLAG_VERBOSECALL;
 
 #if defined(ENABLE_REPLACEMENT) && defined(ENABLE_INLINING)
-       if (opt_Inline)
+       if (opt_Inline && (jd->m->hitcountdown > 0) && (jd->code->optlevel == 0)) {
                jd->flags |= JITDATA_FLAG_COUNTDOWN;
+       }
 #endif
 
 #if defined(ENABLE_JIT)
@@ -700,18 +701,6 @@ static u1 *jit_compile_intern(jitdata *jd)
 #endif
                RT_TIMING_GET_TIME(time_typecheck);
 
-#if defined(ENABLE_SSA)
-               if (opt_lsra) {
-                       fix_exception_handlers(jd);
-               }
-#endif
-
-               /* Build the CFG.  This has to be done after stack_analyse, as
-                  there happens the JSR elimination. */
-
-               if (!cfg_build(jd))
-                       return NULL;
-
 #if defined(ENABLE_LOOP)
                if (opt_loops) {
                        depthFirst(jd);
@@ -733,13 +722,25 @@ static u1 *jit_compile_intern(jitdata *jd)
 
                /* inlining */
 
-#if defined(ENABLE_INLINING)
+#if defined(ENABLE_INLINING) && (!defined(ENABLE_ESCAPE) || 1)
                if (JITDATA_HAS_FLAG_INLINE(jd)) {
                        if (!inline_inline(jd))
                                return NULL;
                }
 #endif
 
+#if defined(ENABLE_SSA)
+               if (opt_lsra) {
+                       fix_exception_handlers(jd);
+               }
+#endif
+
+               /* Build the CFG.  This has to be done after stack_analyse, as
+                  there happens the JSR elimination. */
+
+               if (!cfg_build(jd))
+                       return NULL;
+
 #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
@@ -770,16 +771,17 @@ static u1 *jit_compile_intern(jitdata *jd)
 #if defined(ENABLE_SSA)
                /* allocate registers */
                if (
-                       (opt_lsra) 
-                       /*&& strncmp(jd->m->name->text, "banana", 6) == 0*/
+                       (opt_lsra &&
+                       jd->code->optlevel > 0) 
+                       /* strncmp(jd->m->name->text, "hottie", 6) == 0*/
                        /*&& jd->exceptiontablelength == 0*/
                ) {
-                       /* printf("=== %s ===\n", jd->m->name->text); */
+                       /*printf("=== %s ===\n", jd->m->name->text);*/
                        jd->ls = DNEW(lsradata);
                        jd->ls = NULL;
                        ssa(jd);
                        /*lsra(jd);*/ regalloc(jd);
-                       eliminate_subbasicblocks(jd);
+                       /*eliminate_subbasicblocks(jd);*/
                        STATISTICS(count_methods_allocated_by_lsra++);
 
                } else
index 448f0cc539d6206c4c5493caef05f0586a6e3f32..c447b1bd2db27018ba14c9e0eb2c7f3a6e3e4cc0 100644 (file)
@@ -383,6 +383,9 @@ struct instruction {
 #if SIZEOF_VOID_P == 4
     flags_operand_t         flags;  /* 4 bytes      */
 #endif
+#if defined(ENABLE_ESCAPE_REASON)
+       void *escape_reasons;
+#endif
 };
 
 
@@ -549,6 +552,9 @@ struct basicblock {
 #define FOR_EACH_INSTRUCTION(bptr, it) \
        for ((it) = (bptr)->iinstr; (it) != (bptr)->iinstr + (bptr)->icount; ++(it))
 
+#define FOR_EACH_INSTRUCTION_REV(bptr, it) \
+       for ((it) = (bptr)->iinstr + (bptr)->icount - 1; (it) != (bptr)->iinstr - 1; --(it))
+
 #if defined(ENABLE_SSA)
 
 #define FOR_EACH_EXHANDLER(bptr, it) \
index 22fb1f2810f7ec0d9abbef087a5d153d69564849..82db44003bf577987776683cb87dbf8f39ad8577 100644 (file)
@@ -118,15 +118,10 @@ typedef struct {
        op_stack_slot_t *ptr;
        op_stack_slot_t *bottom;
        unsigned max;
+       bool *perror_flag;
 } op_stack_t;
 
-#define stack_assert_position(stack, pos) \
-       do { \
-               assert((stack)->elements <= (pos)); \
-               assert((pos) < (stack)->end); \
-       } while (0)
-
-static void op_stack_init(op_stack_t *stack, unsigned max) {
+static void op_stack_init(op_stack_t *stack, unsigned max, bool *perror_flag) {
        op_stack_slot_t *it;
 
        stack->elements = DMNEW(op_stack_slot_t, max * 2);
@@ -140,6 +135,27 @@ static void op_stack_init(op_stack_t *stack, unsigned max) {
 
        stack->ptr = stack->start;
        stack->bottom = stack->start;
+
+       stack->perror_flag = perror_flag;
+}
+
+static void op_stack_set_error(op_stack_t *stack) {
+       *(stack->perror_flag) = true;
+#if BC_ESCAPE_VERBOSE
+       printf("%s: error.\n", __FUNCTION__);
+#endif
+}
+
+static bool op_stack_test_position(op_stack_t *stack, op_stack_slot_t *pos) {
+       if (!(stack->elements <= pos)) {
+               op_stack_set_error(stack);
+               return false;
+       } else if (!(pos < stack->end)) {
+               op_stack_set_error(stack);
+               return false;
+       } else {
+               return true;
+       }
 }
 
 static void op_stack_reset(op_stack_t *stack) {
@@ -160,7 +176,9 @@ static void op_stack_reset(op_stack_t *stack) {
 static op_stack_slot_t op_stack_pop(op_stack_t *stack) {
        op_stack_slot_t ret;
        stack->ptr -= 1;
-       stack_assert_position(stack, stack->ptr);
+       if (! op_stack_test_position(stack, stack->ptr)) {
+               return OP_STACK_SLOT_UNKNOWN;
+       }
        ret = *(stack->ptr);
        if (stack->ptr < stack->bottom) {
                stack->bottom = stack->ptr;
@@ -169,19 +187,24 @@ static op_stack_slot_t op_stack_pop(op_stack_t *stack) {
 }
 
 static void op_stack_push(op_stack_t *stack, op_stack_slot_t element) {
-       stack_assert_position(stack, stack->ptr);
-       *(stack->ptr) = element;
-       stack->ptr += 1;
+       if (op_stack_test_position(stack, stack->ptr)) {
+               *(stack->ptr) = element;
+               stack->ptr += 1;
+       }
 }
 
 static op_stack_slot_t op_stack_get(const op_stack_t *stack, int offset) {
-       stack_assert_position(stack, stack->ptr - offset);
-       return *(stack->ptr - offset);
+       if (op_stack_test_position(stack, stack->ptr - offset)) {
+               return *(stack->ptr - offset);
+       } else {
+               return OP_STACK_SLOT_UNKNOWN;
+       }
 }
 
 static void op_stack_set(op_stack_t *stack, int offset, op_stack_slot_t value) {
-       stack_assert_position(stack, stack->ptr - offset);
-       *(stack->ptr - offset) = value;
+       if (op_stack_test_position(stack, stack->ptr - offset)) {
+               *(stack->ptr - offset) = value;
+       }
 }
 
 static inline void op_stack_push_unknown(op_stack_t *stack) {
@@ -301,13 +324,22 @@ typedef struct {
        u1 *pos;
        u1 *instruction_start;
        s4 offset;
+       bool *perror_flag;
 } jcode_t;
 
-static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset) {
+static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset, bool *perror_flag) {
        jc->start = start;
        jc->end = jc->start + length;
        jc->pos = jc->start;
        jc->offset = offset;
+       jc->perror_flag = perror_flag;
+}
+
+static void jcode_set_error(jcode_t *jc) {
+       *(jc->perror_flag) = true;
+#if BC_ESCAPE_VERBOSE
+       printf("%s: error.\n", __FUNCTION__);
+#endif
 }
 
 static void jcode_move_to_index(jcode_t *jc, s4 index) {
@@ -347,38 +379,56 @@ static s4 jcode_get_index(const jcode_t *jc) {
        return jc->offset + (jc->pos - jc->start);
 }
 
-#define jcode_assert_has_bytes(jc, n) \
-       assert((jc->pos + n) <= jc->end)
+bool jcode_test_has_bytes(jcode_t *jc, s4 n) {
+       if ((jc->pos + n) <= jc->end) {
+               return true;
+       } else {
+               jcode_set_error(jc);
+               return false;
+       }
+}
 
 static u1 jcode_get_u1(jcode_t *jc) {
        u1 ret;
-       jcode_assert_has_bytes(jc, 1);
-       ret = jc->pos[0];
-       jc->pos += 1;
+       if (jcode_test_has_bytes(jc, 1)) {
+               ret = jc->pos[0];
+               jc->pos += 1;
+       } else {
+               ret = 0;
+       }
        return ret;
 }
 
 static s2 jcode_get_s2(jcode_t *jc) {
        s2 ret;
-       jcode_assert_has_bytes(jc, 2);
-       ret = (jc->pos[0] << 8) | (jc->pos[1]);
-       jc->pos += 2;
+       if (jcode_test_has_bytes(jc, 2)) {
+               ret = (jc->pos[0] << 8) | (jc->pos[1]);
+               jc->pos += 2;
+       } else {
+               ret = 0;
+       }
        return ret;
 }
 
 static u2 jcode_get_u2(jcode_t *jc) {
        u2 ret;
-       jcode_assert_has_bytes(jc, 2);
-       ret = (jc->pos[0] << 8) | (jc->pos[1]);
-       jc->pos += 2;
+       if (jcode_test_has_bytes(jc, 2)) {
+               ret = (jc->pos[0] << 8) | (jc->pos[1]);
+               jc->pos += 2;
+       } else {
+               ret = 0;
+       }
        return ret;
 }
 
 static s4 jcode_get_s4(jcode_t *jc) {
        s4 ret;
-       jcode_assert_has_bytes(jc, 4);
-       ret = (jc->pos[0] << 24) | (jc->pos[1] << 16) | (jc->pos[2] << 8) | (jc->pos[3]);
-       jc->pos += 4;
+       if (jcode_test_has_bytes(jc, 4)) {
+               ret = (jc->pos[0] << 24) | (jc->pos[1] << 16) | (jc->pos[2] << 8) | (jc->pos[3]);
+               jc->pos += 4;
+       } else {
+               ret = 0;
+       }
        return ret;
 }
 
@@ -394,7 +444,9 @@ static s4 jcode_get_branch_target_wide(jcode_t *jc) {
 
 static s4 jcode_get_fall_through_target(jcode_t *jc) {
        int length = bytecode[*jc->instruction_start].length;
-       assert(length > 0);
+       if (length <= 0) {
+               jcode_set_error(jc);
+       }
        return jc->offset + (jc->instruction_start - jc->start) + length;
 }
 
@@ -420,6 +472,8 @@ typedef struct {
        bool verbose;
 #endif
        int depth;
+
+       bool fatal_error;
 } bc_escape_analysis_t;
 
 static void bc_escape_analysis_perform_intern(methodinfo *m, int depth);
@@ -430,13 +484,13 @@ static void bc_escape_analysis_init(bc_escape_analysis_t *be, methodinfo *m, boo
        int a;
        u1 *ite;
        u1 t;
-       int ret_adr;
        unsigned n;
+       int ret_val_is_adr;
 
        be->method = m;
 
        be->stack = DNEW(op_stack_t);
-       op_stack_init(be->stack, m->maxstack);
+       op_stack_init(be->stack, m->maxstack, &(be->fatal_error));
 
        be->basicblocks = DNEW(basicblock_work_list_t);
        basicblock_work_list_init(be->basicblocks);
@@ -464,27 +518,28 @@ static void bc_escape_analysis_init(bc_escape_analysis_t *be, methodinfo *m, boo
 
        assert(l == be->local_to_adr_param_size);
 
-       /* Determine whether return type is address */
-
-       ret_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;
+       ret_val_is_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;
 
        /* Allocate param_escape on heap. */
 
        be->param_escape_size = a;
-       n = a + ret_adr;
+       n = a + ret_val_is_adr;
 
        if (n == 0) {
                /* Use some non-NULL value. */
                be->param_escape = (u1 *)1;
        } else {
                be->param_escape = MNEW(u1, n);
+               be->param_escape += ret_val_is_adr;
        }
 
        for (ite = be->param_escape; ite != be->param_escape + n; ++ite) {
-               *ite = (u1)ESCAPE_NONE;
+               *ite = escape_state_to_u1(ESCAPE_NONE);
        }
 
-       be->param_escape += ret_adr;
+       if (ret_val_is_adr) {
+               be->param_escape[-1] = escape_state_to_u1(ESCAPE_NONE);
+       }
 
        be->adr_param_dirty = DNEW(bit_vector_t);
        bit_vector_init(be->adr_param_dirty, a);
@@ -499,6 +554,8 @@ static void bc_escape_analysis_init(bc_escape_analysis_t *be, methodinfo *m, boo
 #endif
 
        be->depth = depth;
+
+       be->fatal_error = false;
 }
 
 static void bc_escape_analysis_branch_target(bc_escape_analysis_t *be, s4 branch_target) {
@@ -524,8 +581,8 @@ static void bc_escape_analysis_adjust_state(
                                   parameters. */
 
                                if (
-                                       old < ESCAPE_GLOBAL_THROUGH_METHOD && 
-                                       escape_state >= ESCAPE_GLOBAL_THROUGH_METHOD
+                                       old < ESCAPE_GLOBAL && 
+                                       escape_state >= ESCAPE_GLOBAL
                                ) {
                                        be->non_escaping_adr_params -= 1;
                                }
@@ -550,16 +607,17 @@ static void bc_escape_analysis_dirty_2(bc_escape_analysis_t *be, s4 local) {
        bc_escape_analysis_dirty(be, local + 1);
 }
 
-static void bc_escape_analyisis_returned(bc_escape_analysis_t *be, op_stack_slot_t value) {
+static void bc_escape_analysis_returned(bc_escape_analysis_t *be, op_stack_slot_t value) {
        if (op_stack_slot_is_param(value)) {
                /* A parameter is returned, mark it as being returned. */
                bit_vector_set(be->adr_param_returned, value.index);
-       } else if (op_stack_slot_is_unknown(value)) {
-               /* An untracked value is returned.
-                  Conservatively asume a globally escaping value is returned. */
+               /* The escape state of the return value will be adjusted later. */
+       } else {
+               /* Adjust escape state of return value. */
                if (be->method->parseddesc->returntype.type == TYPE_ADR) {
-                       be->param_escape[-1] = (u1)ESCAPE_GLOBAL;
+                       be->param_escape[-1] = escape_state_to_u1(ESCAPE_GLOBAL);
                }
+               bc_escape_analysis_adjust_state(be, value, ESCAPE_GLOBAL);
        }
 }
 
@@ -589,6 +647,25 @@ value_category_t bc_escape_analysis_value_category(bc_escape_analysis_t *be, s4
        }
 }
 
+static void bc_escape_analysis_push_return_value(
+       bc_escape_analysis_t *be,
+       methoddesc *md
+) {
+       switch (md->returntype.type) {
+               case TYPE_LNG:
+               case TYPE_DBL:
+                       op_stack_push_unknown(be->stack);
+                       op_stack_push_unknown(be->stack);
+                       break;
+               case TYPE_VOID:
+                       /* Do nothing */
+                       break;
+               default:
+                       op_stack_push_unknown(be->stack);
+                       break;
+       }
+}
+
 static void bc_escape_analysis_adjust_invoke_parameters(
        bc_escape_analysis_t *be,
        methodinfo *mi
@@ -597,6 +674,8 @@ static void bc_escape_analysis_adjust_invoke_parameters(
        methoddesc *md = mi->parseddesc;
        u1 *paramescape = mi->paramescape;
        s4 stack_depth = md->paramslots;
+       unsigned num_params_returned = 0;
+       op_stack_slot_t param_returned;
 
        /* Process parameters. 
         * The first parameter is at the highest depth on the stack.
@@ -605,10 +684,14 @@ static void bc_escape_analysis_adjust_invoke_parameters(
        for (i = 0; i < md->paramcount; ++i) {
                switch (md->paramtypes[i].type) {
                        case TYPE_ADR:
+                               if (*paramescape & 0x80) {
+                                       num_params_returned += 1;
+                                       param_returned = op_stack_get(be->stack, stack_depth);
+                               }
                                bc_escape_analysis_adjust_state(
                                        be,
                                        op_stack_get(be->stack, stack_depth),
-                                       (escape_state_t)*(paramescape++)
+                                       escape_state_from_u1(*paramescape++)
                                );
                                stack_depth -= 1;
                                break;
@@ -627,7 +710,20 @@ static void bc_escape_analysis_adjust_invoke_parameters(
        for (i = 0; i < md->paramslots; ++i) {
                op_stack_pop(be->stack);
        }
+       
+       /* Push return value. */
 
+       if (md->returntype.type == TYPE_ADR) {
+               if ((num_params_returned == 1) && (mi->paramescape[-1] < ESCAPE_GLOBAL)) {
+                       /* Only a single argument can be returned by the method,
+                          and the retun value does not escape otherwise. */
+                       op_stack_push(be->stack, param_returned);
+               } else {
+                       op_stack_push_unknown(be->stack);
+               }
+       } else {
+               bc_escape_analysis_push_return_value(be, md);
+       }
 }
 
 static void bc_escape_analysis_escape_invoke_parameters(
@@ -638,6 +734,8 @@ static void bc_escape_analysis_escape_invoke_parameters(
        for (i = 0; i < md->paramslots; ++i) {
                bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
        }
+
+       bc_escape_analysis_push_return_value(be, md);
 }
 
 static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *jc) {
@@ -713,7 +811,7 @@ static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *j
           or recurse into callee. 
           Otherwise we must assume, that all parameters escape. */
 
-       if (mi != NULL) {
+       if (mi != NULL && escape_is_monomorphic(be->method, mi)) {
 
                if (mi->paramescape == NULL) {
                        bc_escape_analysis_perform_intern(mi, be->depth + 1);
@@ -730,20 +828,6 @@ static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *j
        } else {
                bc_escape_analysis_escape_invoke_parameters(be, md);
        }
-
-       switch (md->returntype.type) {
-               case TYPE_LNG:
-               case TYPE_DBL:
-                       op_stack_push_unknown(be->stack);
-                       op_stack_push_unknown(be->stack);
-                       break;
-               case TYPE_VOID:
-                       /* Do nothing */
-                       break;
-               default:
-                       op_stack_push_unknown(be->stack);
-                       break;
-       }
 }
 
 static void bc_escape_analysis_parse_tableswitch(
@@ -825,7 +909,7 @@ static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcod
        /* TODO end if all parameters escape */
        /* TODO move code into process_instruction or the like */
 
-       while ((! jcode_end(jc)) && (! bb_end)) {
+       while ((! jcode_end(jc)) && (! bb_end) && (! be->fatal_error)) {
 
                jcode_record_instruction_start(jc);
 
@@ -1390,7 +1474,7 @@ static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcod
 
                        case BC_areturn:
                                /* FIXME */
-                               bc_escape_analyisis_returned(be, op_stack_pop(be->stack));
+                               bc_escape_analysis_returned(be, op_stack_pop(be->stack));
                                bb_end = true;
                                break;
 
@@ -1593,7 +1677,7 @@ static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcod
        }
 #endif
 
-       while (! op_stack_is_empty(be->stack)) {
+       while ((! op_stack_is_empty(be->stack)) && (! be->fatal_error)) {
 #if BC_ESCAPE_VERBOSE
                if (be->verbose) {
                        dprintf(be->depth, "Stack element: ");
@@ -1609,10 +1693,19 @@ static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcod
                }
 #endif
        }
+
+       if (be->fatal_error) {
+#if BC_ESCAPE_VERBOSE
+               if (be->verbose) {
+                       printf("Fatal error while processing basic block. Aborting.\n");
+               }
+#endif
+               assert(0);
+       }
 }
 
 static void    bc_escape_analysis_adjust_return_value(bc_escape_analysis_t *be) {
-       escape_state_t e, pe;
+       escape_state_t re, pe;
        int i;
 
        /* Only calculate, if return value is of type address. */
@@ -1621,22 +1714,20 @@ static void     bc_escape_analysis_adjust_return_value(bc_escape_analysis_t *be) {
                return ;
        }
 
-       /* Get current escape state of return value. */
-
-       e = (escape_state_t)be->param_escape[-1];
-
        /* If a parameter can be returned, adjust to its escape state. */
 
        for (i = 0; i < be->param_escape_size; ++i) {
                if (bit_vector_get(be->adr_param_returned, i)) {
-                       pe = (escape_state_t)be->param_escape[i];
-                       if (pe > e) {
-                               e = pe;
+                       be->param_escape[i] |= 0x80;
+
+                       pe = escape_state_from_u1(be->param_escape[i]);
+                       re = escape_state_from_u1(be->param_escape[-1]);
+                       
+                       if (pe > re) {
+                               be->param_escape[-1] = escape_state_to_u1(pe);
                        }
                }
        }
-
-       be->param_escape[-1] = (u1)e;
 }
 
 static void bc_escape_analysis_analyze(bc_escape_analysis_t *be) {
@@ -1664,7 +1755,8 @@ static void bc_escape_analysis_analyze(bc_escape_analysis_t *be) {
                &jc,
                be->method->jcode,
                be->method->jcodelength,
-               0
+               0,
+               &(be->fatal_error)
        );
 
        /* Process basicblock by basicblock. */
@@ -1702,6 +1794,10 @@ static void bc_escape_analysis_perform_intern(methodinfo *m, int depth) {
        }
 #endif
 
+       if (depth >= 3) {
+               return;
+       }
+
        if (m->paramescape != NULL) {
 #if BC_ESCAPE_VERBOSE
                if (verbose) {  
@@ -1729,7 +1825,14 @@ static void bc_escape_analysis_perform_intern(methodinfo *m, int depth) {
                return;
        }
 
-       /* TODO threshold */
+       if (m->jcodelength > 250) {
+#if BC_ESCAPE_VERBOSE
+               if (verbose) {
+                       dprintf(depth, "Bytecode too long: %d.\n", m->jcodelength);
+               }
+#endif
+               return;
+       }
 
        be = DNEW(bc_escape_analysis_t);
        bc_escape_analysis_init(be, m, verbose, depth);
index b1c0679d584720036e7d81704fc7d160c5d62cfd..7642a5360d156f8fe7e061ba33bcda6486dd2cae 100644 (file)
@@ -1,4 +1,4 @@
-/* src/vm/optimizing/escape.c
+/* src/vm/optimizing/e&scape.c
 
    Copyright (C) 2008
    CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
 
 #include "vm/jit/jit.h"
 #include "vmcore/class.h"
+#include "vmcore/classcache.h"
 #include "vm/jit/optimizing/escape.h"
 
+#include <stdarg.h>
+
+#if defined(ENABLE_ESCAPE_REASON)
+#define ENABLE_REASON
+#endif
+
+#if defined(ENABLE_REASON)
+#define I2(why, tov, es) escape_analysis_record_reason(e, why, iptr, tov, es);
+#else
+#define I2(why, tov, es)
+#endif
+#define I(why, to, from) I2(why, instruction_ ## to (iptr), escape_analysis_get_state(e, instruction_ ## from (iptr)))
+#define E2(why, var) I2(why, var, ESCAPE_GLOBAL)
+#define E(why, which) E2(why, instruction_ ## which (iptr))
+
+typedef enum {
+       RED = 31,
+       GREEN,
+       YELLOW,
+       BLUE,
+       MAGENTA,
+       CYAN,
+       WHITE,
+       COLOR_END
+} color_t;
+
+#define ENABLE_COLOR
+
+static void color_start(color_t color) {
+#if defined(ENABLE_COLOR)
+       if (RED <= color && color < COLOR_END) {
+               printf("\033[%dm", color);
+       }
+#endif
+}
+
+static void color_end() {
+#if defined(ENABLE_COLOR)
+       printf("\033[m");
+       fflush(stdout);
+#endif
+}
+
+static void color_printf(color_t color, const char *fmt, ...) {
+       va_list ap;
+       color_start(color);
+       va_start(ap, fmt);
+       vprintf(fmt, ap);
+       va_end(ap);
+       color_end();
+}
+
+
 /*** escape_state *************************************************************/
 
 const char *escape_state_to_string(escape_state_t escape_state) {
@@ -33,7 +87,7 @@ const char *escape_state_to_string(escape_state_t escape_state) {
                str(ESCAPE_UNKNOWN)
                str(ESCAPE_NONE)
                str(ESCAPE_METHOD)
-               str(ESCAPE_GLOBAL_THROUGH_METHOD)
+               str(ESCAPE_METHOD_RETURN)
                str(ESCAPE_GLOBAL)
                default: return "???";
        }
@@ -150,6 +204,8 @@ typedef struct {
 
        instruction_list_t *allocations;
        instruction_list_t *getfields;
+       instruction_list_t *monitors;
+       instruction_list_t *returns;
 
        struct var_extra **var;
 
@@ -274,12 +330,25 @@ void dependenCy_list_import(dependency_list_t *dl, dependency_list_t *other) {
 
 /*** var_extra ***************************************************************/
 
+#if defined(ENABLE_REASON)
+typedef struct reason {
+       const char *why;
+       instruction *iptr;
+       struct reason *next;
+} reason_t;
+#endif
+
 typedef struct var_extra {
        instruction *allocation;
        escape_state_t escape_state;
        s4 representant;
        dependency_list_t *dependency_list;
-       bool is_arg; /* TODO optimize */
+       unsigned contains_arg:1;
+       unsigned contains_only_args:1;
+       /*signed adr_arg_num:30;*/
+#if defined(ENABLE_REASON)
+       reason_t *reasons;
+#endif
 } var_extra_t;
 
 static void var_extra_init(var_extra_t *ve) {
@@ -287,7 +356,12 @@ static void var_extra_init(var_extra_t *ve) {
        ve->escape_state = ESCAPE_NONE;
        ve->representant = -1;
        ve->dependency_list = NULL;
-       ve->is_arg = false;
+       ve->contains_arg = false;
+       ve->contains_only_args = false;
+       /*ve->adr_arg_num = -1;*/
+#if defined(ENABLE_REASON)
+       ve->reasons = NULL;
+#endif
 }
 
 static inline var_extra_t *var_extra_get_no_alloc(const escape_analysis_t *e, s4 var) {
@@ -371,17 +445,40 @@ static void escape_analysis_init(escape_analysis_t *e, jitdata *jd) {
        e->getfields = DNEW(instruction_list_t);
        instruction_list_init(e->getfields);
 
+       e->monitors = DNEW(instruction_list_t);
+       instruction_list_init(e->monitors);
+
+       e->returns = DNEW(instruction_list_t);
+       instruction_list_init(e->returns);
+
        e->var = DMNEW(var_extra_t *, jd->vartop);
        MZERO(e->var, var_extra_t *, jd->vartop);
 
        e->adr_args_count = 0;
 
-       e->verbose = (
-               strcmp(e->jd->m->clazz->name->text, "gnu/java/util/regex/RESyntax") == 0 
-               && strcmp(e->jd->m->name->text, "<clinit>") == 0
-       );
        e->verbose = 1;
+       e->verbose = strcmp(jd->m->name->text, "<init>") == 0;
+       e->verbose = getenv("EV") != NULL;
+}
+
+#if defined(ENABLE_REASON)
+static void escape_analysis_record_reason(escape_analysis_t *e, const char *why, instruction *iptr, s4 var, escape_state_t es) {
+       var_extra_t *ve;
+       reason_t *re;
+       if (es == ESCAPE_GLOBAL || es == ESCAPE_METHOD_RETURN) {
+               var = var_extra_get_representant(e, var);
+               ve = var_extra_get(e, var);
+               re = NEW(reason_t);
+               re->why = why;
+               re->iptr= iptr;
+               re->next = ve->reasons;
+               ve->reasons = re;
+               if (e->verbose) {
+                       printf("%d escapes because %s\n", var, why);
+               }
+       }
 }
+#endif
 
 static void escape_analysis_set_allocation(escape_analysis_t *e, s4 var, instruction *iptr) {
        var_extra_get(e, var)->allocation = iptr;
@@ -396,12 +493,38 @@ static instruction *escape_analysis_get_allocation(const escape_analysis_t *e, s
        return ve->allocation;
 }
 
-static void escape_analysis_set_is_argument(escape_analysis_t *e, s4 var) {
-       var_extra_get(e, var)->is_arg = true;
+static void escape_analysis_set_contains_argument(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       var_extra_get(e, var)->contains_arg = true;
+}
+
+static bool escape_analysis_get_contains_argument(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       return var_extra_get(e, var)->contains_arg;
+}
+
+static void escape_analysis_set_contains_only_arguments(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       var_extra_get(e, var)->contains_only_args = true;
+}
+
+static bool escape_analysis_get_contains_only_arguments(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       return var_extra_get(e, var)->contains_only_args;
+}
+
+/*
+static void escape_analysis_set_adr_arg_num(escape_analysis_t *e, s4 var, s4 num) {
+       var_extra_get(e, var)->adr_arg_num = num;
+}
+
+static s4 escape_analysis_get_adr_arg_num(escape_analysis_t *e, s4 var) {
+       return var_extra_get(e, var)->adr_arg_num;
 }
+*/
 
-static bool escape_analysis_get_is_argument(escape_analysis_t *e, s4 var) {
-       return var_extra_get(e, var)->is_arg;
+static bool escape_analysis_in_same_set(escape_analysis_t *e, s4 var1, s4 var2) {
+       return var_extra_get_representant(e, var1) == var_extra_get_representant(e, var2);
 }
 
 static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
@@ -432,6 +555,10 @@ static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_st
                                        dependency_list_item_get_dependency(it),
                                        escape_state
                                );
+                               {
+                               instruction *iptr = NULL;
+                               I2("propagated by dependency", dependency_list_item_get_dependency(it), escape_state);
+                               }
                        }
                }
        }
@@ -441,12 +568,6 @@ static escape_state_t escape_analysis_get_state(escape_analysis_t *e, s4 var) {
        return var_extra_get_escape_state(e, var);
 }
 
-#define escape_analysis_assert_has_escape(e, var) \
-       assert( \
-               var_extra_get_no_alloc(e, var) && \
-               (var_extra_get_no_alloc(e, var)->escape_state > ESCAPE_UNKNOWN) \
-       )
-
 static classinfo *escape_analysis_classinfo_in_var(escape_analysis_t *e, s4 var) {
        instruction *iptr = escape_analysis_get_allocation(e, var);
 
@@ -484,6 +605,8 @@ static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
                return;
        }
 
+       if (e->verbose) printf("Merging (%d,%d)\n", var1, var2);
+
        ve1 = var_extra_get(e, var1);
        ve2 = var_extra_get(e, var2);
 
@@ -496,10 +619,10 @@ static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
 
        ve2->representant = var1;
 
-       /* Adjust is_argument to logical or. */
+       /* Adjust is_arg to logical or. */
        
-       has_become_arg = ve1->is_arg != ve2->is_arg;
-       ve1->is_arg = ve1->is_arg || ve2->is_arg;
+       has_become_arg = ve1->contains_arg != ve2->contains_arg;
+       ve1->contains_arg = ve1->contains_arg || ve2->contains_arg;
 
        if (e->verbose && has_become_arg) printf("(%d,%d) has become arg.\n", var1, var2);
 
@@ -521,8 +644,35 @@ static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
                                dependency_list_item_get_dependency(itd),
                                ESCAPE_GLOBAL
                        );
+                       {
+                       instruction *iptr = NULL;
+                       E2("has become arg", dependency_list_item_get_dependency(itd));
+                       }
                }
        }
+
+       /* Adjust contains_only_args to logical and. */
+
+       ve1->contains_only_args = ve1->contains_only_args && ve2->contains_only_args;
+
+       /* Adjust address argument number contained in this var. */
+
+       /*
+       if (ve1->adr_arg_num != ve2->adr_arg_num) {
+               ve1->adr_arg_num = -1;
+       }
+       */
+#if defined(ENABLE_REASON)
+       if (ve1->reasons) {
+               reason_t *re = ve1->reasons;
+               while (re->next != NULL) {
+                       re = re->next;
+               }
+               re->next = ve2->reasons;
+       } else {
+               ve1->reasons = ve2->reasons;
+       }
+#endif
 }
 
 static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *store) {
@@ -534,7 +684,9 @@ static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *st
        dependency_list_add(dl, store);
 
        if (e->verbose) {
-               printf("dependency_list_add\n");
+               printf("dependency_list_add: %d.dependency_list.add( { ", obj);
+               show_icmd(e->jd, store, 0, 3);
+               printf(" } )\n"); 
        }
 }
 
@@ -545,12 +697,16 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
        u1 *paramescape;
        unsigned i;
        instruction **iarg;
-       constant_FMIref *fmi;
        methodinfo *mi;
-       resolve_result_t result;
+       escape_state_t es;
+       const char *why;
 
        if (e->verbose) {
-               printf("processing %s@%d\n", icmd_table[iptr->opc].name, iptr->line);
+               color_start(CYAN);
+               printf("%d: ", iptr->line);
+               show_icmd(e->jd, iptr, 0, 3);
+               color_end();
+               printf("\n");
        }
 
        switch (instruction_get_opcode(iptr)) {
@@ -568,46 +724,51 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
 
                        if (c == NULL) {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
-                               if (e->verbose) printf("1\n");
+                               E("unresolved class", dst)
                        } else if (c->finalizer != NULL) {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
-                               if (e->verbose) printf("3\n");
+                               E("finalizer", dst)
                        } else {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
-                               if (e->verbose) printf("2\n");
                        }
 
                        instruction_list_add(e->allocations, iptr);
 
                        break;
 
+               case ICMD_MONITORENTER:
+               case ICMD_MONITOREXIT:
+               
+                       instruction_list_add(e->monitors, iptr);
+
+                       break;
+
                case ICMD_NEWARRAY:
                case ICMD_ANEWARRAY:
                        
                        escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
                        escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        instruction_list_add(e->allocations, iptr);
-
+                       E("untracked array", dst)
                        break;
 
                case ICMD_PUTSTATIC:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               */
                                escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                               E("putstatic", s1)
                        }
                        break;
 
                case ICMD_PUTFIELD:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               escape_analysis_assert_has_escape(e, instruction_s2(iptr));
-                               */
-                               if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                               if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
                                        escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_GLOBAL);
+                                       /* If s1 is currently not an argument, but can contain one later because
+                                          of a phi function, the merge function takes care to make all
+                                          dependencies escape globally. */
+                                       E("putfield into argument", s2)
                                } else {
+                                       I("putfield inherit", s2, s1);
                                        escape_analysis_ensure_state(e, instruction_s2(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
                                        escape_analysis_add_dependency(e, iptr);
                                }
@@ -615,13 +776,13 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                        break;
 
                case ICMD_AASTORE:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       escape_analysis_assert_has_escape(e, instruction_s3(iptr));
-                       */
-                       if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                       if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
+                               if (e->verbose) printf("Contains argument.\n");
                                escape_analysis_ensure_state(e, instruction_s3(iptr), ESCAPE_GLOBAL);
+                               E("aastore into argument", s3)
                        } else {
+                               if (e->verbose) printf("Contains no argument.\n");
+                               I("aastore", s3, s1)
                                escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
                                escape_analysis_add_dependency(e, iptr);
                        }
@@ -630,22 +791,21 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                case ICMD_GETSTATIC:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                               E("loaded from static var", dst)
                                escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        }
                        break;
 
                case ICMD_GETFIELD:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               */
 
-                               if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                               if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
                                        /* Fields loaded from arguments escape globally.
                                           x = arg.foo;
                                           x.bar = y;
                                           => y escapes globally. */
                                        escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                                       E("loaded from arg", dst)
                                } else {
                                        escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
                                }
@@ -657,19 +817,15 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                        break;
 
                case ICMD_ARRAYLENGTH:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        break;
 
                case ICMD_AALOAD:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
 
-                       if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                       if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
                                /* If store into argument, escapes globally. See ICMD_GETFIELD. */
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                               E("aaload from argument", dst)
                        } else {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
                        }
@@ -681,36 +837,27 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
 
                case ICMD_IF_ACMPEQ:
                case ICMD_IF_ACMPNE:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       escape_analysis_assert_has_escape(e, instruction_s2(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_METHOD);
                        break;
 
                case ICMD_IFNULL:
                case ICMD_IFNONNULL:
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
+                       break;
+
                case ICMD_CHECKNULL:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
+                       escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
                        break;
 
                case ICMD_CHECKCAST:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        break;
 
                case ICMD_INSTANCEOF:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        break;
 
@@ -721,15 +868,25 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                        count = instruction_arg_count(iptr);
                        mi = instruction_local_methodinfo(iptr);
                        paramescape = NULL;
+                       why = "???";
 
                        if (mi != NULL) {
                                /* If the method could be resolved, it already is. */
                                paramescape = mi->paramescape;
 
+                               if (e->verbose) {
+                                       if (paramescape) {
+                                               printf("Paramescape for callee available.\n");
+                                       }
+                               }
+
+                               if (paramescape) why = "Available param escape";
+
                                if (paramescape == NULL) {
                                        if (e->verbose) {
                                                printf("BC escape analyzing callee.\n");
                                        }
+                                       why = "BC param escape";
                                        bc_escape_analysis_perform(mi);
                                        paramescape = mi->paramescape;
                                }
@@ -737,26 +894,66 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                                if (e->verbose) {
                                        printf("Unresolved callee.\n");
                                }
+                               why = "Unresolved callee";
+                       }
+
+                       if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
+                               if (mi != NULL && !escape_is_monomorphic(e->jd->m, mi)) {
+                                       if (e->verbose) {
+                                               printf("Not monomorphic.\n");
+                                       }
+                                       why = "Polymorphic";
+                                       paramescape = NULL;
+                               }
                        }
 
+                       /* Set the escape state of the return value.
+                          This is: global if we down have information of the callee, or the callee
+                          supplied escape state. */
+
+                       if (instruction_return_type(iptr) == TYPE_ADR) {
+                               if (paramescape == NULL) {
+                                       escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                                       E(why, dst);
+                               } else {
+                                       es = escape_state_from_u1(paramescape[-1]);
+                                       I2(why, instruction_dst(iptr), es)
+                                       escape_analysis_ensure_state(e, instruction_dst(iptr), es);
+                               }
+                               escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
+                       }
+                       
                        for (i = 0; i < count; ++i) {
                                if (instruction_arg_type(iptr, i) == TYPE_ADR) {
 
-                                       /*
-                                       escape_analysis_assert_has_escape(e, instruction_arg(iptr, i));
-                                       */
                                        if (paramescape == NULL) {
                                                escape_analysis_ensure_state(
                                                        e, 
                                                        instruction_arg(iptr, i), 
-                                                       instruction_local_methodinfo(iptr) && instruction_local_methodinfo(iptr)->jcode ?
-                                                               ESCAPE_GLOBAL_THROUGH_METHOD :
-                                                               ESCAPE_GLOBAL
+                                                       ESCAPE_GLOBAL
                                                );
-                                       } else if ((escape_state_t)*paramescape < ESCAPE_METHOD) {
-                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_METHOD);
+                                               E2(why, instruction_arg(iptr, i));
+                                       } else if (escape_state_from_u1(*paramescape) <= ESCAPE_METHOD) {
+                                               es = escape_state_from_u1(*paramescape);
+
+                                               if (es < ESCAPE_METHOD) {
+                                                       es = ESCAPE_METHOD;
+                                               }
+
+                                               I2(why, instruction_arg(iptr, i), es);
+                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), es);
+
+                                               if (*paramescape & 0x80) {
+                                                       /* Parameter can be returned from method.
+                                                          This creates an alias to the retur value.
+                                                          If the return value escapes, the ES of the parameter needs 
+                                                          to be adjusted. */
+                                                       escape_analysis_merge(e, instruction_arg(iptr, i), instruction_dst(iptr));
+                                                       I2("return alias", instruction_arg(iptr, i), instruction_dst(iptr));
+                                               }
                                        } else {
-                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), (escape_state_t)*paramescape);
+                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_GLOBAL);
+                                               E2(why, instruction_arg(iptr, i));
                                        }
 
                                        if (paramescape != NULL) {
@@ -765,25 +962,20 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                                }
                        }
 
-                       if (instruction_return_type(iptr) == TYPE_ADR) {
-                               escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
-                               escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
-                       }
-
                        break;
 
                case ICMD_ATHROW:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                       E("throw", s1)
                        break;
 
                case ICMD_ARETURN:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
-                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                       /* If we return only arguments, the return value escapes only the method.
+                          ESCAPE_METHOD for now, and check later, if a different value than an
+                          argument is possibly returned. */
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD_RETURN);
+                       E("return", s1)
+                       instruction_list_add(e->returns, iptr);
                        break;
 
                case ICMD_ALOAD:
@@ -791,9 +983,6 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                case ICMD_MOVE:
                case ICMD_COPY:
                        if (instruction_dst_type(iptr, jd) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               */
                                escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
                                escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        }
@@ -821,6 +1010,10 @@ static void escape_analysis_process_instructions(escape_analysis_t *e) {
 
        FOR_EACH_BASICBLOCK(e->jd, bptr) {
 
+               if (e->verbose) {
+                       color_printf(CYAN, "=== BB %d ===\n", bptr->nr);        
+               }
+
                for (iptr = bptr->phis; iptr != bptr->phis + bptr->phicount; ++iptr) {
                        escape_analysis_process_instruction(e, iptr);
                }
@@ -832,12 +1025,30 @@ static void escape_analysis_process_instructions(escape_analysis_t *e) {
        }
 }
 
+static void escape_analysis_post_process_returns(escape_analysis_t *e) {
+       instruction_list_item_t *iti;
+       instruction *iptr;
+
+       if (e->verbose) printf("Post processing returns:\n");
+
+       FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
+               iptr = iti->instr;
+
+               if (! escape_analysis_get_contains_only_arguments(e, instruction_s1(iptr))) {
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                       E("return of not argument", s1)
+               }
+       }
+}
+
 static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
        instruction_list_item_t *iti;
        dependency_list_item_t *itd;
        instruction *iptr;
        dependency_list_t *dl;
 
+       if (e->verbose) printf("Post processing getfields:\n");
+
        FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
 
                iptr = iti->instr;
@@ -860,6 +1071,7 @@ static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
                                                dependency_list_item_get_dependency(itd),
                                                escape_analysis_get_state(e, instruction_dst(iptr))
                                        );
+                                       I2("post process getfield", dependency_list_item_get_dependency(itd), escape_analysis_get_state(e, instruction_dst(iptr)));
                                }
                        }
                }
@@ -867,44 +1079,59 @@ static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
        }
 }
 
-static void display_allocation(escape_analysis_t *e, const char *prefix, const instruction *iptr, escape_state_t es) {
-       const char *cl = "WTF";
-       classinfo *c;
+static void escape_analysis_mark_monitors(escape_analysis_t *e) {
+       instruction_list_item_t *iti;
+       instruction *iptr;
+
+       FOR_EACH_INSTRUCTION_LIST(e->monitors, iti) {
+               iptr = iti->instr;
 
-       if (instruction_get_opcode(iptr) == ICMD_NEW) {
-               c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
-               if (c) {
-                       cl = c->name->text;
+               /* TODO if argument does not escape, mark. */
+               if (escape_analysis_get_state(e, instruction_arg(iptr, 0)) != ESCAPE_GLOBAL) {
+                       if (e->verbose) {
+                               printf("Monitor on thread local object!\n");
+                       }
                }
        }
-       
-
-       printf(
-               " %s %s %s: %s %s @%d %s\n", 
-               prefix,
-               e->jd->m->clazz->name->text,
-               e->jd->m->name->text,
-               icmd_table[iptr->opc].name,
-               cl,
-               iptr->line,
-               escape_state_to_string(es)
-       );
 }
 
 static void escape_analysis_mark_allocations(escape_analysis_t *e) {
        instruction_list_item_t *iti;
+       instruction *iptr;
        escape_state_t es;
-/*
        FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
-               es = escape_analysis_get_state(e, instruction_dst(iti->instr));
-               if (es < ESCAPE_GLOBAL_THROUGH_METHOD) {
-                       display_allocation(e, "****", iti->instr, es);
+               iptr = iti->instr;
+               es = escape_analysis_get_state(e, instruction_dst(iptr));
+
+#if defined(ENABLE_REASON)
+               if (instruction_get_opcode(iptr) == ICMD_NEW) {
+                       var_extra_t *ve;
+                       iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_escape_reason_new);
+                       ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
+                       iptr->escape_reasons = ve->reasons;
+                       if (es < ESCAPE_METHOD_RETURN) {
+                               assert(!ve->reasons);
+                               reason_t *r = NEW(reason_t);
+                               r->why = "No escape\n";
+                               r->iptr = NULL;
+                               r->next = NULL;
+                               iptr->escape_reasons = r;
+                       } else {
+                               assert(iptr->escape_reasons);
+                       }
                }
-               if (es == ESCAPE_GLOBAL_THROUGH_METHOD) {
-                       display_allocation(e, "!!!!", iti->instr, es);
+#endif
+
+/*
+               if (instruction_get_opcode(iptr) == ICMD_NEW) {
+                       es = escape_analysis_get_state(e, instruction_dst(iptr));
+                       if (es < ESCAPE_METHOD_RETURN) {
+                               iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_tlh_new);
+                               e->jd->code->flags |= CODE_FLAG_TLH;
+                       }
                }
-       }
 */
+       }
 }
 
 static void escape_analysis_process_arguments(escape_analysis_t *e) {
@@ -922,7 +1149,9 @@ static void escape_analysis_process_arguments(escape_analysis_t *e) {
                if (t == TYPE_ADR) {
                        if (varindex != UNUSED) {
                                escape_analysis_ensure_state(e, varindex, ESCAPE_NONE);
-                               escape_analysis_set_is_argument(e, varindex);
+                               escape_analysis_set_contains_argument(e, varindex);
+                               escape_analysis_set_contains_only_arguments(e, varindex);
+                               /*escape_analysis_set_adr_arg_num(e, varindex, e->adr_args_count);*/
                        }
                        e->adr_args_count += 1;
                }
@@ -937,11 +1166,18 @@ static void escape_analysis_export_arguments(escape_analysis_t *e) {
        s4 varindex;
        methoddesc *md;
        u1 *paramescape;
+       instruction_list_item_t *iti;
+       instruction *iptr;
+       escape_state_t es, re;
+       int ret_val_is_adr;
        
        md = e->jd->m->parseddesc;
 
-       paramescape = MNEW(u1, e->adr_args_count);
-       e->jd->m->paramescape = paramescape;
+       ret_val_is_adr = (md->returntype.type == TYPE_ADR) ? 1 : 0;
+
+       paramescape = MNEW(u1, e->adr_args_count + ret_val_is_adr);
+
+       e->jd->m->paramescape = paramescape + ret_val_is_adr;
 
        for (p = 0, l = 0; p < md->paramcount; ++p) {
                t = md->paramtypes[p].type;
@@ -950,16 +1186,59 @@ static void escape_analysis_export_arguments(escape_analysis_t *e) {
                        if (varindex == UNUSED) {
                                *paramescape = (u1)ESCAPE_NONE;
                        } else {
-                               *paramescape = (u1)escape_analysis_get_state(e, varindex);
-                       }
-                       if (e->verbose) {
-                               printf("adr parameter %d: %s\n", p, escape_state_to_string((escape_state_t)*paramescape));
+                               es = escape_analysis_get_state(e, varindex);
+
+                               if (es == ESCAPE_METHOD_RETURN) {
+                                       *paramescape = escape_state_to_u1(ESCAPE_METHOD) | 0x80;
+                                       if (e->verbose) {
+                                               printf("non-escaping adr parameter returned: %d\n", p);
+                                       }
+                               } else {
+                                       *paramescape = escape_state_to_u1(es);
+                               }
+
                        }
                        paramescape += 1;
                }
                l += IS_2_WORD_TYPE(t) ? 2 : 1;
        }
+
+       if (ret_val_is_adr) {
+               /* Calculate escape state of return value as maximum escape state of all
+                  values returned. */
+
+               re = ESCAPE_NONE;
+
+               FOR_EACH_INSTRUCTION_LIST(e->returns, iti) {
+                       iptr = iti->instr;
+                       es = escape_analysis_get_state(e, instruction_s1(iptr));
+
+                       if (es > re) {
+                               re = es;
+                       }
+               }
+
+               e->jd->m->paramescape[-1] = escape_state_to_u1(re);
+       }
+}
+
+#if defined(ENABLE_REASON)
+void print_escape_reasons() {
+       reason_t *re = THREADOBJECT->escape_reasons;
+
+       fprintf(stderr, "DYN_REASON");
+       
+       for (; re; re = re->next) {
+               fprintf(stderr,":%s", re->why);
+       }
+
+       fprintf(stderr, "\n");
+}
+
+void set_escape_reasons(void *vp) {
+       THREADOBJECT->escape_reasons = vp;
 }
+#endif
 
 static void escape_analysis_display(escape_analysis_t *e) {
        instruction_list_item_t *iti;
@@ -968,13 +1247,26 @@ static void escape_analysis_display(escape_analysis_t *e) {
 
        FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
                iptr = iti->instr;
-               ve = var_extra_get(e, instruction_dst(iptr));
+               ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
+               show_icmd(e->jd, iptr-1, 0, 3);
+               printf("\n");
+               show_icmd(e->jd, iptr, 0, 3);
+               printf("\n");
                printf(
-                       "%s@%d: %s\n", 
+                       "%s@%d: --%s-- %d\n\n", 
                        icmd_table[iptr->opc].name, 
                        iptr->line, 
-                       escape_state_to_string(ve->escape_state)
+                       escape_state_to_string(ve->escape_state),
+                       ve->representant
                );
+#if defined(ENABLE_REASON)
+               {
+                       reason_t *re;
+                       for (re = ve->reasons; re; re = re->next) {
+                               printf("ESCAPE_REASON: %s\n", re->why);
+                       }
+               }
+#endif
        }
 }
 
@@ -983,25 +1275,72 @@ void escape_analysis_perform(jitdata *jd) {
 
        jd->m->flags |= ACC_METHOD_EA;
 
-       /*bc_escape_analysis_perform(jd->m);*/
-
        e = DNEW(escape_analysis_t);
        escape_analysis_init(e, jd);
 
        if (e->verbose) 
-               printf("==== %s/%s ====\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
+               color_printf(RED, "\n\n==== %s/%s ====\n\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
                
-       /*fprintf(stderr, ".");*/
-
        escape_analysis_process_arguments(e);
        escape_analysis_process_instructions(e);
        escape_analysis_post_process_getfields(e);
+       escape_analysis_post_process_returns(e);
+
        escape_analysis_export_arguments(e);
        if (e->verbose) escape_analysis_display(e);
+
+       if (e->verbose) {
+               int i, j, r;
+               for (i = 0; i < jd->vartop; ++i) {
+                       r = var_extra_get_representant(e, i);
+                       if (i == r) {
+                               printf("EES of %d: ", i);
+                               for (j = 0; j < jd->vartop; ++j) {
+                                       if (var_extra_get_representant(e, j) == r) {
+                                               printf("%d, ", j);
+                                       }
+                               }
+                               printf("\n");
+                       }
+               }
+               printf("\n");
+       }
+
        escape_analysis_mark_allocations(e);
+       escape_analysis_mark_monitors(e);
 
        jd->m->flags &= ~ACC_METHOD_EA;
 }
 
 void escape_analysis_escape_check(void *vp) {
 }
+
+/*** monomorphic *************************************************************/
+
+bool escape_is_monomorphic(methodinfo *caller, methodinfo *callee) {
+
+       /* Non-speculative case */
+
+       if (callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
+               return true;
+       }
+
+       if (
+               (callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED| ACC_ABSTRACT))
+               == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)
+       ) {
+
+               /* Mark that we have used the information about monomorphy. */
+
+               callee->flags |= ACC_METHOD_MONOMORPHY_USED;
+
+               /* We assume the callee is monomorphic. */
+
+               method_add_assumption_monomorphic(caller, callee);
+
+               return true;
+       }
+
+       return false;
+}
+
index 2f427fa31b6c2faf245a3748704b98485e62e234..5b5f7b6eeb7c377afbb76fc157cb3195f19df92c 100644 (file)
@@ -31,14 +31,24 @@ typedef enum {
        ESCAPE_UNKNOWN,
        ESCAPE_NONE,
        ESCAPE_METHOD,
-       ESCAPE_GLOBAL_THROUGH_METHOD,
+       ESCAPE_METHOD_RETURN,
        ESCAPE_GLOBAL
 } escape_state_t;
 
+static inline escape_state_t escape_state_from_u1(u1 x) {
+       return (escape_state_t)(x & ~0x80);
+}
+
+static inline u1 escape_state_to_u1(escape_state_t x) {
+       return (u1)x;
+}
+
 void escape_analysis_perform(jitdata *jd);
 
 void escape_analysis_escape_check(void *vp);
 
 void bc_escape_analysis_perform(methodinfo *m);
 
+bool escape_is_monomorphic(methodinfo *caller, methodinfo *callee);
+
 #endif
index 721323e4bb0df7409dca7d2981c95c6da8c458c1..793a6605d4ca8bc86886a0669a687da3bbe057d0 100644 (file)
@@ -133,6 +133,7 @@ void ssa(jitdata *jd) {
                yssa(jd);
        }
        /*pythonpass_run(jd, "foo", "after");*/
+       cfg_remove_root(jd);
        return;
 
        ls = jd->ls;
index 0f8c1306dcb754a625a7291c8dda1c008fb1b983..29864f17f311bbeb8489fe0fb7d672a642ff6b2e 100644 (file)
 #include <limits.h>
 #include <stdio.h>
 
-#define ELIMINATE_NOP_LOAD_STORE
+/*#define ELIMINATE_NOP_LOAD_STORE*/
 #define FIXME(x) x
 #define SSA_VERIFY
-/* #define SSA_VERBOSE */
+/*#define SSA_VERBOSE */
 
 /*
 __attribute__((always_inline))
@@ -345,8 +345,8 @@ static inline void instruction_set_uses(instruction *iptr, s4 *buf, s4 *uses, un
 
 /*** vars *******************************************************************/
 
-#define VARS_CATEGORY_SHIFT 29
-#define VARS_INDEX_MASK 0x1FFFFFFF
+#define VARS_CATEGORY_SHIFT 28
+#define VARS_INDEX_MASK 0x0FFFFFFF
 
 #define VARS_CATEGORY_LOCAL 0
 #define VARS_CATEGORY_STACK 1
@@ -354,8 +354,15 @@ static inline void instruction_set_uses(instruction *iptr, s4 *buf, s4 *uses, un
 
 #define VAR_TYPE_SUBSTITUED 666
 
+#define OLD_INDEX_UNUSED -2
+
+typedef struct {
+       varinfo v;
+       s4 old_index;
+} vars_item_t;
+
 typedef struct {
-       varinfo items[9000]; /* XXX hardcoded max */
+       vars_item_t items[9000]; /* XXX hardcoded max */
        unsigned max;
        unsigned count;
        unsigned category;
@@ -365,7 +372,8 @@ static inline unsigned vars_add_item(vars_t *vs, const varinfo *item) {
        unsigned i = vs->count;
        assert(i < vs->max);
        vs->count += 1;
-       vs->items[i] = *item;
+       vs->items[i].v = *item;
+       vs->items[i].old_index = OLD_INDEX_UNUSED;
        return (vs->category << VARS_CATEGORY_SHIFT) | i;
 }
 
@@ -378,7 +386,7 @@ static inline unsigned vars_add(vars_t *vs) {
 
 static inline varinfo *vars_back(vars_t *vs) {
        assert(vs->count > 0);
-       return vs->items + (vs->count - 1);
+       return &(vs->items[vs->count - 1].v);
 }
 
 static inline void vars_init(vars_t *vs, unsigned category) {
@@ -400,8 +408,8 @@ static void vars_subst(vars_t *vs, unsigned varindex, unsigned replacementindex)
        varindex = vars_get_index(varindex);
        replacementindex = vars_get_index(replacementindex);
 
-       vs->items[varindex].type = VAR_TYPE_SUBSTITUED;
-       vs->items[varindex].vv.regoff = replacementindex;
+       vs->items[varindex].v.type = VAR_TYPE_SUBSTITUED;
+       vs->items[varindex].v.vv.ii[1] = replacementindex;
 }
 
 static unsigned vars_resolve_subst(const vars_t *vs, unsigned varindex) {
@@ -410,36 +418,80 @@ static unsigned vars_resolve_subst(const vars_t *vs, unsigned varindex) {
 #endif
        varindex = vars_get_index(varindex);
 
-       if (vs->items[varindex].type == VAR_TYPE_SUBSTITUED) /*fprintf(stderr, "*")*/;
+       if (vs->items[varindex].v.type == VAR_TYPE_SUBSTITUED) /*fprintf(stderr, "*")*/;
 
-       while (vs->items[varindex].type == VAR_TYPE_SUBSTITUED) {
+       while (vs->items[varindex].v.type == VAR_TYPE_SUBSTITUED) {
                assert(loop_ctr++ != vs->count);
-               varindex = vs->items[varindex].vv.regoff;
+               varindex = vs->items[varindex].v.vv.ii[1];
        }
 
        return (vs->category << VARS_CATEGORY_SHIFT) | varindex ;
 }
 
 static void vars_copy_to_final(vars_t *vs, varinfo *dst) {
-       const varinfo *it;
+       const vars_item_t *it;
        unsigned subst;
 
        for (it = vs->items; it != vs->items + vs->count; ++it, ++dst) {
 
                /* Copy variable. */
 
-               *dst = *it;
+               *dst = it->v;
 
                /* Eliminate VAR_TYPE_SUBSTITUED as it leads to problems. */
 
                if (dst->type == VAR_TYPE_SUBSTITUED) {
                        subst = vars_get_index(vars_resolve_subst(vs, it - vs->items));
-                       dst->type = vs->items[subst].type;
+                       dst->type = vs->items[subst].v.type;
 
                }
        }
 }
 
+static void vars_import(vars_t *vs, varinfo *v, unsigned count, s4 old_index) {
+       vars_item_t *it;
+
+       assert((vs->count + count) <= vs->max);
+
+       it = vs->items + vs->count;
+       vs->count += count;
+
+       while (count-- > 0) {
+               it->v = *v;
+               it->old_index = old_index;
+               it += 1;
+               v += 1;
+               old_index += 1;
+       }
+}
+
+static inline void vars_record_old_index(vars_t *vs, unsigned varindex, s4 old_index) {
+       vars_item_t *item;
+       varindex = vars_get_index(varindex);
+
+       assert(varindex < vs->count);
+
+       item = vs->items + varindex;
+
+       assert(
+               item->old_index == OLD_INDEX_UNUSED || 
+               item->old_index == old_index
+       );
+
+       item->old_index = old_index;
+}
+
+static inline s4 vars_get_old_index(vars_t *vs, unsigned varindex) {
+       s4 old;
+
+       varindex = vars_get_index(varindex);
+
+       assert(varindex < vs->count);
+       old = vs->items[varindex].old_index;
+       assert(old != OLD_INDEX_UNUSED);
+
+       return old;
+}
 
 /*** phis *******************************************************************/
 
@@ -486,13 +538,15 @@ FIXME() inline void phis_print(const phis_t *ps) {
 }
 #endif
 
-static inline void phis_copy_to(const phis_t *ps, instruction *dst) {
-       MCOPY(
-               dst,
-               ps->items,
-               instruction,
-               ps->count
-       );
+static inline unsigned phis_copy_to(const phis_t *ps, instruction *dst) {
+       instruction *it;
+       instruction *out = dst;
+
+       FOR_EACH_PHI_FUNCTION(ps, it) {
+               *(out++) = *it;
+       }
+
+       return (out - dst);
 }
 
 /*** state_array ************************************************************/
@@ -680,31 +734,41 @@ instruction *traversal_create_phi(traversal_t *t, vars_t *v, unsigned argcount,
 
        state_array_set(t->state_array, index, phi);
 
+       vars_record_old_index(v, phi->dst.varindex, index);
+
        return phi;
 }
 
 static void traversal_rename_def(traversal_t *t, vars_t *vars, instruction *iptr) {
        const varinfo *v;
        unsigned index;
+       s4 old;
 
        state_array_assert_items(t->state_array);
 
        v = t->ops->var_num_to_varinfo(t->ops_vp, iptr->dst.varindex);
        index = t->ops->var_num_to_index(t->ops_vp, iptr->dst.varindex);
 
+       old = iptr->dst.varindex;
        iptr->dst.varindex = vars_add_item(vars, v);
        state_array_set(t->state_array, index, iptr);
+
+       vars_record_old_index(vars, iptr->dst.varindex, index);
 }
 
-static void traversal_rename_use(traversal_t *t, s4 *puse) {
+static void traversal_rename_use(traversal_t *t, vars_t *vars, s4 *puse) {
        unsigned index;
+       s4 old;
 
        state_array_assert_items(t->state_array);
 
        index = t->ops->var_num_to_index(t->ops_vp, *puse);
 
        assert(state_array_get(t->state_array, index));
+       old = *puse;
        *puse = state_array_get_var(t->state_array, index);
+
+       vars_record_old_index(vars, *puse, index);
 }
 
 static inline unsigned traversal_variables_count(traversal_t *t) {
@@ -862,6 +926,18 @@ typedef struct ssa_info {
 
        basicblock_chain_t *new_blocks;
 
+       struct {
+               s4 maxlocals;
+               s4 maxinterfaces;
+               s4 *local_map;
+               varinfo *var;
+               s4 vartop;
+               s4 varcount;
+               s4 localcount;
+       } original;
+
+       unsigned keep_in_out:1;
+
 } ssa_info, ssa_info_t;
 
 void ssa_info_init(ssa_info_t *ssa, jitdata *jd) {
@@ -871,8 +947,7 @@ void ssa_info_init(ssa_info_t *ssa, jitdata *jd) {
        vars_init(ssa->locals, VARS_CATEGORY_LOCAL);
 
        /* Initialize first version of locals, that is always available. */
-       MCOPY(ssa->locals->items, jd->var, varinfo, jd->localcount);
-       ssa->locals->count = jd->localcount;
+       vars_import(ssa->locals, jd->var, jd->localcount, 0);
 
        ssa->stack = DNEW(vars_t);
        vars_init(ssa->stack, VARS_CATEGORY_STACK);
@@ -882,16 +957,26 @@ void ssa_info_init(ssa_info_t *ssa, jitdata *jd) {
 
        ssa->new_blocks = DNEW(basicblock_chain_t);
        basicblock_chain_init(ssa->new_blocks);
+
+       ssa->original.maxlocals = jd->maxlocals;
+       ssa->original.maxinterfaces = jd->maxinterfaces;
+       ssa->original.local_map = jd->local_map;
+       ssa->original.var = jd->var;
+       ssa->original.vartop = jd->vartop;
+       ssa->original.varcount = jd->varcount;
+       ssa->original.localcount = jd->localcount;
+
+       ssa->keep_in_out = false;
 }
 
 /*** others_mapping *********************************************************/
 
 static inline void others_mapping_set(ssa_info *ssa, s4 var, s4 new_var) {
-       ssa->jd->var[var].vv.regoff = new_var;
+       ssa->jd->var[var].vv.ii[1] = new_var;
 }
 
 static inline s4 others_mapping_get(const ssa_info *ssa, s4 var) {
-       return ssa->jd->var[var].vv.regoff;
+       return ssa->jd->var[var].vv.ii[1];
 }
 
 /*** code *******************************************************************/
@@ -907,6 +992,8 @@ void fix_exception_handlers(jitdata *jd) {
        basicblock_chain_t chain;
        basicblock *last = NULL;
        basicblock *marker = NULL;
+       s4 vartop;
+       unsigned i;
 
        if (jd->exceptiontablelength == 0) {
                return;
@@ -914,22 +1001,38 @@ void fix_exception_handlers(jitdata *jd) {
 
        basicblock_chain_init(&chain);
 
-       /* We need to allocate new iovars */
+       /* Remember, where we started adding IO variables. */
 
-       avail_vars = (jd->varcount - jd->vartop);
-       add_vars = jd->exceptiontablelength;
-
-       if (add_vars > avail_vars) {
-               add_vars -= avail_vars;
-               jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, jd->varcount + add_vars);
-               jd->varcount += add_vars;
-       }
+       vartop = jd->vartop;
 
        /* For each exception handler block, create one block with a prologue block */
 
        FOR_EACH_BASICBLOCK(jd, bptr) {
                if (bptr->type == BBTYPE_EXH) {
 
+                       /*
+             
+            +---- EXH (exh)-------+
+            |  in0 in1 in2 exc    |
+                       |  .....              |
+            +---------------------+
+
+            === TRANSFORMED TO ===>
+
+            +---- PROL (exh) -------+
+            |  in0 in1 in2          |
+            |  GETEXECEPTION => OU3 |
+            |  GOTO REAL_EXH        |
+            |  in0 in1 in2 OU3      |
+            +-----------------------+
+
+            +---- REAL_EXH (std) -+
+            |  in0 in1 in2 exc    |
+                       |  ......             |
+            +---------------------+
+
+                       */
+
                        bptr->type = BBTYPE_STD;
                        bptr->predecessorcount = 0; /* legacy */
 
@@ -940,7 +1043,24 @@ void fix_exception_handlers(jitdata *jd) {
 
                        iptr = DMNEW(instruction, 2);
                        MZERO(iptr, instruction, 2);
+                       
+                       /* Create outvars */
+
+                       exh->outdepth = bptr->indepth;
+
+                       if (exh->outdepth > 0) {
+                               exh->outvars = DMNEW(s4, exh->outdepth);
+                               for (i = 0; i < exh->outdepth; ++i) {
+                                       exh->outvars[i] = vartop++;
+                               }
+                       }
+
+                       /* Create invars */
 
+                       exh->indepth = exh->outdepth - 1;
+                       exh->invars = exh->outvars;
+
+#if 0
                        /* Create new outvar */
 
                        assert(jd->vartop < jd->varcount);
@@ -948,6 +1068,7 @@ void fix_exception_handlers(jitdata *jd) {
                        jd->vartop += 1;
                        jd->var[v].type = TYPE_ADR;
                        jd->var[v].flags = INOUT;
+#endif
 
                        exh->nr = jd->basicblockcount;
                        jd->basicblockcount += 1;
@@ -955,9 +1076,11 @@ void fix_exception_handlers(jitdata *jd) {
                        exh->type = BBTYPE_EXH;
                        exh->icount = 2;
                        exh->iinstr = iptr;
+/*
                        exh->outdepth = 1;
                        exh->outvars = DNEW(s4);
                        exh->outvars[0] = v;
+*/
                        exh->predecessorcount = -1; /* legacy */
                        exh->flags = BBFINISHED;
                        exh->method = jd->m;
@@ -967,7 +1090,7 @@ void fix_exception_handlers(jitdata *jd) {
                        /* Get exception */
 
                        iptr->opc = ICMD_GETEXCEPTION;
-                       iptr->dst.varindex = v;
+                       iptr->dst.varindex = exh->outvars[exh->outdepth - 1];
                        iptr += 1;
 
                        /* Goto real exception handler */
@@ -986,6 +1109,19 @@ void fix_exception_handlers(jitdata *jd) {
                }
        }
 
+       /* We need to allocate the new iovars in the var array */
+
+       avail_vars = (jd->varcount - jd->vartop);
+       add_vars = (vartop - jd->vartop);
+
+       if (add_vars > avail_vars) {
+               add_vars -= avail_vars;
+               jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, jd->varcount + add_vars);
+               jd->varcount += add_vars;
+       }
+
+       jd->vartop = vartop;
+
        /* Put the chain of exception handlers between just before the last
           basic block (end marker). */
 
@@ -1003,9 +1139,68 @@ void fix_exception_handlers(jitdata *jd) {
 
        for (ee = jd->exceptiontable; ee; ee = ee->down) {
                assert(ee->handler->vp);
-               ee->handler = ee->handler->vp;
+
+               bptr = ee->handler;
+               exh = (basicblock *)ee->handler->vp;
+
+               ee->handler = exh;
+
+               /* Set up IO variables in newly craeted exception handlers. */
+
+               for (i = 0; i < exh->outdepth; ++i) {
+                       v = exh->outvars[i];
+
+                       jd->var[v].flags = INOUT;
+                       jd->var[v].type = jd->var[ bptr->invars[i] ].type;
+               }
+       }
+
+}
+
+void unfix_exception_handlers(jitdata *jd) {
+       basicblock *bptr, *exh;
+       unsigned i;
+       exception_entry *ee;
+#if !defined(NDEBUG)
+       bool found = false;
+#endif
+
+       FOR_EACH_BASICBLOCK(jd, bptr) {
+               if (bptr->type == BBTYPE_EXH) {
+                       assert(bptr->iinstr[1].opc == ICMD_GOTO);
+                       exh = bptr->iinstr[1].dst.block;
+
+                       bptr->type = BBDELETED;
+                       bptr->icount = 0;
+                       bptr->indepth = 0;
+                       bptr->outdepth = 0;
+                       exh->type = BBTYPE_EXH;
+                       bptr->vp = exh;
+               
+                       /* bptr is no more a predecessor of exh */
+
+                       for (i = 0; i < exh->predecessorcount; ++i) {
+                               if (exh->predecessors[i] == bptr) {
+                                       exh->predecessors[i] = exh->predecessors[exh->predecessorcount - 1];
+                                       exh->predecessorcount -= 1;
+#if !defined(NDEBUG)
+                                       found = true;
+#endif
+                                       break;
+                               }
+                       }
+
+                       assert(found);
+
+               } else {
+                       bptr->vp = NULL;
+               }
        }
 
+       for (ee = jd->exceptiontable; ee; ee = ee->down) {
+               assert(ee->handler->vp);
+               ee->handler = ee->handler->vp;
+       }
 }
 
 /*** ssa_enter ***************************************************************/
@@ -1119,6 +1314,10 @@ static void ssa_enter_verify_no_redundant_phis(ssa_info_t *ssa) {
        basicblock *bptr;
        basicblock_info_t *bbi;
        instruction *itph;
+
+       /* XXX */
+       return;
+
        FOR_EACH_BASICBLOCK(ssa->jd, bptr) {
                if (basicblock_reached(bptr)) {
                        bbi = bb_info(bptr);
@@ -1241,6 +1440,14 @@ static void ssa_enter_process_pei(ssa_info *ssa, basicblock *bb, unsigned pei) {
                        basicblock_get_ex_predecessor_index(bb, pei, *itsucc),
                        ssa->locals
                );
+
+               ssa_enter_merge(
+                       bbi->stack,
+                       succi->stack,
+                       *itsucc,
+                       basicblock_get_ex_predecessor_index(bb, pei, *itsucc),
+                       ssa->stack
+               );
        }
 }
 
@@ -1249,6 +1456,9 @@ static FIXME(bool) ssa_enter_eliminate_redundant_phis(traversal_t *t, vars_t *vs
        instruction *itph;
        bool ret = false;
 
+       /* XXX */
+       return;
+
        FOR_EACH_PHI_FUNCTION(t->phis, itph) {
 
                phi_calculate_redundancy(itph);
@@ -1346,23 +1556,33 @@ static void ssa_enter_process_block(ssa_info *ssa, basicblock *bb) {
                state_array_allocate_items(bbi->stack->state_array);
        }
 
+#if 0
        /* Exception handlers have a clean stack. */
 
+       /* Not true with inlining. */
+
        if (bb->type == BBTYPE_EXH) {
                state_array_assert_no_items(bbi->stack->state_array);
                state_array_allocate_items(bbi->stack->state_array);
        }
+#endif
 
        /* Some in/out vars get marked as INOUT in simplereg,
           and are not marked at this point. 
           Mark them manually. */
 
        for (ituse = bb->invars; ituse != bb->invars + bb->indepth; ++ituse) {
+               if (ssa->keep_in_out && ssa->jd->var[*ituse].type == TYPE_RET) {
+                       continue;
+               }
                ssa->jd->var[*ituse].flags |= INOUT;
                ssa->jd->var[*ituse].flags &= ~PREALLOC;
        }
 
        for (ituse = bb->outvars; ituse != bb->outvars + bb->outdepth; ++ituse) {
+               if (ssa->keep_in_out && ssa->jd->var[*ituse].type == TYPE_RET) {
+                       continue;
+               }
                ssa->jd->var[*ituse].flags |= INOUT;
                ssa->jd->var[*ituse].flags &= ~PREALLOC;
        }
@@ -1404,11 +1624,13 @@ static void ssa_enter_process_block(ssa_info *ssa, basicblock *bb) {
                        if (var_is_local(ssa->jd, *ituse)) {
                                traversal_rename_use(
                                        bbi->locals, 
+                                       ssa->locals,
                                        ituse
                                );
                        } else if (var_is_inout(ssa->jd, *ituse)) {
                                traversal_rename_use(
                                        bbi->stack,
+                                       ssa->stack,
                                        ituse
                                );
                        } else {
@@ -1437,6 +1659,7 @@ static void ssa_enter_process_block(ssa_info *ssa, basicblock *bb) {
                                        ssa->others,
                                        ssa->jd->var + iptr->dst.varindex
                                );
+                               vars_record_old_index(ssa->others, iptr->dst.varindex, old);
                                others_mapping_set(ssa, old, iptr->dst.varindex);
                        }
                }
@@ -1456,6 +1679,7 @@ static void ssa_enter_export_variables(ssa_info *ssa) {
        s4 *it;
        unsigned i, j;
        jitdata *jd = ssa->jd;
+       s4 *local_map;
 
        vartop = ssa->locals->count + ssa->stack->count + ssa->others->count;
        vars = DMNEW(varinfo, vartop);
@@ -1470,13 +1694,15 @@ static void ssa_enter_export_variables(ssa_info *ssa) {
        /* Grow local map to accomodate all new locals and iovars.
           But keep the local map for version 1 of locals, that contains the holes. */
        
-       jd->local_map = DMREALLOC(
-               jd->local_map, 
-               s4, 
-               5 * jd->maxlocals, 
+       local_map = DMNEW(
+               s4,
                5 * (jd->maxlocals + ssa->locals->count + ssa->stack->count - jd->localcount)
        );
 
+       MCOPY(local_map, jd->local_map, s4, 5 * jd->maxlocals);
+
+       jd->local_map = local_map;
+
        it = jd->local_map + (jd->maxlocals * 5); /* start adding entries here */
 
        /* Add version > 1 of all locals */
@@ -1524,19 +1750,15 @@ static void ssa_enter_export_phis(ssa_info_t *ssa) {
        FOR_EACH_BASICBLOCK(ssa->jd, bptr) {
                bbi = bb_info(bptr);
                if (bbi != NULL) {
-                       bptr->phicount = 
-                               bbi->locals->phis->count + 
-                               bbi->stack->phis->count;
-
-                       bptr->phis = DMNEW(instruction, bptr->phicount);
+                       bptr->phis = DMNEW(instruction, bbi->locals->phis->count + bbi->stack->phis->count);
 
                        dst = bptr->phis;
 
-                       phis_copy_to(bbi->locals->phis, dst);
+                       dst += phis_copy_to(bbi->locals->phis, dst);
 
-                       dst += bbi->locals->phis->count;
+                       dst += phis_copy_to(bbi->stack->phis, dst);
 
-                       phis_copy_to(bbi->stack->phis, dst);
+                       bptr->phicount = dst - bptr->phis;
                }
        }
 }
@@ -1569,8 +1791,10 @@ void ssa_enter_eliminate_categories(ssa_info_t *ssa) {
 
                bbi = bb_info(bb);
 
-               bb->indepth = 0;
-               bb->outdepth = 0;
+               if (! ssa->keep_in_out) {
+                       bb->indepth = 0;
+                       bb->outdepth = 0;
+               }
 
                if (bbi != NULL) {
                        FOR_EACH_PHI_FUNCTION(bbi->locals->phis, itph) {
@@ -2055,20 +2279,115 @@ static void ssa_leave_create_exceptional_phi_moves(ssa_info *ssa) {
        }
 }
 
+void ssa_simple_leave_restore(ssa_info_t *ssa, basicblock *bptr, s4 *pvar) {
+       s4 var = *pvar;
+       s4 index;
+       basicblock_info_t *bbi;
+
+       if (var < ssa->locals->count) {
+               *pvar = vars_get_old_index(ssa->locals, var);
+       } else if (var < ssa->locals->count + ssa->stack->count) {
+
+               index = vars_get_old_index(
+                       ssa->stack,
+                       var - ssa->locals->count
+               );
+
+               bbi = bb_info(bptr);
+
+               /* We have to determine whether to take an invar or an outvar for
+                  the stack depth ``index''.
+                  The state array contains the last definition of the stack element
+                  at the given depth.
+               */
+
+               if (state_array_get_var(bbi->stack->state_array, index) == var) {
+                       /* The last definition of a stack depth inside the basicblock.
+                          This is the outvar at the given depth.
+                          If there is no outvar at the given depth, it must be an invar.
+                       */
+                       if (index < bptr->outdepth) {
+                               *pvar = bptr->outvars[index];
+                       } else if (index < bptr->indepth) {
+                               *pvar = bptr->invars[index];
+                       } else {
+                               assert(0);
+                       }
+               } else {
+                       /* A different than the last definition of a stack depth.
+                          This must be an invar.
+                       */
+                       assert(index < bptr->indepth);
+                       *pvar = bptr->invars[index];
+               }
+       } else {
+               *pvar = vars_get_old_index(
+                       ssa->others,
+                       var - ssa->locals->count - ssa->stack->count
+               );
+       }
+}
+
+void ssa_simple_leave(ssa_info_t *ssa) {
+       basicblock *bptr;
+       instruction *iptr;
+       s4 *ituse, *uses;
+       unsigned uses_count;
+
+       FOR_EACH_BASICBLOCK(ssa->jd, bptr) {
+               if (bptr->type == BBTYPE_EXH) {
+                       /* (Aritifical) exception handler blocks will be eliminated. */
+                       continue;
+               }
+               /* In reverse order. We need to rename the definition after any use! */
+               FOR_EACH_INSTRUCTION_REV(bptr, iptr) {
+                       if (instruction_has_dst(iptr)) {
+                               ssa_simple_leave_restore(ssa, bptr, &(iptr->dst.varindex));
+                       }
+                       instruction_get_uses(iptr, ssa->s_buf, &uses, &uses_count);
+                       for (ituse = uses; ituse != uses + uses_count; ++ituse) {
+                               ssa_simple_leave_restore(ssa, bptr, ituse);
+                       }
+                       instruction_set_uses(iptr, ssa->s_buf, uses, uses_count);
+               }
+               bptr->phicount = 0;
+       }
+
+       unfix_exception_handlers(ssa->jd);
+
+       ssa->jd->maxlocals = ssa->original.maxlocals;
+       ssa->jd->maxinterfaces = ssa->original.maxinterfaces;
+       ssa->jd->local_map =ssa->original.local_map;
+       ssa->jd->var = ssa->original.var;
+       ssa->jd->vartop = ssa->original.vartop;
+       ssa->jd->varcount = ssa->original.varcount;
+       ssa->jd->localcount = ssa->original.localcount;
+}
+
+#include "vmcore/rt-timing.h"
+
 void yssa(jitdata *jd) {
        basicblock *it;
        basicblock_info_t *iti;
        ssa_info *ssa;
 
+       struct timespec bs, es, be, ee;
+
+       RT_TIMING_GET_TIME(bs);
+
 #ifdef SSA_VERBOSE
-       printf("=============== [ before %s ] =========================\n", jd->m->name->text);
-       show_method(jd, 3);
-       printf("=============== [ /before ] =========================\n");
+       bool verb = true;
+       if (verb) {
+               printf("=============== [ before %s ] =========================\n", jd->m->name->text);
+               show_method(jd, 3);
+               printf("=============== [ /before ] =========================\n");
+       }
 #endif
 
        ssa = DNEW(ssa_info);
 
        ssa_info_init(ssa, jd);
+       ssa->keep_in_out = true;
 
        FOR_EACH_BASICBLOCK(jd, it) {
                if (basicblock_reached(it)) {
@@ -2094,18 +2413,38 @@ void yssa(jitdata *jd) {
 
        /*ssa_enter_create_phi_graph(ssa);*/
 
+       RT_TIMING_GET_TIME(be);
        escape_analysis_perform(ssa->jd);
+       RT_TIMING_GET_TIME(ee);
 
+       /*
        ssa_leave_create_phi_moves(ssa);
 
        ssa_leave_create_exceptional_phi_moves(ssa);
+       */
+       
+#ifdef SSA_VERBOSE
+       if (verb) {
+               printf("=============== [ mid ] =========================\n");
+               show_method(jd, 3);
+               printf("=============== [ /mid ] =========================\n");
+       }
+#endif
+
+       ssa_simple_leave(ssa);
 
 #ifdef SSA_VERBOSE
-       printf("=============== [ after ] =========================\n");
-       show_method(jd, 3);
-       printf("=============== [ /after ] =========================\n");
+       if (verb) {
+               printf("=============== [ after ] =========================\n");
+               show_method(jd, 3);
+               printf("=============== [ /after ] =========================\n");
+       }
 #endif
 
+       RT_TIMING_GET_TIME(es);
+
+       RT_TIMING_TIME_DIFF(bs, es, RT_TIMING_1);
+       RT_TIMING_TIME_DIFF(be, ee, RT_TIMING_2);
 }
 
 void eliminate_subbasicblocks(jitdata *jd) {
index 66e989f006371a76bb23070191d9531136cbc7cf..b4196b1f4477200aa59f08b2af57e931875f0a3a 100644 (file)
@@ -53,6 +53,7 @@ struct varinfo {
                float f;
                double d;
                basicblock *retaddr;
+               s4 ii[2];
        } vv;
 #if defined(ENABLE_VERIFIER)
        typeinfo_t typeinfo;       /* type info for reference types              */
index 5895bec0688a9368f4e8491e57c582ef0bf5be16..58f883c1ae997643f684efffb53abe806239c24e 100644 (file)
@@ -56,7 +56,9 @@
 
 #include "vmcore/options.h"
 #include "vmcore/classcache.h"
-
+#if defined(ENABLE_RT_TIMING)
+#include "vmcore/rt-timing.h"
+#endif
 
 #define REPLACE_PATCH_DYNAMIC_CALL
 /*#define REPLACE_PATCH_ALL*/
@@ -72,7 +74,6 @@
 #undef REPLACE_RA_TOP_OF_FRAME
 #undef REPLACE_RA_LINKAGE_AREA
 #undef REPLACE_LEAFMETHODS_RA_REGISTER
-#undef REPLACE_REG_RA
 
 /* i386, x86_64 and m68k */
 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
 #elif defined(__ALPHA__)
 #define REPLACE_RA_TOP_OF_FRAME
 #define REPLACE_LEAFMETHODS_RA_REGISTER
-#define REPLACE_REG_RA REG_RA
 /* powerpc */
 #elif defined(__POWERPC__)
 #define REPLACE_RA_LINKAGE_AREA
 #define REPLACE_LEAFMETHODS_RA_REGISTER
-#define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
 /* s390 */
 #elif defined(__S390__)
 #define REPLACE_RA_TOP_OF_FRAME
-#define REPLACE_REG_RA REG_ITMP3
 #endif
 
 
@@ -1232,6 +1230,12 @@ static void replace_read_executionstate(rplpoint *rp,
                replace_read_value(es, &instra, &(frame->instance));
 #endif
        }
+#if defined(__I386__)
+       else if (!(rp->method->flags & ACC_STATIC)) {
+               /* On i386 we always pass the first argument on stack. */
+               frame->instance.a = *(java_object_t **)(basesp + 1);
+       } 
+#endif
 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
 
        /* read stack slots */
@@ -1463,6 +1467,12 @@ static void replace_write_executionstate(rplpoint *rp,
 
                if (!topframe && ra->index == RPLALLOC_PARAM) {
                        /* skip it */
+                       /*
+                       ra->index = RPLALLOC_PARAM;
+                       replace_val_t v;
+                       v.l = 0;
+                       replace_write_value(es,ra,&v);
+                       */
                }
                else {
                        assert(i < frame->javastackdepth);
@@ -1483,81 +1493,72 @@ static void replace_write_executionstate(rplpoint *rp,
 }
 
 
-/* replace_pop_activation_record ***********************************************
+/* md_pop_stackframe ***********************************************************
+
+   Restore callee-saved registers (including the RA register),
+   set the stack pointer to the next stackframe,
+   set the PC to the return address of the popped frame.
 
-   Peel a stack frame from the execution state.
-   
    *** This function imitates the effects of the method epilog ***
    *** and returning from the method call.                     ***
 
    IN:
-          es...............execution state
-          frame............source frame, receives synchronization slots
+       es...............execution state
 
    OUT:
        *es..............the execution state after popping the stack frame
-  
+                        NOTE: es->code and es->pv are NOT updated.
+
 *******************************************************************************/
 
-u1* replace_pop_activation_record(executionstate_t *es,
-                                                                 sourceframe_t *frame)
+void md_pop_stackframe(executionstate_t *es)
 {
        u1 *ra;
-       u1 *pv;
+       s4 ra_align_off;
        s4 reg;
        s4 i;
-       s4 count;
-       codeinfo *code;
        stackslot_t *basesp;
        stackslot_t *sp;
 
        assert(es->code);
-       assert(frame);
+
+       /* alignment offset of RA */
+
+       ra_align_off = 0;
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+    if (es->code->stackframesize)
+               ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P;
+#endif
 
        /* read the return address */
 
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
        if (code_is_leafmethod(es->code))
-               ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
+               ra = es->ra;
        else
 #endif
                ra = md_stacktrace_get_returnaddress(es->sp,
-                               SIZE_OF_STACKSLOT * es->code->stackframesize);
-
-       DOLOG( printf("RA = %p\n", (void*)ra); );
-
-       assert(ra);
+                          SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off);
 
        /* calculate the base of the stack frame */
 
        sp = (stackslot_t *) es->sp;
        basesp = sp + es->code->stackframesize;
 
-       /* read slots used for synchronization */
-
-       assert(frame->syncslotcount == 0);
-       assert(frame->syncslots == NULL);
-       count = code_get_sync_slot_count(es->code);
-       frame->syncslotcount = count;
-       frame->syncslots = DMNEW(replace_val_t, count);
-       for (i=0; i<count; ++i) {
-               frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
-       }
-
        /* restore return address, if part of frame */
 
 #if defined(REPLACE_RA_TOP_OF_FRAME)
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
        if (!code_is_leafmethod(es->code))
 #endif
-               es->intregs[REPLACE_REG_RA] = *--basesp;
+               es->ra = (u1*) (ptrint) *--basesp;
 #endif /* REPLACE_RA_TOP_OF_FRAME */
 
 #if defined(REPLACE_RA_LINKAGE_AREA)
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
        if (!code_is_leafmethod(es->code))
 #endif
-               es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
+               es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
 #endif /* REPLACE_RA_LINKAGE_AREA */
 
        /* restore saved int registers */
@@ -1596,37 +1597,19 @@ u1* replace_pop_activation_record(executionstate_t *es,
        es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
 
 #if defined(REPLACE_RA_BETWEEN_FRAMES)
-       es->sp += SIZE_OF_STACKSLOT; /* skip return address */
+       es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */
 #endif
 
-       /* Set the new pc. Subtract one so we do not hit the replacement point */
-       /* of the instruction following the call, if there is one.             */
-
-       es->pc = ra - 1;
-
-       /* find the new codeinfo */
-
-       pv = md_codegen_get_pv_from_pc(ra);
-       DOLOG( printf("PV = %p\n", (void*) pv); );
-
-       code = code_get_codeinfo_for_pv(pv);
-       DOLOG( printf("CODE = %p\n", (void*) code); );
-
-       /* return NULL if we reached native code */
+       /* set the program counter to the return address */
 
-       es->pv = pv;
-       es->code = code;
+       es->pc = ra;
 
        /* in debugging mode clobber non-saved registers */
 
 #if !defined(NDEBUG)
        /* for debugging */
        for (i=0; i<INT_REG_CNT; ++i)
-               if ((nregdescint[i] != REG_SAV)
-#if defined(REG_RA)
-                               && (i != REPLACE_REG_RA)
-#endif
-                       )
+               if (nregdescint[i] != REG_SAV)
                        es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
        for (i=0; i<FLT_REG_CNT; ++i)
                if (nregdescfloat[i] != REG_SAV)
@@ -1637,6 +1620,211 @@ u1* replace_pop_activation_record(executionstate_t *es,
                        es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
 # endif
 #endif /* !defined(NDEBUG) */
+}
+
+
+/* md_push_stackframe **********************************************************
+
+   Save the given return address, build the new stackframe,
+   and store callee-saved registers.
+
+   *** This function imitates the effects of a call and the ***
+   *** method prolog of the callee.                         ***
+
+   IN:
+       es...............execution state
+       calleecode.......the code we are "calling"
+       ra...............the return address to save
+
+   OUT:
+       *es..............the execution state after pushing the stack frame
+                        NOTE: es->pc, es->code, and es->pv are NOT updated.
+
+*******************************************************************************/
+
+void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
+{
+       s4           reg;
+       s4           i;
+       stackslot_t *basesp;
+       stackslot_t *sp;
+
+       assert(es);
+       assert(calleecode);
+
+       /* write the return address */
+
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+       es->sp -= SIZEOF_VOID_P;
+       *((void **)es->sp) = (void *) ra;
+       if (calleecode->stackframesize)
+               es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
+#endif /* REPLACE_RA_BETWEEN_FRAMES */
+
+       es->ra = (u1*) (ptrint) ra;
+
+       /* build the stackframe */
+
+       DOLOG( printf("building stackframe of %d words at %p\n",
+                                 calleecode->stackframesize, (void*)es->sp); );
+
+       sp = (stackslot_t *) es->sp;
+       basesp = sp;
+
+       sp -= calleecode->stackframesize;
+       es->sp = (u1*) sp;
+
+       /* in debug mode, invalidate stack frame first */
+
+       /* XXX may not invalidate linkage area used by native code! */
+
+#if !defined(NDEBUG) && 0
+       for (i=0; i< (basesp - sp) && i < 1; ++i) {
+               sp[i] = 0xdeaddeadU;
+       }
+#endif
+
+#if defined(__I386__)
+       /* Stackslot 0 may contain the object instance for vftbl patching.
+          Destroy it, so there's no undefined value used. */
+       if ((basesp - sp) > 0) {
+               sp[0] = 0;
+       }
+#endif
+
+       /* save the return address register */
+
+#if defined(REPLACE_RA_TOP_OF_FRAME)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (!code_is_leafmethod(calleecode))
+#endif
+               *--basesp = (ptrint) ra;
+#endif /* REPLACE_RA_TOP_OF_FRAME */
+
+#if defined(REPLACE_RA_LINKAGE_AREA)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (!code_is_leafmethod(calleecode))
+#endif
+               basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
+#endif /* REPLACE_RA_LINKAGE_AREA */
+
+       /* save int registers */
+
+       reg = INT_REG_CNT;
+       for (i=0; i<calleecode->savedintcount; ++i) {
+               while (nregdescint[--reg] != REG_SAV)
+                       ;
+               *--basesp = es->intregs[reg];
+
+               /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+               es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
+#endif
+       }
+
+       /* save flt registers */
+
+       /* XXX align? */
+       reg = FLT_REG_CNT;
+       for (i=0; i<calleecode->savedfltcount; ++i) {
+               while (nregdescfloat[--reg] != REG_SAV)
+                       ;
+               basesp -= STACK_SLOTS_PER_FLOAT;
+               *(double*)basesp = es->fltregs[reg];
+
+               /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+               *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
+#endif
+       }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       /* save adr registers */
+
+       reg = ADR_REG_CNT;
+       for (i=0; i<calleecode->savedadrcount; ++i) {
+               while (nregdescadr[--reg] != REG_SAV)
+                       ;
+               *--basesp = es->adrregs[reg];
+
+               /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+               es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
+#endif
+       }
+#endif
+}
+
+
+/* replace_pop_activation_record ***********************************************
+
+   Peel a stack frame from the execution state.
+
+   *** This function imitates the effects of the method epilog ***
+   *** and returning from the method call.                     ***
+
+   IN:
+       es...............execution state
+       frame............source frame, receives synchronization slots
+
+   OUT:
+       *es..............the execution state after popping the stack frame
+
+   RETURN VALUE:
+       the return address of the poped activation record
+
+*******************************************************************************/
+
+u1* replace_pop_activation_record(executionstate_t *es,
+                                                                 sourceframe_t *frame)
+{
+       u1 *ra;
+       u1 *pv;
+       s4 i;
+       s4 count;
+       codeinfo *code;
+       stackslot_t *sp;
+
+       assert(es->code);
+       assert(frame);
+
+       /* calculate the base of the stack frame */
+
+       sp = (stackslot_t *) es->sp;
+       assert(frame->syncslotcount == 0);
+       assert(frame->syncslots == NULL);
+       count = code_get_sync_slot_count(es->code);
+       frame->syncslotcount = count;
+       frame->syncslots = DMNEW(replace_val_t, count);
+       for (i=0; i<count; ++i) {
+               frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
+       }
+
+       /* pop the stackframe */
+
+       md_pop_stackframe(es);
+
+       ra = es->pc;
+
+       DOLOG( printf("RA = %p\n", (void*)ra); );
+
+       /* Subtract one from the PC so we do not hit the replacement point */
+       /* of the instruction following the call, if there is one.         */
+
+       es->pc--;
+
+       /* find the new codeinfo */
+
+       pv = md_codegen_get_pv_from_pc(ra);
+       DOLOG( printf("PV = %p\n", (void*) pv); );
+
+       code = code_get_codeinfo_for_pv(pv);
+       DOLOG( printf("CODE = %p\n", (void*) code); );
+
+       /* return NULL if we reached native code */
+
+       es->pv = pv;
+       es->code = code;
 
        return (code) ? ra : NULL;
 }
@@ -1830,8 +2018,11 @@ void replace_patch_future_calls(u1 *ra,
 
                /* we can only patch such calls if we are at the entry point */
 
+#if !defined(__I386__)
+               /* On i386 we always know the instance argument. */
                if (!atentry)
                        return;
+#endif
 
                assert((calleem->flags & ACC_STATIC) == 0);
 
@@ -1859,6 +2050,11 @@ void replace_patch_future_calls(u1 *ra,
        else {
                /* the call was statically bound */
 
+#if defined(__I386__)
+               /* It happens that there is a patcher trap. (pm) */
+               if (*(u2 *)(patchpos - 1) == 0x0b0f) {
+               } else
+#endif
                replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static   ");
        }
 }
@@ -1888,10 +2084,8 @@ void replace_push_activation_record(executionstate_t *es,
                                                                        sourceframe_t *callerframe,
                                                                        sourceframe_t *calleeframe)
 {
-       s4           reg;
        s4           i;
        s4           count;
-       stackslot_t *basesp;
        stackslot_t *sp;
        u1          *ra;
        codeinfo    *calleecode;
@@ -1915,120 +2109,25 @@ void replace_push_activation_record(executionstate_t *es,
        else
                ra = es->pc + 1 /* XXX this is ugly */;
 
-       /* write the return address */
-
-#if defined(REPLACE_RA_BETWEEN_FRAMES)
-       es->sp -= SIZE_OF_STACKSLOT;
-
-       *((stackslot_t *)es->sp) = (stackslot_t) ra;
-#endif /* REPLACE_RA_BETWEEN_FRAMES */
+       /* push the stackframe */
 
-#if defined(REPLACE_REG_RA)
-       es->intregs[REPLACE_REG_RA] = (ptrint) ra;
-#endif
+       md_push_stackframe(es, calleecode, ra);
 
-       /* we move into a new code unit */
+       /* we move into a new code unit, set code, PC, PV */
 
        es->code = calleecode;
-
-       /* set the new pc XXX not needed? */
-
-       es->pc = calleecode->entrypoint;
-
-       /* build the stackframe */
-
-       DOLOG( printf("building stackframe of %d words at %p\n",
-                                 calleecode->stackframesize, (void*)es->sp); );
-
-       sp = (stackslot_t *) es->sp;
-       basesp = sp;
-
-       sp -= calleecode->stackframesize;
-       es->sp = (u1*) sp;
-
-       /* in debug mode, invalidate stack frame first */
-
-       /* XXX may not invalidate linkage area used by native code! */
-#if !defined(NDEBUG) && 0
-       for (i=0; i<(basesp - sp); ++i) {
-               sp[i] = 0xdeaddeadU;
-       }
-#endif
-
-       /* save the return address register */
-
-#if defined(REPLACE_RA_TOP_OF_FRAME)
-#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
-       if (!code_is_leafmethod(calleecode))
-#endif
-               *--basesp = (ptrint) ra;
-#endif /* REPLACE_RA_TOP_OF_FRAME */
-
-#if defined(REPLACE_RA_LINKAGE_AREA)
-#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
-       if (!code_is_leafmethod(calleecode))
-#endif
-               basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
-#endif /* REPLACE_RA_LINKAGE_AREA */
-
-       /* save int registers */
-
-       reg = INT_REG_CNT;
-       for (i=0; i<calleecode->savedintcount; ++i) {
-               while (nregdescint[--reg] != REG_SAV)
-                       ;
-               *--basesp = es->intregs[reg];
-
-               /* XXX may not clobber saved regs used by native code! */
-#if !defined(NDEBUG) && 0
-               es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
-#endif
-       }
-
-       /* save flt registers */
-
-       /* XXX align? */
-       reg = FLT_REG_CNT;
-       for (i=0; i<calleecode->savedfltcount; ++i) {
-               while (nregdescfloat[--reg] != REG_SAV)
-                       ;
-               basesp -= STACK_SLOTS_PER_FLOAT;
-               *(double*)basesp = es->fltregs[reg];
-
-               /* XXX may not clobber saved regs used by native code! */
-#if !defined(NDEBUG) && 0
-               *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
-#endif
-       }
-
-#if defined(HAS_ADDRESS_REGISTER_FILE)
-       /* save adr registers */
-
-       reg = ADR_REG_CNT;
-       for (i=0; i<calleecode->savedadrcount; ++i) {
-               while (nregdescadr[--reg] != REG_SAV)
-                       ;
-               *--basesp = es->adrregs[reg];
-
-               /* XXX may not clobber saved regs used by native code! */
-#if !defined(NDEBUG) && 0
-               es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
-#endif
-       }
-#endif
+       es->pc = calleecode->entrypoint; /* XXX not needed? */
+       es->pv = calleecode->entrypoint;
 
        /* write slots used for synchronization */
 
+       sp = (stackslot_t *) es->sp;
        count = code_get_sync_slot_count(calleecode);
        assert(count == calleeframe->syncslotcount);
        for (i=0; i<count; ++i) {
                sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
        }
 
-       /* set the PV */
-
-       es->pv = calleecode->entrypoint;
-
        /* redirect future invocations */
 
        if (callerframe && rpcall) {
@@ -2144,7 +2243,7 @@ no_match:
 
 *******************************************************************************/
 
-rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
+rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
 {
        rplpoint *found;
        rplpoint *rp;
@@ -2158,14 +2257,20 @@ rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
        rp = code->rplpoints;
        for (i=0; i<code->rplpointcount; ++i, ++rp) {
                DOLOG( replace_replacement_point_println(rp, 2); );
-               if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
-                       found = rp;
+               if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
+                       if (desired_flags) {
+                               if (rp->flags & desired_flags) {
+                                       found = rp;
+                               }
+                       } else {
+                               found = rp;
+                       }
+               }
        }
 
        return found;
 }
 
-
 /* replace_pop_native_frame ****************************************************
 
    Unroll a native frame in the execution state and create a source frame
@@ -2492,7 +2597,7 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
                        /* find the replacement point at the call site */
 
 after_machine_frame:
-                       rp = replace_find_replacement_point_for_pc(es->code, es->pc);
+                       rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
 
                        if (rp == NULL)
                                vm_abort("could not find replacement point while unrolling call");
@@ -2763,6 +2868,12 @@ static void replace_me(rplpoint *rp, executionstate_t *es)
        origcode = es->code;
        origrp   = rp;
 
+#if defined(ENABLE_TLH)
+       printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);
+#endif
+
+       /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
+
        DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
                                 stat_replacements, (void*)THREADOBJECT,
                                 rp->id, (void*)rp);
@@ -2888,6 +2999,9 @@ bool replace_me_wrapper(u1 *pc, void *context)
        codeinfo         *code;
        rplpoint         *rp;
        executionstate_t  es;
+#if defined(ENABLE_RT_TIMING)
+       struct timespec time_start, time_end;
+#endif
 
        /* search the codeinfo for the given PC */
 
@@ -2896,11 +3010,14 @@ bool replace_me_wrapper(u1 *pc, void *context)
 
        /* search for a replacement point at the given PC */
 
-       rp = replace_find_replacement_point_for_pc(code, pc);
+       rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
 
        /* check if the replacement point belongs to given PC and is active */
 
-       if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
+       if ((rp != NULL) && (rp->pc == pc)
+           && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
+
+               DOLOG( printf("valid replacement point\n"); );
 
 #if !defined(NDEBUG)
                executionstate_sanity_check(context);
@@ -2919,8 +3036,17 @@ bool replace_me_wrapper(u1 *pc, void *context)
 
                /* do the actual replacement */
 
+#if defined(ENABLE_RT_TIMING)
+               RT_TIMING_GET_TIME(time_start);
+#endif
+
                replace_me(rp, &es);
 
+#if defined(ENABLE_RT_TIMING)
+               RT_TIMING_GET_TIME(time_end);
+               RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
+#endif
+
                /* write execution state to current context */
 
                md_executionstate_write(&es, context);
index 0b429ccadba6ef1cc03c43d1298c5e5c24aedfc8..7287f0968e56b600c981ef66ad0061dca47e385e 100644 (file)
@@ -549,6 +549,18 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
                }
 #endif /* defined(ENABLE_INLINING) */
 
+#if defined(ENABLE_SSA)
+       
+               iptr = bptr->phis;
+
+               for (i = 0; i < bptr->phicount; i++, iptr++) {
+                       printf("%4d:%4d:  ", iptr->line, iptr->flags.bits >> INS_FLAG_ID_SHIFT);
+
+                       show_icmd(jd, iptr, deadcode, irstage);
+                       printf("\n");
+               }
+#endif
+
                iptr = bptr->iinstr;
 
                for (i = 0; i < bptr->icount; i++, iptr++) {
@@ -1425,6 +1437,19 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
        case ICMD_GETEXCEPTION:
                SHOW_DST(iptr);
                break;
+#if defined(ENABLE_SSA)        
+       case ICMD_PHI:
+               printf("[ ");
+               for (i = 0; i < iptr->s1.argcount; ++i) {
+                       SHOW_VARIABLE(iptr->sx.s23.s2.iargs[i]->dst.varindex);
+               }
+               printf("] ");
+               SHOW_DST(iptr);
+               if (iptr->flags.bits & (1 << 0)) printf("used ");
+               if (iptr->flags.bits & (1 << 1)) printf("redundantAll ");
+               if (iptr->flags.bits & (1 << 2)) printf("redundantOne ");
+               break;
+#endif
        }
        fflush(stdout);
 }
index 9f3a10558661672aaf9549c2f42b2567920a9019..562bb0907e5c2aa5b28e2a20601cf06bdc428ab2 100644 (file)
@@ -184,6 +184,15 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
                p = jit_compile_handle(m, sfi.pv, ra, (void *) val);
                break;
 
+#if defined(ENABLE_REPLACEMENT)
+       case TRAP_COUNTDOWN:
+#if defined(__I386__)
+               replace_me_wrapper((char*)xpc - 13, context);
+#endif
+               p = NULL;
+               break;
+#endif
+
        default:
                /* Let's try to get a backtrace. */
 
index 22d116d2d7188aa21dec4e0d0e447141428f22df..37e8daeb7d362077aa0b5ea88a392d0b2dea373e 100644 (file)
@@ -523,6 +523,15 @@ static bool linker_overwrite_method(methodinfo *mg,
 
        if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) {
                do {
+
+#if defined(ENABLE_TLH)
+                       if (mg->flags & ACC_METHOD_MONOMORPHY_USED) {
+                               printf("%s/%s is evil! the siner is %s/%s\n", mg->clazz->name->text, mg->name->text,
+                                       ms->clazz->name->text, ms->name->text);
+                               ms->flags |= ACC_METHOD_PARENT_MONOMORPHY_USED;                                 
+                       }
+#endif
+
                        if (mg->flags & ACC_METHOD_IMPLEMENTED) {
                                /* this adds another implementation */
 
index 393ad44728396b57ca6a1053e69340eb08874ed8..d1fb1b29611c7f325089fd54a22f5add8c516199 100644 (file)
@@ -1037,7 +1037,6 @@ void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
        m->assumptions = as;
 }
 
-
 /* method_break_assumption_monomorphic *****************************************
 
    Break the assumption that this method is monomorphic. All callers that
@@ -1064,10 +1063,21 @@ void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
                );
 
                method_add_to_worklist(as->context, wl);
+
+#if defined(ENABLE_TLH) && 0
+               /* XXX hack */
+               method_assumption *as2;
+               as2 = m->assumptions;
+               m->assumptions = NULL;
+               method_break_assumption_monomorphic(as->context, wl);
+               /*
+               assert(m->assumptions == NULL);
+               m->assumptions = as2;*/
+#endif
+
        }
 }
 
-
 /* method_printflags ***********************************************************
 
    Prints the flags of a method to stdout like.
index 7e535bef0fd4cd1f698ca7815b5d034014f73487..eb4a7533ba6799b2e7d71ba0b28f4108a1963bb6 100644 (file)
@@ -116,9 +116,20 @@ static struct rt_timing_stat rt_timing_stat_defs[] = {
        { RT_TIMING_GC_COMPACT      ,RT_TIMING_GC_TOTAL       , "gc: compaction phase" },
        { RT_TIMING_GC_ROOTSET2     ,RT_TIMING_GC_TOTAL       , "gc: rootset writeback" },
        { RT_TIMING_GC_TOTAL        ,-1                       , "total garbage collection time" },
+#endif
+       { -1                        ,-1                       , "" },
+
+#if defined(ENABLE_REPLACEMENT)
+       { RT_TIMING_REPLACE         ,-1                       , "replacement" },
        { -1                        ,-1                       , "" },
 #endif
 
+       { RT_TIMING_1               ,-1                       , "temporary timer 1" },
+       { RT_TIMING_2               ,-1                       , "temporary timer 2" },
+       { RT_TIMING_3               ,-1                       , "temporary timer 3" },
+       { RT_TIMING_4               ,-1                       , "temporary timer 4" },
+       { -1                        ,-1                       , "" },
+
     { 0                         ,-1                       , NULL }
 };
 
index d78e8c986420da1eaac8557c227e7ab86a1df4d7..01b3c80aaf1f219624a11ac0ec9d2b975c18bc07 100644 (file)
 #define RT_TIMING_GC_ROOTSET2      53
 #define RT_TIMING_GC_TOTAL         54
 
-#define RT_TIMING_N                55
+#define RT_TIMING_REPLACE          55
+
+#define RT_TIMING_1                56
+#define RT_TIMING_2                57
+#define RT_TIMING_3                58
+#define RT_TIMING_4                59
+
+#define RT_TIMING_N                60
 
 void rt_timing_gettime(struct timespec *ts);