X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstack.c;h=e692269d25bf2c6846b3dac13efe6597a0c8a94c;hb=b0dfcc457440aa84e2f1ccee8bcefad72615a344;hp=07c5d0a0da08ca48fc7e9b83b7a1d342cba465e2;hpb=40fe44d409aff1bdd645b20b338bb2b765e418c4;p=cacao.git diff --git a/src/vm/jit/stack.c b/src/vm/jit/stack.c index 07c5d0a0d..e692269d2 100644 --- a/src/vm/jit/stack.c +++ b/src/vm/jit/stack.c @@ -1,9 +1,7 @@ /* src/vm/jit/stack.c - stack analysis - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -22,16 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Andreas Krall - - Changes: Edwin Steiner - Christian Thalinger - Christian Ullrich - - $Id: stack.c 5510 2006-09-15 12:48:24Z christian $ - */ @@ -53,15 +41,13 @@ #include "vm/global.h" #include "vm/builtin.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" #include "vm/types.h" #include "vm/jit/abi.h" #include "vm/jit/cfg.h" #include "vm/jit/codegen-common.h" +#include "vm/jit/parse.h" #include "vm/jit/show.h" #if defined(ENABLE_DISASSEMBLER) @@ -71,35 +57,26 @@ #include "vm/jit/jit.h" #include "vm/jit/stack.h" +#if 0 #if defined(ENABLE_SSA) # include "vm/jit/optimizing/lsra.h" # include "vm/jit/optimizing/ssa.h" #elif defined(ENABLE_LSRA) # include "vm/jit/allocator/lsra.h" #endif +#endif -/*#define STACK_VERBOSE*/ +#include "vmcore/options.h" +#include "vm/resolve.h" +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif -/* macro for saving #ifdefs ***************************************************/ +/*#define STACK_VERBOSE*/ -#if defined(ENABLE_INTRP) -#define IF_INTRP(x) if (opt_intrp) { x } -#define IF_NO_INTRP(x) if (!opt_intrp) { x } -#else -#define IF_INTRP(x) -#define IF_NO_INTRP(x) { x } -#endif -#if defined(ENABLE_INTRP) -#if defined(ENABLE_JIT) -#define IF_JIT(x) if (!opt_intrp) { x } -#else -#define IF_JIT(x) -#endif -#else /* !defined(ENABLE_INTRP) */ -#define IF_JIT(x) { x } -#endif /* defined(ENABLE_INTRP) */ +/* macro for saving #ifdefs ***************************************************/ #if defined(ENABLE_STATISTICS) #define STATISTICS_STACKDEPTH_DISTRIBUTION(distr) \ @@ -115,6 +92,20 @@ #define STATISTICS_STACKDEPTH_DISTRIBUTION(distr) #endif + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + + +/* For returnAddresses we use a field of the typeinfo to store from which */ +/* subroutine the returnAddress will return, if used. */ +/* XXX It would be nicer to use typeinfo.typeclass, but the verifier seems */ +/* to need it initialised to NULL. This should be investigated. */ + +#if defined(ENABLE_VERIFIER) +#define SBRSTART typeinfo.elementclass.any +#endif + + /* stackdata_t ***************************************************************** This struct holds internal data during stack analysis. @@ -125,18 +116,21 @@ typedef struct stackdata_t stackdata_t; struct stackdata_t { basicblock *bptr; /* the current basic block being analysed */ - stackptr new; /* next free stackelement */ + stackelement_t *new; /* next free stackelement */ s4 vartop; /* next free variable index */ s4 localcount; /* number of locals (at the start of var) */ - s4 varcount; /* total number of variables allocated */ + s4 varcount; /* maximum number of variables expected */ + s4 varsallocated; /* total number of variables allocated */ + s4 maxlocals; /* max. number of Java locals */ varinfo *var; /* variable array (same as jd->var) */ + s4 *javalocals; /* map from Java locals to jd->var indices */ methodinfo *m; /* the method being analysed */ jitdata *jd; /* current jitdata */ basicblock *last_real_block; /* the last block before the empty one */ bool repeat; /* if true, iterate the analysis again */ - exceptiontable **handlers; /* exception handlers for the current block */ - exceptiontable *extableend; /* points to the last exception entry */ - stackelement exstack; /* instack for exception handlers */ + exception_entry **handlers; /* exception handlers for the current block */ + exception_entry *extableend; /* points to the last exception entry */ + stackelement_t exstack; /* instack for exception handlers */ }; @@ -152,24 +146,24 @@ struct stackdata_t { /* Pay attention to not release a localvar once implementing it! */ #define RELEASE_INDEX(sd, varindex) -#define GET_NEW_VAR(sd, new_varindex, newtype) \ +#define GET_NEW_VAR(sd, newvarindex, newtype) \ do { \ - GET_NEW_INDEX((sd), (new_varindex)); \ - (sd).var[new_index].type = (newtype); \ + GET_NEW_INDEX((sd), (newvarindex)); \ + (sd).var[newvarindex].type = (newtype); \ } while (0) /* macros for querying variable properties **************************/ -#define IS_OUTVAR(sp) \ - (sd.var[(sp)->varnum].flags & OUTVAR) +#define IS_INOUT(sp) \ + (sd.var[(sp)->varnum].flags & INOUT) #define IS_PREALLOC(sp) \ (sd.var[(sp)->varnum].flags & PREALLOC) #define IS_TEMPVAR(sp) \ ( ((sp)->varnum >= sd.localcount) \ - && !(sd.var[(sp)->varnum].flags & (OUTVAR | PREALLOC)) ) + && !(sd.var[(sp)->varnum].flags & (INOUT | PREALLOC)) ) #define IS_LOCALVAR_SD(sd, sp) \ @@ -184,14 +178,9 @@ struct stackdata_t { #define SET_TEMPVAR(sp) \ do { \ if (IS_LOCALVAR((sp))) { \ - GET_NEW_VAR(sd, new_index, (sp)->type); \ - sd.var[new_index].flags = (sp)->flags; \ - (sp)->varnum = new_index; \ - (sp)->varkind = TEMPVAR; \ - if ((sp)->creator) \ - (sp)->creator->dst.varindex = new_index; \ + stack_change_to_tempvar(&sd, (sp), iptr); \ } \ - sd.var[(sp)->varnum].flags &= ~(OUTVAR | PREALLOC); \ + sd.var[(sp)->varnum].flags &= ~(INOUT | PREALLOC); \ } while (0); #define SET_PREALLOC(sp) \ @@ -328,11 +317,26 @@ struct stackdata_t { /* macro for propagating constant values ****************************/ -#define COPY_VAL_AND_TYPE(sd, sindex, dindex) \ +#if defined(ENABLE_VERIFIER) +#define COPY_VAL_AND_TYPE_VAR(sv, dv) \ do { \ - (sd).var[(dindex)].type = (sd).var[(sindex)].type; \ - (sd).var[(dindex)].vv = (sd).var[(sindex)].vv; \ - } while (0) \ + if (((dv)->type = (sv)->type) == TYPE_RET) { \ + (dv)->vv = (sv)->vv; \ + (dv)->SBRSTART = (sv)->SBRSTART; \ + } \ + } while (0) +#else +#define COPY_VAL_AND_TYPE_VAR(sv, dv) \ + do { \ + (dv)->type = (sv)->type; \ + if (((dv)->type = (sv)->type) == TYPE_RET) { \ + (dv)->vv = (sv)->vv; \ + } \ + } while (0) +#endif + +#define COPY_VAL_AND_TYPE(sd, sindex, dindex) \ + COPY_VAL_AND_TYPE_VAR((sd).var + (sindex), (sd).var + (dindex)) /* stack modelling macros *******************************************/ @@ -473,12 +477,22 @@ struct stackdata_t { (d)->creator = iptr; \ } while (0) +#define MOVE_TO_TEMP(sp) \ + do { \ + GET_NEW_INDEX(sd, new_index); \ + iptr->opc = ICMD_MOVE; \ + iptr->s1.varindex = (sp)->varnum; \ + iptr->dst.varindex = new_index; \ + COPY_VAL_AND_TYPE(sd, (sp)->varnum, new_index); \ + (sp)->varnum = new_index; \ + (sp)->varkind = TEMPVAR; \ + } while (0) /* macros for branching / reaching basic blocks *********************/ #define BRANCH_TARGET(bt, tempbptr) \ do { \ - tempbptr = BLOCK_OF((bt).insindex); \ + tempbptr = (bt).block; \ tempbptr = stack_mark_reached(&sd, tempbptr, curstack, \ stackdepth); \ if (tempbptr == NULL) \ @@ -493,7 +507,7 @@ struct stackdata_t { /* forward declarations *******************************************************/ static void stack_create_invars(stackdata_t *sd, basicblock *b, - stackptr curstack, int stackdepth); + stackelement_t * curstack, int stackdepth); static void stack_create_invars_from_outvars(stackdata_t *sd, basicblock *b); #if defined(STACK_VERBOSE) @@ -502,6 +516,8 @@ static void stack_verbose_show_variable(stackdata_t *sd, s4 index); static void stack_verbose_show_block(stackdata_t *sd, basicblock *bptr); static void stack_verbose_block_enter(stackdata_t *sd, bool reanalyse); static void stack_verbose_block_exit(stackdata_t *sd, bool superblockend); +static void stack_verbose_show_state(stackdata_t *sd, instruction *iptr, + stackelement_t * curstack); #endif @@ -520,6 +536,10 @@ bool stack_init(void) /* stack_grow_variable_array *************************************************** Grow the variable array so the given number of additional variables fits in. + The number is added to `varcount`, which is the maximum number of variables + we expect to need at this point. The actual number of variables + (`varsallocated`) may be larger than that, in order to avoid too many + reallocations. IN: sd...........stack analysis data @@ -529,20 +549,23 @@ bool stack_init(void) static void stack_grow_variable_array(stackdata_t *sd, s4 num) { - s4 newcount; + s4 newsize; assert(num >= 0); - if (num == 0) - return; + if (sd->varcount + num > sd->varsallocated) { + newsize = 2*sd->varsallocated + num; - /* XXX avoid too many reallocations */ - newcount = sd->varcount + num; + sd->var = DMREALLOC(sd->var, varinfo, sd->varsallocated, newsize); + MZERO(sd->var + sd->varsallocated, varinfo, (newsize - sd->varsallocated)); + sd->varsallocated = newsize; + sd->jd->var = sd->var; + } + + sd->varcount += num; + sd->jd->varcount += num; - sd->var = DMREALLOC(sd->var, varinfo, sd->varcount, newcount); - sd->varcount = newcount; - sd->jd->var = sd->var; - sd->jd->varcount = newcount; + assert(sd->varcount <= sd->varsallocated); } @@ -566,7 +589,8 @@ static void stack_append_block(stackdata_t *sd, basicblock *b) b->next = sd->last_real_block->next; sd->last_real_block->next = b; sd->last_real_block = b; - sd->jd->new_basicblockcount++; + b->nr = sd->jd->basicblockcount++; + b->next->nr = b->nr + 1; } @@ -596,18 +620,18 @@ static basicblock * stack_clone_block(stackdata_t *sd, basicblock *b) clone->iinstr = NULL; clone->inlocals = NULL; + clone->javalocals = NULL; clone->invars = NULL; clone->original = (b->original) ? b->original : b; clone->copied_to = clone->original->copied_to; clone->original->copied_to = clone; - clone->nr = sd->m->c_debug_nr++; clone->next = NULL; clone->flags = BBREACHED; stack_append_block(sd, clone); - /* allocate space for the invars of the clone */ + /* reserve space for the invars of the clone */ stack_grow_variable_array(sd, b->indepth); @@ -619,6 +643,89 @@ static basicblock * stack_clone_block(stackdata_t *sd, basicblock *b) } +/* stack_create_locals ********************************************************* + + Create the local variables for the start of the given basic block. + + IN: + sd...........stack analysis data + b............block to create the locals for + +*******************************************************************************/ + +static void stack_create_locals(stackdata_t *sd, basicblock *b) +{ + s4 i; + s4 *jl; + varinfo *dv; + + /* copy the current state of the local variables */ + /* (one extra local is needed by the verifier) */ + + dv = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS); + b->inlocals = dv; + for (i=0; ilocalcount; ++i) + *dv++ = sd->var[i]; + + /* the current map from java locals to cacao variables */ + + jl = DMNEW(s4, sd->maxlocals); + b->javalocals = jl; + MCOPY(jl, sd->javalocals, s4, sd->maxlocals); +} + + +/* stack_merge_locals ********************************************************** + + Merge local variables at the beginning of the given basic block. + + IN: + sd...........stack analysis data + b............the block that is reached + +*******************************************************************************/ + +static void stack_merge_locals(stackdata_t *sd, basicblock *b) +{ + s4 i; + varinfo *dv; + varinfo *sv; + + /* If a javalocal is mapped to different cacao locals along the */ + /* incoming control-flow edges, it becomes undefined. */ + + for (i=0; imaxlocals; ++i) { + if (b->javalocals[i] != UNUSED && b->javalocals[i] != sd->javalocals[i]) { + b->javalocals[i] = UNUSED; + if (b->flags >= BBFINISHED) + b->flags = BBTYPECHECK_REACHED; + if (b->nr <= sd->bptr->nr) + sd->repeat = true; + } + } + +#if defined(ENABLE_VERIFIER) + if (b->inlocals) { + for (i=0; ilocalcount; ++i) { + dv = b->inlocals + i; + sv = sd->var + i; + if ((sv->type == TYPE_RET && dv->type == TYPE_RET) + && (sv->SBRSTART != dv->SBRSTART)) + { +#if defined(STACK_VERBOSE) + printf("JSR MISMATCH: setting variable %d to VOID\n", i); +#endif + dv->type = TYPE_VOID; + if (b->flags >= BBFINISHED) + b->flags = BBTYPECHECK_REACHED; + sd->repeat = true; /* This is very rare, so just repeat */ + } + } + } +#endif /* defined(ENABLE_VERIFIER) */ +} + + /* stack_create_invars ********************************************************* Create the invars for the given basic block. Also make a copy of the locals. @@ -635,12 +742,13 @@ static basicblock * stack_clone_block(stackdata_t *sd, basicblock *b) *******************************************************************************/ static void stack_create_invars(stackdata_t *sd, basicblock *b, - stackptr curstack, int stackdepth) + stackelement_t * curstack, int stackdepth) { - stackptr sp; + stackelement_t * sp; int i; int index; - varinfo *v; + varinfo *dv; + varinfo *sv; assert(sd->vartop + stackdepth <= sd->varcount); @@ -653,22 +761,13 @@ static void stack_create_invars(stackdata_t *sd, basicblock *b, i = stackdepth; for (sp = curstack; i--; sp = sp->prev) { b->invars[i] = --index; - v = sd->var + index; - v->type = sp->type; - v->flags = OUTVAR; - v->vv = sd->var[sp->varnum].vv; -#if defined(STACK_VERBOSE) && 0 - printf("\tinvar[%d]: %d\n", i, sd->var[b->invars[i]]); -#endif + dv = sd->var + index; + sv = sd->var + sp->varnum; + dv->flags = INOUT; + COPY_VAL_AND_TYPE_VAR(sv, dv); } - /* copy the current state of the local variables */ - /* (one extra local is needed by the verifier) */ - - v = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS); - b->inlocals = v; - for (i=0; ilocalcount; ++i) - *v++ = sd->var[i]; + stack_create_locals(sd, b); } @@ -703,19 +802,12 @@ static void stack_create_invars_from_outvars(stackdata_t *sd, basicblock *b) for (i=0; ivar + sd->bptr->outvars[i]; b->invars[i] = sd->vartop++; - dv->type = sv->type; - dv->flags = OUTVAR; - dv->vv = sv->vv; + dv->flags = INOUT; + COPY_VAL_AND_TYPE_VAR(sv, dv); } } - /* copy the current state of the local variables */ - /* (one extra local is needed by the verifier) */ - - dv = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS); - b->inlocals = dv; - for (i=0; ilocalcount; ++i) - *dv++ = sd->var[i]; + stack_create_locals(sd, b); } @@ -737,12 +829,14 @@ static void stack_create_invars_from_outvars(stackdata_t *sd, basicblock *b) *******************************************************************************/ static basicblock * stack_check_invars(stackdata_t *sd, basicblock *b, - stackptr curstack, int stackdepth) + stackelement_t * curstack, int stackdepth) { int i; - stackptr sp; + stackelement_t * sp; basicblock *orig; bool separable; + varinfo *sv; + varinfo *dv; #if defined(STACK_VERBOSE) printf("stack_check_invars(L%03d)\n", b->nr); @@ -759,10 +853,12 @@ static basicblock * stack_check_invars(stackdata_t *sd, basicblock *b, i = orig->indepth; +#if defined(ENABLE_VERIFIER) if (i != stackdepth) { exceptions_throw_verifyerror(sd->m, "Stack depth mismatch"); return NULL; } +#endif do { separable = false; @@ -774,24 +870,41 @@ static basicblock * stack_check_invars(stackdata_t *sd, basicblock *b, sp = curstack; for (i = orig->indepth; i--; sp = sp->prev) { - if (sd->var[b->invars[i]].type != sp->type) { - exceptions_throw_verifyerror_for_stack(sd->m, - sd->var[b->invars[i]].type); + dv = sd->var + b->invars[i]; + sv = sd->var + sp->varnum; + +#if defined(ENABLE_VERIFIER) + if (dv->type != sp->type) { + exceptions_throw_verifyerror_for_stack(sd->m, dv->type); return NULL; } +#endif if (sp->type == TYPE_RET) { - if (sd->var[b->invars[i]].vv.retaddr != sd->var[sp->varnum].vv.retaddr) { +#if defined(ENABLE_VERIFIER) + if (dv->SBRSTART != sv->SBRSTART) { + exceptions_throw_verifyerror(sd->m, "Mismatched stack types"); + return NULL; + } +#endif + if (dv->vv.retaddr != sv->vv.retaddr) { separable = true; - break; + /* don't break! have to check the remaining stackslots */ } } } if (b->inlocals) { for (i=0; ilocalcount; ++i) { - if (sd->var[i].type == TYPE_RET && b->inlocals[i].type == TYPE_RET) { - if (sd->var[i].vv.retaddr != b->inlocals[i].vv.retaddr) { + dv = b->inlocals + i; + sv = sd->var + i; + if (sv->type == TYPE_RET && dv->type == TYPE_RET) { + if ( +#if defined(ENABLE_VERIFIER) + (sv->SBRSTART == dv->SBRSTART) && +#endif + (sv->vv.retaddr != dv->vv.retaddr)) + { separable = true; break; } @@ -800,8 +913,10 @@ static basicblock * stack_check_invars(stackdata_t *sd, basicblock *b, } if (!separable) { - /* XXX mark mixed type variables void */ /* XXX cascading collapse? */ + + stack_merge_locals(sd, b); + #if defined(STACK_VERBOSE) printf("------> using L%03d\n", b->nr); #endif @@ -857,10 +972,12 @@ static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock i = orig->indepth; n = sd->bptr->outdepth; +#if defined(ENABLE_VERIFIER) if (i != n) { exceptions_throw_verifyerror(sd->m, "Stack depth mismatch"); return NULL; } +#endif do { separable = false; @@ -875,15 +992,24 @@ static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock for (i=0; ivar + sd->bptr->outvars[i]; + +#if defined(ENABLE_VERIFIER) if (sv->type != dv->type) { exceptions_throw_verifyerror_for_stack(sd->m, dv->type); return NULL; } +#endif if (dv->type == TYPE_RET) { +#if defined(ENABLE_VERIFIER) + if (sv->SBRSTART != dv->SBRSTART) { + exceptions_throw_verifyerror(sd->m, "Mismatched stack types"); + return NULL; + } +#endif if (sv->vv.retaddr != dv->vv.retaddr) { separable = true; - break; + /* don't break! have to check the remaining stackslots */ } } } @@ -891,8 +1017,15 @@ static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock if (b->inlocals) { for (i=0; ilocalcount; ++i) { - if (sd->var[i].type == TYPE_RET && b->inlocals[i].type == TYPE_RET) { - if (sd->var[i].vv.retaddr != b->inlocals[i].vv.retaddr) { + dv = b->inlocals + i; + sv = sd->var + i; + if ( +#if defined(ENABLE_VERIFIER) + (sv->SBRSTART == dv->SBRSTART) && +#endif + (sv->type == TYPE_RET && dv->type == TYPE_RET)) + { + if (sv->vv.retaddr != dv->vv.retaddr) { separable = true; break; } @@ -901,8 +1034,10 @@ static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock } if (!separable) { - /* XXX mark mixed type variables void */ /* XXX cascading collapse? */ + + stack_merge_locals(sd, b); + #if defined(STACK_VERBOSE) printf("------> using L%03d\n", b->nr); #endif @@ -931,9 +1066,9 @@ static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock *******************************************************************************/ -static stackptr stack_create_instack(stackdata_t *sd) +static stackelement_t * stack_create_instack(stackdata_t *sd) { - stackptr sp; + stackelement_t * sp; int depth; int index; @@ -977,13 +1112,17 @@ static stackptr stack_create_instack(stackdata_t *sd) *******************************************************************************/ -static basicblock *stack_mark_reached(stackdata_t *sd, basicblock *b, stackptr curstack, int stackdepth) +static basicblock *stack_mark_reached(stackdata_t *sd, basicblock *b, stackelement_t * curstack, int stackdepth) { + assert(b != NULL); + #if defined(STACK_VERBOSE) printf("stack_mark_reached(L%03d from L%03d)\n", b->nr, sd->bptr->nr); #endif + /* mark targets of backward branches */ - if (b <= sd->bptr) + + if (b->nr <= sd->bptr->nr) b->bitflags |= BBFLAG_REPLACEMENT; if (b->flags < BBREACHED) { @@ -1025,11 +1164,15 @@ static basicblock *stack_mark_reached(stackdata_t *sd, basicblock *b, stackptr c static basicblock *stack_mark_reached_from_outvars(stackdata_t *sd, basicblock *b) { + assert(b != NULL); + #if defined(STACK_VERBOSE) printf("stack_mark_reached_from_outvars(L%03d from L%03d)\n", b->nr, sd->bptr->nr); #endif + /* mark targets of backward branches */ - if (b <= sd->bptr) + + if (b->nr <= sd->bptr->nr) b->bitflags |= BBFLAG_REPLACEMENT; if (b->flags < BBREACHED) { @@ -1055,9 +1198,10 @@ static basicblock *stack_mark_reached_from_outvars(stackdata_t *sd, basicblock * /* stack_reach_next_block ****************************************************** - Mark the following block reached and propagate the outvars of the current block - and the current locals to it. This function specializes the target block, - if necessary, and returns a pointer to the specialized target. + Mark the following block reached and propagate the outvars of the + current block and the current locals to it. This function + specializes the target block, if necessary, and returns a pointer + to the specialized target. IN: sd...........stack analysis data @@ -1075,7 +1219,8 @@ static bool stack_reach_next_block(stackdata_t *sd) tbptr = (sd->bptr->original) ? sd->bptr->original : sd->bptr; tbptr = stack_mark_reached_from_outvars(sd, tbptr->next); - if (!tbptr) + + if (tbptr == NULL) return false; if (tbptr != sd->bptr->next) { @@ -1086,6 +1231,9 @@ static bool stack_reach_next_block(stackdata_t *sd) assert(iptr->opc == ICMD_NOP); iptr->opc = ICMD_GOTO; iptr->dst.block = tbptr; +#if defined(STACK_VERBOSE) + if (iptr->line == 0) printf("goto with line 0 in L%03d\n", sd->bptr->nr); +#endif if (tbptr->flags < BBFINISHED) sd->repeat = true; /* XXX check if we really need to repeat */ @@ -1172,14 +1320,13 @@ bool stack_reanalyse_block(stackdata_t *sd) s4 blockvarstart; s4 invarshift; s4 blockvarshift; - s4 i, j; + s4 i, varindex; s4 *argp; branch_target_t *table; lookup_target_t *lookup; bool superblockend; - bool maythrow; bool cloneinstructions; - exceptiontable *ex; + exception_entry *ex; #if defined(STACK_VERBOSE) stack_verbose_block_enter(sd, true); @@ -1201,10 +1348,12 @@ bool stack_reanalyse_block(stackdata_t *sd) MCOPY(iptr, orig->iinstr, instruction, len); iptr[len].opc = ICMD_NOP; + iptr[len].line = 0; + iptr[len].flags.bits = 0; b->iinstr = iptr; b->icount = ++len; - /* allocate space for the clone's block variables */ + /* reserve space for the clone's block variables */ stack_grow_variable_array(sd, orig->varcount); @@ -1241,17 +1390,17 @@ bool stack_reanalyse_block(stackdata_t *sd) /* clone exception handlers */ for (i=0; sd->handlers[i]; ++i) { - ex = DNEW(exceptiontable); + ex = DNEW(exception_entry); ex->handler = sd->handlers[i]->handler; ex->start = b; - ex->end = b; /* XXX hack, see end of new_stack_analyse */ + ex->end = b; /* XXX hack, see end of stack_analyse */ ex->catchtype = sd->handlers[i]->catchtype; ex->down = NULL; assert(sd->extableend->down == NULL); sd->extableend->down = ex; sd->extableend = ex; - sd->jd->cd->exceptiontablelength++; + sd->jd->exceptiontablelength++; sd->handlers[i] = ex; } @@ -1268,7 +1417,7 @@ bool stack_reanalyse_block(stackdata_t *sd) if (b->original) { /* find exception handlers for the cloned block */ len = 0; - ex = sd->jd->cd->exceptiontable; + ex = sd->jd->exceptiontable; for (; ex != NULL; ex = ex->down) { /* XXX the cloned exception handlers have identical */ /* start end end blocks. */ @@ -1293,6 +1442,8 @@ bool stack_reanalyse_block(stackdata_t *sd) if (b->inlocals) MCOPY(sd->var, b->inlocals, varinfo, sd->localcount); + MCOPY(sd->javalocals, b->javalocals, s4, sd->maxlocals); + /* reach exception handlers for this block */ if (!stack_reach_handlers(sd)) @@ -1302,27 +1453,28 @@ bool stack_reanalyse_block(stackdata_t *sd) for (len = b->icount; len--; iptr++) { #if defined(STACK_VERBOSE) - new_show_icmd(sd->jd, iptr, false, SHOW_STACK); + show_icmd(sd->jd, iptr, false, SHOW_STACK); printf("\n"); #endif - maythrow = false; - switch (iptr->opc) { case ICMD_RET: - j = iptr->s1.varindex; + varindex = iptr->s1.varindex; - if (sd->var[j].type != TYPE_RET) { +#if defined(ENABLE_VERIFIER) + if (sd->var[varindex].type != TYPE_RET) { exceptions_throw_verifyerror(sd->m, "RET with non-returnAddress value"); return false; } +#endif - iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[j].vv.retaddr); + iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[varindex].vv.retaddr); superblockend = true; break; case ICMD_JSR: iptr->sx.s23.s3.jsrtarget.block = stack_mark_reached_from_outvars(sd, iptr->sx.s23.s3.jsrtarget.block); + RELOCATE(iptr->dst.varindex); superblockend = true; break; @@ -1332,14 +1484,10 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_CHECKNULL: case ICMD_PUTSTATICCONST: - maythrow = true; break; case ICMD_NOP: case ICMD_IINC: - case ICMD_INLINE_START: - case ICMD_INLINE_END: - case ICMD_INLINE_GOTO: break; case ICMD_GOTO: @@ -1350,7 +1498,6 @@ bool stack_reanalyse_block(stackdata_t *sd) /* pop 0 push 1 const */ case ICMD_ACONST: - maythrow = true; case ICMD_ICONST: case ICMD_LCONST: case ICMD_FCONST: @@ -1379,7 +1526,6 @@ bool stack_reanalyse_block(stackdata_t *sd) RELOCATE(iptr->sx.s23.s2.varindex); RELOCATE(iptr->s1.varindex); RELOCATE(iptr->dst.varindex); - maythrow = true; break; /* pop 3 push 0 */ @@ -1395,7 +1541,6 @@ bool stack_reanalyse_block(stackdata_t *sd) RELOCATE(iptr->sx.s23.s3.varindex); RELOCATE(iptr->sx.s23.s2.varindex); RELOCATE(iptr->s1.varindex); - maythrow = true; break; /* pop 1 push 0 store */ @@ -1407,15 +1552,26 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_ASTORE: RELOCATE(iptr->s1.varindex); - j = iptr->dst.varindex; - COPY_VAL_AND_TYPE(*sd, iptr->s1.varindex, j); + varindex = iptr->dst.varindex; + COPY_VAL_AND_TYPE(*sd, iptr->s1.varindex, varindex); + i = iptr->sx.s23.s3.javaindex; + if (iptr->flags.bits & INS_FLAG_RETADDR) { + iptr->sx.s23.s2.retaddrnr = + JAVALOCAL_FROM_RETADDR(sd->var[varindex].vv.retaddr->nr); + sd->javalocals[i] = iptr->sx.s23.s2.retaddrnr; + } + else + sd->javalocals[i] = varindex; + if (iptr->flags.bits & INS_FLAG_KILL_PREV) + sd->javalocals[i-1] = UNUSED; + if (iptr->flags.bits & INS_FLAG_KILL_NEXT) + sd->javalocals[i+1] = UNUSED; break; /* pop 1 push 0 */ case ICMD_ARETURN: case ICMD_ATHROW: - maythrow = true; case ICMD_IRETURN: case ICMD_LRETURN: case ICMD_FRETURN: @@ -1426,7 +1582,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_PUTSTATIC: case ICMD_PUTFIELDCONST: - maythrow = true; case ICMD_POP: RELOCATE(iptr->s1.varindex); break; @@ -1497,7 +1652,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_MONITORENTER: case ICMD_MONITOREXIT: RELOCATE(iptr->s1.varindex); - maythrow = true; break; /* pop 2 push 0 branch */ @@ -1516,32 +1670,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_IF_LCMPGT: case ICMD_IF_LCMPLE: - case ICMD_IF_FCMPEQ: - case ICMD_IF_FCMPNE: - - case ICMD_IF_FCMPL_LT: - case ICMD_IF_FCMPL_GE: - case ICMD_IF_FCMPL_GT: - case ICMD_IF_FCMPL_LE: - - case ICMD_IF_FCMPG_LT: - case ICMD_IF_FCMPG_GE: - case ICMD_IF_FCMPG_GT: - case ICMD_IF_FCMPG_LE: - - case ICMD_IF_DCMPEQ: - case ICMD_IF_DCMPNE: - - case ICMD_IF_DCMPL_LT: - case ICMD_IF_DCMPL_GE: - case ICMD_IF_DCMPL_GT: - case ICMD_IF_DCMPL_LE: - - case ICMD_IF_DCMPG_LT: - case ICMD_IF_DCMPG_GE: - case ICMD_IF_DCMPG_GT: - case ICMD_IF_DCMPG_LE: - case ICMD_IF_ACMPEQ: case ICMD_IF_ACMPNE: RELOCATE(iptr->sx.s23.s2.varindex); @@ -1558,7 +1686,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_BASTORECONST: case ICMD_CASTORECONST: case ICMD_SASTORECONST: - maythrow = true; case ICMD_POP2: RELOCATE(iptr->sx.s23.s2.varindex); RELOCATE(iptr->s1.varindex); @@ -1579,7 +1706,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_IREM: case ICMD_LDIV: case ICMD_LREM: - maythrow = true; case ICMD_IADD: case ICMD_ISUB: case ICMD_IMUL: @@ -1625,7 +1751,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_INSTANCEOF: case ICMD_NEWARRAY: case ICMD_ANEWARRAY: - maythrow = true; case ICMD_GETFIELD: case ICMD_IADDCONST: case ICMD_ISUBCONST: @@ -1678,7 +1803,6 @@ bool stack_reanalyse_block(stackdata_t *sd) case ICMD_GETSTATIC: case ICMD_NEW: - maythrow = true; RELOCATE(iptr->dst.varindex); break; @@ -1700,7 +1824,6 @@ bool stack_reanalyse_block(stackdata_t *sd) argp = iptr->sx.s23.s2.args; } - maythrow = true; while (--i >= 0) { RELOCATE(*argp); argp++; @@ -1709,14 +1832,13 @@ bool stack_reanalyse_block(stackdata_t *sd) break; default: - *exceptionptr = - new_internalerror("Unknown ICMD %d during stack re-analysis", - iptr->opc); + exceptions_throw_internalerror("Unknown ICMD %d during stack re-analysis", + iptr->opc); return false; } /* switch */ #if defined(STACK_VERBOSE) - new_show_icmd(sd->jd, iptr, false, SHOW_STACK); + show_icmd(sd->jd, iptr, false, SHOW_STACK); printf("\n"); #endif } @@ -1741,6 +1863,127 @@ bool stack_reanalyse_block(stackdata_t *sd) } +/* stack_change_to_tempvar ***************************************************** + + Change the given stackslot to a TEMPVAR. This includes creating a new + temporary variable and changing the dst.varindex of the creator of the + stacklot to the new variable index. If this stackslot has been passed + through ICMDs between the point of its creation and the current point, + then the variable index is also changed in these ICMDs. + + IN: + sd...........stack analysis data + sp...........stackslot to change + ilimit.......instruction up to which to look for ICMDs passing-through + the stackslot (exclusive). This may point exactly after the + last instruction, in which case the search is done to the + basic block end. + +*******************************************************************************/ + +static void stack_change_to_tempvar(stackdata_t *sd, stackelement_t * sp, + instruction *ilimit) +{ + s4 newindex; + s4 oldindex; + instruction *iptr; + s4 depth; + s4 i; + + oldindex = sp->varnum; + + /* create a new temporary variable */ + + GET_NEW_VAR(*sd, newindex, sp->type); + + sd->var[newindex].flags = sp->flags; + + /* change the stackslot */ + + sp->varnum = newindex; + sp->varkind = TEMPVAR; + + /* change the dst.varindex of the stackslot's creator */ + + if (sp->creator) + sp->creator->dst.varindex = newindex; + + /* handle ICMDs this stackslot passed through, if any */ + + if (sp->flags & PASSTHROUGH) { + iptr = (sp->creator) ? (sp->creator + 1) : sd->bptr->iinstr; + + /* assert that the limit points to an ICMD, or after the last one */ + + assert(ilimit >= sd->bptr->iinstr); + assert(ilimit <= sd->bptr->iinstr + sd->bptr->icount); + + /* find the stackdepth under sp plus one */ + /* Note: This number is usually known when this function is called, */ + /* but calculating it here is less error-prone and should not be */ + /* a performance problem. */ + + for (depth = 0; sp != NULL; sp = sp->prev) + depth++; + + /* iterate over all instructions in the range and replace */ + + for (; iptr < ilimit; ++iptr) { + switch (iptr->opc) { + case ICMD_INVOKESTATIC: + case ICMD_INVOKESPECIAL: + case ICMD_INVOKEVIRTUAL: + case ICMD_INVOKEINTERFACE: + case ICMD_BUILTIN: + i = iptr->s1.argcount - depth; + if (iptr->sx.s23.s2.args[i] == oldindex) { + iptr->sx.s23.s2.args[i] = newindex; + } + break; + /* IMPORTANT: If any ICMD sets the PASSTHROUGH flag of a */ + /* stackslot, it must be added in this switch! */ + } + } + } +} + + +/* stack_init_javalocals ******************************************************* + + Initialize the mapping from Java locals to cacao variables at method entry. + + IN: + sd...........stack analysis data + +*******************************************************************************/ + +static void stack_init_javalocals(stackdata_t *sd) +{ + s4 *jl; + s4 type,i,j; + methoddesc *md; + jitdata *jd; + + jd = sd->jd; + + jl = DMNEW(s4, sd->maxlocals); + jd->basicblocks[0].javalocals = jl; + + for (i=0; imaxlocals; ++i) + jl[i] = UNUSED; + + md = jd->m->parseddesc; + j = 0; + for (i=0; iparamcount; ++i) { + type = md->paramtypes[i].type; + jl[j] = jd->local_map[5*j + type]; + j++; + if (IS_2_WORD_TYPE(type)) + j++; + } +} + + /* stack_analyse *************************************************************** Analyse_stack uses the intermediate code created by parse.c to @@ -1765,35 +2008,31 @@ bool stack_reanalyse_block(stackdata_t *sd) *******************************************************************************/ -bool new_stack_analyse(jitdata *jd) +bool stack_analyse(jitdata *jd) { methodinfo *m; /* method being analyzed */ codeinfo *code; - codegendata *cd; registerdata *rd; stackdata_t sd; -#if defined(ENABLE_SSA) - lsradata *ls; -#endif - int b_index; /* basic block index */ int stackdepth; - stackptr curstack; /* current stack top */ - stackptr copy; + stackelement_t *curstack; /* current stack top */ + stackelement_t *copy; int opcode; /* opcode of current instruction */ - int i, j; + int i, varindex; int javaindex; + int type; /* operand type */ int len; /* # of instructions after the current one */ bool superblockend; /* if true, no fallthrough to next block */ bool deadcode; /* true if no live code has been reached */ instruction *iptr; /* the current instruction */ basicblock *tbptr; basicblock *original; - exceptiontable *ex; + exception_entry *ex; - stackptr *last_store_boundary; - stackptr coalescing_boundary; + stackelement_t **last_store_boundary; + stackelement_t *coalescing_boundary; - stackptr src1, src2, src3, src4, dst1, dst2; + stackelement_t *src1, *src2, *src3, *src4, *dst1, *dst2; branch_target_t *table; lookup_target_t *lookup; @@ -1809,18 +2048,14 @@ bool new_stack_analyse(jitdata *jd) int new_index; /* used to get a new var index with GET_NEW_INDEX*/ #if defined(STACK_VERBOSE) - new_show_method(jd, SHOW_PARSE); + show_method(jd, SHOW_PARSE); #endif /* get required compiler data - initialization */ m = jd->m; code = jd->code; - cd = jd->cd; rd = jd->rd; -#if defined(ENABLE_SSA) - ls = jd->ls; -#endif /* initialize the stackdata_t struct */ @@ -1830,14 +2065,18 @@ bool new_stack_analyse(jitdata *jd) sd.vartop = jd->vartop; sd.localcount = jd->localcount; sd.var = jd->var; - sd.handlers = DMNEW(exceptiontable *, cd->exceptiontablelength + 1); + sd.varsallocated = sd.varcount; + sd.maxlocals = m->maxlocals; + sd.javalocals = DMNEW(s4, sd.maxlocals); + sd.handlers = DMNEW(exception_entry *, jd->exceptiontablelength + 1); + + /* prepare the variable for exception handler stacks */ + /* (has been reserved by STACK_EXTRA_VARS, or VERIFIER_EXTRA_VARS) */ + sd.exstack.type = TYPE_ADR; sd.exstack.prev = NULL; - sd.exstack.varnum = 0; /* XXX do we need a real variable index here? */ - -#if defined(ENABLE_LSRA) - m->maxlifetimes = 0; -#endif + sd.exstack.varnum = sd.localcount; + sd.var[sd.exstack.varnum].type = TYPE_ADR; #if defined(ENABLE_STATISTICS) iteration_count = 0; @@ -1846,7 +2085,7 @@ bool new_stack_analyse(jitdata *jd) /* find the last real basic block */ sd.last_real_block = NULL; - tbptr = jd->new_basicblocks; + tbptr = jd->basicblocks; while (tbptr->next) { sd.last_real_block = tbptr; tbptr = tbptr->next; @@ -1855,29 +2094,34 @@ bool new_stack_analyse(jitdata *jd) /* find the last exception handler */ - if (cd->exceptiontablelength) - sd.extableend = cd->exceptiontable + cd->exceptiontablelength - 1; + if (jd->exceptiontablelength) + sd.extableend = jd->exceptiontable + jd->exceptiontablelength - 1; else sd.extableend = NULL; /* init jd->interface_map */ + jd->maxinterfaces = m->maxstack; jd->interface_map = DMNEW(interface_info, m->maxstack * 5); for (i = 0; i < m->maxstack * 5; i++) jd->interface_map[i].flags = UNUSED; - last_store_boundary = DMNEW(stackptr, cd->maxlocals); + last_store_boundary = DMNEW(stackelement_t *, m->maxlocals); /* initialize flags and invars (none) of first block */ - jd->new_basicblocks[0].flags = BBREACHED; - jd->new_basicblocks[0].invars = NULL; - jd->new_basicblocks[0].indepth = 0; - jd->new_basicblocks[0].inlocals = + jd->basicblocks[0].flags = BBREACHED; + jd->basicblocks[0].invars = NULL; + jd->basicblocks[0].indepth = 0; + jd->basicblocks[0].inlocals = DMNEW(varinfo, jd->localcount + VERIFIER_EXTRA_LOCALS); - MCOPY(jd->new_basicblocks[0].inlocals, jd->var, varinfo, + MCOPY(jd->basicblocks[0].inlocals, jd->var, varinfo, jd->localcount + VERIFIER_EXTRA_LOCALS); + /* initialize java local mapping of first block */ + + stack_init_javalocals(&sd); + /* stack analysis loop (until fixpoint reached) **************************/ do { @@ -1887,11 +2131,12 @@ bool new_stack_analyse(jitdata *jd) /* initialize loop over basic blocks */ - sd.bptr = jd->new_basicblocks; + sd.bptr = jd->basicblocks; superblockend = true; - sd.repeat = false; - curstack = NULL; stackdepth = 0; - deadcode = true; + sd.repeat = false; + curstack = NULL; + stackdepth = 0; + deadcode = true; /* iterate over basic blocks *****************************************/ @@ -1903,9 +2148,22 @@ bool new_stack_analyse(jitdata *jd) continue; } + if (sd.bptr->flags == BBTYPECHECK_REACHED) { + /* re-analyse a block because its input changed */ + + deadcode = false; + + if (!stack_reanalyse_block(&sd)) + return false; + + superblockend = true; /* XXX */ + continue; + } + if (superblockend && (sd.bptr->flags < BBREACHED)) { - /* This block has not been reached so far, and we */ - /* don't fall into it, so we'll have to iterate again. */ + /* This block has not been reached so far, and we + don't fall into it, so we'll have to iterate + again. */ sd.repeat = true; continue; @@ -1919,15 +2177,19 @@ bool new_stack_analyse(jitdata *jd) } if (sd.bptr->original && sd.bptr->original->flags < BBFINISHED) { - /* This block is a clone and the original has not been */ - /* analysed, yet. Analyse it on the next iteration. */ + /* This block is a clone and the original has not been + analysed, yet. Analyse it on the next + iteration. */ sd.repeat = true; + /* XXX superblockend? */ continue; } /* This block has to be analysed now. */ + deadcode = false; + /* XXX The rest of this block is still indented one level too */ /* much in order to avoid a giant diff by changing that. */ @@ -1946,7 +2208,7 @@ bool new_stack_analyse(jitdata *jd) original = (sd.bptr->original) ? sd.bptr->original : sd.bptr; len = 0; - ex = cd->exceptiontable; + ex = jd->exceptiontable; for (; ex != NULL; ex = ex->down) { if ((ex->start <= original) && (ex->end > original)) { sd.handlers[len++] = ex; @@ -1965,7 +2227,7 @@ bool new_stack_analyse(jitdata *jd) /* reset the new pointer for allocating stackslots */ - sd.new = jd->new_stack; + sd.new = jd->stack; /* create the instack of this block */ @@ -1976,13 +2238,13 @@ bool new_stack_analyse(jitdata *jd) if (sd.bptr->inlocals) MCOPY(sd.var, sd.bptr->inlocals, varinfo, sd.localcount); + MCOPY(sd.javalocals, sd.bptr->javalocals, s4, sd.maxlocals); + /* set up local variables for analyzing this block */ - deadcode = false; superblockend = false; len = sd.bptr->icount; iptr = sd.bptr->iinstr; - b_index = sd.bptr - jd->new_basicblocks; /* mark the block as analysed */ @@ -1991,7 +2253,7 @@ bool new_stack_analyse(jitdata *jd) /* reset variables for dependency checking */ coalescing_boundary = sd.new; - for( i = 0; i < cd->maxlocals; i++) + for( i = 0; i < m->maxlocals; i++) last_store_boundary[i] = sd.new; /* remember the start of this block's variables */ @@ -2012,16 +2274,7 @@ bool new_stack_analyse(jitdata *jd) while (--len >= 0) { #if defined(STACK_VERBOSE) - new_show_icmd(jd, iptr, false, SHOW_PARSE); printf("\n"); - for( copy = curstack; copy; copy = copy->prev ) { - printf("%2d(%d", copy->varnum, copy->type); - if (IS_OUTVAR(copy)) - printf("S"); - if (IS_PREALLOC(copy)) - printf("A"); - printf(") "); - } - printf("\n"); + stack_verbose_show_state(&sd, iptr, curstack); #endif /* fetch the current opcode */ @@ -2030,20 +2283,16 @@ bool new_stack_analyse(jitdata *jd) /* automatically replace some ICMDs with builtins */ -#if defined(USEBUILTINTABLE) - IF_NO_INTRP( - bte = builtintable_get_automatic(opcode); + bte = builtintable_get_automatic(opcode); - if (bte && bte->opcode == opcode) { - iptr->opc = ICMD_BUILTIN; - iptr->flags.bits = 0; - iptr->sx.s23.s3.bte = bte; - /* iptr->line is already set */ - jd->isleafmethod = false; - goto icmd_BUILTIN; - } - ); -#endif /* defined(USEBUILTINTABLE) */ + if ((bte != NULL) && (bte->opcode == opcode)) { + iptr->opc = ICMD_BUILTIN; + iptr->flags.bits &= INS_FLAG_ID_MASK; + iptr->sx.s23.s3.bte = bte; + /* iptr->line is already set */ + code_unflag_leafmethod(code); + goto icmd_BUILTIN; + } /* main opcode switch *************************************/ @@ -2062,24 +2311,23 @@ icmd_NOP: COUNT(count_check_null); USE_S1(TYPE_ADR); CLR_SX; - CLR_DST; /* XXX live through? */ + iptr->dst.varindex = iptr->s1.varindex; break; case ICMD_RET: - j = iptr->s1.varindex = + varindex = iptr->s1.varindex = jd->local_map[iptr->s1.varindex * 5 + TYPE_ADR]; - if (sd.var[j].type != TYPE_RET) { +#if defined(ENABLE_VERIFIER) + if (sd.var[varindex].type != TYPE_RET) { exceptions_throw_verifyerror(m, "RET with non-returnAddress value"); return false; } +#endif CLR_SX; - iptr->dst.block = stack_mark_reached(&sd, sd.var[j].vv.retaddr, curstack, stackdepth); -#if 0 - IF_NO_INTRP( rd->locals[iptr->s1.localindex/*XXX invalid here*/][TYPE_ADR].type = TYPE_ADR; ); -#endif + iptr->dst.block = stack_mark_reached(&sd, sd.var[varindex].vv.retaddr, curstack, stackdepth); superblockend = true; break; @@ -2088,6 +2336,8 @@ icmd_NOP: CLR_SX; OP0_0; superblockend = true; + sd.jd->returncount++; + sd.jd->returnblock = sd.bptr; break; @@ -2371,7 +2621,6 @@ icmd_NOP: case ICMD_BASTORE: case ICMD_CASTORE: case ICMD_SASTORE: - IF_INTRP( goto normal_ICONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY if (iptr->sx.val.i != 0) goto normal_ICONST; @@ -2406,7 +2655,6 @@ icmd_NOP: case ICMD_PUTSTATIC: case ICMD_PUTFIELD: - IF_INTRP( goto normal_ICONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY if (iptr->sx.val.i != 0) goto normal_ICONST; @@ -2422,10 +2670,32 @@ putconst_tail: if (iptr[1].flags.bits & INS_FLAG_UNRESOLVED) { iptr->sx.s23.s3.uf = iptr[1].sx.s23.s3.uf; iptr->flags.bits |= INS_FLAG_UNRESOLVED; + fmiref = iptr->sx.s23.s3.uf->fieldref; } else { - iptr->sx.s23.s3.fmiref = iptr[1].sx.s23.s3.fmiref; + fmiref = iptr[1].sx.s23.s3.fmiref; + iptr->sx.s23.s3.fmiref = fmiref; + } + +#if defined(ENABLE_VERIFIER) + expectedtype = fmiref->parseddesc.fd->type; + switch (iptr[0].opc) { + case ICMD_ICONST: + if (expectedtype != TYPE_INT) + goto throw_stack_type_error; + break; + case ICMD_LCONST: + if (expectedtype != TYPE_LNG) + goto throw_stack_type_error; + break; + case ICMD_ACONST: + if (expectedtype != TYPE_ADR) + goto throw_stack_type_error; + break; + default: + assert(0); } +#endif /* defined(ENABLE_VERIFIER) */ switch (iptr[1].opc) { case ICMD_PUTSTATIC: @@ -2699,7 +2969,7 @@ normal_ICONST: icmd_lconst_lcmp_tail: /* convert LCONST, LCMP, IFXX to IF_LXX */ - iptr->dst.insindex = iptr[2].dst.insindex; + iptr->dst.block = iptr[2].dst.block; iptr[1].opc = ICMD_NOP; iptr[2].opc = ICMD_NOP; @@ -2737,7 +3007,6 @@ normal_ICONST: #if SUPPORT_CONST_STORE case ICMD_LASTORE: - IF_INTRP( goto normal_LCONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY if (iptr->sx.val.l != 0) goto normal_LCONST; @@ -2760,7 +3029,6 @@ normal_ICONST: case ICMD_PUTSTATIC: case ICMD_PUTFIELD: - IF_INTRP( goto normal_LCONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY if (iptr->sx.val.l != 0) goto normal_LCONST; @@ -2810,8 +3078,6 @@ normal_LCONST: coalescing_boundary = sd.new; COUNT(count_pcmd_load); #if SUPPORT_CONST_STORE - IF_INTRP( goto normal_ACONST; ) - /* We can only optimize if the ACONST is resolved * and there is an instruction after it. */ @@ -2870,27 +3136,18 @@ normal_ACONST: case ICMD_DLOAD: case ICMD_ALOAD: COUNT(count_load_instruction); - i = opcode - ICMD_ILOAD; /* type */ + type = opcode - ICMD_ILOAD; - j = iptr->s1.varindex = - jd->local_map[iptr->s1.varindex * 5 + i]; + varindex = iptr->s1.varindex = + jd->local_map[iptr->s1.varindex * 5 + type]; - if (sd.var[j].type == TYPE_RET) { +#if defined(ENABLE_VERIFIER) + if (sd.var[varindex].type == TYPE_RET) { exceptions_throw_verifyerror(m, "forbidden load of returnAddress"); return false; } - -#if defined(ENABLE_SSA) - if (ls != NULL) { - GET_NEW_VAR(sd, new_index, i); - DST(i, new_index); - stackdepth++; - } - else - -#else - LOAD(i, j); #endif + LOAD(type, varindex); break; /* pop 2 push 1 */ @@ -2923,23 +3180,17 @@ normal_ACONST: case ICMD_IINC: STATISTICS_STACKDEPTH_DISTRIBUTION(count_store_depth); -#if defined(ENABLE_SSA) - if (ls != NULL) { - iptr->s1.varindex = - jd->local_map[iptr->s1.varindex * 5 +TYPE_INT]; - } - else { -#endif - last_store_boundary[iptr->s1.varindex] = sd.new; + javaindex = iptr->s1.varindex; + last_store_boundary[javaindex] = sd.new; iptr->s1.varindex = - jd->local_map[iptr->s1.varindex * 5 + TYPE_INT]; + jd->local_map[javaindex * 5 + TYPE_INT]; copy = curstack; i = stackdepth - 1; while (copy) { if ((copy->varkind == LOCALVAR) && - (copy->varnum == iptr->s1.varindex)) + (jd->reverselocalmap[copy->varnum] == javaindex)) { assert(IS_LOCALVAR(copy)); SET_TEMPVAR(copy); @@ -2947,9 +3198,6 @@ normal_ACONST: i--; copy = copy->prev; } -#if defined(ENABLE_SSA) - } -#endif iptr->dst.varindex = iptr->s1.varindex; break; @@ -2963,12 +3211,39 @@ normal_ACONST: case ICMD_ASTORE: REQUIRE(1); - i = opcode - ICMD_ISTORE; /* type */ + type = opcode - ICMD_ISTORE; javaindex = iptr->dst.varindex; - j = iptr->dst.varindex = - jd->local_map[javaindex * 5 + i]; + varindex = iptr->dst.varindex = + jd->local_map[javaindex * 5 + type]; + + COPY_VAL_AND_TYPE(sd, curstack->varnum, varindex); - COPY_VAL_AND_TYPE(sd, curstack->varnum, j); + iptr->sx.s23.s3.javaindex = javaindex; + + if (curstack->type == TYPE_RET) { + iptr->flags.bits |= INS_FLAG_RETADDR; + iptr->sx.s23.s2.retaddrnr = + JAVALOCAL_FROM_RETADDR(sd.var[varindex].vv.retaddr->nr); + sd.javalocals[javaindex] = iptr->sx.s23.s2.retaddrnr; + } + else + sd.javalocals[javaindex] = varindex; + + /* invalidate the following javalocal for 2-word types */ + + if (IS_2_WORD_TYPE(type)) { + sd.javalocals[javaindex+1] = UNUSED; + iptr->flags.bits |= INS_FLAG_KILL_NEXT; + } + + /* invalidate 2-word types if second half was overwritten */ + + if (javaindex > 0 && (i = sd.javalocals[javaindex-1]) >= 0) { + if (IS_2_WORD_TYPE(sd.var[i].type)) { + sd.javalocals[javaindex-1] = UNUSED; + iptr->flags.bits |= INS_FLAG_KILL_PREV; + } + } #if defined(ENABLE_STATISTICS) if (opt_stat) { @@ -2986,18 +3261,14 @@ normal_ACONST: } #endif -#if defined(ENABLE_SSA) - if (ls != NULL) { -#endif /* check for conflicts as described in Figure 5.2 */ copy = curstack->prev; i = stackdepth - 2; while (copy) { if ((copy->varkind == LOCALVAR) && - (copy->varnum == j)) + (jd->reverselocalmap[copy->varnum] == javaindex)) { - copy->varkind = TEMPVAR; assert(IS_LOCALVAR(copy)); SET_TEMPVAR(copy); } @@ -3007,7 +3278,7 @@ normal_ACONST: /* if the variable is already coalesced, don't bother */ - /* We do not need to check against OUTVAR, as invars */ + /* We do not need to check against INOUT, as invars */ /* are always before the coalescing boundary. */ if (curstack->varkind == LOCALVAR) @@ -3023,11 +3294,11 @@ normal_ACONST: if (curstack < coalescing_boundary) goto assume_conflict; - /* there is no DEF LOCALVAR(j) while curstack is live */ + /* there is no DEF LOCALVAR(varindex) while curstack is live */ copy = sd.new; /* most recent stackslot created + 1 */ while (--copy > curstack) { - if (copy->varkind == LOCALVAR && copy->varnum == j) + if (copy->varkind == LOCALVAR && jd->reverselocalmap[copy->varnum] == javaindex) goto assume_conflict; } @@ -3035,21 +3306,22 @@ normal_ACONST: assert((curstack->varkind == TEMPVAR) || (curstack->varkind == UNDEFVAR)); assert(!IS_LOCALVAR(curstack)); /* XXX correct? */ - assert(!IS_OUTVAR(curstack)); + assert(!IS_INOUT(curstack)); assert(!IS_PREALLOC(curstack)); assert(curstack->creator); assert(curstack->creator->dst.varindex == curstack->varnum); + assert(!(curstack->flags & PASSTHROUGH)); RELEASE_INDEX(sd, curstack); curstack->varkind = LOCALVAR; - curstack->varnum = j; - curstack->creator->dst.varindex = j; + curstack->varnum = varindex; + curstack->creator->dst.varindex = varindex; goto store_tail; /* revert the coalescing, if it has been done earlier */ assume_conflict: if ((curstack->varkind == LOCALVAR) - && (curstack->varnum == j)) + && (jd->reverselocalmap[curstack->varnum] == javaindex)) { assert(IS_LOCALVAR(curstack)); SET_TEMPVAR(curstack); @@ -3058,14 +3330,11 @@ assume_conflict: /* remember the stack boundary at this store */ store_tail: last_store_boundary[javaindex] = sd.new; -#if defined(ENABLE_SSA) - } /* if (ls != NULL) */ -#endif if (opcode == ICMD_ASTORE && curstack->type == TYPE_RET) - STORE(TYPE_RET, j); + STORE(TYPE_RET, varindex); else - STORE(opcode - ICMD_ISTORE, j); + STORE(opcode - ICMD_ISTORE, varindex); break; /* pop 3 push 0 */ @@ -3077,7 +3346,7 @@ store_tail: COUNT(count_check_bound); COUNT(count_pcmd_mem); - bte = builtintable_get_internal(BUILTIN_canstore); + bte = builtintable_get_internal(BUILTIN_FAST_canstore); md = bte->md; if (md->memuse > rd->memuse) @@ -3145,14 +3414,16 @@ store_tail: case ICMD_DRETURN: case ICMD_ARETURN: coalescing_boundary = sd.new; - /* Assert here that no LOCAL or OUTVARS get */ + /* Assert here that no LOCAL or INOUTS get */ /* preallocated, since tha macros are not */ /* available in md-abi.c! */ - IF_JIT( if (IS_TEMPVAR(curstack)) \ - md_return_alloc(jd, curstack); ) + if (IS_TEMPVAR(curstack)) + md_return_alloc(jd, curstack); COUNT(count_pcmd_return); OP1_0(opcode - ICMD_IRETURN); superblockend = true; + sd.jd->returncount++; + sd.jd->returnblock = sd.bptr; break; case ICMD_ATHROW: @@ -3362,6 +3633,11 @@ icmd_DUP_X1: POPANY; POPANY; stackdepth -= 2; + /* move non-temporary sources out of the way */ + if (!IS_TEMPVAR(src2)) { + MOVE_TO_TEMP(src2); iptr++; len--; + } + DUP_SLOT(src2); dst1 = curstack; stackdepth++; MOVE_UP(src1); iptr++; len--; @@ -3403,6 +3679,14 @@ icmd_DUP2_X1: POPANY; POPANY; POPANY; stackdepth -= 3; + /* move non-temporary sources out of the way */ + if (!IS_TEMPVAR(src2)) { + MOVE_TO_TEMP(src2); iptr++; len--; + } + if (!IS_TEMPVAR(src3)) { + MOVE_TO_TEMP(src3); iptr++; len--; + } + DUP_SLOT(src2); dst1 = curstack; stackdepth++; DUP_SLOT(src3); dst2 = curstack; stackdepth++; @@ -3449,6 +3733,14 @@ icmd_DUP_X2: POPANY; POPANY; POPANY; stackdepth -= 3; + /* move non-temporary sources out of the way */ + if (!IS_TEMPVAR(src2)) { + MOVE_TO_TEMP(src2); iptr++; len--; + } + if (!IS_TEMPVAR(src3)) { + MOVE_TO_TEMP(src3); iptr++; len--; + } + DUP_SLOT(src3); dst1 = curstack; stackdepth++; MOVE_UP(src1); iptr++; len--; @@ -3516,6 +3808,17 @@ icmd_DUP_X2: POPANY; POPANY; POPANY; POPANY; stackdepth -= 4; + /* move non-temporary sources out of the way */ + if (!IS_TEMPVAR(src2)) { + MOVE_TO_TEMP(src2); iptr++; len--; + } + if (!IS_TEMPVAR(src3)) { + MOVE_TO_TEMP(src3); iptr++; len--; + } + if (!IS_TEMPVAR(src4)) { + MOVE_TO_TEMP(src4); iptr++; len--; + } + DUP_SLOT(src3); dst1 = curstack; stackdepth++; DUP_SLOT(src4); dst2 = curstack; stackdepth++; @@ -3548,6 +3851,11 @@ icmd_DUP_X2: POPANY; POPANY; stackdepth -= 2; + /* move non-temporary sources out of the way */ + if (!IS_TEMPVAR(src1)) { + MOVE_TO_TEMP(src1); iptr++; len--; + } + MOVE_UP(src2); iptr++; len--; MOVE_UP(src1); @@ -3665,7 +3973,7 @@ icmd_DUP_X2: case ICMD_IFEQ: iptr->opc = ICMD_IF_LCMPEQ; icmd_lcmp_if_tail: - iptr->dst.insindex = iptr[1].dst.insindex; + iptr->dst.block = iptr[1].dst.block; iptr[1].opc = ICMD_NOP; OP2_BRANCH(TYPE_LNG, TYPE_LNG); @@ -3697,172 +4005,6 @@ normal_LCMP: OP2_1(TYPE_LNG, TYPE_LNG, TYPE_INT); break; - /* XXX why is this deactivated? */ -#if 0 - case ICMD_FCMPL: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_FCMPL; - - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr->opc = ICMD_IF_FCMPEQ; - icmd_if_fcmpl_tail: - iptr->dst.insindex = iptr[1].dst.insindex; - iptr[1].opc = ICMD_NOP; - - OP2_BRANCH(TYPE_FLT, TYPE_FLT); - BRANCH(tbptr); - - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr->opc = ICMD_IF_FCMPNE; - goto icmd_if_fcmpl_tail; - case ICMD_IFLT: - iptr->opc = ICMD_IF_FCMPL_LT; - goto icmd_if_fcmpl_tail; - case ICMD_IFGT: - iptr->opc = ICMD_IF_FCMPL_GT; - goto icmd_if_fcmpl_tail; - case ICMD_IFLE: - iptr->opc = ICMD_IF_FCMPL_LE; - goto icmd_if_fcmpl_tail; - case ICMD_IFGE: - iptr->opc = ICMD_IF_FCMPL_GE; - goto icmd_if_fcmpl_tail; - default: - goto normal_FCMPL; - } - break; - -normal_FCMPL: - OPTT2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); - break; - - case ICMD_FCMPG: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_FCMPG; - - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr->opc = ICMD_IF_FCMPEQ; - icmd_if_fcmpg_tail: - iptr->dst.insindex = iptr[1].dst.insindex; - iptr[1].opc = ICMD_NOP; - - OP2_BRANCH(TYPE_FLT, TYPE_FLT); - BRANCH(tbptr); - - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr->opc = ICMD_IF_FCMPNE; - goto icmd_if_fcmpg_tail; - case ICMD_IFLT: - iptr->opc = ICMD_IF_FCMPG_LT; - goto icmd_if_fcmpg_tail; - case ICMD_IFGT: - iptr->opc = ICMD_IF_FCMPG_GT; - goto icmd_if_fcmpg_tail; - case ICMD_IFLE: - iptr->opc = ICMD_IF_FCMPG_LE; - goto icmd_if_fcmpg_tail; - case ICMD_IFGE: - iptr->opc = ICMD_IF_FCMPG_GE; - goto icmd_if_fcmpg_tail; - default: - goto normal_FCMPG; - } - break; - -normal_FCMPG: - OP2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); - break; - - case ICMD_DCMPL: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_DCMPL; - - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr->opc = ICMD_IF_DCMPEQ; - icmd_if_dcmpl_tail: - iptr->dst.insindex = iptr[1].dst.insindex; - iptr[1].opc = ICMD_NOP; - - OP2_BRANCH(TYPE_DBL, TYPE_DBL); - BRANCH(tbptr); - - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr->opc = ICMD_IF_DCMPNE; - goto icmd_if_dcmpl_tail; - case ICMD_IFLT: - iptr->opc = ICMD_IF_DCMPL_LT; - goto icmd_if_dcmpl_tail; - case ICMD_IFGT: - iptr->opc = ICMD_IF_DCMPL_GT; - goto icmd_if_dcmpl_tail; - case ICMD_IFLE: - iptr->opc = ICMD_IF_DCMPL_LE; - goto icmd_if_dcmpl_tail; - case ICMD_IFGE: - iptr->opc = ICMD_IF_DCMPL_GE; - goto icmd_if_dcmpl_tail; - default: - goto normal_DCMPL; - } - break; - -normal_DCMPL: - OPTT2_1(TYPE_DBL, TYPE_INT); - break; - - case ICMD_DCMPG: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_DCMPG; - - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr->opc = ICMD_IF_DCMPEQ; - icmd_if_dcmpg_tail: - iptr->dst.insindex = iptr[1].dst.insindex; - iptr[1].opc = ICMD_NOP; - - OP2_BRANCH(TYPE_DBL, TYPE_DBL); - BRANCH(tbptr); - - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr->opc = ICMD_IF_DCMPNE; - goto icmd_if_dcmpg_tail; - case ICMD_IFLT: - iptr->opc = ICMD_IF_DCMPG_LT; - goto icmd_if_dcmpg_tail; - case ICMD_IFGT: - iptr->opc = ICMD_IF_DCMPG_GT; - goto icmd_if_dcmpg_tail; - case ICMD_IFLE: - iptr->opc = ICMD_IF_DCMPG_LE; - goto icmd_if_dcmpg_tail; - case ICMD_IFGE: - iptr->opc = ICMD_IF_DCMPG_GE; - goto icmd_if_dcmpg_tail; - default: - goto normal_DCMPG; - } - break; - -normal_DCMPG: - OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); - break; -#else case ICMD_FCMPL: case ICMD_FCMPG: COUNT(count_pcmd_op); @@ -3874,7 +4016,6 @@ normal_DCMPG: COUNT(count_pcmd_op); OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); break; -#endif /* pop 1 push 1 */ @@ -4009,14 +4150,17 @@ normal_DCMPG: case ICMD_JSR: OP0_1(TYPE_RET); + tbptr = iptr->sx.s23.s3.jsrtarget.block; + tbptr->type = BBTYPE_SBR; + assert(sd.bptr->next); /* XXX exception */ sd.var[curstack->varnum].vv.retaddr = sd.bptr->next; - - tbptr = BLOCK_OF(iptr->sx.s23.s3.jsrtarget.insindex); - tbptr->type = BBTYPE_SBR; +#if defined(ENABLE_VERIFIER) + sd.var[curstack->varnum].SBRSTART = (void*) tbptr; +#endif tbptr = stack_mark_reached(&sd, tbptr, curstack, stackdepth); - if (!tbptr) + if (tbptr == NULL) return false; iptr->sx.s23.s3.jsrtarget.block = tbptr; @@ -4070,8 +4214,6 @@ icmd_BUILTIN: REQUIRE(i); - /* XXX optimize for <= 2 args */ - /* XXX not for ICMD_BUILTIN */ iptr->s1.argcount = stackdepth; iptr->sx.s23.s2.args = DMNEW(s4, stackdepth); @@ -4081,7 +4223,7 @@ icmd_BUILTIN: /* do not change STACKVARs or LOCALVARS to ARGVAR*/ /* -> won't help anyway */ - if (!(IS_OUTVAR(copy) || IS_LOCALVAR(copy))) { + if (!(IS_INOUT(copy) || IS_LOCALVAR(copy))) { #if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) /* If we pass float arguments in integer argument registers, we @@ -4098,40 +4240,34 @@ icmd_BUILTIN: SET_PREALLOC(copy); -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif - if (md->params[i].inmemory) { - sd.var[copy->varnum].vv.regoff = - md->params[i].regoff; - sd.var[copy->varnum].flags |= - INMEMORY; - } - else { - if (IS_FLT_DBL_TYPE(copy->type)) { + if (md->params[i].inmemory) { + sd.var[copy->varnum].vv.regoff = + md->params[i].regoff; + sd.var[copy->varnum].flags |= + INMEMORY; + } + else { + if (IS_FLT_DBL_TYPE(copy->type)) { #if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) - assert(0); /* XXX is this assert ok? */ + assert(0); /* XXX is this assert ok? */ #else - sd.var[copy->varnum].vv.regoff = - rd->argfltregs[md->params[i].regoff]; + sd.var[copy->varnum].vv.regoff = + md->params[i].regoff; #endif /* SUPPORT_PASS_FLOATARGS_IN_INTREGS */ - } - else { + } + else { #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(copy->type)) - sd.var[copy->varnum].vv.regoff = - PACK_REGS( rd->argintregs[GET_LOW_REG(md->params[i].regoff)], - rd->argintregs[GET_HIGH_REG(md->params[i].regoff)]); + if (IS_2_WORD_TYPE(copy->type)) + sd.var[copy->varnum].vv.regoff = + PACK_REGS(GET_LOW_REG(md->params[i].regoff), + GET_HIGH_REG(md->params[i].regoff)); - else + else #endif /* SUPPORT_COMBINE_INTEGER_REGISTERS */ - sd.var[copy->varnum].vv.regoff = - rd->argintregs[md->params[i].regoff]; - } + sd.var[copy->varnum].vv.regoff = + md->params[i].regoff; } -#if defined(ENABLE_INTRP) - } /* end if (!opt_intrp) */ -#endif + } } } copy = copy->prev; @@ -4139,15 +4275,13 @@ icmd_BUILTIN: /* deal with live-through stack slots "under" the */ /* arguments */ - /* XXX not for ICMD_BUILTIN */ i = md->paramcount; while (copy) { - SET_TEMPVAR(copy); iptr->sx.s23.s2.args[i++] = copy->varnum; sd.var[copy->varnum].flags |= SAVEDVAR; - copy->flags |= SAVEDVAR; + copy->flags |= SAVEDVAR | PASSTHROUGH; copy = copy->prev; } @@ -4169,16 +4303,10 @@ icmd_BUILTIN: } break; - case ICMD_INLINE_START: - case ICMD_INLINE_END: - CLR_S1; - CLR_DST; - break; - case ICMD_MULTIANEWARRAY: coalescing_boundary = sd.new; - if (rd->argintreguse < 3) - rd->argintreguse = 3; + if (rd->argintreguse < MIN(3, INT_ARG_CNT)) + rd->argintreguse = MIN(3, INT_ARG_CNT); i = iptr->s1.argcount; @@ -4211,7 +4339,7 @@ icmd_BUILTIN: /* check INT type here? Currently typecheck does this. */ iptr->sx.s23.s2.args[i] = copy->varnum; if (!(sd.var[copy->varnum].flags & SAVEDVAR) - && (!IS_OUTVAR(copy)) + && (!IS_INOUT(copy)) && (!IS_LOCALVAR(copy)) ) { copy->varkind = ARGVAR; sd.var[copy->varnum].flags |= @@ -4238,6 +4366,7 @@ icmd_BUILTIN: } while (copy) { sd.var[copy->varnum].flags |= SAVEDVAR; + copy->flags |= SAVEDVAR; copy = copy->prev; } @@ -4252,8 +4381,8 @@ icmd_BUILTIN: break; default: - *exceptionptr = - new_internalerror("Unknown ICMD %d", opcode); + exceptions_throw_internalerror("Unknown ICMD %d during stack analysis", + opcode); return false; } /* switch */ @@ -4261,6 +4390,12 @@ icmd_BUILTIN: iptr++; } /* while instructions */ + /* show state after last instruction */ + +#if defined(STACK_VERBOSE) + stack_verbose_show_state(&sd, NULL, curstack); +#endif + /* stack slots at basic block end become interfaces */ sd.bptr->outdepth = stackdepth; @@ -4269,7 +4404,6 @@ icmd_BUILTIN: i = stackdepth - 1; for (copy = curstack; copy; i--, copy = copy->prev) { varinfo *v; - s4 t; /* with the new vars rd->interfaces will be removed */ /* and all in and outvars have to be STACKVARS! */ @@ -4277,45 +4411,45 @@ icmd_BUILTIN: /* create an unresolvable conflict */ SET_TEMPVAR(copy); - t = copy->type; - if (t == TYPE_RET) - t = TYPE_ADR; + type = copy->type; v = sd.var + copy->varnum; - v->flags |= OUTVAR; + v->flags |= INOUT; - if (jd->interface_map[i*5 + t].flags == UNUSED) { - /* no interface var until now for this depth and */ - /* type */ - jd->interface_map[i*5 + t].flags = v->flags; - } - else { - jd->interface_map[i*5 + t].flags |= v->flags; + /* do not allocate variables for returnAddresses */ + + if (type != TYPE_RET) { + if (jd->interface_map[i*5 + type].flags == UNUSED) { + /* no interface var until now for this depth and */ + /* type */ + jd->interface_map[i*5 + type].flags = v->flags; + } + else { + jd->interface_map[i*5 + type].flags |= v->flags; + } } sd.bptr->outvars[i] = copy->varnum; } /* check if interface slots at basic block begin must be saved */ - IF_NO_INTRP( - for (i=0; iindepth; ++i) { - varinfo *v = sd.var + sd.bptr->invars[i]; - s4 t; - t = v->type; - if (t == TYPE_RET) - t = TYPE_ADR; + for (i=0; iindepth; ++i) { + varinfo *v = sd.var + sd.bptr->invars[i]; + + type = v->type; - if (jd->interface_map[i*5 + t].flags == UNUSED) { + if (type != TYPE_RET) { + if (jd->interface_map[i*5 + type].flags == UNUSED) { /* no interface var until now for this depth and */ /* type */ - jd->interface_map[i*5 + t].flags = v->flags; + jd->interface_map[i*5 + type].flags = v->flags; } else { - jd->interface_map[i*5 + t].flags |= v->flags; + jd->interface_map[i*5 + type].flags |= v->flags; } } - ); + } /* store the number of this block's variables */ @@ -4335,16 +4469,35 @@ icmd_BUILTIN: } while (sd.repeat && !deadcode); - /* XXX reset TYPE_RET to TYPE_ADR */ + /* reset locals of TYPE_RET|VOID to TYPE_ADR */ + + /* A local variable may be used as both a returnAddress and a reference */ + /* type variable, as we do not split variables between these types when */ + /* renaming locals. While returnAddresses have been eliminated now, we */ + /* must assume that the variable is still used as TYPE_ADR. */ + /* The only way that a local can be TYPE_VOID at this point, is that it */ + /* was a TYPE_RET variable for which incompatible returnAddresses were */ + /* merged. Thus we must treat TYPE_VOID in the same way as TYPE_RET */ + /* here. */ + /* XXX: It would be nice to remove otherwise unused returnAddress */ + /* variables from the local variable array, so they are not */ + /* allocated by simplereg. (For LSRA this is not needed). */ + + for (i=0; iexceptiontable; + ex = jd->exceptiontable; for (; ex != NULL; ex = ex->down) { if (ex->start == ex->end) { assert(ex->end->next); @@ -4352,22 +4505,26 @@ icmd_BUILTIN: } } + /* store number of created variables */ + + jd->vartop = sd.vartop; + /* gather statistics *****************************************************/ #if defined(ENABLE_STATISTICS) if (opt_stat) { - if (jd->new_basicblockcount > count_max_basic_blocks) - count_max_basic_blocks = jd->new_basicblockcount; - count_basic_blocks += jd->new_basicblockcount; - if (jd->new_instructioncount > count_max_javainstr) - count_max_javainstr = jd->new_instructioncount; - count_javainstr += jd->new_instructioncount; - if (jd->new_stackcount > count_upper_bound_new_stack) - count_upper_bound_new_stack = jd->new_stackcount; - if ((sd.new - jd->new_stack) > count_max_new_stack) - count_max_new_stack = (sd.new - jd->new_stack); - - sd.bptr = jd->new_basicblocks; + if (jd->basicblockcount > count_max_basic_blocks) + count_max_basic_blocks = jd->basicblockcount; + count_basic_blocks += jd->basicblockcount; + if (jd->instructioncount > count_max_javainstr) + count_max_javainstr = jd->instructioncount; + count_javainstr += jd->instructioncount; + if (jd->stackcount > count_upper_bound_new_stack) + count_upper_bound_new_stack = jd->stackcount; + if ((sd.new - jd->stack) > count_max_new_stack) + count_max_new_stack = (sd.new - jd->stack); + + sd.bptr = jd->basicblocks; for (; sd.bptr; sd.bptr = sd.bptr->next) { if (sd.bptr->flags > BBREACHED) { if (sd.bptr->indepth >= 10) @@ -4407,21 +4564,21 @@ icmd_BUILTIN: else count_analyse_iterations[4]++; - if (jd->new_basicblockcount <= 5) + if (jd->basicblockcount <= 5) count_method_bb_distribution[0]++; - else if (jd->new_basicblockcount <= 10) + else if (jd->basicblockcount <= 10) count_method_bb_distribution[1]++; - else if (jd->new_basicblockcount <= 15) + else if (jd->basicblockcount <= 15) count_method_bb_distribution[2]++; - else if (jd->new_basicblockcount <= 20) + else if (jd->basicblockcount <= 20) count_method_bb_distribution[3]++; - else if (jd->new_basicblockcount <= 30) + else if (jd->basicblockcount <= 30) count_method_bb_distribution[4]++; - else if (jd->new_basicblockcount <= 40) + else if (jd->basicblockcount <= 40) count_method_bb_distribution[5]++; - else if (jd->new_basicblockcount <= 50) + else if (jd->basicblockcount <= 50) count_method_bb_distribution[6]++; - else if (jd->new_basicblockcount <= 75) + else if (jd->basicblockcount <= 75) count_method_bb_distribution[7]++; else count_method_bb_distribution[8]++; @@ -4444,10 +4601,6 @@ throw_stack_overflow: exceptions_throw_verifyerror(m, "Stack size too large"); return false; -throw_stack_depth_error: - exceptions_throw_verifyerror(m,"Stack depth mismatch"); - return false; - throw_stack_type_error: exceptions_throw_verifyerror_for_stack(m, expectedtype); return false; @@ -4460,14 +4613,52 @@ throw_stack_category_error: } +/* stack_javalocals_store ****************************************************** + + Model the effect of a ?STORE instruction upon the given javalocals array. + + IN: + iptr.............the ?STORE instruction + javalocals.......the javalocals array to modify + +*******************************************************************************/ + +void stack_javalocals_store(instruction *iptr, s4 *javalocals) +{ + s4 varindex; /* index into the jd->var array */ + s4 javaindex; /* java local index */ + + varindex = iptr->dst.varindex; + javaindex = iptr->sx.s23.s3.javaindex; + + if (javaindex != UNUSED) { + assert(javaindex >= 0); + if (iptr->flags.bits & INS_FLAG_RETADDR) + javalocals[javaindex] = iptr->sx.s23.s2.retaddrnr; + else + javalocals[javaindex] = varindex; + + if (iptr->flags.bits & INS_FLAG_KILL_PREV) + javalocals[javaindex-1] = UNUSED; + + if (iptr->flags.bits & INS_FLAG_KILL_NEXT) + javalocals[javaindex+1] = UNUSED; + } +} + + /* functions for verbose stack analysis output ********************************/ #if defined(STACK_VERBOSE) static void stack_verbose_show_varinfo(stackdata_t *sd, varinfo *v) { printf("%c", show_jit_type_letters[v->type]); - if (v->type == TYPE_RET) + if (v->type == TYPE_RET) { printf("{L%03d}", v->vv.retaddr->nr); +#if defined(ENABLE_VERIFIER) + printf("{start=L%03d}", ((basicblock *)v->SBRSTART)->nr); +#endif + } } @@ -4492,7 +4683,9 @@ static void stack_verbose_show_block(stackdata_t *sd, basicblock *bptr) } else putchar('-'); - printf("] inlocals ["); + printf("] javalocals "); + show_javalocals_array(sd->jd, sd->javalocals, sd->maxlocals, SHOW_STACK); + printf(" inlocals ["); if (bptr->inlocals) { for (i=0; ilocalcount; ++i) { if (i) @@ -4533,7 +4726,7 @@ static void stack_verbose_block_enter(stackdata_t *sd, bool reanalyse) int i; printf("======================================== STACK %sANALYSE BLOCK ", - (reanalyse) ? "RE-" : ""); + (reanalyse) ? ((sd->bptr->iinstr == NULL) ? "CLONE-" : "RE-") : ""); stack_verbose_show_block(sd, sd->bptr); printf("\n"); @@ -4554,6 +4747,47 @@ static void stack_verbose_block_exit(stackdata_t *sd, bool superblockend) stack_verbose_show_block(sd, sd->bptr); printf("\n"); } + +static void stack_verbose_show_state(stackdata_t *sd, instruction *iptr, stackelement_t *curstack) +{ + stackelement_t *sp; + s4 i; + s4 depth; + varinfo *v; + stackelement_t **stack; + + printf(" javalocals "); + show_javalocals_array(sd->jd, sd->javalocals, sd->maxlocals, SHOW_STACK); + printf(" stack ["); + + for(i = 0, sp = curstack; sp; sp = sp->prev) + i++; + depth = i; + + stack = MNEW(stackelement_t *, depth); + for(sp = curstack; sp; sp = sp->prev) + stack[--i] = sp; + + for(i=0; ivar[sp->varnum]); + + if (v->flags & INOUT) + putchar('I'); + if (v->flags & PREALLOC) + putchar('A'); + printf("%d:%c", sp->varnum, show_jit_type_letters[sp->type]); + if (v->type == TYPE_RET) { + printf("(L%03d)", v->vv.retaddr->nr); + } + } + printf("] ... "); + if (iptr) + show_icmd(sd->jd, iptr, false, SHOW_PARSE); + printf("\n"); +} #endif