From: Peter Molnar Date: Wed, 9 Jul 2008 18:00:49 +0000 (+0200) Subject: Merged with tip. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=7659949229c634784f7d27aa8b679fdd4c8351ab;hp=cd6b0057ea56e331b0c90e4f934edc3f4140e14e;p=cacao.git Merged with tip. --- diff --git a/configure.ac b/configure.ac index c8ddf37b8..1dbd15e1f 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/mm/Makefile.am b/src/mm/Makefile.am index 22c39cec2..afd9feef0 100644 --- a/src/mm/Makefile.am +++ b/src/mm/Makefile.am @@ -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 index 000000000..e46cf8760 --- /dev/null +++ b/src/mm/tlh.c @@ -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 +#include + +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 index 000000000..48b40e307 --- /dev/null +++ b/src/mm/tlh.h @@ -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 +#include + +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: + */ diff --git a/src/threads/posix/thread-posix.c b/src/threads/posix/thread-posix.c index bfcdc58a7..defe4220e 100644 --- a/src/threads/posix/thread-posix.c +++ b/src/threads/posix/thread-posix.c @@ -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. diff --git a/src/threads/posix/thread-posix.h b/src/threads/posix/thread-posix.h index 5c107f863..bb8b4206d 100644 --- a/src/threads/posix/thread-posix.h +++ b/src/threads/posix/thread-posix.h @@ -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 */ diff --git a/src/vm/builtin.c b/src/vm/builtin.c index 62099a7b8..377bad883 100644 --- a/src/vm/builtin.c +++ b/src/vm/builtin.c @@ -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 ************************************************************ diff --git a/src/vm/builtin.h b/src/vm/builtin.h index 769d54267..f898706b8 100644 --- a/src/vm/builtin.h +++ b/src/vm/builtin.h @@ -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 diff --git a/src/vm/builtintable.inc b/src/vm/builtintable.inc index 735c1de70..3f5781fe2 100644 --- a/src/vm/builtintable.inc +++ b/src/vm/builtintable.inc @@ -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, diff --git a/src/vm/global.h b/src/vm/global.h index 5d1e65bf8..2a09e47c1 100644 --- a/src/vm/global.h +++ b/src/vm/global.h @@ -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 **************************************/ diff --git a/src/vm/jit/cfg.c b/src/vm/jit/cfg.c index 652e20097..da46ee966 100644 --- a/src/vm/jit/cfg.c +++ b/src/vm/jit/cfg.c @@ -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); diff --git a/src/vm/jit/code.h b/src/vm/jit/code.h index adff257fe..375379725 100644 --- a/src/vm/jit/code.h +++ b/src/vm/jit/code.h @@ -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 ******************************************************************* diff --git a/src/vm/jit/emit-common.h b/src/vm/jit/emit-common.h index 34fa5ada1..f0f854a03 100644 --- a/src/vm/jit/emit-common.h +++ b/src/vm/jit/emit-common.h @@ -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); diff --git a/src/vm/jit/i386/codegen.c b/src/vm/jit/i386/codegen.c index b384f45a7..7d64347c3 100644 --- a/src/vm/jit/i386/codegen.c +++ b/src/vm/jit/i386/codegen.c @@ -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 ...]] ==> ... */ diff --git a/src/vm/jit/i386/emit.c b/src/vm/jit/i386/emit.c index 74e7f493f..7c61037af 100644 --- a/src/vm/jit/i386/emit.c +++ b/src/vm/jit/i386/emit.c @@ -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 ******************************************************************* diff --git a/src/vm/jit/i386/linux/md-os.c b/src/vm/jit/i386/linux/md-os.c index d445e4798..77a88c63b 100644 --- a/src/vm/jit/i386/linux/md-os.c +++ b/src/vm/jit/i386/linux/md-os.c @@ -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 */ diff --git a/src/vm/jit/i386/md-trap.h b/src/vm/jit/i386/md-trap.h index 0c3965096..3d30a6fc8 100644 --- a/src/vm/jit/i386/md-trap.h +++ b/src/vm/jit/i386/md-trap.h @@ -58,6 +58,7 @@ enum { /* Don't use 8 (could be a normal load offset). */ TRAP_COMPILER = 9, + TRAP_COUNTDOWN = 10, TRAP_END }; diff --git a/src/vm/jit/jit.c b/src/vm/jit/jit.c index e6f17c2d8..971a9dd75 100644 --- a/src/vm/jit/jit.c +++ b/src/vm/jit/jit.c @@ -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 diff --git a/src/vm/jit/jit.h b/src/vm/jit/jit.h index 448f0cc53..c447b1bd2 100644 --- a/src/vm/jit/jit.h +++ b/src/vm/jit/jit.h @@ -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) \ diff --git a/src/vm/jit/optimizing/bytecode_escape.c b/src/vm/jit/optimizing/bytecode_escape.c index 22fb1f281..82db44003 100644 --- a/src/vm/jit/optimizing/bytecode_escape.c +++ b/src/vm/jit/optimizing/bytecode_escape.c @@ -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); diff --git a/src/vm/jit/optimizing/escape.c b/src/vm/jit/optimizing/escape.c index b1c0679d5..7642a5360 100644 --- a/src/vm/jit/optimizing/escape.c +++ b/src/vm/jit/optimizing/escape.c @@ -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 @@ -23,8 +23,62 @@ #include "vm/jit/jit.h" #include "vmcore/class.h" +#include "vmcore/classcache.h" #include "vm/jit/optimizing/escape.h" +#include + +#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, "") == 0 - ); e->verbose = 1; + e->verbose = strcmp(jd->m->name->text, "") == 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; +} + diff --git a/src/vm/jit/optimizing/escape.h b/src/vm/jit/optimizing/escape.h index 2f427fa31..5b5f7b6ee 100644 --- a/src/vm/jit/optimizing/escape.h +++ b/src/vm/jit/optimizing/escape.h @@ -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 diff --git a/src/vm/jit/optimizing/ssa.c b/src/vm/jit/optimizing/ssa.c index 721323e4b..793a6605d 100644 --- a/src/vm/jit/optimizing/ssa.c +++ b/src/vm/jit/optimizing/ssa.c @@ -133,6 +133,7 @@ void ssa(jitdata *jd) { yssa(jd); } /*pythonpass_run(jd, "foo", "after");*/ + cfg_remove_root(jd); return; ls = jd->ls; diff --git a/src/vm/jit/optimizing/ssa3.c b/src/vm/jit/optimizing/ssa3.c index 0f8c1306d..29864f17f 100644 --- a/src/vm/jit/optimizing/ssa3.c +++ b/src/vm/jit/optimizing/ssa3.c @@ -47,10 +47,10 @@ #include #include -#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) { diff --git a/src/vm/jit/reg.h b/src/vm/jit/reg.h index 66e989f00..b4196b1f4 100644 --- a/src/vm/jit/reg.h +++ b/src/vm/jit/reg.h @@ -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 */ diff --git a/src/vm/jit/replace.c b/src/vm/jit/replace.c index 5895bec06..58f883c1a 100644 --- a/src/vm/jit/replace.c +++ b/src/vm/jit/replace.c @@ -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__) @@ -81,16 +82,13 @@ #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; isyncslots[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; iintregs[i] = (ptrint) 0x33dead3333dead33ULL; for (i=0; iadrregs[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; isavedintcount; ++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; isavedfltcount; ++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; isavedadrcount; ++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; isyncslots[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; isavedintcount; ++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; isavedfltcount; ++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; isavedadrcount; ++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; imemuse + 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; irplpointcount; ++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); diff --git a/src/vm/jit/show.c b/src/vm/jit/show.c index 0b429ccad..7287f0968 100644 --- a/src/vm/jit/show.c +++ b/src/vm/jit/show.c @@ -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); } diff --git a/src/vm/jit/trap.c b/src/vm/jit/trap.c index 9f3a10558..562bb0907 100644 --- a/src/vm/jit/trap.c +++ b/src/vm/jit/trap.c @@ -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. */ diff --git a/src/vmcore/linker.c b/src/vmcore/linker.c index 22d116d2d..37e8daeb7 100644 --- a/src/vmcore/linker.c +++ b/src/vmcore/linker.c @@ -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 */ diff --git a/src/vmcore/method.c b/src/vmcore/method.c index 393ad4472..d1fb1b296 100644 --- a/src/vmcore/method.c +++ b/src/vmcore/method.c @@ -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. diff --git a/src/vmcore/rt-timing.c b/src/vmcore/rt-timing.c index 7e535bef0..eb4a7533b 100644 --- a/src/vmcore/rt-timing.c +++ b/src/vmcore/rt-timing.c @@ -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 } }; diff --git a/src/vmcore/rt-timing.h b/src/vmcore/rt-timing.h index d78e8c986..01b3c80aa 100644 --- a/src/vmcore/rt-timing.h +++ b/src/vmcore/rt-timing.h @@ -109,7 +109,14 @@ #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);