X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstack.c;h=abd53cd55fe27493a4aae73e0aa6ec61ba57eeea;hb=70c12f6f829ced45efe992c109a3a8b45af29c99;hp=5e3a1e47d449737b7c9e374d05e1533a0c871e75;hpb=f4d2073b5e9b785e1475b4a6d34bccc5902a841b;p=cacao.git diff --git a/src/vm/jit/stack.c b/src/vm/jit/stack.c index 5e3a1e47d..abd53cd55 100644 --- a/src/vm/jit/stack.c +++ b/src/vm/jit/stack.c @@ -30,7 +30,7 @@ Christian Thalinger Christian Ullrich - $Id: stack.c 5132 2006-07-14 16:56:35Z edwin $ + $Id: stack.c 5675 2006-10-04 19:38:28Z edwin $ */ @@ -40,23 +40,28 @@ #include #include #include - -#include "vm/types.h" +#include #include "arch.h" #include "md-abi.h" #include "mm/memory.h" + #include "native/native.h" + #include "toolbox/logging.h" + #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/jit/codegen-common.h" +#include "vm/types.h" + #include "vm/jit/abi.h" +#include "vm/jit/cfg.h" +#include "vm/jit/codegen-common.h" #include "vm/jit/show.h" #if defined(ENABLE_DISASSEMBLER) @@ -66,7 +71,10 @@ #include "vm/jit/jit.h" #include "vm/jit/stack.h" -#if defined(ENABLE_LSRA) +#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 @@ -75,120 +83,157 @@ /* macro for saving #ifdefs ***************************************************/ -#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) */ - #if defined(ENABLE_STATISTICS) #define STATISTICS_STACKDEPTH_DISTRIBUTION(distr) \ - do { \ - if (opt_stat) { \ - if (stackdepth >= 10) \ - count_store_depth[10]++; \ - else \ - count_store_depth[stackdepth]++; \ - } \ - } while (0) + do { \ + if (opt_stat) { \ + if (stackdepth >= 10) \ + count_store_depth[10]++; \ + else \ + count_store_depth[stackdepth]++; \ + } \ + } while (0) #else /* !defined(ENABLE_STATISTICS) */ #define STATISTICS_STACKDEPTH_DISTRIBUTION(distr) #endif -/* stack_init ****************************************************************** +/* stackdata_t ***************************************************************** - Initialized the stack analysis subsystem (called by jit_init). + This struct holds internal data during stack analysis. *******************************************************************************/ -bool stack_init(void) -{ - return true; -} +typedef struct stackdata_t stackdata_t; +struct stackdata_t { + basicblock *bptr; /* the current basic block being analysed */ + stackptr 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 */ + varinfo *var; /* variable array (same as jd->var) */ + 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 */ +}; -/* stack_analyse *************************************************************** - Analyse_stack uses the intermediate code created by parse.c to - build a model of the JVM operand stack for the current method. - - The following checks are performed: - - check for operand stack underflow (before each instruction) - - check for operand stack overflow (after[1] each instruction) - - check for matching stack depth at merging points - - check for matching basic types[2] at merging points - - check basic types for instruction input (except for BUILTIN* - opcodes, INVOKE* opcodes and MULTIANEWARRAY) - - [1]) Checking this after the instruction should be ok. parse.c - counts the number of required stack slots in such a way that it is - only vital that we don't exceed `maxstack` at basic block - boundaries. - - [2]) 'basic types' means the distinction between INT, LONG, FLOAT, - DOUBLE and ADDRESS types. Subtypes of INT and different ADDRESS - types are not discerned. +/* macros for allocating/releasing variable indices *****************/ -*******************************************************************************/ +#define GET_NEW_INDEX(sd, new_varindex) \ + do { \ + assert((sd).vartop < (sd).varcount); \ + (new_varindex) = ((sd).vartop)++; \ + } while (0) -#define BLOCK_OF(index) \ - (jd->new_basicblocks + jd->new_basicblockindex[index]) +/* Not implemented now - could be used to reuse varindices. */ +/* Pay attention to not release a localvar once implementing it! */ +#define RELEASE_INDEX(sd, varindex) + +#define GET_NEW_VAR(sd, new_varindex, newtype) \ + do { \ + GET_NEW_INDEX((sd), (new_varindex)); \ + (sd).var[new_index].type = (newtype); \ + } while (0) + + +/* macros for querying variable properties **************************/ + +#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 & (INOUT | PREALLOC)) ) + + +#define IS_LOCALVAR_SD(sd, sp) \ + ((sp)->varnum < (sd).localcount) + +#define IS_LOCALVAR(sp) \ + IS_LOCALVAR_SD(sd, (sp)) + + +/* macros for setting variable properties ****************************/ + +#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; \ + } \ + sd.var[(sp)->varnum].flags &= ~(INOUT | PREALLOC); \ + } while (0); + +#define SET_PREALLOC(sp) \ + do { \ + assert(!IS_LOCALVAR((sp))); \ + sd.var[(sp)->varnum].flags |= PREALLOC; \ + } while (0); -#define CLR_S1 \ - (iptr->s1.var = NULL) -#define USE_S1_LOCAL(type1) +/* macros for source operands ***************************************/ + +#define CLR_S1 \ + (iptr->s1.varindex = -1) #define USE_S1(type1) \ do { \ - REQUIRE_1; \ + REQUIRE(1); \ CHECK_BASIC_TYPE(type1, curstack->type); \ - iptr->s1.var = curstack; \ + iptr->s1.varindex = curstack->varnum; \ } while (0) #define USE_S1_ANY \ do { \ - REQUIRE_1; \ - iptr->s1.var = curstack; \ + REQUIRE(1); \ + iptr->s1.varindex = curstack->varnum; \ } while (0) #define USE_S1_S2(type1, type2) \ do { \ - REQUIRE_2; \ + REQUIRE(2); \ CHECK_BASIC_TYPE(type1, curstack->prev->type); \ CHECK_BASIC_TYPE(type2, curstack->type); \ - iptr->sx.s23.s2.var = curstack; \ - iptr->s1.var = curstack->prev; \ + iptr->sx.s23.s2.varindex = curstack->varnum; \ + iptr->s1.varindex = curstack->prev->varnum; \ } while (0) #define USE_S1_S2_ANY_ANY \ do { \ - REQUIRE_2; \ - iptr->sx.s23.s2.var = curstack; \ - iptr->s1.var = curstack->prev; \ + REQUIRE(2); \ + iptr->sx.s23.s2.varindex = curstack->varnum; \ + iptr->s1.varindex = curstack->prev->varnum; \ } while (0) #define USE_S1_S2_S3(type1, type2, type3) \ do { \ - REQUIRE_3; \ + REQUIRE(3); \ CHECK_BASIC_TYPE(type1, curstack->prev->prev->type); \ CHECK_BASIC_TYPE(type2, curstack->prev->type); \ CHECK_BASIC_TYPE(type3, curstack->type); \ - iptr->sx.s23.s3.var = curstack; \ - iptr->sx.s23.s2.var = curstack->prev; \ - iptr->s1.var = curstack->prev->prev; \ + iptr->sx.s23.s3.varindex = curstack->varnum; \ + iptr->sx.s23.s2.varindex = curstack->prev->varnum; \ + iptr->s1.varindex = curstack->prev->prev->varnum; \ + } while (0) + +/* The POPANY macro does NOT check stackdepth, or set stackdepth! */ +#define POPANY \ + do { \ + if (curstack->varkind == UNDEFVAR) \ + curstack->varkind = TEMPVAR; \ + curstack = curstack->prev; \ } while (0) #define POP_S1(type1) \ @@ -242,3090 +287,2068 @@ bool stack_init(void) #define CLR_SX \ (iptr->sx.val.l = 0) + +/* macros for setting the destination operand ***********************/ + #define CLR_DST \ - (iptr->dst.var = NULL) + (iptr->dst.varindex = -1) -#define NEW_DST(typed, depth) \ +#define DST(typed, index) \ do { \ - NEWSTACKn(typed, (depth)); \ - iptr->dst.var = curstack; \ + NEWSTACKn((typed),(index)); \ + curstack->creator = iptr; \ + iptr->dst.varindex = (index); \ } while (0) -#define NEW_DST_LOCALVAR(typed, index) \ +#define DST_LOCALVAR(typed, index) \ do { \ - NEWSTACK(typed, LOCALVAR, (index)); \ - iptr->dst.var = curstack; \ + NEWSTACK((typed), LOCALVAR, (index)); \ + curstack->creator = iptr; \ + iptr->dst.varindex = (index); \ } while (0) -#define NEW_OP0_0 \ - do { \ - CLR_S1; \ - CLR_DST; \ - } while (0) -#define NEW_OP0_BRANCH \ +/* macro for propagating constant values ****************************/ + +#define COPY_VAL_AND_TYPE(sd, sindex, dindex) \ do { \ - CLR_S1; \ - } while (0) + (sd).var[(dindex)].type = (sd).var[(sindex)].type; \ + (sd).var[(dindex)].vv = (sd).var[(sindex)].vv; \ + } while (0) \ + -#define NEW_OP0_1(typed) \ +/* stack modelling macros *******************************************/ + +#define OP0_1(typed) \ do { \ CLR_S1; \ - NEW_DST(typed, stackdepth); \ + GET_NEW_VAR(sd, new_index, (typed)); \ + DST((typed), new_index); \ stackdepth++; \ } while (0) -#define NEW_OP1_0(type1) \ +#define OP1_0_ANY \ do { \ - POP_S1(type1); \ + POP_S1_ANY; \ CLR_DST; \ stackdepth--; \ } while (0) -#define NEW_OP1_0_ANY \ +#define OP1_BRANCH(type1) \ do { \ - POP_S1_ANY; \ - CLR_DST; \ + POP_S1(type1); \ stackdepth--; \ } while (0) -#define NEW_OP1_BRANCH(type1) \ +#define OP1_1(type1, typed) \ do { \ POP_S1(type1); \ + GET_NEW_VAR(sd, new_index, (typed)); \ + DST(typed, new_index); \ + } while (0) + +#define OP2_1(type1, type2, typed) \ + do { \ + POP_S1_S2(type1, type2); \ + GET_NEW_VAR(sd, new_index, (typed)); \ + DST(typed, new_index); \ stackdepth--; \ } while (0) -#define NEW_OP1_1(type1, typed) \ +#define OP0_0 \ + do { \ + CLR_S1; \ + CLR_DST; \ + } while (0) + +#define OP0_BRANCH \ + do { \ + CLR_S1; \ + } while (0) + +#define OP1_0(type1) \ do { \ POP_S1(type1); \ - NEW_DST(typed, stackdepth - 1); \ + CLR_DST; \ + stackdepth--; \ } while (0) -#define NEW_OP2_0(type1, type2) \ +#define OP2_0(type1, type2) \ do { \ POP_S1_S2(type1, type2); \ CLR_DST; \ stackdepth -= 2; \ } while (0) -#define NEW_OP2_BRANCH(type1, type2) \ +#define OP2_BRANCH(type1, type2) \ do { \ POP_S1_S2(type1, type2); \ stackdepth -= 2; \ } while (0) -#define NEW_OP2_0_ANY_ANY \ +#define OP2_0_ANY_ANY \ do { \ POP_S1_S2_ANY_ANY; \ CLR_DST; \ stackdepth -= 2; \ } while (0) -#define NEW_OP2_1(type1, type2, typed) \ - do { \ - POP_S1_S2(type1, type2); \ - NEW_DST(typed, stackdepth - 2); \ - stackdepth--; \ - } while (0) - -#define NEW_OP3_0(type1, type2, type3) \ +#define OP3_0(type1, type2, type3) \ do { \ POP_S1_S2_S3(type1, type2, type3); \ CLR_DST; \ stackdepth -= 3; \ } while (0) -#define NEW_LOAD(type1, index) \ +#define LOAD(type1, index) \ do { \ - NEW_DST_LOCALVAR(type1, index); \ + DST_LOCALVAR(type1, index); \ stackdepth++; \ } while (0) -#define NEW_STORE(type1, index) \ +#define STORE(type1, index) \ do { \ POP_S1(type1); \ stackdepth--; \ } while (0) -#define BRANCH_TARGET(bt, tempbptr, tempsp) \ + +/* macros for DUP elimination ***************************************/ + +/* XXX replace NEW_VAR with NEW_INDEX */ +#define DUP_SLOT(sp) \ + do { \ + GET_NEW_VAR(sd, new_index, (sp)->type); \ + COPY_VAL_AND_TYPE(sd, (sp)->varnum, new_index); \ + NEWSTACK((sp)->type, TEMPVAR, new_index); \ + } while(0) + +/* does not check input stackdepth */ +#define MOVE_UP(sp) \ do { \ - (bt).block = tempbptr = BLOCK_OF((bt).insindex); \ - MARKREACHED(tempbptr, tempsp); \ + iptr->opc = ICMD_MOVE; \ + iptr->s1.varindex = (sp)->varnum; \ + DUP_SLOT(sp); \ + curstack->creator = iptr; \ + iptr->dst.varindex = curstack->varnum; \ + stackdepth++; \ } while (0) -#define BRANCH(tempbptr, tempsp) \ +/* does not check input stackdepth */ +#define COPY_UP(sp) \ do { \ - iptr->dst.block = tempbptr = BLOCK_OF(iptr->dst.insindex); \ - MARKREACHED(tempbptr, tempsp); \ + SET_TEMPVAR((sp)); \ + iptr->opc = ICMD_COPY; \ + iptr->s1.varindex = (sp)->varnum; \ + DUP_SLOT(sp); \ + curstack->creator = iptr; \ + iptr->dst.varindex = curstack->varnum; \ + stackdepth++; \ } while (0) -#define DUP_SLOT(sp) \ +#define COPY_DOWN(s, d) \ do { \ - if ((sp)->varkind == STACKVAR) \ - NEWSTACK((sp)->type, TEMPVAR, stackdepth); \ - else \ - NEWSTACK((sp)->type, (sp)->varkind, (sp)->varnum); \ - } while(0) + SET_TEMPVAR((s)); \ + iptr->opc = ICMD_COPY; \ + iptr->s1.varindex = (s)->varnum; \ + iptr->dst.varindex = (d)->varnum; \ + (d)->creator = iptr; \ + } while (0) -bool new_stack_analyse(jitdata *jd) -{ - methodinfo *m; /* method being analyzed */ - codeinfo *code; - codegendata *cd; - registerdata *rd; - int b_count; /* basic block counter */ - int b_index; /* basic block index */ - int stackdepth; - stackptr curstack; /* current stack top */ - stackptr new; - stackptr copy; - int opcode; /* opcode of current instruction */ - int i, j; - int len; /* # of instructions after the current one */ - bool superblockend; /* if true, no fallthrough to next block */ - bool repeat; /* if true, outermost loop must run again */ - bool deadcode; /* true if no live code has been reached */ - new_instruction *iptr; /* the current instruction */ - basicblock *bptr; /* the current basic block */ - basicblock *tbptr; - s4 *last_store; /* instruction index of last XSTORE */ - /* [ local_index * 5 + type ] */ - s4 last_pei; /* ins. index of last possible exception */ - /* used for conflict resolution for copy */ - /* elimination (XLOAD, IINC, XSTORE) */ - s4 last_dupx; - branch_target_t *table; - lookup_target_t *lookup; -#if defined(ENABLE_VERIFIER) - int expectedtype; /* used by CHECK_BASIC_TYPE */ -#endif - builtintable_entry *bte; - methoddesc *md; - constant_FMIref *fmiref; -#if defined(ENABLE_STATISTICS) - int iteration_count; /* number of iterations of analysis */ -#endif +#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) -#if defined(STACK_VERBOSE) - new_show_method(jd, SHOW_PARSE); -#endif +/* macros for branching / reaching basic blocks *********************/ - /* get required compiler data - initialization */ +#define BRANCH_TARGET(bt, tempbptr) \ + do { \ + tempbptr = BLOCK_OF((bt).insindex); \ + tempbptr = stack_mark_reached(&sd, tempbptr, curstack, \ + stackdepth); \ + if (tempbptr == NULL) \ + return false; \ + (bt).block = tempbptr; \ + } while (0) - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; +#define BRANCH(tempbptr) \ + BRANCH_TARGET(iptr->dst, tempbptr) -#if defined(ENABLE_LSRA) - m->maxlifetimes = 0; -#endif -#if defined(ENABLE_STATISTICS) - iteration_count = 0; +/* forward declarations *******************************************************/ + +static void stack_create_invars(stackdata_t *sd, basicblock *b, + stackptr curstack, int stackdepth); +static void stack_create_invars_from_outvars(stackdata_t *sd, basicblock *b); + +#if defined(STACK_VERBOSE) +static void stack_verbose_show_varinfo(stackdata_t *sd, varinfo *v); +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); #endif - last_store = DMNEW(s4 , cd->maxlocals * 5); - /* initialize in-stack of first block */ +/* stack_init ****************************************************************** - new = jd->new_stack; - jd->new_basicblocks[0].flags = BBREACHED; - jd->new_basicblocks[0].instack = 0; - jd->new_basicblocks[0].indepth = 0; + Initialized the stack analysis subsystem (called by jit_init). - /* initialize in-stack of exception handlers */ +*******************************************************************************/ - for (i = 0; i < cd->exceptiontablelength; i++) { - bptr = BLOCK_OF(cd->exceptiontable[i].handlerpc); - bptr->flags = BBREACHED; - bptr->type = BBTYPE_EXH; - bptr->instack = new; - bptr->indepth = 1; - bptr->pre_count = 10000; - STACKRESET; - NEWXSTACK; - } +bool stack_init(void) +{ + return true; +} - /* count predecessors of each block **************************************/ -#if CONDITIONAL_LOADCONST - /* XXX move this to a separate function */ - { - b_count = jd->new_basicblockcount; - bptr = jd->new_basicblocks; - for (; --b_count >= 0; bptr++) { - if (bptr->icount == 0) - continue; +/* stack_grow_variable_array *************************************************** - /* get the last instruction of the block */ + Grow the variable array so the given number of additional variables fits in. - iptr = /* XXX */ (new_instruction *) bptr->iinstr + (bptr->icount - 1); + IN: + sd...........stack analysis data + num..........number of additional variables - switch (iptr->opc) { - /* instruction stopping control flow */ - case ICMD_RET: - case ICMD_RETURN: - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: - case ICMD_DRETURN: - case ICMD_ARETURN: - case ICMD_ATHROW: - break; +*******************************************************************************/ - /* conditional branches */ - case ICMD_IFEQ: - case ICMD_IFNE: - case ICMD_IFLT: - case ICMD_IFGE: - case ICMD_IFGT: - case ICMD_IFLE: - case ICMD_IFNULL: - case ICMD_IFNONNULL: - case ICMD_IF_ICMPEQ: - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: - case ICMD_IF_ACMPEQ: - case ICMD_IF_ACMPNE: - /* XXX add missing conditional branches */ - bptr[1].pre_count++; - /* FALLTHROUGH */ - - /* unconditional branch */ - case ICMD_GOTO: - BLOCK_OF(iptr->dst.insindex)->pre_count++; - break; +static void stack_grow_variable_array(stackdata_t *sd, s4 num) +{ + s4 newcount; - /* switches */ - case ICMD_TABLESWITCH: - table = iptr->dst.table; - BLOCK_OF((table++)->insindex)->pre_count++; - i = iptr->sx.s23.s3.tablehigh - - iptr->sx.s23.s2.tablelow + 1; - while (--i >= 0) { - BLOCK_OF((table++)->insindex)->pre_count++; - } - break; + assert(num >= 0); - case ICMD_LOOKUPSWITCH: - lookup = iptr->dst.lookup; - BLOCK_OF(iptr->sx.s23.s3.lookupdefault.insindex)->pre_count++; - i = iptr->sx.s23.s2.lookupcount; - while (--i >= 0) { - BLOCK_OF((lookup++)->target.insindex)->pre_count++; - } - break; + if (num == 0) + return; - /* default - fall into next block */ - default: - bptr[1].pre_count++; - break; - } /* end switch */ - } /* end basic block loop */ - } -#endif /* CONDITIONAL_LOADCONST */ + /* XXX avoid too many reallocations */ + newcount = sd->varcount + num; - /* stack analysis loop (until fixpoint reached) **************************/ + sd->var = DMREALLOC(sd->var, varinfo, sd->varcount, newcount); + sd->varcount = newcount; + sd->jd->var = sd->var; + sd->jd->varcount = newcount; +} - do { -#if defined(ENABLE_STATISTICS) - iteration_count++; -#endif - /* initialize loop over basic blocks */ +/* stack_append_block ********************************************************** - b_count = jd->new_basicblockcount; - bptr = jd->new_basicblocks; - superblockend = true; - repeat = false; - STACKRESET; - deadcode = true; + Append the given block after the last real block of the method (before + the pseudo-block at the end). - /* iterate over basic blocks *****************************************/ + IN: + sd...........stack analysis data + b............the block to append + +*******************************************************************************/ - while (--b_count >= 0) { +static void stack_append_block(stackdata_t *sd, basicblock *b) +{ #if defined(STACK_VERBOSE) - printf("ANALYZING BLOCK L%03d\n", bptr->debug_nr); + printf("APPENDING BLOCK L%0d\n", b->nr); #endif - if (bptr->flags == BBDELETED) { - /* This block has been deleted - do nothing. */ - } - else if (superblockend && (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. */ - repeat = true; - } - else if (bptr->flags <= BBREACHED) { - if (superblockend) { - /* We know that bptr->flags == BBREACHED. */ - /* This block has been reached before. */ - stackdepth = bptr->indepth; - } - else if (bptr->flags < BBREACHED) { - /* This block is reached for the first time now */ - /* by falling through from the previous block. */ - COPYCURSTACK(copy); - bptr->instack = copy; - bptr->indepth = stackdepth; - } - else { - /* This block has been reached before. now we are */ - /* falling into it from the previous block. */ - /* Check that stack depth is well-defined. */ - CHECK_STACK_DEPTH(bptr->indepth, stackdepth); - } + b->next = sd->last_real_block->next; + sd->last_real_block->next = b; + sd->last_real_block = b; + sd->jd->basicblockcount++; +} - /* set up local variables for analyzing this block */ - curstack = bptr->instack; - deadcode = false; - superblockend = false; - bptr->flags = BBFINISHED; - len = bptr->icount; - iptr = /* XXX */ (new_instruction *) bptr->iinstr; - b_index = bptr - jd->new_basicblocks; +/* stack_clone_block *********************************************************** - /* reset variables for dependency checking */ + Create a copy of the given block and insert it at the end of the method. - last_pei = -1; - last_dupx = -1; - for( i = 0; i < cd->maxlocals; i++) - for( j = 0; j < 5; j++) - last_store[5 * i + j] = -1; + CAUTION: This function does not copy the any variables or the instruction + list. It _does_, however, reserve space for the block's invars in the + variable array. - /* XXX store the start of the block's stack representation */ + IN: + sd...........stack analysis data + b............the block to clone - bptr->stack = new; + RETURN VALUE: + a pointer to the copy - /* iterate over ICMDs ****************************************/ +*******************************************************************************/ + +static basicblock * stack_clone_block(stackdata_t *sd, basicblock *b) +{ + basicblock *clone; + + clone = DNEW(basicblock); + *clone = *b; + + clone->iinstr = NULL; + clone->inlocals = 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_block_nr++; + clone->next = NULL; + clone->flags = BBREACHED; + + stack_append_block(sd, clone); + + /* allocate space for the invars of the clone */ + + stack_grow_variable_array(sd, b->indepth); - 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("%d ", copy->type); - } - printf("\n"); + printf("cloning block L%03d ------> L%03d\n", b->nr, clone->nr); #endif - /* fetch the current opcode */ + return clone; +} - opcode = iptr->opc; - /* automatically replace some ICMDs with builtins */ +/* stack_create_invars ********************************************************* -#if defined(USEBUILTINTABLE) - IF_NO_INTRP( - bte = builtintable_get_automatic(opcode); - - if (bte && bte->opcode == opcode) { - iptr->opc = ICMD_BUILTIN; - iptr->flags.bits = INS_FLAG_NOCHECK; - iptr->sx.s23.s3.bte = bte; - /* iptr->line is already set */ - jd->isleafmethod = false; - goto icmd_BUILTIN; - } - ); -#endif /* defined(USEBUILTINTABLE) */ + Create the invars for the given basic block. Also make a copy of the locals. - /* main opcode switch *************************************/ + IN: + sd...........stack analysis data + b............block to create the invars for + curstack.....current stack top + stackdepth...current stack depth - switch (opcode) { + This function creates STACKDEPTH invars and sets their types to the + types to the types of the corresponding slot in the current stack. - /* pop 0 push 0 */ +*******************************************************************************/ - case ICMD_NOP: -icmd_NOP: - CLR_SX; - NEW_OP0_0; - break; +static void stack_create_invars(stackdata_t *sd, basicblock *b, + stackptr curstack, int stackdepth) +{ + stackptr sp; + int i; + int index; + varinfo *v; + + assert(sd->vartop + stackdepth <= sd->varcount); + + b->indepth = stackdepth; + b->invars = DMNEW(s4, stackdepth); + + /* allocate the variable indices */ + index = (sd->vartop += stackdepth); + + i = stackdepth; + for (sp = curstack; i--; sp = sp->prev) { + b->invars[i] = --index; + v = sd->var + index; + v->type = sp->type; + v->flags = INOUT; + v->vv = sd->var[sp->varnum].vv; +#if defined(STACK_VERBOSE) && 0 + printf("\tinvar[%d]: %d\n", i, sd->var[b->invars[i]]); +#endif + } - case ICMD_CHECKNULL: - COUNT(count_check_null); - USE_S1(TYPE_ADR); - CLR_SX; - CLR_DST; /* XXX live through? */ - break; + /* copy the current state of the local variables */ + /* (one extra local is needed by the verifier) */ - case ICMD_IFEQ_ICONST: - case ICMD_IFNE_ICONST: - case ICMD_IFLT_ICONST: - case ICMD_IFGE_ICONST: - case ICMD_IFGT_ICONST: - case ICMD_IFLE_ICONST: - case ICMD_ELSE_ICONST: - USE_S1(TYPE_INT); - CLR_SX; - CLR_DST; /* XXX live through? */ - break; + v = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS); + b->inlocals = v; + for (i=0; ilocalcount; ++i) + *v++ = sd->var[i]; +} - case ICMD_RET: - USE_S1_LOCAL(TYPE_ADR); - CLR_SX; - CLR_DST; - IF_NO_INTRP( rd->locals[iptr->s1.localindex][TYPE_ADR].type = TYPE_ADR; ); - superblockend = true; - break; - - case ICMD_RETURN: - COUNT(count_pcmd_return); - CLR_SX; - NEW_OP0_0; - superblockend = true; - break; - - - /* pop 0 push 1 const */ - - /************************** ICONST OPTIMIZATIONS **************************/ - - case ICMD_ICONST: - COUNT(count_pcmd_load); - if (len == 0) - goto normal_ICONST; - - switch (iptr[1].opc) { - case ICMD_IADD: - iptr->opc = ICMD_IADDCONST; - /* FALLTHROUGH */ - - icmd_iconst_tail: - iptr[1].opc = ICMD_NOP; - NEW_OP1_1(TYPE_INT, TYPE_INT); - COUNT(count_pcmd_op); - break; - - case ICMD_ISUB: - iptr->opc = ICMD_ISUBCONST; - goto icmd_iconst_tail; -#if SUPPORT_CONST_MUL - case ICMD_IMUL: - iptr->opc = ICMD_IMULCONST; - goto icmd_iconst_tail; -#else /* SUPPORT_CONST_MUL */ - case ICMD_IMUL: - if (iptr->sx.val.i == 0x00000002) - iptr->sx.val.i = 1; - else if (iptr->sx.val.i == 0x00000004) - iptr->sx.val.i = 2; - else if (iptr->sx.val.i == 0x00000008) - iptr->sx.val.i = 3; - else if (iptr->sx.val.i == 0x00000010) - iptr->sx.val.i = 4; - else if (iptr->sx.val.i == 0x00000020) - iptr->sx.val.i = 5; - else if (iptr->sx.val.i == 0x00000040) - iptr->sx.val.i = 6; - else if (iptr->sx.val.i == 0x00000080) - iptr->sx.val.i = 7; - else if (iptr->sx.val.i == 0x00000100) - iptr->sx.val.i = 8; - else if (iptr->sx.val.i == 0x00000200) - iptr->sx.val.i = 9; - else if (iptr->sx.val.i == 0x00000400) - iptr->sx.val.i = 10; - else if (iptr->sx.val.i == 0x00000800) - iptr->sx.val.i = 11; - else if (iptr->sx.val.i == 0x00001000) - iptr->sx.val.i = 12; - else if (iptr->sx.val.i == 0x00002000) - iptr->sx.val.i = 13; - else if (iptr->sx.val.i == 0x00004000) - iptr->sx.val.i = 14; - else if (iptr->sx.val.i == 0x00008000) - iptr->sx.val.i = 15; - else if (iptr->sx.val.i == 0x00010000) - iptr->sx.val.i = 16; - else if (iptr->sx.val.i == 0x00020000) - iptr->sx.val.i = 17; - else if (iptr->sx.val.i == 0x00040000) - iptr->sx.val.i = 18; - else if (iptr->sx.val.i == 0x00080000) - iptr->sx.val.i = 19; - else if (iptr->sx.val.i == 0x00100000) - iptr->sx.val.i = 20; - else if (iptr->sx.val.i == 0x00200000) - iptr->sx.val.i = 21; - else if (iptr->sx.val.i == 0x00400000) - iptr->sx.val.i = 22; - else if (iptr->sx.val.i == 0x00800000) - iptr->sx.val.i = 23; - else if (iptr->sx.val.i == 0x01000000) - iptr->sx.val.i = 24; - else if (iptr->sx.val.i == 0x02000000) - iptr->sx.val.i = 25; - else if (iptr->sx.val.i == 0x04000000) - iptr->sx.val.i = 26; - else if (iptr->sx.val.i == 0x08000000) - iptr->sx.val.i = 27; - else if (iptr->sx.val.i == 0x10000000) - iptr->sx.val.i = 28; - else if (iptr->sx.val.i == 0x20000000) - iptr->sx.val.i = 29; - else if (iptr->sx.val.i == 0x40000000) - iptr->sx.val.i = 30; - else if (iptr->sx.val.i == 0x80000000) - iptr->sx.val.i = 31; - else - goto normal_ICONST; - - iptr->opc = ICMD_IMULPOW2; - goto icmd_iconst_tail; -#endif /* SUPPORT_CONST_MUL */ - case ICMD_IDIV: - if (iptr->sx.val.i == 0x00000002) - iptr->sx.val.i = 1; - else if (iptr->sx.val.i == 0x00000004) - iptr->sx.val.i = 2; - else if (iptr->sx.val.i == 0x00000008) - iptr->sx.val.i = 3; - else if (iptr->sx.val.i == 0x00000010) - iptr->sx.val.i = 4; - else if (iptr->sx.val.i == 0x00000020) - iptr->sx.val.i = 5; - else if (iptr->sx.val.i == 0x00000040) - iptr->sx.val.i = 6; - else if (iptr->sx.val.i == 0x00000080) - iptr->sx.val.i = 7; - else if (iptr->sx.val.i == 0x00000100) - iptr->sx.val.i = 8; - else if (iptr->sx.val.i == 0x00000200) - iptr->sx.val.i = 9; - else if (iptr->sx.val.i == 0x00000400) - iptr->sx.val.i = 10; - else if (iptr->sx.val.i == 0x00000800) - iptr->sx.val.i = 11; - else if (iptr->sx.val.i == 0x00001000) - iptr->sx.val.i = 12; - else if (iptr->sx.val.i == 0x00002000) - iptr->sx.val.i = 13; - else if (iptr->sx.val.i == 0x00004000) - iptr->sx.val.i = 14; - else if (iptr->sx.val.i == 0x00008000) - iptr->sx.val.i = 15; - else if (iptr->sx.val.i == 0x00010000) - iptr->sx.val.i = 16; - else if (iptr->sx.val.i == 0x00020000) - iptr->sx.val.i = 17; - else if (iptr->sx.val.i == 0x00040000) - iptr->sx.val.i = 18; - else if (iptr->sx.val.i == 0x00080000) - iptr->sx.val.i = 19; - else if (iptr->sx.val.i == 0x00100000) - iptr->sx.val.i = 20; - else if (iptr->sx.val.i == 0x00200000) - iptr->sx.val.i = 21; - else if (iptr->sx.val.i == 0x00400000) - iptr->sx.val.i = 22; - else if (iptr->sx.val.i == 0x00800000) - iptr->sx.val.i = 23; - else if (iptr->sx.val.i == 0x01000000) - iptr->sx.val.i = 24; - else if (iptr->sx.val.i == 0x02000000) - iptr->sx.val.i = 25; - else if (iptr->sx.val.i == 0x04000000) - iptr->sx.val.i = 26; - else if (iptr->sx.val.i == 0x08000000) - iptr->sx.val.i = 27; - else if (iptr->sx.val.i == 0x10000000) - iptr->sx.val.i = 28; - else if (iptr->sx.val.i == 0x20000000) - iptr->sx.val.i = 29; - else if (iptr->sx.val.i == 0x40000000) - iptr->sx.val.i = 30; - else if (iptr->sx.val.i == 0x80000000) - iptr->sx.val.i = 31; - else - goto normal_ICONST; - - iptr->opc = ICMD_IDIVPOW2; - goto icmd_iconst_tail; - - case ICMD_IREM: - /*log_text("stack.c: ICMD_ICONST/ICMD_IREM");*/ - if ((iptr->sx.val.i == 0x00000002) || - (iptr->sx.val.i == 0x00000004) || - (iptr->sx.val.i == 0x00000008) || - (iptr->sx.val.i == 0x00000010) || - (iptr->sx.val.i == 0x00000020) || - (iptr->sx.val.i == 0x00000040) || - (iptr->sx.val.i == 0x00000080) || - (iptr->sx.val.i == 0x00000100) || - (iptr->sx.val.i == 0x00000200) || - (iptr->sx.val.i == 0x00000400) || - (iptr->sx.val.i == 0x00000800) || - (iptr->sx.val.i == 0x00001000) || - (iptr->sx.val.i == 0x00002000) || - (iptr->sx.val.i == 0x00004000) || - (iptr->sx.val.i == 0x00008000) || - (iptr->sx.val.i == 0x00010000) || - (iptr->sx.val.i == 0x00020000) || - (iptr->sx.val.i == 0x00040000) || - (iptr->sx.val.i == 0x00080000) || - (iptr->sx.val.i == 0x00100000) || - (iptr->sx.val.i == 0x00200000) || - (iptr->sx.val.i == 0x00400000) || - (iptr->sx.val.i == 0x00800000) || - (iptr->sx.val.i == 0x01000000) || - (iptr->sx.val.i == 0x02000000) || - (iptr->sx.val.i == 0x04000000) || - (iptr->sx.val.i == 0x08000000) || - (iptr->sx.val.i == 0x10000000) || - (iptr->sx.val.i == 0x20000000) || - (iptr->sx.val.i == 0x40000000) || - (iptr->sx.val.i == 0x80000000)) - { - iptr->opc = ICMD_IREMPOW2; - iptr->sx.val.i -= 1; - goto icmd_iconst_tail; - } - goto normal_ICONST; -#if SUPPORT_CONST_LOGICAL - case ICMD_IAND: - iptr->opc = ICMD_IANDCONST; - goto icmd_iconst_tail; - - case ICMD_IOR: - iptr->opc = ICMD_IORCONST; - goto icmd_iconst_tail; - - case ICMD_IXOR: - iptr->opc = ICMD_IXORCONST; - goto icmd_iconst_tail; - -#endif /* SUPPORT_CONST_LOGICAL */ - case ICMD_ISHL: - iptr->opc = ICMD_ISHLCONST; - goto icmd_iconst_tail; - - case ICMD_ISHR: - iptr->opc = ICMD_ISHRCONST; - goto icmd_iconst_tail; - - case ICMD_IUSHR: - iptr->opc = ICMD_IUSHRCONST; - goto icmd_iconst_tail; -#if SUPPORT_LONG_SHIFT - case ICMD_LSHL: - iptr->opc = ICMD_LSHLCONST; - goto icmd_lconst_tail; - - case ICMD_LSHR: - iptr->opc = ICMD_LSHRCONST; - goto icmd_lconst_tail; - - case ICMD_LUSHR: - iptr->opc = ICMD_LUSHRCONST; - goto icmd_lconst_tail; -#endif /* SUPPORT_LONG_SHIFT */ - case ICMD_IF_ICMPEQ: - iptr[1].opc = ICMD_IFEQ; - /* FALLTHROUGH */ - - icmd_if_icmp_tail: - /* set the constant for the following icmd */ - iptr[1].sx.val.i = iptr->sx.val.i; - - /* this instruction becomes a nop */ - iptr->opc = ICMD_NOP; - goto icmd_NOP; - - case ICMD_IF_ICMPLT: - iptr[1].opc = ICMD_IFLT; - goto icmd_if_icmp_tail; - - case ICMD_IF_ICMPLE: - iptr[1].opc = ICMD_IFLE; - goto icmd_if_icmp_tail; - - case ICMD_IF_ICMPNE: - iptr[1].opc = ICMD_IFNE; - goto icmd_if_icmp_tail; - - case ICMD_IF_ICMPGT: - iptr[1].opc = ICMD_IFGT; - goto icmd_if_icmp_tail; - - case ICMD_IF_ICMPGE: - iptr[1].opc = ICMD_IFGE; - goto icmd_if_icmp_tail; - -#if SUPPORT_CONST_STORE - case ICMD_IASTORE: - 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; -# endif - switch (iptr[1].opc) { - case ICMD_IASTORE: - iptr->opc = ICMD_IASTORECONST; - break; - case ICMD_BASTORE: - iptr->opc = ICMD_BASTORECONST; - break; - case ICMD_CASTORE: - iptr->opc = ICMD_CASTORECONST; - break; - case ICMD_SASTORE: - iptr->opc = ICMD_SASTORECONST; - break; - } - - iptr[1].opc = ICMD_NOP; - - /* copy the constant to s3 */ - /* XXX constval -> astoreconstval? */ - iptr->sx.s23.s3.constval = iptr->sx.val.i; - NEW_OP2_0(TYPE_ADR, TYPE_INT); - COUNT(count_pcmd_op); - break; - - 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; -# endif - /* XXX check field type? */ - - /* copy the constant to s2 */ - /* XXX constval -> fieldconstval? */ - iptr->sx.s23.s2.constval = iptr->sx.val.i; - -putconst_tail: - /* set the field reference (s3) */ - if (iptr[1].flags.bits & INS_FLAG_UNRESOLVED) - iptr->sx.s23.s3.fmiref = iptr[1].sx.s23.s3.fmiref; - else - iptr->sx.s23.s3.uf = iptr[1].sx.s23.s3.uf; - - switch (iptr[1].opc) { - case ICMD_PUTSTATIC: - iptr->opc = ICMD_PUTSTATICCONST; - NEW_OP0_0; - break; - case ICMD_PUTFIELD: - iptr->opc = ICMD_PUTFIELDCONST; - NEW_OP1_0(TYPE_ADR); - break; - } - - iptr[1].opc = ICMD_NOP; - COUNT(count_pcmd_op); - break; -#endif /* SUPPORT_CONST_STORE */ - - default: - goto normal_ICONST; - } - - /* if we get here, the ICONST has been optimized */ - break; - -normal_ICONST: - /* normal case of an unoptimized ICONST */ - NEW_OP0_1(TYPE_INT); - break; - - /************************** LCONST OPTIMIZATIONS **************************/ - - case ICMD_LCONST: - COUNT(count_pcmd_load); - if (len == 0) - goto normal_LCONST; - - /* switch depending on the following instruction */ - - switch (iptr[1].opc) { -#if SUPPORT_LONG_ADD - case ICMD_LADD: - iptr->opc = ICMD_LADDCONST; - /* FALLTHROUGH */ - - icmd_lconst_tail: - /* instruction of type LONG -> LONG */ - iptr[1].opc = ICMD_NOP; - NEW_OP1_1(TYPE_LNG, TYPE_LNG); - COUNT(count_pcmd_op); - break; - - case ICMD_LSUB: - iptr->opc = ICMD_LSUBCONST; - goto icmd_lconst_tail; - -#endif /* SUPPORT_LONG_ADD */ -#if SUPPORT_LONG_MUL && SUPPORT_CONST_MUL - case ICMD_LMUL: - iptr->opc = ICMD_LMULCONST; - goto icmd_lconst_tail; -#else /* SUPPORT_LONG_MUL && SUPPORT_CONST_MUL */ -# if SUPPORT_LONG_SHIFT - case ICMD_LMUL: - if (iptr->sx.val.l == 0x00000002) - iptr->sx.val.i = 1; - else if (iptr->sx.val.l == 0x00000004) - iptr->sx.val.i = 2; - else if (iptr->sx.val.l == 0x00000008) - iptr->sx.val.i = 3; - else if (iptr->sx.val.l == 0x00000010) - iptr->sx.val.i = 4; - else if (iptr->sx.val.l == 0x00000020) - iptr->sx.val.i = 5; - else if (iptr->sx.val.l == 0x00000040) - iptr->sx.val.i = 6; - else if (iptr->sx.val.l == 0x00000080) - iptr->sx.val.i = 7; - else if (iptr->sx.val.l == 0x00000100) - iptr->sx.val.i = 8; - else if (iptr->sx.val.l == 0x00000200) - iptr->sx.val.i = 9; - else if (iptr->sx.val.l == 0x00000400) - iptr->sx.val.i = 10; - else if (iptr->sx.val.l == 0x00000800) - iptr->sx.val.i = 11; - else if (iptr->sx.val.l == 0x00001000) - iptr->sx.val.i = 12; - else if (iptr->sx.val.l == 0x00002000) - iptr->sx.val.i = 13; - else if (iptr->sx.val.l == 0x00004000) - iptr->sx.val.i = 14; - else if (iptr->sx.val.l == 0x00008000) - iptr->sx.val.i = 15; - else if (iptr->sx.val.l == 0x00010000) - iptr->sx.val.i = 16; - else if (iptr->sx.val.l == 0x00020000) - iptr->sx.val.i = 17; - else if (iptr->sx.val.l == 0x00040000) - iptr->sx.val.i = 18; - else if (iptr->sx.val.l == 0x00080000) - iptr->sx.val.i = 19; - else if (iptr->sx.val.l == 0x00100000) - iptr->sx.val.i = 20; - else if (iptr->sx.val.l == 0x00200000) - iptr->sx.val.i = 21; - else if (iptr->sx.val.l == 0x00400000) - iptr->sx.val.i = 22; - else if (iptr->sx.val.l == 0x00800000) - iptr->sx.val.i = 23; - else if (iptr->sx.val.l == 0x01000000) - iptr->sx.val.i = 24; - else if (iptr->sx.val.l == 0x02000000) - iptr->sx.val.i = 25; - else if (iptr->sx.val.l == 0x04000000) - iptr->sx.val.i = 26; - else if (iptr->sx.val.l == 0x08000000) - iptr->sx.val.i = 27; - else if (iptr->sx.val.l == 0x10000000) - iptr->sx.val.i = 28; - else if (iptr->sx.val.l == 0x20000000) - iptr->sx.val.i = 29; - else if (iptr->sx.val.l == 0x40000000) - iptr->sx.val.i = 30; - else if (iptr->sx.val.l == 0x80000000) - iptr->sx.val.i = 31; - else { - goto normal_LCONST; - } - iptr->opc = ICMD_LMULPOW2; - goto icmd_lconst_tail; -# endif /* SUPPORT_LONG_SHIFT */ -#endif /* SUPPORT_LONG_MUL && SUPPORT_CONST_MUL */ -#if SUPPORT_LONG_DIV_POW2 - case ICMD_LDIV: - if (iptr->sx.val.l == 0x00000002) - iptr->sx.val.i = 1; - else if (iptr->sx.val.l == 0x00000004) - iptr->sx.val.i = 2; - else if (iptr->sx.val.l == 0x00000008) - iptr->sx.val.i = 3; - else if (iptr->sx.val.l == 0x00000010) - iptr->sx.val.i = 4; - else if (iptr->sx.val.l == 0x00000020) - iptr->sx.val.i = 5; - else if (iptr->sx.val.l == 0x00000040) - iptr->sx.val.i = 6; - else if (iptr->sx.val.l == 0x00000080) - iptr->sx.val.i = 7; - else if (iptr->sx.val.l == 0x00000100) - iptr->sx.val.i = 8; - else if (iptr->sx.val.l == 0x00000200) - iptr->sx.val.i = 9; - else if (iptr->sx.val.l == 0x00000400) - iptr->sx.val.i = 10; - else if (iptr->sx.val.l == 0x00000800) - iptr->sx.val.i = 11; - else if (iptr->sx.val.l == 0x00001000) - iptr->sx.val.i = 12; - else if (iptr->sx.val.l == 0x00002000) - iptr->sx.val.i = 13; - else if (iptr->sx.val.l == 0x00004000) - iptr->sx.val.i = 14; - else if (iptr->sx.val.l == 0x00008000) - iptr->sx.val.i = 15; - else if (iptr->sx.val.l == 0x00010000) - iptr->sx.val.i = 16; - else if (iptr->sx.val.l == 0x00020000) - iptr->sx.val.i = 17; - else if (iptr->sx.val.l == 0x00040000) - iptr->sx.val.i = 18; - else if (iptr->sx.val.l == 0x00080000) - iptr->sx.val.i = 19; - else if (iptr->sx.val.l == 0x00100000) - iptr->sx.val.i = 20; - else if (iptr->sx.val.l == 0x00200000) - iptr->sx.val.i = 21; - else if (iptr->sx.val.l == 0x00400000) - iptr->sx.val.i = 22; - else if (iptr->sx.val.l == 0x00800000) - iptr->sx.val.i = 23; - else if (iptr->sx.val.l == 0x01000000) - iptr->sx.val.i = 24; - else if (iptr->sx.val.l == 0x02000000) - iptr->sx.val.i = 25; - else if (iptr->sx.val.l == 0x04000000) - iptr->sx.val.i = 26; - else if (iptr->sx.val.l == 0x08000000) - iptr->sx.val.i = 27; - else if (iptr->sx.val.l == 0x10000000) - iptr->sx.val.i = 28; - else if (iptr->sx.val.l == 0x20000000) - iptr->sx.val.i = 29; - else if (iptr->sx.val.l == 0x40000000) - iptr->sx.val.i = 30; - else if (iptr->sx.val.l == 0x80000000) - iptr->sx.val.i = 31; - else { - goto normal_LCONST; - } - iptr->opc = ICMD_LDIVPOW2; - goto icmd_lconst_tail; -#endif /* SUPPORT_LONG_DIV_POW2 */ - -#if SUPPORT_LONG_REM_POW2 - case ICMD_LREM: - if ((iptr->sx.val.l == 0x00000002) || - (iptr->sx.val.l == 0x00000004) || - (iptr->sx.val.l == 0x00000008) || - (iptr->sx.val.l == 0x00000010) || - (iptr->sx.val.l == 0x00000020) || - (iptr->sx.val.l == 0x00000040) || - (iptr->sx.val.l == 0x00000080) || - (iptr->sx.val.l == 0x00000100) || - (iptr->sx.val.l == 0x00000200) || - (iptr->sx.val.l == 0x00000400) || - (iptr->sx.val.l == 0x00000800) || - (iptr->sx.val.l == 0x00001000) || - (iptr->sx.val.l == 0x00002000) || - (iptr->sx.val.l == 0x00004000) || - (iptr->sx.val.l == 0x00008000) || - (iptr->sx.val.l == 0x00010000) || - (iptr->sx.val.l == 0x00020000) || - (iptr->sx.val.l == 0x00040000) || - (iptr->sx.val.l == 0x00080000) || - (iptr->sx.val.l == 0x00100000) || - (iptr->sx.val.l == 0x00200000) || - (iptr->sx.val.l == 0x00400000) || - (iptr->sx.val.l == 0x00800000) || - (iptr->sx.val.l == 0x01000000) || - (iptr->sx.val.l == 0x02000000) || - (iptr->sx.val.l == 0x04000000) || - (iptr->sx.val.l == 0x08000000) || - (iptr->sx.val.l == 0x10000000) || - (iptr->sx.val.l == 0x20000000) || - (iptr->sx.val.l == 0x40000000) || - (iptr->sx.val.l == 0x80000000)) - { - iptr->opc = ICMD_LREMPOW2; - iptr->sx.val.l -= 1; - goto icmd_lconst_tail; - } - goto normal_LCONST; -#endif /* SUPPORT_LONG_REM_POW2 */ - -#if SUPPORT_LONG_LOGICAL && SUPPORT_CONST_LOGICAL - - case ICMD_LAND: - iptr->opc = ICMD_LANDCONST; - goto icmd_lconst_tail; - - case ICMD_LOR: - iptr->opc = ICMD_LORCONST; - goto icmd_lconst_tail; - - case ICMD_LXOR: - iptr->opc = ICMD_LXORCONST; - goto icmd_lconst_tail; -#endif /* SUPPORT_LONG_LOGICAL && SUPPORT_CONST_LOGICAL */ - -#if SUPPORT_LONG_CMP_CONST - case ICMD_LCMP: - if ((len <= 1) || (iptr[2].sx.val.i != 0)) - goto normal_LCONST; - - /* switch on the instruction after LCONST - LCMP */ - - switch (iptr[2].opc) { - case ICMD_IFEQ: - iptr->opc = ICMD_IF_LEQ; - /* FALLTHROUGH */ - - icmd_lconst_lcmp_tail: - /* convert LCONST, LCMP, IFXX to IF_LXX */ - iptr->dst.insindex = iptr[2].dst.insindex; - iptr[1].opc = ICMD_NOP; - iptr[2].opc = ICMD_NOP; - - NEW_OP1_BRANCH(TYPE_LNG); - BRANCH(tbptr, copy); - COUNT(count_pcmd_bra); - COUNT(count_pcmd_op); - break; - - case ICMD_IFNE: - iptr->opc = ICMD_IF_LNE; - goto icmd_lconst_lcmp_tail; - - case ICMD_IFLT: - iptr->opc = ICMD_IF_LLT; - goto icmd_lconst_lcmp_tail; - - case ICMD_IFGT: - iptr->opc = ICMD_IF_LGT; - goto icmd_lconst_lcmp_tail; - - case ICMD_IFLE: - iptr->opc = ICMD_IF_LLE; - goto icmd_lconst_lcmp_tail; - - case ICMD_IFGE: - iptr->opc = ICMD_IF_LGE; - goto icmd_lconst_lcmp_tail; - - default: - goto normal_LCONST; - } /* end switch on opcode after LCONST - LCMP */ - break; -#endif /* SUPPORT_LONG_CMP_CONST */ - -#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; -# endif -#if SIZEOF_VOID_P == 4 - /* the constant must fit into a ptrint */ - if (iptr->sx.val.l < -0x80000000L || iptr->sx.val.l >= 0x80000000L) - goto normal_LCONST; -#endif - /* move the constant to s3 */ - iptr->sx.s23.s3.constval = iptr->sx.val.l; - - iptr->opc = ICMD_LASTORECONST; - NEW_OP2_0(TYPE_ADR, TYPE_INT); - - iptr[1].opc = ICMD_NOP; - COUNT(count_pcmd_op); - break; - - 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; -# endif -#if SIZEOF_VOID_P == 4 - /* the constant must fit into a ptrint */ - if (iptr->sx.val.l < -0x80000000L || iptr->sx.val.l >= 0x80000000L) - goto normal_LCONST; -#endif - /* XXX check field type? */ - - /* copy the constant to s2 */ - /* XXX constval -> fieldconstval? */ - iptr->sx.s23.s2.constval = iptr->sx.val.l; - goto putconst_tail; - -#endif /* SUPPORT_CONST_STORE */ - - default: - goto normal_LCONST; - } /* end switch opcode after LCONST */ +/* stack_create_invars_from_outvars ******************************************** - /* if we get here, the LCONST has been optimized */ - break; + Create the invars for the given basic block. Also make a copy of the locals. + Types are propagated from the outvars of the current block. -normal_LCONST: - /* the normal case of an unoptimized LCONST */ - NEW_OP0_1(TYPE_LNG); - break; + IN: + sd...........stack analysis data + b............block to create the invars for - /************************ END OF LCONST OPTIMIZATIONS *********************/ +*******************************************************************************/ - case ICMD_FCONST: - COUNT(count_pcmd_load); - NEW_OP0_1(TYPE_FLT); - break; +static void stack_create_invars_from_outvars(stackdata_t *sd, basicblock *b) +{ + int i; + int n; + varinfo *sv, *dv; - case ICMD_DCONST: - COUNT(count_pcmd_load); - NEW_OP0_1(TYPE_DBL); - break; + n = sd->bptr->outdepth; + assert(sd->vartop + n <= sd->varcount); - /************************** ACONST OPTIMIZATIONS **************************/ + b->indepth = n; + b->invars = DMNEW(s4, n); - case ICMD_ACONST: - COUNT(count_pcmd_load); -#if SUPPORT_CONST_STORE - IF_INTRP( goto normal_ACONST; ) + if (n) { + dv = sd->var + sd->vartop; - /* We can only optimize if the ACONST is resolved - * and there is an instruction after it. */ + /* allocate the invars */ - if ((len == 0) || (iptr->flags.bits & INS_FLAG_UNRESOLVED)) - goto normal_ACONST; + for (i=0; ivar + sd->bptr->outvars[i]; + b->invars[i] = sd->vartop++; + dv->type = sv->type; + dv->flags = INOUT; + dv->vv = sv->vv; + } + } - switch (iptr[1].opc) { - case ICMD_AASTORE: - /* We can only optimize for NULL values - * here because otherwise a checkcast is - * required. */ - if (iptr->sx.val.anyptr != NULL) - goto normal_ACONST; + /* copy the current state of the local variables */ + /* (one extra local is needed by the verifier) */ - /* copy the constant (NULL) to s3 */ - iptr->sx.s23.s3.constval = 0; - iptr->opc = ICMD_AASTORECONST; - NEW_OP2_0(TYPE_ADR, TYPE_INT); + dv = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS); + b->inlocals = dv; + for (i=0; ilocalcount; ++i) + *dv++ = sd->var[i]; +} - iptr[1].opc = ICMD_NOP; - COUNT(count_pcmd_op); - break; - case ICMD_PUTSTATIC: - case ICMD_PUTFIELD: -# if SUPPORT_CONST_STORE_ZERO_ONLY - if (iptr->sx.val.anyptr != NULL) - goto normal_ACONST; -# endif - /* XXX check field type? */ - /* copy the constant to s2 */ - /* XXX constval -> fieldconstval? */ - iptr->sx.s23.s2.constval = (ptrint) iptr->sx.val.anyptr; +/* stack_check_invars ********************************************************** - goto putconst_tail; + Check the current stack against the invars of the given basic block. + Depth and types must match. - default: - goto normal_ACONST; - } + IN: + sd...........stack analysis data + b............block which invars to check against + curstack.....current stack top + stackdepth...current stack depth - /* if we get here the ACONST has been optimized */ - break; + RETURN VALUE: + the destinaton block + NULL.........a VerifyError has been thrown -normal_ACONST: -#endif /* SUPPORT_CONST_STORE */ - NEW_OP0_1(TYPE_ADR); - break; +*******************************************************************************/ +static basicblock * stack_check_invars(stackdata_t *sd, basicblock *b, + stackptr curstack, int stackdepth) +{ + int i; + stackptr sp; + basicblock *orig; + bool separable; - /* pop 0 push 1 load */ +#if defined(STACK_VERBOSE) + printf("stack_check_invars(L%03d)\n", b->nr); +#endif - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - COUNT(count_load_instruction); - i = opcode - ICMD_ILOAD; - IF_NO_INTRP( rd->locals[iptr->s1.localindex][i].type = i; ) - NEW_LOAD(i, iptr->s1.localindex); - break; + /* find original of b */ + if (b->original) + b = b->original; + orig = b; - /* pop 2 push 1 */ +#if defined(STACK_VERBOSE) + printf("original is L%03d\n", orig->nr); +#endif - case ICMD_LALOAD: - case ICMD_FALOAD: - case ICMD_DALOAD: - case ICMD_AALOAD: - COUNT(count_check_null); - COUNT(count_check_bound); - COUNT(count_pcmd_mem); - NEW_OP2_1(TYPE_ADR, TYPE_INT, opcode - ICMD_IALOAD); - break; + i = orig->indepth; - case ICMD_IALOAD: - case ICMD_BALOAD: - case ICMD_CALOAD: - case ICMD_SALOAD: - COUNT(count_check_null); - COUNT(count_check_bound); - COUNT(count_pcmd_mem); - NEW_OP2_1(TYPE_ADR, TYPE_INT, TYPE_INT); - break; + if (i != stackdepth) { + exceptions_throw_verifyerror(sd->m, "Stack depth mismatch"); + return NULL; + } - /* pop 0 push 0 iinc */ + do { + separable = false; - case ICMD_IINC: - STATISTICS_STACKDEPTH_DISTRIBUTION(count_store_depth); +#if defined(STACK_VERBOSE) + printf("checking against "); + stack_verbose_show_block(sd, b); printf("\n"); +#endif - last_store[5 * iptr->s1.localindex + TYPE_INT] = bptr->icount - len - 1; + 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); + return NULL; + } - copy = curstack; - i = stackdepth - 1; - while (copy) { - if ((copy->varkind == LOCALVAR) && - (copy->varnum == iptr->s1.localindex)) - { - copy->varkind = TEMPVAR; - copy->varnum = i; - } - i--; - copy = copy->prev; - } + if (sp->type == TYPE_RET) { + if (sd->var[b->invars[i]].vv.retaddr != sd->var[sp->varnum].vv.retaddr) { + separable = true; + break; + } + } + } - iptr->dst.localindex = iptr->s1.localindex; + 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) { + separable = true; break; + } + } + } + } - /* pop 1 push 0 store */ - - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - REQUIRE_1; - - i = opcode - ICMD_ISTORE; /* type */ - IF_NO_INTRP( rd->locals[iptr->dst.localindex][i].type = i; ) - -#if defined(ENABLE_STATISTICS) - if (opt_stat) { - count_pcmd_store++; - i = new - curstack; - if (i >= 20) - count_store_length[20]++; - else - count_store_length[i]++; - i = stackdepth - 1; - if (i >= 10) - count_store_depth[10]++; - else - count_store_depth[i]++; - } + if (!separable) { + /* XXX mark mixed type variables void */ + /* XXX cascading collapse? */ +#if defined(STACK_VERBOSE) + printf("------> using L%03d\n", b->nr); #endif - /* check for conflicts as described in Figure 5.2 */ - copy = curstack->prev; - i = stackdepth - 2; - while (copy) { - if ((copy->varkind == LOCALVAR) && - (copy->varnum == iptr->dst.localindex)) - { - copy->varkind = TEMPVAR; - copy->varnum = i; - } - i--; - copy = copy->prev; - } - - if ((curstack->varkind == LOCALVAR) - && (curstack->varnum == iptr->dst.localindex)) - { - curstack->varkind = TEMPVAR; - curstack->varnum = stackdepth-1; - } - - last_store[5 * iptr->dst.localindex + (opcode - ICMD_ISTORE)] = bptr->icount - len - 1; - - NEW_STORE(opcode - ICMD_ISTORE, iptr->dst.localindex); - break; + return b; + } + } while ((b = b->copied_to) != NULL); - /* pop 3 push 0 */ + b = stack_clone_block(sd, orig); + if (!b) + return NULL; - case ICMD_AASTORE: - COUNT(count_check_null); - COUNT(count_check_bound); - COUNT(count_pcmd_mem); + stack_create_invars(sd, b, curstack, stackdepth); + return b; +} - bte = builtintable_get_internal(BUILTIN_canstore); - md = bte->md; - if (md->memuse > rd->memuse) - rd->memuse = md->memuse; - if (md->argintreguse > rd->argintreguse) - rd->argintreguse = md->argintreguse; - /* XXX non-leaf method? */ +/* stack_check_invars_from_outvars ********************************************* - /* make all stack variables saved */ + Check the outvars of the current block against the invars of the given block. + Depth and types must match. - copy = curstack; - while (copy) { - copy->flags |= SAVEDVAR; - copy = copy->prev; - } + IN: + sd...........stack analysis data + b............block which invars to check against - NEW_OP3_0(TYPE_ADR, TYPE_INT, TYPE_ADR); - break; + RETURN VALUE: + the destinaton block + NULL.........a VerifyError has been thrown +*******************************************************************************/ - case ICMD_LASTORE: - case ICMD_FASTORE: - case ICMD_DASTORE: - COUNT(count_check_null); - COUNT(count_check_bound); - COUNT(count_pcmd_mem); - NEW_OP3_0(TYPE_ADR, TYPE_INT, opcode - ICMD_IASTORE); - break; +static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock *b) +{ + int i; + int n; + varinfo *sv, *dv; + basicblock *orig; + bool separable; - case ICMD_IASTORE: - case ICMD_BASTORE: - case ICMD_CASTORE: - case ICMD_SASTORE: - COUNT(count_check_null); - COUNT(count_check_bound); - COUNT(count_pcmd_mem); - NEW_OP3_0(TYPE_ADR, TYPE_INT, TYPE_INT); - break; +#if defined(STACK_VERBOSE) + printf("stack_check_invars_from_outvars(L%03d)\n", b->nr); +#endif - /* pop 1 push 0 */ + /* find original of b */ + if (b->original) + b = b->original; + orig = b; - case ICMD_POP: -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_1; - if (IS_2_WORD_TYPE(curstack->type)) - goto throw_stack_category_error; - } +#if defined(STACK_VERBOSE) + printf("original is L%03d\n", orig->nr); #endif - NEW_OP1_0_ANY; - break; - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: - case ICMD_DRETURN: - case ICMD_ARETURN: - IF_JIT( md_return_alloc(jd, curstack); ) - COUNT(count_pcmd_return); - NEW_OP1_0(opcode - ICMD_IRETURN); - superblockend = true; - break; + i = orig->indepth; + n = sd->bptr->outdepth; - case ICMD_ATHROW: - COUNT(count_check_null); - NEW_OP1_0(TYPE_ADR); - STACKRESET; - superblockend = true; - break; + if (i != n) { + exceptions_throw_verifyerror(sd->m, "Stack depth mismatch"); + return NULL; + } - case ICMD_PUTSTATIC: - COUNT(count_pcmd_mem); - NEW_INSTRUCTION_GET_FIELDREF(iptr, fmiref); - NEW_OP1_0(fmiref->parseddesc.fd->type); - break; + do { + separable = false; - /* pop 1 push 0 branch */ +#if defined(STACK_VERBOSE) + printf("checking against "); + stack_verbose_show_block(sd, b); printf("\n"); +#endif - case ICMD_IFNULL: - case ICMD_IFNONNULL: - COUNT(count_pcmd_bra); - NEW_OP1_BRANCH(TYPE_ADR); - BRANCH(tbptr, copy); - break; + if (n) { + dv = sd->var + b->invars[0]; - case ICMD_IFEQ: - case ICMD_IFNE: - case ICMD_IFLT: - case ICMD_IFGE: - case ICMD_IFGT: - case ICMD_IFLE: - COUNT(count_pcmd_bra); - /* iptr->sx.val.i is set implicitly in parse by - clearing the memory or from IF_ICMPxx - optimization. */ + for (i=0; ivar + sd->bptr->outvars[i]; + if (sv->type != dv->type) { + exceptions_throw_verifyerror_for_stack(sd->m, dv->type); + return NULL; + } - NEW_OP1_BRANCH(TYPE_INT); -/* iptr->sx.val.i = 0; */ - BRANCH(tbptr, copy); + if (dv->type == TYPE_RET) { + if (sv->vv.retaddr != dv->vv.retaddr) { + separable = true; break; + } + } + } + } - /* pop 0 push 0 branch */ - - case ICMD_GOTO: - COUNT(count_pcmd_bra); - NEW_OP0_BRANCH; - BRANCH(tbptr, copy); - superblockend = true; + 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) { + separable = true; break; + } + } + } + } - /* pop 1 push 0 table branch */ + if (!separable) { + /* XXX mark mixed type variables void */ + /* XXX cascading collapse? */ +#if defined(STACK_VERBOSE) + printf("------> using L%03d\n", b->nr); +#endif + return b; + } + } while ((b = b->copied_to) != NULL); - case ICMD_TABLESWITCH: - COUNT(count_pcmd_table); - NEW_OP1_BRANCH(TYPE_INT); + b = stack_clone_block(sd, orig); + if (!b) + return NULL; - table = iptr->dst.table; - BRANCH_TARGET(*table, tbptr, copy); - table++; + stack_create_invars_from_outvars(sd, b); + return b; +} - i = iptr->sx.s23.s3.tablehigh - - iptr->sx.s23.s2.tablelow + 1; - while (--i >= 0) { - BRANCH_TARGET(*table, tbptr, copy); - table++; - } - superblockend = true; - break; +/* stack_create_instack ******************************************************** - /* pop 1 push 0 table branch */ + Create the instack of the current basic block. - case ICMD_LOOKUPSWITCH: - COUNT(count_pcmd_table); - NEW_OP1_BRANCH(TYPE_INT); + IN: + sd...........stack analysis data - BRANCH_TARGET(iptr->sx.s23.s3.lookupdefault, tbptr, copy); + RETURN VALUE: + the current stack top at the start of the basic block. - lookup = iptr->dst.lookup; +*******************************************************************************/ - i = iptr->sx.s23.s2.lookupcount; +static stackptr stack_create_instack(stackdata_t *sd) +{ + stackptr sp; + int depth; + int index; + + if ((depth = sd->bptr->indepth) == 0) + return NULL; + + sp = (sd->new += depth); + + while (depth--) { + sp--; + index = sd->bptr->invars[depth]; + sp->varnum = index; + sp->type = sd->var[index].type; + sp->prev = sp - 1; + sp->creator = NULL; + sp->flags = 0; + sp->varkind = STACKVAR; + } + sp->prev = NULL; - while (--i >= 0) { - BRANCH_TARGET(lookup->target, tbptr, copy); - lookup++; - } - superblockend = true; - break; + /* return the top of the created stack */ + return sd->new - 1; +} - case ICMD_MONITORENTER: - case ICMD_MONITOREXIT: - COUNT(count_check_null); - NEW_OP1_0(TYPE_ADR); - break; - /* pop 2 push 0 branch */ +/* stack_mark_reached ********************************************************** - case ICMD_IF_ICMPEQ: - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: - COUNT(count_pcmd_bra); - NEW_OP2_BRANCH(TYPE_INT, TYPE_INT); - BRANCH(tbptr, copy); - break; + Mark the given block reached and propagate the current stack and locals to + it. This function specializes the target block, if necessary, and returns + a pointer to the specialized target. - case ICMD_IF_ACMPEQ: - case ICMD_IF_ACMPNE: - COUNT(count_pcmd_bra); - NEW_OP2_BRANCH(TYPE_ADR, TYPE_ADR); - BRANCH(tbptr, copy); - break; + IN: + sd...........stack analysis data + b............the block to reach + curstack.....the current stack top + stackdepth...the current stack depth - /* pop 2 push 0 */ + RETURN VALUE: + a pointer to (a specialized version of) the target + NULL.........a VerifyError has been thrown - case ICMD_PUTFIELD: - COUNT(count_check_null); - COUNT(count_pcmd_mem); - NEW_INSTRUCTION_GET_FIELDREF(iptr, fmiref); - NEW_OP2_0(TYPE_ADR, fmiref->parseddesc.fd->type); - break; +*******************************************************************************/ - case ICMD_POP2: - REQUIRE_1; - if (!IS_2_WORD_TYPE(curstack->type)) { - /* ..., cat1 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } +static basicblock *stack_mark_reached(stackdata_t *sd, basicblock *b, stackptr curstack, int stackdepth) +{ +#if defined(STACK_VERBOSE) + printf("stack_mark_reached(L%03d from L%03d)\n", b->nr, sd->bptr->nr); #endif - NEW_OP2_0_ANY_ANY; /* pop two slots */ - } - else { - iptr->opc = ICMD_POP; - NEW_OP1_0_ANY; /* pop one (two-word) slot */ - } - break; + /* mark targets of backward branches */ + if (b <= sd->bptr) + b->bitflags |= BBFLAG_REPLACEMENT; - /* pop 0 push 1 dup */ + if (b->flags < BBREACHED) { + /* b is reached for the first time. Create its invars. */ - case ICMD_DUP: -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_1; - if (IS_2_WORD_TYPE(curstack->type)) - goto throw_stack_category_error; - } +#if defined(STACK_VERBOSE) + printf("reached L%03d for the first time\n", b->nr); #endif - last_dupx = bptr->icount - len - 1; - COUNT(count_dup_instruction); -icmd_DUP: - USE_S1_ANY; /* XXX live through */ - DUP_SLOT(iptr->s1.var); - iptr->dst.var = curstack; - stackdepth++; - break; + stack_create_invars(sd, b, curstack, stackdepth); - case ICMD_DUP2: - last_dupx = bptr->icount - len - 1; - REQUIRE_1; - if (IS_2_WORD_TYPE(curstack->type)) { - /* ..., cat2 */ - iptr->opc = ICMD_DUP; - goto icmd_DUP; - } - else { - REQUIRE_2; - /* ..., ????, cat1 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } -#endif - iptr->dst.dupslots = DMNEW(stackptr, 2 + 2); - iptr->dst.dupslots[0] = curstack->prev; /* XXX live through */ - iptr->dst.dupslots[1] = curstack; /* XXX live through */ - - DUP_SLOT(iptr->dst.dupslots[0]); - iptr->dst.dupslots[2+0] = curstack; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[2+1] = curstack; - stackdepth += 2; - } - break; + b->flags = BBREACHED; - /* pop 2 push 3 dup */ + return b; + } + else { + /* b has been reached before. Check that its invars match. */ - case ICMD_DUP_X1: -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->type) || - IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } -#endif - last_dupx = bptr->icount - len - 1; + return stack_check_invars(sd, b, curstack, stackdepth); + } +} -icmd_DUP_X1: - iptr->dst.dupslots = DMNEW(stackptr, 2 + 3); - iptr->dst.dupslots[0] = curstack->prev; - iptr->dst.dupslots[1] = curstack; - POPANY; POPANY; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[2+0] = curstack; - DUP_SLOT(iptr->dst.dupslots[0]); - iptr->dst.dupslots[2+1] = curstack; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[2+2] = curstack; - stackdepth++; - break; +/* stack_mark_reached_from_outvars ********************************************* - case ICMD_DUP2_X1: - last_dupx = bptr->icount - len - 1; - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->type)) { - /* ..., ????, cat2 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } -#endif - iptr->opc = ICMD_DUP_X1; - goto icmd_DUP_X1; - } - else { - /* ..., ????, cat1 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_3; - if (IS_2_WORD_TYPE(curstack->prev->type) - || IS_2_WORD_TYPE(curstack->prev->prev->type)) - goto throw_stack_category_error; - } -#endif + Mark the given 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. -icmd_DUP2_X1: - iptr->dst.dupslots = DMNEW(stackptr, 3 + 5); - iptr->dst.dupslots[0] = curstack->prev->prev; - iptr->dst.dupslots[1] = curstack->prev; - iptr->dst.dupslots[2] = curstack; - POPANY; POPANY; POPANY; + IN: + sd...........stack analysis data + b............the block to reach - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[3+0] = curstack; - DUP_SLOT(iptr->dst.dupslots[2]); - iptr->dst.dupslots[3+1] = curstack; - DUP_SLOT(iptr->dst.dupslots[0]); - iptr->dst.dupslots[3+2] = curstack; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[3+3] = curstack; - DUP_SLOT(iptr->dst.dupslots[2]); - iptr->dst.dupslots[3+4] = curstack; - stackdepth += 2; - } - break; + RETURN VALUE: + a pointer to (a specialized version of) the target + NULL.........a VerifyError has been thrown - /* pop 3 push 4 dup */ +*******************************************************************************/ - case ICMD_DUP_X2: - last_dupx = bptr->icount - len - 1; - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->prev->type)) { - /* ..., cat2, ???? */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->type)) - goto throw_stack_category_error; - } -#endif - iptr->opc = ICMD_DUP_X1; - goto icmd_DUP_X1; - } - else { - /* ..., cat1, ???? */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_3; - if (IS_2_WORD_TYPE(curstack->type) - || IS_2_WORD_TYPE(curstack->prev->prev->type)) - goto throw_stack_category_error; - } +static basicblock *stack_mark_reached_from_outvars(stackdata_t *sd, basicblock *b) +{ +#if defined(STACK_VERBOSE) + printf("stack_mark_reached_from_outvars(L%03d from L%03d)\n", b->nr, sd->bptr->nr); #endif -icmd_DUP_X2: - iptr->dst.dupslots = DMNEW(stackptr, 3 + 4); - iptr->dst.dupslots[0] = curstack->prev->prev; - iptr->dst.dupslots[1] = curstack->prev; - iptr->dst.dupslots[2] = curstack; - POPANY; POPANY; POPANY; + /* mark targets of backward branches */ + if (b <= sd->bptr) + b->bitflags |= BBFLAG_REPLACEMENT; - DUP_SLOT(iptr->dst.dupslots[2]); - iptr->dst.dupslots[3+0] = curstack; - DUP_SLOT(iptr->dst.dupslots[0]); - iptr->dst.dupslots[3+1] = curstack; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[3+2] = curstack; - DUP_SLOT(iptr->dst.dupslots[2]); - iptr->dst.dupslots[3+3] = curstack; - stackdepth++; - } - break; + if (b->flags < BBREACHED) { + /* b is reached for the first time. Create its invars. */ - case ICMD_DUP2_X2: - last_dupx = bptr->icount - len - 1; - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->type)) { - /* ..., ????, cat2 */ - if (IS_2_WORD_TYPE(curstack->prev->type)) { - /* ..., cat2, cat2 */ - iptr->opc = ICMD_DUP_X1; - goto icmd_DUP_X1; - } - else { - /* ..., cat1, cat2 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_3; - if (IS_2_WORD_TYPE(curstack->prev->prev->type)) - goto throw_stack_category_error; - } +#if defined(STACK_VERBOSE) + printf("reached L%03d for the first time\n", b->nr); #endif - iptr->opc = ICMD_DUP_X2; - goto icmd_DUP_X2; - } - } - REQUIRE_3; - /* ..., ????, ????, cat1 */ + stack_create_invars_from_outvars(sd, b); - if (IS_2_WORD_TYPE(curstack->prev->prev->type)) { - /* ..., cat2, ????, cat1 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } -#endif - iptr->opc = ICMD_DUP2_X1; - goto icmd_DUP2_X1; - } - else { - /* ..., cat1, ????, cat1 */ -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_4; - if (IS_2_WORD_TYPE(curstack->prev->type) - || IS_2_WORD_TYPE(curstack->prev->prev->prev->type)) - goto throw_stack_category_error; - } + b->flags = BBREACHED; + + return b; + } + else { + /* b has been reached before. Check that its invars match. */ + + return stack_check_invars_from_outvars(sd, b); + } +} + + +/* 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. + + IN: + sd...........stack analysis data + + RETURN VALUE: + a pointer to (a specialized version of) the following block + NULL.........a VerifyError has been thrown + +*******************************************************************************/ + +static bool stack_reach_next_block(stackdata_t *sd) +{ + basicblock *tbptr; + instruction *iptr; + + tbptr = (sd->bptr->original) ? sd->bptr->original : sd->bptr; + tbptr = stack_mark_reached_from_outvars(sd, tbptr->next); + if (!tbptr) + return false; + + if (tbptr != sd->bptr->next) { +#if defined(STACK_VERBOSE) + printf("NEXT IS NON-CONSEQUITIVE L%03d\n", tbptr->nr); #endif - iptr->dst.dupslots = DMNEW(stackptr, 4 + 6); - iptr->dst.dupslots[0] = curstack->prev->prev->prev; - iptr->dst.dupslots[1] = curstack->prev->prev; - iptr->dst.dupslots[2] = curstack->prev; - iptr->dst.dupslots[3] = curstack; - POPANY; POPANY; POPANY; POPANY; + iptr = sd->bptr->iinstr + sd->bptr->icount - 1; + assert(iptr->opc == ICMD_NOP); + iptr->opc = ICMD_GOTO; + iptr->dst.block = tbptr; - DUP_SLOT(iptr->dst.dupslots[2]); - iptr->dst.dupslots[4+0] = curstack; - DUP_SLOT(iptr->dst.dupslots[3]); - iptr->dst.dupslots[4+1] = curstack; - DUP_SLOT(iptr->dst.dupslots[0]); - iptr->dst.dupslots[4+2] = curstack; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[4+3] = curstack; - DUP_SLOT(iptr->dst.dupslots[2]); - iptr->dst.dupslots[4+4] = curstack; - DUP_SLOT(iptr->dst.dupslots[3]); - iptr->dst.dupslots[4+5] = curstack; - stackdepth += 2; - } - break; + if (tbptr->flags < BBFINISHED) + sd->repeat = true; /* XXX check if we really need to repeat */ + } - /* pop 2 push 2 swap */ + return true; +} - case ICMD_SWAP: - last_dupx = bptr->icount - len - 1; -#ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->type) - || IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } -#endif - iptr->dst.dupslots = DMNEW(stackptr, 2 + 2); - iptr->dst.dupslots[0] = curstack->prev; - iptr->dst.dupslots[1] = curstack; - POPANY; POPANY; - DUP_SLOT(iptr->dst.dupslots[1]); - iptr->dst.dupslots[2+0] = curstack; - DUP_SLOT(iptr->dst.dupslots[0]); - iptr->dst.dupslots[2+1] = curstack; - break; +/* stack_reach_handlers ******************************************************** - /* pop 2 push 1 */ + Reach the exception handlers for the current block. - case ICMD_IDIV: - case ICMD_IREM: -#if !SUPPORT_DIVISION - bte = iptr->sx.s23.s3.bte; - md = bte->md; + IN: + sd...........stack analysis data - if (md->memuse > rd->memuse) - rd->memuse = md->memuse; - if (md->argintreguse > rd->argintreguse) - rd->argintreguse = md->argintreguse; + RETURN VALUE: + true.........everything ok + false........a VerifyError has been thrown - /* make all stack variables saved */ +*******************************************************************************/ - copy = curstack; - while (copy) { - copy->flags |= SAVEDVAR; - copy = copy->prev; - } - /* FALLTHROUGH */ +static bool stack_reach_handlers(stackdata_t *sd) +{ + s4 i; + basicblock *tbptr; -#endif /* !SUPPORT_DIVISION */ +#if defined(STACK_VERBOSE) + printf("reaching exception handlers...\n"); +#endif - case ICMD_ISHL: - case ICMD_ISHR: - case ICMD_IUSHR: - case ICMD_IADD: - case ICMD_ISUB: - case ICMD_IMUL: - case ICMD_IAND: - case ICMD_IOR: - case ICMD_IXOR: - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_INT, TYPE_INT, TYPE_INT); - break; + for (i=0; sd->handlers[i]; ++i) { + tbptr = sd->handlers[i]->handler; - case ICMD_LDIV: - case ICMD_LREM: -#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) - bte = iptr->sx.s23.s3.bte; - md = bte->md; + tbptr->type = BBTYPE_EXH; + tbptr->predecessorcount = CFG_UNKNOWN_PREDECESSORS; - if (md->memuse > rd->memuse) - rd->memuse = md->memuse; - if (md->argintreguse > rd->argintreguse) - rd->argintreguse = md->argintreguse; - /* XXX non-leaf method? */ + /* reach (and specialize) the handler block */ - /* make all stack variables saved */ + tbptr = stack_mark_reached(sd, tbptr, &(sd->exstack), 1); - copy = curstack; - while (copy) { - copy->flags |= SAVEDVAR; - copy = copy->prev; - } - /* FALLTHROUGH */ + if (tbptr == NULL) + return false; -#endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */ + sd->handlers[i]->handler = tbptr; + } - case ICMD_LMUL: - case ICMD_LADD: - case ICMD_LSUB: -#if SUPPORT_LONG_LOGICAL - case ICMD_LAND: - case ICMD_LOR: - case ICMD_LXOR: -#endif /* SUPPORT_LONG_LOGICAL */ - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_LNG, TYPE_LNG, TYPE_LNG); - break; + return true; +} - case ICMD_LSHL: - case ICMD_LSHR: - case ICMD_LUSHR: - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_LNG, TYPE_INT, TYPE_LNG); - break; - case ICMD_FADD: - case ICMD_FSUB: - case ICMD_FMUL: - case ICMD_FDIV: - case ICMD_FREM: - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_FLT, TYPE_FLT, TYPE_FLT); - break; +/* stack_reanalyse_block ****************************************************** - case ICMD_DADD: - case ICMD_DSUB: - case ICMD_DMUL: - case ICMD_DDIV: - case ICMD_DREM: - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_DBL, TYPE_DBL, TYPE_DBL); - break; + Re-analyse the current block. This is called if either the block itself + has already been analysed before, or the current block is a clone of an + already analysed block, and this clone is reached for the first time. + In the latter case, this function does all that is necessary for fully + cloning the block (cloning the instruction list and variables, etc.). - case ICMD_LCMP: - COUNT(count_pcmd_op); -#if SUPPORT_LONG_CMP_CONST - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_LCMP; + IN: + sd...........stack analysis data - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr->opc = ICMD_IF_LCMPEQ; - icmd_lcmp_if_tail: - iptr->dst.insindex = iptr[1].dst.insindex; - iptr[1].opc = ICMD_NOP; + RETURN VALUE: + true.........everything ok + false........a VerifyError has been thrown - NEW_OP2_BRANCH(TYPE_LNG, TYPE_LNG); - BRANCH(tbptr, copy); +*******************************************************************************/ - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr->opc = ICMD_IF_LCMPNE; - goto icmd_lcmp_if_tail; - case ICMD_IFLT: - iptr->opc = ICMD_IF_LCMPLT; - goto icmd_lcmp_if_tail; - case ICMD_IFGT: - iptr->opc = ICMD_IF_LCMPGT; - goto icmd_lcmp_if_tail; - case ICMD_IFLE: - iptr->opc = ICMD_IF_LCMPLE; - goto icmd_lcmp_if_tail; - case ICMD_IFGE: - iptr->opc = ICMD_IF_LCMPGE; - goto icmd_lcmp_if_tail; - default: - goto normal_LCMP; - } - break; -normal_LCMP: -#endif /* SUPPORT_LONG_CMP_CONST */ - NEW_OP2_1(TYPE_LNG, TYPE_LNG, TYPE_INT); - break; +#define RELOCATE(index) \ + do { \ + if ((index) >= blockvarstart) \ + (index) += blockvarshift; \ + else if ((index) >= invarstart) \ + (index) += invarshift; \ + } while (0) - /* 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; +bool stack_reanalyse_block(stackdata_t *sd) +{ + instruction *iptr; + basicblock *b; + basicblock *orig; + s4 len; + s4 invarstart; + s4 blockvarstart; + s4 invarshift; + s4 blockvarshift; + s4 i, j; + s4 *argp; + branch_target_t *table; + lookup_target_t *lookup; + bool superblockend; + bool maythrow; + bool cloneinstructions; + exceptiontable *ex; - 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; +#if defined(STACK_VERBOSE) + stack_verbose_block_enter(sd, true); +#endif - NEW_OP2_BRANCH(TYPE_FLT, TYPE_FLT); - BRANCH(tbptr, copy); + b = sd->bptr; - 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; + if (!b->iinstr) { + orig = b->original; + assert(orig != NULL); -normal_FCMPL: - OPTT2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); - break; + /* clone the instruction list */ - case ICMD_FCMPG: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_FCMPG; + cloneinstructions = true; - 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; + assert(orig->iinstr); + len = orig->icount; + iptr = DMNEW(instruction, len + 1); - NEW_OP2_BRANCH(TYPE_FLT, TYPE_FLT); - BRANCH(tbptr, copy); + MCOPY(iptr, orig->iinstr, instruction, len); + iptr[len].opc = ICMD_NOP; + b->iinstr = iptr; + b->icount = ++len; - 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; + /* allocate space for the clone's block variables */ -normal_FCMPG: - NEW_OP2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); - break; + stack_grow_variable_array(sd, orig->varcount); - case ICMD_DCMPL: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_DCMPL; + /* we already have the invars set */ - 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; + assert(b->indepth == orig->indepth); - NEW_OP2_BRANCH(TYPE_DBL, TYPE_DBL); - BRANCH(tbptr, copy); + /* calculate relocation shifts for invars and block variables */ - 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; + if (orig->indepth) { + invarstart = orig->invars[0]; + invarshift = b->invars[0] - invarstart; + } + else { + invarstart = INT_MAX; + invarshift = 0; + } + blockvarstart = orig->varstart; + blockvarshift = sd->vartop - blockvarstart; -normal_DCMPL: - OPTT2_1(TYPE_DBL, TYPE_INT); - break; + /* copy block variables */ - case ICMD_DCMPG: - COUNT(count_pcmd_op); - if ((len == 0) || (iptr[1].sx.val.i != 0)) - goto normal_DCMPG; + b->varstart = sd->vartop; + b->varcount = orig->varcount; + sd->vartop += b->varcount; + MCOPY(sd->var + b->varstart, sd->var + orig->varstart, varinfo, b->varcount); + + /* copy outvars */ + + b->outdepth = orig->outdepth; + b->outvars = DMNEW(s4, orig->outdepth); + MCOPY(b->outvars, orig->outvars, s4, orig->outdepth); - 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; + /* clone exception handlers */ - NEW_OP2_BRANCH(TYPE_DBL, TYPE_DBL); - BRANCH(tbptr, copy); + for (i=0; sd->handlers[i]; ++i) { + ex = DNEW(exceptiontable); + ex->handler = sd->handlers[i]->handler; + ex->start = b; + ex->end = b; /* XXX hack, see end of stack_analyse */ + ex->catchtype = sd->handlers[i]->catchtype; + ex->down = NULL; - 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; + assert(sd->extableend->down == NULL); + sd->extableend->down = ex; + sd->extableend = ex; + sd->jd->cd->exceptiontablelength++; -normal_DCMPG: - NEW_OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); - break; -#else - case ICMD_FCMPL: - case ICMD_FCMPG: - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); - break; + sd->handlers[i] = ex; + } + } + else { + cloneinstructions = false; + invarshift = 0; + blockvarshift = 0; + invarstart = sd->vartop; + blockvarstart = sd->vartop; + iptr = b->iinstr; + } - case ICMD_DCMPL: - case ICMD_DCMPG: - COUNT(count_pcmd_op); - NEW_OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); - break; + if (b->original) { + /* find exception handlers for the cloned block */ + len = 0; + ex = sd->jd->cd->exceptiontable; + for (; ex != NULL; ex = ex->down) { + /* XXX the cloned exception handlers have identical */ + /* start end end blocks. */ + if ((ex->start == b) && (ex->end == b)) { + sd->handlers[len++] = ex; + } + } + sd->handlers[len] = NULL; + } + +#if defined(STACK_VERBOSE) + printf("invarstart = %d, blockvarstart = %d\n", invarstart, blockvarstart); + printf("invarshift = %d, blockvarshift = %d\n", invarshift, blockvarshift); #endif - /* pop 1 push 1 */ + /* mark block as finished */ - case ICMD_INEG: - case ICMD_INT2BYTE: - case ICMD_INT2CHAR: - case ICMD_INT2SHORT: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_INT, TYPE_INT); - break; - case ICMD_LNEG: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_LNG, TYPE_LNG); - break; - case ICMD_FNEG: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_FLT, TYPE_FLT); - break; - case ICMD_DNEG: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_DBL, TYPE_DBL); - break; + b->flags = BBFINISHED; - case ICMD_I2L: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_INT, TYPE_LNG); - break; - case ICMD_I2F: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_INT, TYPE_FLT); - break; - case ICMD_I2D: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_INT, TYPE_DBL); - break; - case ICMD_L2I: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_LNG, TYPE_INT); - break; - case ICMD_L2F: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_LNG, TYPE_FLT); - break; - case ICMD_L2D: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_LNG, TYPE_DBL); - break; - case ICMD_F2I: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_FLT, TYPE_INT); - break; - case ICMD_F2L: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_FLT, TYPE_LNG); - break; - case ICMD_F2D: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_FLT, TYPE_DBL); - break; - case ICMD_D2I: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_DBL, TYPE_INT); - break; - case ICMD_D2L: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_DBL, TYPE_LNG); - break; - case ICMD_D2F: - COUNT(count_pcmd_op); - NEW_OP1_1(TYPE_DBL, TYPE_FLT); - break; + /* initialize locals at the start of this block */ - case ICMD_CHECKCAST: - if (iptr->flags.bits & INS_FLAG_ARRAY) { - /* array type cast-check */ + if (b->inlocals) + MCOPY(sd->var, b->inlocals, varinfo, sd->localcount); - bte = builtintable_get_internal(BUILTIN_arraycheckcast); - md = bte->md; + /* reach exception handlers for this block */ - if (md->memuse > rd->memuse) - rd->memuse = md->memuse; - if (md->argintreguse > rd->argintreguse) - rd->argintreguse = md->argintreguse; + if (!stack_reach_handlers(sd)) + return false; - /* make all stack variables saved */ + superblockend = false; - copy = curstack; - while (copy) { - copy->flags |= SAVEDVAR; - copy = copy->prev; - } - } - NEW_OP1_1(TYPE_ADR, TYPE_ADR); - break; + for (len = b->icount; len--; iptr++) { +#if defined(STACK_VERBOSE) + show_icmd(sd->jd, iptr, false, SHOW_STACK); + printf("\n"); +#endif - case ICMD_INSTANCEOF: - case ICMD_ARRAYLENGTH: - NEW_OP1_1(TYPE_ADR, TYPE_INT); - break; + maythrow = false; - case ICMD_NEWARRAY: - case ICMD_ANEWARRAY: - NEW_OP1_1(TYPE_INT, TYPE_ADR); - break; + switch (iptr->opc) { + case ICMD_RET: + j = iptr->s1.varindex; - case ICMD_GETFIELD: - COUNT(count_check_null); - COUNT(count_pcmd_mem); - NEW_INSTRUCTION_GET_FIELDREF(iptr, fmiref); - NEW_OP1_1(TYPE_ADR, fmiref->parseddesc.fd->type); - break; + if (sd->var[j].type != TYPE_RET) { + exceptions_throw_verifyerror(sd->m, "RET with non-returnAddress value"); + return false; + } - /* pop 0 push 1 */ + iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[j].vv.retaddr); + superblockend = true; + break; - case ICMD_GETSTATIC: - COUNT(count_pcmd_mem); - NEW_INSTRUCTION_GET_FIELDREF(iptr, fmiref); - NEW_OP0_1(fmiref->parseddesc.fd->type); - break; + case ICMD_JSR: + iptr->sx.s23.s3.jsrtarget.block = stack_mark_reached_from_outvars(sd, iptr->sx.s23.s3.jsrtarget.block); + superblockend = true; + break; - case ICMD_NEW: - NEW_OP0_1(TYPE_ADR); - break; + case ICMD_RETURN: + superblockend = true; + break; - case ICMD_JSR: - NEW_OP0_1(TYPE_ADR); + case ICMD_CHECKNULL: + case ICMD_PUTSTATICCONST: + maythrow = true; + break; - BRANCH_TARGET(iptr->sx.s23.s3.jsrtarget, tbptr, copy); + case ICMD_NOP: + case ICMD_IINC: + case ICMD_INLINE_START: + case ICMD_INLINE_END: + case ICMD_INLINE_GOTO: + break; - tbptr->type = BBTYPE_SBR; + case ICMD_GOTO: + iptr->dst.block = stack_mark_reached_from_outvars(sd, iptr->dst.block); + superblockend = true; + break; - /* We need to check for overflow right here because - * the pushed value is poped afterwards */ - NEW_CHECKOVERFLOW; + /* pop 0 push 1 const */ - /* calculate stack after return */ - POPANY; - stackdepth--; - break; + case ICMD_ACONST: + maythrow = true; + case ICMD_ICONST: + case ICMD_LCONST: + case ICMD_FCONST: + case ICMD_DCONST: - /* pop many push any */ + /* pop 0 push 1 load */ - case ICMD_BUILTIN: -#if defined(USEBUILTINTABLE) -icmd_BUILTIN: -#endif - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto _callhandling; + case ICMD_ILOAD: + case ICMD_LLOAD: + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ALOAD: + RELOCATE(iptr->dst.varindex); + break; - case ICMD_INVOKESTATIC: - case ICMD_INVOKESPECIAL: - case ICMD_INVOKEVIRTUAL: - case ICMD_INVOKEINTERFACE: - COUNT(count_pcmd_met); - NEW_INSTRUCTION_GET_METHODDESC(iptr, md); - /* XXX resurrect this COUNT? */ -/* if (lm->flags & ACC_STATIC) */ -/* {COUNT(count_check_null);} */ + /* pop 2 push 1 */ + + case ICMD_IALOAD: + case ICMD_LALOAD: + case ICMD_FALOAD: + case ICMD_DALOAD: + case ICMD_AALOAD: + case ICMD_BALOAD: + case ICMD_CALOAD: + case ICMD_SALOAD: + RELOCATE(iptr->sx.s23.s2.varindex); + RELOCATE(iptr->s1.varindex); + RELOCATE(iptr->dst.varindex); + maythrow = true; + break; - _callhandling: + /* pop 3 push 0 */ + + case ICMD_IASTORE: + case ICMD_LASTORE: + case ICMD_FASTORE: + case ICMD_DASTORE: + case ICMD_AASTORE: + case ICMD_BASTORE: + case ICMD_CASTORE: + case ICMD_SASTORE: + RELOCATE(iptr->sx.s23.s3.varindex); + RELOCATE(iptr->sx.s23.s2.varindex); + RELOCATE(iptr->s1.varindex); + maythrow = true; + break; - last_pei = bptr->icount - len - 1; + /* pop 1 push 0 store */ - i = md->paramcount; + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + RELOCATE(iptr->s1.varindex); - if (md->memuse > rd->memuse) - rd->memuse = md->memuse; - if (md->argintreguse > rd->argintreguse) - rd->argintreguse = md->argintreguse; - if (md->argfltreguse > rd->argfltreguse) - rd->argfltreguse = md->argfltreguse; + j = iptr->dst.varindex; + COPY_VAL_AND_TYPE(*sd, iptr->s1.varindex, j); + break; - REQUIRE(i); + /* pop 1 push 0 */ - /* XXX optimize for <= 2 args */ - iptr->s1.argcount = i; - iptr->sx.s23.s2.args = DMNEW(stackptr, i); + case ICMD_ARETURN: + case ICMD_ATHROW: + maythrow = true; + case ICMD_IRETURN: + case ICMD_LRETURN: + case ICMD_FRETURN: + case ICMD_DRETURN: + RELOCATE(iptr->s1.varindex); + superblockend = true; + break; - copy = curstack; - for (i-- ; i >= 0; i--) { - iptr->sx.s23.s2.args[i] = copy; + case ICMD_PUTSTATIC: + case ICMD_PUTFIELDCONST: + maythrow = true; + case ICMD_POP: + RELOCATE(iptr->s1.varindex); + break; -#if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) - /* If we pass float arguments in integer argument registers, we - * are not allowed to precolor them here. Floats have to be moved - * to this regs explicitly in codegen(). - * Only arguments that are passed by stack anyway can be precolored - * (michi 2005/07/24) */ - if (!(copy->flags & SAVEDVAR) && - (!IS_FLT_DBL_TYPE(copy->type) || md->params[i].inmemory)) { -#else - if (!(copy->flags & SAVEDVAR)) { -#endif - copy->varkind = ARGVAR; - copy->varnum = i; + /* pop 1 push 0 branch */ -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif - if (md->params[i].inmemory) { - copy->flags = INMEMORY; - copy->regoff = md->params[i].regoff; - } - else { - copy->flags = 0; - if (IS_FLT_DBL_TYPE(copy->type)) { -#if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) - assert(0); /* XXX is this assert ok? */ -#else - copy->regoff = - rd->argfltregs[md->params[i].regoff]; -#endif /* SUPPORT_PASS_FLOATARGS_IN_INTREGS */ - } - else { -#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(copy->type)) - copy->regoff = PACK_REGS( - rd->argintregs[GET_LOW_REG(md->params[i].regoff)], - rd->argintregs[GET_HIGH_REG(md->params[i].regoff)]); - else -#endif /* SUPPORT_COMBINE_INTEGER_REGISTERS */ - copy->regoff = - rd->argintregs[md->params[i].regoff]; - } - } -#if defined(ENABLE_INTRP) - } /* end if (!opt_intrp) */ -#endif - } - copy = copy->prev; - } + case ICMD_IFNULL: + case ICMD_IFNONNULL: - while (copy) { - copy->flags |= SAVEDVAR; - copy = copy->prev; - } + case ICMD_IFEQ: + case ICMD_IFNE: + case ICMD_IFLT: + case ICMD_IFGE: + case ICMD_IFGT: + case ICMD_IFLE: - i = md->paramcount; + case ICMD_IF_LEQ: + case ICMD_IF_LNE: + case ICMD_IF_LLT: + case ICMD_IF_LGE: + case ICMD_IF_LGT: + case ICMD_IF_LLE: + RELOCATE(iptr->s1.varindex); + iptr->dst.block = stack_mark_reached_from_outvars(sd, iptr->dst.block); + break; - stackdepth -= i; - while (--i >= 0) { - POPANY; - } + /* pop 1 push 0 table branch */ - if (md->returntype.type != TYPE_VOID) { - NEW_DST(md->returntype.type, stackdepth); - stackdepth++; - } - break; + case ICMD_TABLESWITCH: + i = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1 + 1; - case ICMD_INLINE_START: - case ICMD_INLINE_END: - CLR_S1; - CLR_DST; - break; + if (cloneinstructions) { + table = DMNEW(branch_target_t, i); + MCOPY(table, iptr->dst.table, branch_target_t, i); + iptr->dst.table = table; + } + else { + table = iptr->dst.table; + } + + RELOCATE(iptr->s1.varindex); + while (i--) { + table->block = stack_mark_reached_from_outvars(sd, table->block); + table++; + } + superblockend = true; + break; + + case ICMD_LOOKUPSWITCH: + i = iptr->sx.s23.s2.lookupcount; + if (cloneinstructions) { + lookup = DMNEW(lookup_target_t, i); + MCOPY(lookup, iptr->dst.lookup, lookup_target_t, i); + iptr->dst.lookup = lookup; + } + else { + lookup = iptr->dst.lookup; + } + RELOCATE(iptr->s1.varindex); + while (i--) { + lookup->target.block = stack_mark_reached_from_outvars(sd, lookup->target.block); + lookup++; + } + iptr->sx.s23.s3.lookupdefault.block = stack_mark_reached_from_outvars(sd, iptr->sx.s23.s3.lookupdefault.block); + superblockend = true; + break; + + case ICMD_MONITORENTER: + case ICMD_MONITOREXIT: + RELOCATE(iptr->s1.varindex); + maythrow = true; + break; - case ICMD_MULTIANEWARRAY: - if (rd->argintreguse < 3) - rd->argintreguse = 3; + /* pop 2 push 0 branch */ - i = iptr->s1.argcount; + case ICMD_IF_ICMPEQ: + case ICMD_IF_ICMPNE: + case ICMD_IF_ICMPLT: + case ICMD_IF_ICMPGE: + case ICMD_IF_ICMPGT: + case ICMD_IF_ICMPLE: - REQUIRE(i); + case ICMD_IF_LCMPEQ: + case ICMD_IF_LCMPNE: + case ICMD_IF_LCMPLT: + case ICMD_IF_LCMPGE: + case ICMD_IF_LCMPGT: + case ICMD_IF_LCMPLE: - iptr->sx.s23.s2.args = DMNEW(stackptr, i); + case ICMD_IF_FCMPEQ: + case ICMD_IF_FCMPNE: -#if defined(SPECIALMEMUSE) -# if defined(__DARWIN__) - if (rd->memuse < (i + INT_ARG_CNT + LA_WORD_SIZE)) - rd->memuse = i + LA_WORD_SIZE + INT_ARG_CNT; -# else - if (rd->memuse < (i + LA_WORD_SIZE + 3)) - rd->memuse = i + LA_WORD_SIZE + 3; -# endif -#else -# if defined(__I386__) - if (rd->memuse < i + 3) - rd->memuse = i + 3; /* n integer args spilled on stack */ -# elif defined(__MIPS__) && SIZEOF_VOID_P == 4 - if (rd->memuse < i + 2) - rd->memuse = i + 2; /* 4*4 bytes callee save space */ -# else - if (rd->memuse < i) - rd->memuse = i; /* n integer args spilled on stack */ -# endif /* defined(__I386__) */ -#endif - copy = curstack; - while (--i >= 0) { - /* check INT type here? Currently typecheck does this. */ - iptr->sx.s23.s2.args[i] = copy; - if (!(copy->flags & SAVEDVAR)) { - copy->varkind = ARGVAR; - copy->varnum = i + INT_ARG_CNT; - copy->flags |= INMEMORY; -#if defined(SPECIALMEMUSE) -# if defined(__DARWIN__) - copy->regoff = i + LA_WORD_SIZE + INT_ARG_CNT; -# else - copy->regoff = i + LA_WORD_SIZE + 3; -# endif -#else -# if defined(__I386__) - copy->regoff = i + 3; -# elif defined(__MIPS__) && SIZEOF_VOID_P == 4 - copy->regoff = i + 2; -# else - copy->regoff = i; -# endif /* defined(__I386__) */ -#endif /* defined(SPECIALMEMUSE) */ - } - copy = copy->prev; - } - while (copy) { - copy->flags |= SAVEDVAR; - copy = copy->prev; - } + case ICMD_IF_FCMPL_LT: + case ICMD_IF_FCMPL_GE: + case ICMD_IF_FCMPL_GT: + case ICMD_IF_FCMPL_LE: - i = iptr->s1.argcount; - stackdepth -= i; - while (--i >= 0) { - POPANY; - } - NEW_DST(TYPE_ADR, stackdepth); - stackdepth++; - break; + case ICMD_IF_FCMPG_LT: + case ICMD_IF_FCMPG_GE: + case ICMD_IF_FCMPG_GT: + case ICMD_IF_FCMPG_LE: - default: - *exceptionptr = - new_internalerror("Unknown ICMD %d", opcode); - return false; - } /* switch */ + case ICMD_IF_DCMPEQ: + case ICMD_IF_DCMPNE: - NEW_CHECKOVERFLOW; - iptr++; - } /* while instructions */ + case ICMD_IF_DCMPL_LT: + case ICMD_IF_DCMPL_GE: + case ICMD_IF_DCMPL_GT: + case ICMD_IF_DCMPL_LE: - /* set out-stack of block */ + case ICMD_IF_DCMPG_LT: + case ICMD_IF_DCMPG_GE: + case ICMD_IF_DCMPG_GT: + case ICMD_IF_DCMPG_LE: - bptr->outstack = curstack; - bptr->outdepth = stackdepth; + case ICMD_IF_ACMPEQ: + case ICMD_IF_ACMPNE: + RELOCATE(iptr->sx.s23.s2.varindex); + RELOCATE(iptr->s1.varindex); + iptr->dst.block = stack_mark_reached_from_outvars(sd, iptr->dst.block); + break; - /* stack slots at basic block end become interfaces */ + /* pop 2 push 0 */ + + case ICMD_PUTFIELD: + case ICMD_IASTORECONST: + case ICMD_LASTORECONST: + case ICMD_AASTORECONST: + case ICMD_BASTORECONST: + case ICMD_CASTORECONST: + case ICMD_SASTORECONST: + maythrow = true; + case ICMD_POP2: + RELOCATE(iptr->sx.s23.s2.varindex); + RELOCATE(iptr->s1.varindex); + break; - i = stackdepth - 1; - for (copy = curstack; copy; i--, copy = copy->prev) { - if ((copy->varkind == STACKVAR) && (copy->varnum > i)) - copy->varkind = TEMPVAR; - else { - copy->varkind = STACKVAR; - copy->varnum = i; - } - IF_NO_INTRP( - rd->interfaces[i][copy->type].type = copy->type; - rd->interfaces[i][copy->type].flags |= copy->flags; - ); - } + /* pop 0 push 1 copy */ - /* check if interface slots at basic block begin must be saved */ + case ICMD_COPY: + case ICMD_MOVE: + RELOCATE(iptr->dst.varindex); + RELOCATE(iptr->s1.varindex); + COPY_VAL_AND_TYPE(*sd, iptr->s1.varindex, iptr->dst.varindex); + break; - IF_NO_INTRP( - i = bptr->indepth - 1; - for (copy = bptr->instack; copy; i--, copy = copy->prev) { - rd->interfaces[i][copy->type].type = copy->type; - if (copy->varkind == STACKVAR) { - if (copy->flags & SAVEDVAR) - rd->interfaces[i][copy->type].flags |= SAVEDVAR; - } - } - ); + /* pop 2 push 1 */ + + case ICMD_IDIV: + case ICMD_IREM: + case ICMD_LDIV: + case ICMD_LREM: + maythrow = true; + case ICMD_IADD: + case ICMD_ISUB: + case ICMD_IMUL: + case ICMD_ISHL: + case ICMD_ISHR: + case ICMD_IUSHR: + case ICMD_IAND: + case ICMD_IOR: + case ICMD_IXOR: + case ICMD_LADD: + case ICMD_LSUB: + case ICMD_LMUL: + case ICMD_LOR: + case ICMD_LAND: + case ICMD_LXOR: + case ICMD_LSHL: + case ICMD_LSHR: + case ICMD_LUSHR: + case ICMD_FADD: + case ICMD_FSUB: + case ICMD_FMUL: + case ICMD_FDIV: + case ICMD_FREM: + case ICMD_DADD: + case ICMD_DSUB: + case ICMD_DMUL: + case ICMD_DDIV: + case ICMD_DREM: + case ICMD_LCMP: + case ICMD_FCMPL: + case ICMD_FCMPG: + case ICMD_DCMPL: + case ICMD_DCMPG: + RELOCATE(iptr->sx.s23.s2.varindex); + RELOCATE(iptr->s1.varindex); + RELOCATE(iptr->dst.varindex); + break; - } /* if */ - else - superblockend = true; + /* pop 1 push 1 */ + + case ICMD_CHECKCAST: + case ICMD_ARRAYLENGTH: + case ICMD_INSTANCEOF: + case ICMD_NEWARRAY: + case ICMD_ANEWARRAY: + maythrow = true; + case ICMD_GETFIELD: + case ICMD_IADDCONST: + case ICMD_ISUBCONST: + case ICMD_IMULCONST: + case ICMD_IMULPOW2: + case ICMD_IDIVPOW2: + case ICMD_IREMPOW2: + case ICMD_IANDCONST: + case ICMD_IORCONST: + case ICMD_IXORCONST: + case ICMD_ISHLCONST: + case ICMD_ISHRCONST: + case ICMD_IUSHRCONST: + case ICMD_LADDCONST: + case ICMD_LSUBCONST: + case ICMD_LMULCONST: + case ICMD_LMULPOW2: + case ICMD_LDIVPOW2: + case ICMD_LREMPOW2: + case ICMD_LANDCONST: + case ICMD_LORCONST: + case ICMD_LXORCONST: + case ICMD_LSHLCONST: + case ICMD_LSHRCONST: + case ICMD_LUSHRCONST: + case ICMD_INEG: + case ICMD_INT2BYTE: + case ICMD_INT2CHAR: + case ICMD_INT2SHORT: + case ICMD_LNEG: + case ICMD_FNEG: + case ICMD_DNEG: + case ICMD_I2L: + case ICMD_I2F: + case ICMD_I2D: + case ICMD_L2I: + case ICMD_L2F: + case ICMD_L2D: + case ICMD_F2I: + case ICMD_F2L: + case ICMD_F2D: + case ICMD_D2I: + case ICMD_D2L: + case ICMD_D2F: + RELOCATE(iptr->s1.varindex); + RELOCATE(iptr->dst.varindex); + break; - bptr++; - } /* while blocks */ - } while (repeat && !deadcode); + /* pop 0 push 1 */ - /* gather statistics *****************************************************/ + case ICMD_GETSTATIC: + case ICMD_NEW: + maythrow = true; + RELOCATE(iptr->dst.varindex); + break; -#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 ((new - jd->new_stack) > count_max_new_stack) - count_max_new_stack = (new - jd->new_stack); - - b_count = jd->new_basicblockcount; - bptr = jd->new_basicblocks; - while (--b_count >= 0) { - if (bptr->flags > BBREACHED) { - if (bptr->indepth >= 10) - count_block_stack[10]++; - else - count_block_stack[bptr->indepth]++; - len = bptr->icount; - if (len < 10) - count_block_size_distribution[len]++; - else if (len <= 12) - count_block_size_distribution[10]++; - else if (len <= 14) - count_block_size_distribution[11]++; - else if (len <= 16) - count_block_size_distribution[12]++; - else if (len <= 18) - count_block_size_distribution[13]++; - else if (len <= 20) - count_block_size_distribution[14]++; - else if (len <= 25) - count_block_size_distribution[15]++; - else if (len <= 30) - count_block_size_distribution[16]++; - else - count_block_size_distribution[17]++; - } - bptr++; - } + /* pop many push any */ + + case ICMD_INVOKESTATIC: + case ICMD_INVOKESPECIAL: + case ICMD_INVOKEVIRTUAL: + case ICMD_INVOKEINTERFACE: + case ICMD_BUILTIN: + case ICMD_MULTIANEWARRAY: + i = iptr->s1.argcount; + if (cloneinstructions) { + argp = DMNEW(s4, i); + MCOPY(argp, iptr->sx.s23.s2.args, s4, i); + iptr->sx.s23.s2.args = argp; + } + else { + argp = iptr->sx.s23.s2.args; + } - if (iteration_count == 1) - count_analyse_iterations[0]++; - else if (iteration_count == 2) - count_analyse_iterations[1]++; - else if (iteration_count == 3) - count_analyse_iterations[2]++; - else if (iteration_count == 4) - count_analyse_iterations[3]++; - else - count_analyse_iterations[4]++; + maythrow = true; + while (--i >= 0) { + RELOCATE(*argp); + argp++; + } + RELOCATE(iptr->dst.varindex); + break; - if (jd->new_basicblockcount <= 5) - count_method_bb_distribution[0]++; - else if (jd->new_basicblockcount <= 10) - count_method_bb_distribution[1]++; - else if (jd->new_basicblockcount <= 15) - count_method_bb_distribution[2]++; - else if (jd->new_basicblockcount <= 20) - count_method_bb_distribution[3]++; - else if (jd->new_basicblockcount <= 30) - count_method_bb_distribution[4]++; - else if (jd->new_basicblockcount <= 40) - count_method_bb_distribution[5]++; - else if (jd->new_basicblockcount <= 50) - count_method_bb_distribution[6]++; - else if (jd->new_basicblockcount <= 75) - count_method_bb_distribution[7]++; - else - count_method_bb_distribution[8]++; + default: + *exceptionptr = + new_internalerror("Unknown ICMD %d during stack re-analysis", + iptr->opc); + return false; + } /* switch */ + +#if defined(STACK_VERBOSE) + show_icmd(sd->jd, iptr, false, SHOW_STACK); + printf("\n"); +#endif } -#endif /* defined(ENABLE_STATISTICS) */ - /* everything's ok *******************************************************/ + /* relocate outvars */ - return true; + for (i=0; ioutdepth; ++i) { + RELOCATE(b->outvars[i]); + } - /* goto labels for throwing verifier exceptions **************************/ +#if defined(STACK_VERBOSE) + stack_verbose_block_exit(sd, superblockend); +#endif -#if defined(ENABLE_VERIFIER) + /* propagate to the next block */ -throw_stack_underflow: - *exceptionptr = - new_verifyerror(m, "Unable to pop operand off an empty stack"); - return false; + if (!superblockend) + if (!stack_reach_next_block(sd)) + return false; -throw_stack_overflow: - *exceptionptr = new_verifyerror(m, "Stack size too large"); - return false; + return true; +} -throw_stack_depth_error: - *exceptionptr = new_verifyerror(m,"Stack depth mismatch"); - return false; -throw_stack_type_error: - exceptions_throw_verifyerror_for_stack(m, expectedtype); - return false; +/* stack_analyse *************************************************************** -throw_stack_category_error: - *exceptionptr = - new_verifyerror(m, "Attempt to split long or double on the stack"); - return false; + Analyse_stack uses the intermediate code created by parse.c to + build a model of the JVM operand stack for the current method. + + The following checks are performed: + - check for operand stack underflow (before each instruction) + - check for operand stack overflow (after[1] each instruction) + - check for matching stack depth at merging points + - check for matching basic types[2] at merging points + - check basic types for instruction input (except for BUILTIN* + opcodes, INVOKE* opcodes and MULTIANEWARRAY) + + [1]) Checking this after the instruction should be ok. parse.c + counts the number of required stack slots in such a way that it is + only vital that we don't exceed `maxstack` at basic block + boundaries. + + [2]) 'basic types' means the distinction between INT, LONG, FLOAT, + DOUBLE and ADDRESS types. Subtypes of INT and different ADDRESS + types are not discerned. -#endif -} +*******************************************************************************/ bool stack_analyse(jitdata *jd) { - methodinfo *m; + methodinfo *m; /* method being analyzed */ codeinfo *code; codegendata *cd; registerdata *rd; - int b_count; - int b_index; + stackdata_t sd; +#if defined(ENABLE_SSA) + lsradata *ls; +#endif + int b_index; /* basic block index */ int stackdepth; - stackptr curstack; - stackptr new; + stackptr curstack; /* current stack top */ stackptr copy; - int opcode, i, j, len, loops; - int superblockend, repeat, deadcode; - instruction *iptr; - basicblock *bptr; + int opcode; /* opcode of current instruction */ + int i, j; + int javaindex; + 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; - s4 *s4ptr; - void **tptr; - s4 *last_store;/* instruction index of last XSTORE */ - /* [ local_index * 5 + type ] */ - s4 last_pei; /* instruction index of last possible exception */ - /* used for conflict resolution for copy */ - /* elimination (XLOAD, IINC, XSTORE) */ - s4 last_dupx; + basicblock *original; + exceptiontable *ex; + + stackptr *last_store_boundary; + stackptr coalescing_boundary; + + stackptr src1, src2, src3, src4, dst1, dst2; + + branch_target_t *table; + lookup_target_t *lookup; #if defined(ENABLE_VERIFIER) - int expectedtype; /* used by CHECK_BASIC_TYPE */ + int expectedtype; /* used by CHECK_BASIC_TYPE */ #endif - builtintable_entry *bte; methoddesc *md; + constant_FMIref *fmiref; +#if defined(ENABLE_STATISTICS) + int iteration_count; /* number of iterations of analysis */ +#endif + int new_index; /* used to get a new var index with GET_NEW_INDEX*/ + +#if defined(STACK_VERBOSE) + show_method(jd, SHOW_PARSE); +#endif - /* get required compiler data */ + /* 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 */ + + sd.m = m; + sd.jd = jd; + sd.varcount = jd->varcount; + sd.vartop = jd->vartop; + sd.localcount = jd->localcount; + sd.var = jd->var; + sd.handlers = DMNEW(exceptiontable *, cd->exceptiontablelength + 1); + 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 + +#if defined(ENABLE_STATISTICS) + iteration_count = 0; +#endif + + /* find the last real basic block */ + + sd.last_real_block = NULL; + tbptr = jd->basicblocks; + while (tbptr->next) { + sd.last_real_block = tbptr; + tbptr = tbptr->next; + } + assert(sd.last_real_block); + + /* find the last exception handler */ + + if (cd->exceptiontablelength) + sd.extableend = cd->exceptiontable + cd->exceptiontablelength - 1; + else + sd.extableend = NULL; + + /* init jd->interface_map */ + + 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); + + /* initialize flags and invars (none) of first block */ + + 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->basicblocks[0].inlocals, jd->var, varinfo, + jd->localcount + VERIFIER_EXTRA_LOCALS); + + /* stack analysis loop (until fixpoint reached) **************************/ + + do { +#if defined(ENABLE_STATISTICS) + iteration_count++; +#endif + + /* initialize loop over basic blocks */ + + sd.bptr = jd->basicblocks; + superblockend = true; + sd.repeat = false; + curstack = NULL; stackdepth = 0; + deadcode = true; + + /* iterate over basic blocks *****************************************/ + + for (; sd.bptr; sd.bptr = sd.bptr->next) { + + if (sd.bptr->flags == BBDELETED) { + /* This block has been deleted - do nothing. */ + + 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. */ + + sd.repeat = true; + continue; + } + + if (sd.bptr->flags > BBREACHED) { + /* This block is already finished. */ + + superblockend = true; + continue; + } + + 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. */ + + sd.repeat = true; + continue; + } -#if defined(ENABLE_LSRA) - m->maxlifetimes = 0; -#endif + /* This block has to be analysed now. */ - last_store = DMNEW(s4 , cd->maxlocals * 5); - - new = m->stack; - loops = 0; - m->basicblocks[0].flags = BBREACHED; - m->basicblocks[0].instack = 0; - m->basicblocks[0].indepth = 0; - - for (i = 0; i < cd->exceptiontablelength; i++) { - bptr = &m->basicblocks[m->basicblockindex[cd->exceptiontable[i].handlerpc]]; - bptr->flags = BBREACHED; - bptr->type = BBTYPE_EXH; - bptr->instack = new; - bptr->indepth = 1; - bptr->pre_count = 10000; - STACKRESET; - NEWXSTACK; - } + /* XXX The rest of this block is still indented one level too */ + /* much in order to avoid a giant diff by changing that. */ -#if CONDITIONAL_LOADCONST - b_count = m->basicblockcount; - bptr = m->basicblocks; - while (--b_count >= 0) { - if (bptr->icount != 0) { - iptr = bptr->iinstr + bptr->icount - 1; - switch (iptr->opc) { - case ICMD_RET: - case ICMD_RETURN: - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: - case ICMD_DRETURN: - case ICMD_ARETURN: - case ICMD_ATHROW: - break; + /* We know that sd.bptr->flags == BBREACHED. */ + /* This block has been reached before. */ - case ICMD_IFEQ: - case ICMD_IFNE: - case ICMD_IFLT: - case ICMD_IFGE: - case ICMD_IFGT: - case ICMD_IFLE: + assert(sd.bptr->flags == BBREACHED); + stackdepth = sd.bptr->indepth; - case ICMD_IFNULL: - case ICMD_IFNONNULL: + /* find exception handlers for this block */ - case ICMD_IF_ICMPEQ: - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: + /* determine the active exception handlers for this block */ + /* XXX could use a faster algorithm with sorted lists or */ + /* something? */ - case ICMD_IF_ACMPEQ: - case ICMD_IF_ACMPNE: - bptr[1].pre_count++; - case ICMD_GOTO: - m->basicblocks[m->basicblockindex[iptr->op1]].pre_count++; - break; + original = (sd.bptr->original) ? sd.bptr->original : sd.bptr; - case ICMD_TABLESWITCH: - s4ptr = iptr->val.a; - m->basicblocks[m->basicblockindex[*s4ptr++]].pre_count++; - i = *s4ptr++; /* low */ - i = *s4ptr++ - i + 1; /* high */ - while (--i >= 0) { - m->basicblocks[m->basicblockindex[*s4ptr++]].pre_count++; - } - break; - - case ICMD_LOOKUPSWITCH: - s4ptr = iptr->val.a; - m->basicblocks[m->basicblockindex[*s4ptr++]].pre_count++; - i = *s4ptr++; /* count */ - while (--i >= 0) { - m->basicblocks[m->basicblockindex[s4ptr[1]]].pre_count++; - s4ptr += 2; + len = 0; + ex = cd->exceptiontable; + for (; ex != NULL; ex = ex->down) { + if ((ex->start <= original) && (ex->end > original)) { + sd.handlers[len++] = ex; + } } - break; - default: - bptr[1].pre_count++; - break; - } - } - bptr++; - } -#endif /* CONDITIONAL_LOADCONST */ + sd.handlers[len] = NULL; - do { - loops++; - b_count = m->basicblockcount; - bptr = m->basicblocks; - superblockend = true; - repeat = false; - STACKRESET; - deadcode = true; + /* reanalyse cloned block */ - while (--b_count >= 0) { - if (bptr->flags == BBDELETED) { - /* do nothing */ - } - else if (superblockend && (bptr->flags < BBREACHED)) { - repeat = true; - } - else if (bptr->flags <= BBREACHED) { - if (superblockend) { - stackdepth = bptr->indepth; - } - else if (bptr->flags < BBREACHED) { - COPYCURSTACK(copy); - bptr->instack = copy; - bptr->indepth = stackdepth; - } - else { - CHECK_STACK_DEPTH(bptr->indepth, stackdepth); + if (sd.bptr->original) { + if (!stack_reanalyse_block(&sd)) + return false; + continue; } - curstack = bptr->instack; + /* reset the new pointer for allocating stackslots */ + + sd.new = jd->stack; + + /* create the instack of this block */ + + curstack = stack_create_instack(&sd); + + /* initialize locals at the start of this block */ + + if (sd.bptr->inlocals) + MCOPY(sd.var, sd.bptr->inlocals, varinfo, sd.localcount); + + /* set up local variables for analyzing this block */ + deadcode = false; superblockend = false; - bptr->flags = BBFINISHED; - len = bptr->icount; - iptr = bptr->iinstr; - b_index = bptr - m->basicblocks; + len = sd.bptr->icount; + iptr = sd.bptr->iinstr; + b_index = sd.bptr - jd->basicblocks; + + /* mark the block as analysed */ + + sd.bptr->flags = BBFINISHED; + + /* reset variables for dependency checking */ - last_pei = -1; - last_dupx = -1; + coalescing_boundary = sd.new; for( i = 0; i < cd->maxlocals; i++) - for( j = 0; j < 5; j++) - last_store[5 * i + j] = -1; + last_store_boundary[i] = sd.new; - bptr->stack = new; + /* remember the start of this block's variables */ + + sd.bptr->varstart = sd.vartop; + +#if defined(STACK_VERBOSE) + stack_verbose_block_enter(&sd, false); +#endif + + /* reach exception handlers for this block */ + + if (!stack_reach_handlers(&sd)) + return false; + + /* iterate over ICMDs ****************************************/ while (--len >= 0) { + +#if defined(STACK_VERBOSE) + 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_INOUT(copy)) + printf("S"); + if (IS_PREALLOC(copy)) + printf("A"); + printf(") "); + } + printf("\n"); +#endif + + /* fetch the current opcode */ + opcode = iptr->opc; + /* automatically replace some ICMDs with builtins */ + #if defined(USEBUILTINTABLE) -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif - bte = builtintable_get_automatic(opcode); - - if (bte && bte->opcode == opcode) { - iptr->opc = ICMD_BUILTIN; - iptr->op1 = false; /* don't check for exception */ - iptr->val.a = bte; - jd->isleafmethod = false; - goto builtin; - } -# if defined(ENABLE_INTRP) + 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 #endif /* defined(USEBUILTINTABLE) */ - /* this is the main switch */ + /* main opcode switch *************************************/ switch (opcode) { /* pop 0 push 0 */ - case ICMD_CHECKNULL: - COUNT(count_check_null); case ICMD_NOP: +icmd_NOP: + CLR_SX; + OP0_0; + break; - case ICMD_IFEQ_ICONST: - case ICMD_IFNE_ICONST: - case ICMD_IFLT_ICONST: - case ICMD_IFGE_ICONST: - case ICMD_IFGT_ICONST: - case ICMD_IFLE_ICONST: - case ICMD_ELSE_ICONST: - SETDST; + case ICMD_CHECKNULL: + coalescing_boundary = sd.new; + COUNT(count_check_null); + USE_S1(TYPE_ADR); + CLR_SX; + CLR_DST; /* XXX live through? */ break; case ICMD_RET: -#if defined(ENABLE_INTRP) - if (!opt_intrp) -#endif - rd->locals[iptr->op1][TYPE_ADR].type = TYPE_ADR; + j = iptr->s1.varindex = + jd->local_map[iptr->s1.varindex * 5 + TYPE_ADR]; + + if (sd.var[j].type != TYPE_RET) { + exceptions_throw_verifyerror(m, "RET with non-returnAddress value"); + return false; + } + + CLR_SX; + + iptr->dst.block = stack_mark_reached(&sd, sd.var[j].vv.retaddr, curstack, stackdepth); + superblockend = true; + break; + case ICMD_RETURN: COUNT(count_pcmd_return); - SETDST; + CLR_SX; + OP0_0; superblockend = true; break; + /* pop 0 push 1 const */ - + + /************************** ICONST OPTIMIZATIONS **************************/ + case ICMD_ICONST: COUNT(count_pcmd_load); - if (len > 0) { - switch (iptr[1].opc) { + if (len == 0) + goto normal_ICONST; + + switch (iptr[1].opc) { case ICMD_IADD: - iptr[0].opc = ICMD_IADDCONST; + iptr->opc = ICMD_IADDCONST; + /* FALLTHROUGH */ + icmd_iconst_tail: iptr[1].opc = ICMD_NOP; OP1_1(TYPE_INT, TYPE_INT); COUNT(count_pcmd_op); break; + case ICMD_ISUB: - iptr[0].opc = ICMD_ISUBCONST; + iptr->opc = ICMD_ISUBCONST; goto icmd_iconst_tail; #if SUPPORT_CONST_MUL case ICMD_IMUL: - iptr[0].opc = ICMD_IMULCONST; + iptr->opc = ICMD_IMULCONST; goto icmd_iconst_tail; #else /* SUPPORT_CONST_MUL */ case ICMD_IMUL: - if (iptr[0].val.i == 0x00000002) - iptr[0].val.i = 1; - else if (iptr[0].val.i == 0x00000004) - iptr[0].val.i = 2; - else if (iptr[0].val.i == 0x00000008) - iptr[0].val.i = 3; - else if (iptr[0].val.i == 0x00000010) - iptr[0].val.i = 4; - else if (iptr[0].val.i == 0x00000020) - iptr[0].val.i = 5; - else if (iptr[0].val.i == 0x00000040) - iptr[0].val.i = 6; - else if (iptr[0].val.i == 0x00000080) - iptr[0].val.i = 7; - else if (iptr[0].val.i == 0x00000100) - iptr[0].val.i = 8; - else if (iptr[0].val.i == 0x00000200) - iptr[0].val.i = 9; - else if (iptr[0].val.i == 0x00000400) - iptr[0].val.i = 10; - else if (iptr[0].val.i == 0x00000800) - iptr[0].val.i = 11; - else if (iptr[0].val.i == 0x00001000) - iptr[0].val.i = 12; - else if (iptr[0].val.i == 0x00002000) - iptr[0].val.i = 13; - else if (iptr[0].val.i == 0x00004000) - iptr[0].val.i = 14; - else if (iptr[0].val.i == 0x00008000) - iptr[0].val.i = 15; - else if (iptr[0].val.i == 0x00010000) - iptr[0].val.i = 16; - else if (iptr[0].val.i == 0x00020000) - iptr[0].val.i = 17; - else if (iptr[0].val.i == 0x00040000) - iptr[0].val.i = 18; - else if (iptr[0].val.i == 0x00080000) - iptr[0].val.i = 19; - else if (iptr[0].val.i == 0x00100000) - iptr[0].val.i = 20; - else if (iptr[0].val.i == 0x00200000) - iptr[0].val.i = 21; - else if (iptr[0].val.i == 0x00400000) - iptr[0].val.i = 22; - else if (iptr[0].val.i == 0x00800000) - iptr[0].val.i = 23; - else if (iptr[0].val.i == 0x01000000) - iptr[0].val.i = 24; - else if (iptr[0].val.i == 0x02000000) - iptr[0].val.i = 25; - else if (iptr[0].val.i == 0x04000000) - iptr[0].val.i = 26; - else if (iptr[0].val.i == 0x08000000) - iptr[0].val.i = 27; - else if (iptr[0].val.i == 0x10000000) - iptr[0].val.i = 28; - else if (iptr[0].val.i == 0x20000000) - iptr[0].val.i = 29; - else if (iptr[0].val.i == 0x40000000) - iptr[0].val.i = 30; - else if (iptr[0].val.i == 0x80000000) - iptr[0].val.i = 31; - else { - PUSHCONST(TYPE_INT); - break; - } - iptr[0].opc = ICMD_IMULPOW2; + if (iptr->sx.val.i == 0x00000002) + iptr->sx.val.i = 1; + else if (iptr->sx.val.i == 0x00000004) + iptr->sx.val.i = 2; + else if (iptr->sx.val.i == 0x00000008) + iptr->sx.val.i = 3; + else if (iptr->sx.val.i == 0x00000010) + iptr->sx.val.i = 4; + else if (iptr->sx.val.i == 0x00000020) + iptr->sx.val.i = 5; + else if (iptr->sx.val.i == 0x00000040) + iptr->sx.val.i = 6; + else if (iptr->sx.val.i == 0x00000080) + iptr->sx.val.i = 7; + else if (iptr->sx.val.i == 0x00000100) + iptr->sx.val.i = 8; + else if (iptr->sx.val.i == 0x00000200) + iptr->sx.val.i = 9; + else if (iptr->sx.val.i == 0x00000400) + iptr->sx.val.i = 10; + else if (iptr->sx.val.i == 0x00000800) + iptr->sx.val.i = 11; + else if (iptr->sx.val.i == 0x00001000) + iptr->sx.val.i = 12; + else if (iptr->sx.val.i == 0x00002000) + iptr->sx.val.i = 13; + else if (iptr->sx.val.i == 0x00004000) + iptr->sx.val.i = 14; + else if (iptr->sx.val.i == 0x00008000) + iptr->sx.val.i = 15; + else if (iptr->sx.val.i == 0x00010000) + iptr->sx.val.i = 16; + else if (iptr->sx.val.i == 0x00020000) + iptr->sx.val.i = 17; + else if (iptr->sx.val.i == 0x00040000) + iptr->sx.val.i = 18; + else if (iptr->sx.val.i == 0x00080000) + iptr->sx.val.i = 19; + else if (iptr->sx.val.i == 0x00100000) + iptr->sx.val.i = 20; + else if (iptr->sx.val.i == 0x00200000) + iptr->sx.val.i = 21; + else if (iptr->sx.val.i == 0x00400000) + iptr->sx.val.i = 22; + else if (iptr->sx.val.i == 0x00800000) + iptr->sx.val.i = 23; + else if (iptr->sx.val.i == 0x01000000) + iptr->sx.val.i = 24; + else if (iptr->sx.val.i == 0x02000000) + iptr->sx.val.i = 25; + else if (iptr->sx.val.i == 0x04000000) + iptr->sx.val.i = 26; + else if (iptr->sx.val.i == 0x08000000) + iptr->sx.val.i = 27; + else if (iptr->sx.val.i == 0x10000000) + iptr->sx.val.i = 28; + else if (iptr->sx.val.i == 0x20000000) + iptr->sx.val.i = 29; + else if (iptr->sx.val.i == 0x40000000) + iptr->sx.val.i = 30; + else if (iptr->sx.val.i == 0x80000000) + iptr->sx.val.i = 31; + else + goto normal_ICONST; + + iptr->opc = ICMD_IMULPOW2; goto icmd_iconst_tail; #endif /* SUPPORT_CONST_MUL */ case ICMD_IDIV: - if (iptr[0].val.i == 0x00000002) - iptr[0].val.i = 1; - else if (iptr[0].val.i == 0x00000004) - iptr[0].val.i = 2; - else if (iptr[0].val.i == 0x00000008) - iptr[0].val.i = 3; - else if (iptr[0].val.i == 0x00000010) - iptr[0].val.i = 4; - else if (iptr[0].val.i == 0x00000020) - iptr[0].val.i = 5; - else if (iptr[0].val.i == 0x00000040) - iptr[0].val.i = 6; - else if (iptr[0].val.i == 0x00000080) - iptr[0].val.i = 7; - else if (iptr[0].val.i == 0x00000100) - iptr[0].val.i = 8; - else if (iptr[0].val.i == 0x00000200) - iptr[0].val.i = 9; - else if (iptr[0].val.i == 0x00000400) - iptr[0].val.i = 10; - else if (iptr[0].val.i == 0x00000800) - iptr[0].val.i = 11; - else if (iptr[0].val.i == 0x00001000) - iptr[0].val.i = 12; - else if (iptr[0].val.i == 0x00002000) - iptr[0].val.i = 13; - else if (iptr[0].val.i == 0x00004000) - iptr[0].val.i = 14; - else if (iptr[0].val.i == 0x00008000) - iptr[0].val.i = 15; - else if (iptr[0].val.i == 0x00010000) - iptr[0].val.i = 16; - else if (iptr[0].val.i == 0x00020000) - iptr[0].val.i = 17; - else if (iptr[0].val.i == 0x00040000) - iptr[0].val.i = 18; - else if (iptr[0].val.i == 0x00080000) - iptr[0].val.i = 19; - else if (iptr[0].val.i == 0x00100000) - iptr[0].val.i = 20; - else if (iptr[0].val.i == 0x00200000) - iptr[0].val.i = 21; - else if (iptr[0].val.i == 0x00400000) - iptr[0].val.i = 22; - else if (iptr[0].val.i == 0x00800000) - iptr[0].val.i = 23; - else if (iptr[0].val.i == 0x01000000) - iptr[0].val.i = 24; - else if (iptr[0].val.i == 0x02000000) - iptr[0].val.i = 25; - else if (iptr[0].val.i == 0x04000000) - iptr[0].val.i = 26; - else if (iptr[0].val.i == 0x08000000) - iptr[0].val.i = 27; - else if (iptr[0].val.i == 0x10000000) - iptr[0].val.i = 28; - else if (iptr[0].val.i == 0x20000000) - iptr[0].val.i = 29; - else if (iptr[0].val.i == 0x40000000) - iptr[0].val.i = 30; - else if (iptr[0].val.i == 0x80000000) - iptr[0].val.i = 31; - else { - PUSHCONST(TYPE_INT); - break; - } - iptr[0].opc = ICMD_IDIVPOW2; + if (iptr->sx.val.i == 0x00000002) + iptr->sx.val.i = 1; + else if (iptr->sx.val.i == 0x00000004) + iptr->sx.val.i = 2; + else if (iptr->sx.val.i == 0x00000008) + iptr->sx.val.i = 3; + else if (iptr->sx.val.i == 0x00000010) + iptr->sx.val.i = 4; + else if (iptr->sx.val.i == 0x00000020) + iptr->sx.val.i = 5; + else if (iptr->sx.val.i == 0x00000040) + iptr->sx.val.i = 6; + else if (iptr->sx.val.i == 0x00000080) + iptr->sx.val.i = 7; + else if (iptr->sx.val.i == 0x00000100) + iptr->sx.val.i = 8; + else if (iptr->sx.val.i == 0x00000200) + iptr->sx.val.i = 9; + else if (iptr->sx.val.i == 0x00000400) + iptr->sx.val.i = 10; + else if (iptr->sx.val.i == 0x00000800) + iptr->sx.val.i = 11; + else if (iptr->sx.val.i == 0x00001000) + iptr->sx.val.i = 12; + else if (iptr->sx.val.i == 0x00002000) + iptr->sx.val.i = 13; + else if (iptr->sx.val.i == 0x00004000) + iptr->sx.val.i = 14; + else if (iptr->sx.val.i == 0x00008000) + iptr->sx.val.i = 15; + else if (iptr->sx.val.i == 0x00010000) + iptr->sx.val.i = 16; + else if (iptr->sx.val.i == 0x00020000) + iptr->sx.val.i = 17; + else if (iptr->sx.val.i == 0x00040000) + iptr->sx.val.i = 18; + else if (iptr->sx.val.i == 0x00080000) + iptr->sx.val.i = 19; + else if (iptr->sx.val.i == 0x00100000) + iptr->sx.val.i = 20; + else if (iptr->sx.val.i == 0x00200000) + iptr->sx.val.i = 21; + else if (iptr->sx.val.i == 0x00400000) + iptr->sx.val.i = 22; + else if (iptr->sx.val.i == 0x00800000) + iptr->sx.val.i = 23; + else if (iptr->sx.val.i == 0x01000000) + iptr->sx.val.i = 24; + else if (iptr->sx.val.i == 0x02000000) + iptr->sx.val.i = 25; + else if (iptr->sx.val.i == 0x04000000) + iptr->sx.val.i = 26; + else if (iptr->sx.val.i == 0x08000000) + iptr->sx.val.i = 27; + else if (iptr->sx.val.i == 0x10000000) + iptr->sx.val.i = 28; + else if (iptr->sx.val.i == 0x20000000) + iptr->sx.val.i = 29; + else if (iptr->sx.val.i == 0x40000000) + iptr->sx.val.i = 30; + else if (iptr->sx.val.i == 0x80000000) + iptr->sx.val.i = 31; + else + goto normal_ICONST; + + iptr->opc = ICMD_IDIVPOW2; goto icmd_iconst_tail; + case ICMD_IREM: /*log_text("stack.c: ICMD_ICONST/ICMD_IREM");*/ - if ((iptr[0].val.i == 0x00000002) || - (iptr[0].val.i == 0x00000004) || - (iptr[0].val.i == 0x00000008) || - (iptr[0].val.i == 0x00000010) || - (iptr[0].val.i == 0x00000020) || - (iptr[0].val.i == 0x00000040) || - (iptr[0].val.i == 0x00000080) || - (iptr[0].val.i == 0x00000100) || - (iptr[0].val.i == 0x00000200) || - (iptr[0].val.i == 0x00000400) || - (iptr[0].val.i == 0x00000800) || - (iptr[0].val.i == 0x00001000) || - (iptr[0].val.i == 0x00002000) || - (iptr[0].val.i == 0x00004000) || - (iptr[0].val.i == 0x00008000) || - (iptr[0].val.i == 0x00010000) || - (iptr[0].val.i == 0x00020000) || - (iptr[0].val.i == 0x00040000) || - (iptr[0].val.i == 0x00080000) || - (iptr[0].val.i == 0x00100000) || - (iptr[0].val.i == 0x00200000) || - (iptr[0].val.i == 0x00400000) || - (iptr[0].val.i == 0x00800000) || - (iptr[0].val.i == 0x01000000) || - (iptr[0].val.i == 0x02000000) || - (iptr[0].val.i == 0x04000000) || - (iptr[0].val.i == 0x08000000) || - (iptr[0].val.i == 0x10000000) || - (iptr[0].val.i == 0x20000000) || - (iptr[0].val.i == 0x40000000) || - (iptr[0].val.i == 0x80000000)) { - iptr[0].opc = ICMD_IREMPOW2; - iptr[0].val.i -= 1; + if ((iptr->sx.val.i == 0x00000002) || + (iptr->sx.val.i == 0x00000004) || + (iptr->sx.val.i == 0x00000008) || + (iptr->sx.val.i == 0x00000010) || + (iptr->sx.val.i == 0x00000020) || + (iptr->sx.val.i == 0x00000040) || + (iptr->sx.val.i == 0x00000080) || + (iptr->sx.val.i == 0x00000100) || + (iptr->sx.val.i == 0x00000200) || + (iptr->sx.val.i == 0x00000400) || + (iptr->sx.val.i == 0x00000800) || + (iptr->sx.val.i == 0x00001000) || + (iptr->sx.val.i == 0x00002000) || + (iptr->sx.val.i == 0x00004000) || + (iptr->sx.val.i == 0x00008000) || + (iptr->sx.val.i == 0x00010000) || + (iptr->sx.val.i == 0x00020000) || + (iptr->sx.val.i == 0x00040000) || + (iptr->sx.val.i == 0x00080000) || + (iptr->sx.val.i == 0x00100000) || + (iptr->sx.val.i == 0x00200000) || + (iptr->sx.val.i == 0x00400000) || + (iptr->sx.val.i == 0x00800000) || + (iptr->sx.val.i == 0x01000000) || + (iptr->sx.val.i == 0x02000000) || + (iptr->sx.val.i == 0x04000000) || + (iptr->sx.val.i == 0x08000000) || + (iptr->sx.val.i == 0x10000000) || + (iptr->sx.val.i == 0x20000000) || + (iptr->sx.val.i == 0x40000000) || + (iptr->sx.val.i == 0x80000000)) + { + iptr->opc = ICMD_IREMPOW2; + iptr->sx.val.i -= 1; goto icmd_iconst_tail; } - PUSHCONST(TYPE_INT); - break; + goto normal_ICONST; #if SUPPORT_CONST_LOGICAL case ICMD_IAND: - iptr[0].opc = ICMD_IANDCONST; + iptr->opc = ICMD_IANDCONST; goto icmd_iconst_tail; + case ICMD_IOR: - iptr[0].opc = ICMD_IORCONST; + iptr->opc = ICMD_IORCONST; goto icmd_iconst_tail; + case ICMD_IXOR: - iptr[0].opc = ICMD_IXORCONST; + iptr->opc = ICMD_IXORCONST; goto icmd_iconst_tail; + #endif /* SUPPORT_CONST_LOGICAL */ case ICMD_ISHL: - iptr[0].opc = ICMD_ISHLCONST; + iptr->opc = ICMD_ISHLCONST; goto icmd_iconst_tail; + case ICMD_ISHR: - iptr[0].opc = ICMD_ISHRCONST; + iptr->opc = ICMD_ISHRCONST; goto icmd_iconst_tail; + case ICMD_IUSHR: - iptr[0].opc = ICMD_IUSHRCONST; + iptr->opc = ICMD_IUSHRCONST; goto icmd_iconst_tail; #if SUPPORT_LONG_SHIFT case ICMD_LSHL: - iptr[0].opc = ICMD_LSHLCONST; + iptr->opc = ICMD_LSHLCONST; goto icmd_lconst_tail; + case ICMD_LSHR: - iptr[0].opc = ICMD_LSHRCONST; + iptr->opc = ICMD_LSHRCONST; goto icmd_lconst_tail; + case ICMD_LUSHR: - iptr[0].opc = ICMD_LUSHRCONST; + iptr->opc = ICMD_LUSHRCONST; goto icmd_lconst_tail; #endif /* SUPPORT_LONG_SHIFT */ case ICMD_IF_ICMPEQ: iptr[1].opc = ICMD_IFEQ; + /* FALLTHROUGH */ + icmd_if_icmp_tail: -/* iptr[0].op1 = iptr[1].op1; */ - /* IF_ICMPxx is the last instruction in the - basic block, just remove it. */ - iptr[0].opc = ICMD_NOP; - iptr[1].val.i = iptr[0].val.i; - SETDST; -/* bptr->icount--; */ -/* len--; */ -#if 0 - OP1_0(TYPE_INT); - tbptr = m->basicblocks + - m->basicblockindex[iptr[1].op1]; + /* set the constant for the following icmd */ + iptr[1].sx.val.i = iptr->sx.val.i; - iptr[1].target = (void *) tbptr; + /* this instruction becomes a nop */ + iptr->opc = ICMD_NOP; + goto icmd_NOP; - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); -#endif - break; case ICMD_IF_ICMPLT: iptr[1].opc = ICMD_IFLT; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPLE: iptr[1].opc = ICMD_IFLE; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPNE: iptr[1].opc = ICMD_IFNE; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPGT: iptr[1].opc = ICMD_IFGT; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPGE: iptr[1].opc = ICMD_IFGE; goto icmd_if_icmp_tail; @@ -3335,724 +2358,702 @@ bool stack_analyse(jitdata *jd) case ICMD_BASTORE: case ICMD_CASTORE: case ICMD_SASTORE: -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif # if SUPPORT_CONST_STORE_ZERO_ONLY - if (iptr[0].val.i == 0) { + if (iptr->sx.val.i != 0) + goto normal_ICONST; # endif - switch (iptr[1].opc) { - case ICMD_IASTORE: - iptr[0].opc = ICMD_IASTORECONST; - break; - case ICMD_BASTORE: - iptr[0].opc = ICMD_BASTORECONST; - break; - case ICMD_CASTORE: - iptr[0].opc = ICMD_CASTORECONST; - break; - case ICMD_SASTORE: - iptr[0].opc = ICMD_SASTORECONST; - break; - } + switch (iptr[1].opc) { + case ICMD_IASTORE: + iptr->opc = ICMD_IASTORECONST; + iptr->flags.bits |= INS_FLAG_CHECK; + break; + case ICMD_BASTORE: + iptr->opc = ICMD_BASTORECONST; + iptr->flags.bits |= INS_FLAG_CHECK; + break; + case ICMD_CASTORE: + iptr->opc = ICMD_CASTORECONST; + iptr->flags.bits |= INS_FLAG_CHECK; + break; + case ICMD_SASTORE: + iptr->opc = ICMD_SASTORECONST; + iptr->flags.bits |= INS_FLAG_CHECK; + break; + } - iptr[1].opc = ICMD_NOP; - OPTT2_0(TYPE_INT, TYPE_ADR); - COUNT(count_pcmd_op); -# if SUPPORT_CONST_STORE_ZERO_ONLY - } - else - PUSHCONST(TYPE_INT); -# endif -# if defined(ENABLE_INTRP) - } - else - PUSHCONST(TYPE_INT); -# endif + iptr[1].opc = ICMD_NOP; + + /* copy the constant to s3 */ + /* XXX constval -> astoreconstval? */ + iptr->sx.s23.s3.constval = iptr->sx.val.i; + OP2_0(TYPE_ADR, TYPE_INT); + COUNT(count_pcmd_op); break; case ICMD_PUTSTATIC: case ICMD_PUTFIELD: -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif # if SUPPORT_CONST_STORE_ZERO_ONLY - if (iptr[0].val.i == 0) { + if (iptr->sx.val.i != 0) + goto normal_ICONST; # endif - switch (iptr[1].opc) { - case ICMD_PUTSTATIC: - iptr[0].opc = ICMD_PUTSTATICCONST; - SETDST; - break; - case ICMD_PUTFIELD: - iptr[0].opc = ICMD_PUTFIELDCONST; - OP1_0(TYPE_ADR); - break; - } + /* XXX check field type? */ - iptr[1].opc = ICMD_NOP; - iptr[0].op1 = TYPE_INT; - COUNT(count_pcmd_op); -# if SUPPORT_CONST_STORE_ZERO_ONLY - } - else - PUSHCONST(TYPE_INT); -# endif -# if defined(ENABLE_INTRP) - } - else - PUSHCONST(TYPE_INT); -# endif + /* copy the constant to s2 */ + /* XXX constval -> fieldconstval? */ + iptr->sx.s23.s2.constval = iptr->sx.val.i; + +putconst_tail: + /* set the field reference (s3) */ + 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; + } + else { + iptr->sx.s23.s3.fmiref = iptr[1].sx.s23.s3.fmiref; + } + + switch (iptr[1].opc) { + case ICMD_PUTSTATIC: + iptr->opc = ICMD_PUTSTATICCONST; + OP0_0; + break; + case ICMD_PUTFIELD: + iptr->opc = ICMD_PUTFIELDCONST; + OP1_0(TYPE_ADR); + break; + } + + iptr[1].opc = ICMD_NOP; + COUNT(count_pcmd_op); break; #endif /* SUPPORT_CONST_STORE */ + default: - PUSHCONST(TYPE_INT); - } + goto normal_ICONST; } - else - PUSHCONST(TYPE_INT); + + /* if we get here, the ICONST has been optimized */ + break; + +normal_ICONST: + /* normal case of an unoptimized ICONST */ + OP0_1(TYPE_INT); break; + /************************** LCONST OPTIMIZATIONS **************************/ + case ICMD_LCONST: COUNT(count_pcmd_load); - if (len > 0) { - switch (iptr[1].opc) { + if (len == 0) + goto normal_LCONST; + + /* switch depending on the following instruction */ + + switch (iptr[1].opc) { #if SUPPORT_LONG_ADD case ICMD_LADD: - iptr[0].opc = ICMD_LADDCONST; + iptr->opc = ICMD_LADDCONST; + /* FALLTHROUGH */ + icmd_lconst_tail: + /* instruction of type LONG -> LONG */ iptr[1].opc = ICMD_NOP; - OP1_1(TYPE_LNG,TYPE_LNG); + OP1_1(TYPE_LNG, TYPE_LNG); COUNT(count_pcmd_op); break; + case ICMD_LSUB: - iptr[0].opc = ICMD_LSUBCONST; + iptr->opc = ICMD_LSUBCONST; goto icmd_lconst_tail; + #endif /* SUPPORT_LONG_ADD */ #if SUPPORT_LONG_MUL && SUPPORT_CONST_MUL case ICMD_LMUL: - iptr[0].opc = ICMD_LMULCONST; + iptr->opc = ICMD_LMULCONST; goto icmd_lconst_tail; #else /* SUPPORT_LONG_MUL && SUPPORT_CONST_MUL */ # if SUPPORT_LONG_SHIFT case ICMD_LMUL: - if (iptr[0].val.l == 0x00000002) - iptr[0].val.i = 1; - else if (iptr[0].val.l == 0x00000004) - iptr[0].val.i = 2; - else if (iptr[0].val.l == 0x00000008) - iptr[0].val.i = 3; - else if (iptr[0].val.l == 0x00000010) - iptr[0].val.i = 4; - else if (iptr[0].val.l == 0x00000020) - iptr[0].val.i = 5; - else if (iptr[0].val.l == 0x00000040) - iptr[0].val.i = 6; - else if (iptr[0].val.l == 0x00000080) - iptr[0].val.i = 7; - else if (iptr[0].val.l == 0x00000100) - iptr[0].val.i = 8; - else if (iptr[0].val.l == 0x00000200) - iptr[0].val.i = 9; - else if (iptr[0].val.l == 0x00000400) - iptr[0].val.i = 10; - else if (iptr[0].val.l == 0x00000800) - iptr[0].val.i = 11; - else if (iptr[0].val.l == 0x00001000) - iptr[0].val.i = 12; - else if (iptr[0].val.l == 0x00002000) - iptr[0].val.i = 13; - else if (iptr[0].val.l == 0x00004000) - iptr[0].val.i = 14; - else if (iptr[0].val.l == 0x00008000) - iptr[0].val.i = 15; - else if (iptr[0].val.l == 0x00010000) - iptr[0].val.i = 16; - else if (iptr[0].val.l == 0x00020000) - iptr[0].val.i = 17; - else if (iptr[0].val.l == 0x00040000) - iptr[0].val.i = 18; - else if (iptr[0].val.l == 0x00080000) - iptr[0].val.i = 19; - else if (iptr[0].val.l == 0x00100000) - iptr[0].val.i = 20; - else if (iptr[0].val.l == 0x00200000) - iptr[0].val.i = 21; - else if (iptr[0].val.l == 0x00400000) - iptr[0].val.i = 22; - else if (iptr[0].val.l == 0x00800000) - iptr[0].val.i = 23; - else if (iptr[0].val.l == 0x01000000) - iptr[0].val.i = 24; - else if (iptr[0].val.l == 0x02000000) - iptr[0].val.i = 25; - else if (iptr[0].val.l == 0x04000000) - iptr[0].val.i = 26; - else if (iptr[0].val.l == 0x08000000) - iptr[0].val.i = 27; - else if (iptr[0].val.l == 0x10000000) - iptr[0].val.i = 28; - else if (iptr[0].val.l == 0x20000000) - iptr[0].val.i = 29; - else if (iptr[0].val.l == 0x40000000) - iptr[0].val.i = 30; - else if (iptr[0].val.l == 0x80000000) - iptr[0].val.i = 31; + if (iptr->sx.val.l == 0x00000002) + iptr->sx.val.i = 1; + else if (iptr->sx.val.l == 0x00000004) + iptr->sx.val.i = 2; + else if (iptr->sx.val.l == 0x00000008) + iptr->sx.val.i = 3; + else if (iptr->sx.val.l == 0x00000010) + iptr->sx.val.i = 4; + else if (iptr->sx.val.l == 0x00000020) + iptr->sx.val.i = 5; + else if (iptr->sx.val.l == 0x00000040) + iptr->sx.val.i = 6; + else if (iptr->sx.val.l == 0x00000080) + iptr->sx.val.i = 7; + else if (iptr->sx.val.l == 0x00000100) + iptr->sx.val.i = 8; + else if (iptr->sx.val.l == 0x00000200) + iptr->sx.val.i = 9; + else if (iptr->sx.val.l == 0x00000400) + iptr->sx.val.i = 10; + else if (iptr->sx.val.l == 0x00000800) + iptr->sx.val.i = 11; + else if (iptr->sx.val.l == 0x00001000) + iptr->sx.val.i = 12; + else if (iptr->sx.val.l == 0x00002000) + iptr->sx.val.i = 13; + else if (iptr->sx.val.l == 0x00004000) + iptr->sx.val.i = 14; + else if (iptr->sx.val.l == 0x00008000) + iptr->sx.val.i = 15; + else if (iptr->sx.val.l == 0x00010000) + iptr->sx.val.i = 16; + else if (iptr->sx.val.l == 0x00020000) + iptr->sx.val.i = 17; + else if (iptr->sx.val.l == 0x00040000) + iptr->sx.val.i = 18; + else if (iptr->sx.val.l == 0x00080000) + iptr->sx.val.i = 19; + else if (iptr->sx.val.l == 0x00100000) + iptr->sx.val.i = 20; + else if (iptr->sx.val.l == 0x00200000) + iptr->sx.val.i = 21; + else if (iptr->sx.val.l == 0x00400000) + iptr->sx.val.i = 22; + else if (iptr->sx.val.l == 0x00800000) + iptr->sx.val.i = 23; + else if (iptr->sx.val.l == 0x01000000) + iptr->sx.val.i = 24; + else if (iptr->sx.val.l == 0x02000000) + iptr->sx.val.i = 25; + else if (iptr->sx.val.l == 0x04000000) + iptr->sx.val.i = 26; + else if (iptr->sx.val.l == 0x08000000) + iptr->sx.val.i = 27; + else if (iptr->sx.val.l == 0x10000000) + iptr->sx.val.i = 28; + else if (iptr->sx.val.l == 0x20000000) + iptr->sx.val.i = 29; + else if (iptr->sx.val.l == 0x40000000) + iptr->sx.val.i = 30; + else if (iptr->sx.val.l == 0x80000000) + iptr->sx.val.i = 31; else { - PUSHCONST(TYPE_LNG); - break; + goto normal_LCONST; } - iptr[0].opc = ICMD_LMULPOW2; + iptr->opc = ICMD_LMULPOW2; goto icmd_lconst_tail; # endif /* SUPPORT_LONG_SHIFT */ #endif /* SUPPORT_LONG_MUL && SUPPORT_CONST_MUL */ - #if SUPPORT_LONG_DIV_POW2 case ICMD_LDIV: - if (iptr[0].val.l == 0x00000002) - iptr[0].val.i = 1; - else if (iptr[0].val.l == 0x00000004) - iptr[0].val.i = 2; - else if (iptr[0].val.l == 0x00000008) - iptr[0].val.i = 3; - else if (iptr[0].val.l == 0x00000010) - iptr[0].val.i = 4; - else if (iptr[0].val.l == 0x00000020) - iptr[0].val.i = 5; - else if (iptr[0].val.l == 0x00000040) - iptr[0].val.i = 6; - else if (iptr[0].val.l == 0x00000080) - iptr[0].val.i = 7; - else if (iptr[0].val.l == 0x00000100) - iptr[0].val.i = 8; - else if (iptr[0].val.l == 0x00000200) - iptr[0].val.i = 9; - else if (iptr[0].val.l == 0x00000400) - iptr[0].val.i = 10; - else if (iptr[0].val.l == 0x00000800) - iptr[0].val.i = 11; - else if (iptr[0].val.l == 0x00001000) - iptr[0].val.i = 12; - else if (iptr[0].val.l == 0x00002000) - iptr[0].val.i = 13; - else if (iptr[0].val.l == 0x00004000) - iptr[0].val.i = 14; - else if (iptr[0].val.l == 0x00008000) - iptr[0].val.i = 15; - else if (iptr[0].val.l == 0x00010000) - iptr[0].val.i = 16; - else if (iptr[0].val.l == 0x00020000) - iptr[0].val.i = 17; - else if (iptr[0].val.l == 0x00040000) - iptr[0].val.i = 18; - else if (iptr[0].val.l == 0x00080000) - iptr[0].val.i = 19; - else if (iptr[0].val.l == 0x00100000) - iptr[0].val.i = 20; - else if (iptr[0].val.l == 0x00200000) - iptr[0].val.i = 21; - else if (iptr[0].val.l == 0x00400000) - iptr[0].val.i = 22; - else if (iptr[0].val.l == 0x00800000) - iptr[0].val.i = 23; - else if (iptr[0].val.l == 0x01000000) - iptr[0].val.i = 24; - else if (iptr[0].val.l == 0x02000000) - iptr[0].val.i = 25; - else if (iptr[0].val.l == 0x04000000) - iptr[0].val.i = 26; - else if (iptr[0].val.l == 0x08000000) - iptr[0].val.i = 27; - else if (iptr[0].val.l == 0x10000000) - iptr[0].val.i = 28; - else if (iptr[0].val.l == 0x20000000) - iptr[0].val.i = 29; - else if (iptr[0].val.l == 0x40000000) - iptr[0].val.i = 30; - else if (iptr[0].val.l == 0x80000000) - iptr[0].val.i = 31; + if (iptr->sx.val.l == 0x00000002) + iptr->sx.val.i = 1; + else if (iptr->sx.val.l == 0x00000004) + iptr->sx.val.i = 2; + else if (iptr->sx.val.l == 0x00000008) + iptr->sx.val.i = 3; + else if (iptr->sx.val.l == 0x00000010) + iptr->sx.val.i = 4; + else if (iptr->sx.val.l == 0x00000020) + iptr->sx.val.i = 5; + else if (iptr->sx.val.l == 0x00000040) + iptr->sx.val.i = 6; + else if (iptr->sx.val.l == 0x00000080) + iptr->sx.val.i = 7; + else if (iptr->sx.val.l == 0x00000100) + iptr->sx.val.i = 8; + else if (iptr->sx.val.l == 0x00000200) + iptr->sx.val.i = 9; + else if (iptr->sx.val.l == 0x00000400) + iptr->sx.val.i = 10; + else if (iptr->sx.val.l == 0x00000800) + iptr->sx.val.i = 11; + else if (iptr->sx.val.l == 0x00001000) + iptr->sx.val.i = 12; + else if (iptr->sx.val.l == 0x00002000) + iptr->sx.val.i = 13; + else if (iptr->sx.val.l == 0x00004000) + iptr->sx.val.i = 14; + else if (iptr->sx.val.l == 0x00008000) + iptr->sx.val.i = 15; + else if (iptr->sx.val.l == 0x00010000) + iptr->sx.val.i = 16; + else if (iptr->sx.val.l == 0x00020000) + iptr->sx.val.i = 17; + else if (iptr->sx.val.l == 0x00040000) + iptr->sx.val.i = 18; + else if (iptr->sx.val.l == 0x00080000) + iptr->sx.val.i = 19; + else if (iptr->sx.val.l == 0x00100000) + iptr->sx.val.i = 20; + else if (iptr->sx.val.l == 0x00200000) + iptr->sx.val.i = 21; + else if (iptr->sx.val.l == 0x00400000) + iptr->sx.val.i = 22; + else if (iptr->sx.val.l == 0x00800000) + iptr->sx.val.i = 23; + else if (iptr->sx.val.l == 0x01000000) + iptr->sx.val.i = 24; + else if (iptr->sx.val.l == 0x02000000) + iptr->sx.val.i = 25; + else if (iptr->sx.val.l == 0x04000000) + iptr->sx.val.i = 26; + else if (iptr->sx.val.l == 0x08000000) + iptr->sx.val.i = 27; + else if (iptr->sx.val.l == 0x10000000) + iptr->sx.val.i = 28; + else if (iptr->sx.val.l == 0x20000000) + iptr->sx.val.i = 29; + else if (iptr->sx.val.l == 0x40000000) + iptr->sx.val.i = 30; + else if (iptr->sx.val.l == 0x80000000) + iptr->sx.val.i = 31; else { - PUSHCONST(TYPE_LNG); - break; + goto normal_LCONST; } - iptr[0].opc = ICMD_LDIVPOW2; + iptr->opc = ICMD_LDIVPOW2; goto icmd_lconst_tail; #endif /* SUPPORT_LONG_DIV_POW2 */ #if SUPPORT_LONG_REM_POW2 case ICMD_LREM: - if ((iptr[0].val.l == 0x00000002) || - (iptr[0].val.l == 0x00000004) || - (iptr[0].val.l == 0x00000008) || - (iptr[0].val.l == 0x00000010) || - (iptr[0].val.l == 0x00000020) || - (iptr[0].val.l == 0x00000040) || - (iptr[0].val.l == 0x00000080) || - (iptr[0].val.l == 0x00000100) || - (iptr[0].val.l == 0x00000200) || - (iptr[0].val.l == 0x00000400) || - (iptr[0].val.l == 0x00000800) || - (iptr[0].val.l == 0x00001000) || - (iptr[0].val.l == 0x00002000) || - (iptr[0].val.l == 0x00004000) || - (iptr[0].val.l == 0x00008000) || - (iptr[0].val.l == 0x00010000) || - (iptr[0].val.l == 0x00020000) || - (iptr[0].val.l == 0x00040000) || - (iptr[0].val.l == 0x00080000) || - (iptr[0].val.l == 0x00100000) || - (iptr[0].val.l == 0x00200000) || - (iptr[0].val.l == 0x00400000) || - (iptr[0].val.l == 0x00800000) || - (iptr[0].val.l == 0x01000000) || - (iptr[0].val.l == 0x02000000) || - (iptr[0].val.l == 0x04000000) || - (iptr[0].val.l == 0x08000000) || - (iptr[0].val.l == 0x10000000) || - (iptr[0].val.l == 0x20000000) || - (iptr[0].val.l == 0x40000000) || - (iptr[0].val.l == 0x80000000)) { - iptr[0].opc = ICMD_LREMPOW2; - iptr[0].val.l -= 1; + if ((iptr->sx.val.l == 0x00000002) || + (iptr->sx.val.l == 0x00000004) || + (iptr->sx.val.l == 0x00000008) || + (iptr->sx.val.l == 0x00000010) || + (iptr->sx.val.l == 0x00000020) || + (iptr->sx.val.l == 0x00000040) || + (iptr->sx.val.l == 0x00000080) || + (iptr->sx.val.l == 0x00000100) || + (iptr->sx.val.l == 0x00000200) || + (iptr->sx.val.l == 0x00000400) || + (iptr->sx.val.l == 0x00000800) || + (iptr->sx.val.l == 0x00001000) || + (iptr->sx.val.l == 0x00002000) || + (iptr->sx.val.l == 0x00004000) || + (iptr->sx.val.l == 0x00008000) || + (iptr->sx.val.l == 0x00010000) || + (iptr->sx.val.l == 0x00020000) || + (iptr->sx.val.l == 0x00040000) || + (iptr->sx.val.l == 0x00080000) || + (iptr->sx.val.l == 0x00100000) || + (iptr->sx.val.l == 0x00200000) || + (iptr->sx.val.l == 0x00400000) || + (iptr->sx.val.l == 0x00800000) || + (iptr->sx.val.l == 0x01000000) || + (iptr->sx.val.l == 0x02000000) || + (iptr->sx.val.l == 0x04000000) || + (iptr->sx.val.l == 0x08000000) || + (iptr->sx.val.l == 0x10000000) || + (iptr->sx.val.l == 0x20000000) || + (iptr->sx.val.l == 0x40000000) || + (iptr->sx.val.l == 0x80000000)) + { + iptr->opc = ICMD_LREMPOW2; + iptr->sx.val.l -= 1; goto icmd_lconst_tail; } - PUSHCONST(TYPE_LNG); - break; + goto normal_LCONST; #endif /* SUPPORT_LONG_REM_POW2 */ #if SUPPORT_LONG_LOGICAL && SUPPORT_CONST_LOGICAL case ICMD_LAND: - iptr[0].opc = ICMD_LANDCONST; + iptr->opc = ICMD_LANDCONST; goto icmd_lconst_tail; + case ICMD_LOR: - iptr[0].opc = ICMD_LORCONST; + iptr->opc = ICMD_LORCONST; goto icmd_lconst_tail; + case ICMD_LXOR: - iptr[0].opc = ICMD_LXORCONST; + iptr->opc = ICMD_LXORCONST; goto icmd_lconst_tail; #endif /* SUPPORT_LONG_LOGICAL && SUPPORT_CONST_LOGICAL */ #if SUPPORT_LONG_CMP_CONST case ICMD_LCMP: - if ((len > 1) && (iptr[2].val.i == 0)) { - switch (iptr[2].opc) { + if ((len <= 1) || (iptr[2].sx.val.i != 0)) + goto normal_LCONST; + + /* switch on the instruction after LCONST - LCMP */ + + switch (iptr[2].opc) { case ICMD_IFEQ: - iptr[0].opc = ICMD_IF_LEQ; + iptr->opc = ICMD_IF_LEQ; + /* FALLTHROUGH */ + icmd_lconst_lcmp_tail: - iptr[0].op1 = iptr[2].op1; + /* convert LCONST, LCMP, IFXX to IF_LXX */ + iptr->dst.insindex = iptr[2].dst.insindex; iptr[1].opc = ICMD_NOP; iptr[2].opc = ICMD_NOP; -/* bptr->icount -= 2; */ -/* len -= 2; */ - - OP1_0(TYPE_LNG); - tbptr = m->basicblocks + - m->basicblockindex[iptr[0].op1]; - - iptr[0].target = (void *) tbptr; - - MARKREACHED(tbptr, copy); + OP1_BRANCH(TYPE_LNG); + BRANCH(tbptr); COUNT(count_pcmd_bra); COUNT(count_pcmd_op); break; + case ICMD_IFNE: - iptr[0].opc = ICMD_IF_LNE; + iptr->opc = ICMD_IF_LNE; goto icmd_lconst_lcmp_tail; + case ICMD_IFLT: - iptr[0].opc = ICMD_IF_LLT; + iptr->opc = ICMD_IF_LLT; goto icmd_lconst_lcmp_tail; + case ICMD_IFGT: - iptr[0].opc = ICMD_IF_LGT; + iptr->opc = ICMD_IF_LGT; goto icmd_lconst_lcmp_tail; + case ICMD_IFLE: - iptr[0].opc = ICMD_IF_LLE; + iptr->opc = ICMD_IF_LLE; goto icmd_lconst_lcmp_tail; + case ICMD_IFGE: - iptr[0].opc = ICMD_IF_LGE; + iptr->opc = ICMD_IF_LGE; goto icmd_lconst_lcmp_tail; + default: - PUSHCONST(TYPE_LNG); - } /* switch (iptr[2].opc) */ - } /* if (iptr[2].val.i == 0) */ - else - PUSHCONST(TYPE_LNG); + goto normal_LCONST; + } /* end switch on opcode after LCONST - LCMP */ break; #endif /* SUPPORT_LONG_CMP_CONST */ #if SUPPORT_CONST_STORE case ICMD_LASTORE: -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif # if SUPPORT_CONST_STORE_ZERO_ONLY - if (iptr[0].val.l == 0) { -# endif - iptr[0].opc = ICMD_LASTORECONST; - iptr[1].opc = ICMD_NOP; - OPTT2_0(TYPE_INT, TYPE_ADR); - COUNT(count_pcmd_op); -# if SUPPORT_CONST_STORE_ZERO_ONLY - } - else - PUSHCONST(TYPE_LNG); -# endif -# if defined(ENABLE_INTRP) - } - else - PUSHCONST(TYPE_LNG); + if (iptr->sx.val.l != 0) + goto normal_LCONST; # endif +#if SIZEOF_VOID_P == 4 + /* the constant must fit into a ptrint */ + if (iptr->sx.val.l < -0x80000000L || iptr->sx.val.l >= 0x80000000L) + goto normal_LCONST; +#endif + /* move the constant to s3 */ + iptr->sx.s23.s3.constval = iptr->sx.val.l; + + iptr->opc = ICMD_LASTORECONST; + iptr->flags.bits |= INS_FLAG_CHECK; + OP2_0(TYPE_ADR, TYPE_INT); + + iptr[1].opc = ICMD_NOP; + COUNT(count_pcmd_op); break; case ICMD_PUTSTATIC: case ICMD_PUTFIELD: -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif # if SUPPORT_CONST_STORE_ZERO_ONLY - if (iptr[0].val.l == 0) { + if (iptr->sx.val.l != 0) + goto normal_LCONST; # endif - switch (iptr[1].opc) { - case ICMD_PUTSTATIC: - iptr[0].opc = ICMD_PUTSTATICCONST; - SETDST; - break; - case ICMD_PUTFIELD: - iptr[0].opc = ICMD_PUTFIELDCONST; - OP1_0(TYPE_ADR); - break; - } +#if SIZEOF_VOID_P == 4 + /* the constant must fit into a ptrint */ + if (iptr->sx.val.l < -0x80000000L || iptr->sx.val.l >= 0x80000000L) + goto normal_LCONST; +#endif + /* XXX check field type? */ + + /* copy the constant to s2 */ + /* XXX constval -> fieldconstval? */ + iptr->sx.s23.s2.constval = iptr->sx.val.l; + + goto putconst_tail; - iptr[1].opc = ICMD_NOP; - iptr[0].op1 = TYPE_LNG; - COUNT(count_pcmd_op); -# if SUPPORT_CONST_STORE_ZERO_ONLY - } - else - PUSHCONST(TYPE_LNG); -# endif -# if defined(ENABLE_INTRP) - } - else - PUSHCONST(TYPE_LNG); -# endif - break; #endif /* SUPPORT_CONST_STORE */ + default: - PUSHCONST(TYPE_LNG); - } - } - else - PUSHCONST(TYPE_LNG); + goto normal_LCONST; + } /* end switch opcode after LCONST */ + + /* if we get here, the LCONST has been optimized */ + break; + +normal_LCONST: + /* the normal case of an unoptimized LCONST */ + OP0_1(TYPE_LNG); break; + /************************ END OF LCONST OPTIMIZATIONS *********************/ + case ICMD_FCONST: COUNT(count_pcmd_load); - PUSHCONST(TYPE_FLT); + OP0_1(TYPE_FLT); break; case ICMD_DCONST: COUNT(count_pcmd_load); - PUSHCONST(TYPE_DBL); + OP0_1(TYPE_DBL); break; + /************************** ACONST OPTIMIZATIONS **************************/ + case ICMD_ACONST: + coalescing_boundary = sd.new; COUNT(count_pcmd_load); #if SUPPORT_CONST_STORE -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif - /* We can only optimize if the ACONST is resolved - * and there is an instruction after it. */ + /* We can only optimize if the ACONST is resolved + * and there is an instruction after it. */ - if ((len > 0) && INSTRUCTION_IS_RESOLVED(iptr)) - { - switch (iptr[1].opc) { - case ICMD_AASTORE: - /* We can only optimize for NULL values - * here because otherwise a checkcast is - * required. */ - if (iptr->val.a != NULL) - goto aconst_no_transform; - - iptr[0].opc = ICMD_AASTORECONST; - OPTT2_0(TYPE_INT, TYPE_ADR); - - iptr[1].opc = ICMD_NOP; - COUNT(count_pcmd_op); - break; - - case ICMD_PUTSTATIC: - case ICMD_PUTFIELD: -# if SUPPORT_CONST_STORE_ZERO_ONLY - if (iptr->val.a == 0) { -# endif + if ((len == 0) || (iptr->flags.bits & INS_FLAG_UNRESOLVED)) + goto normal_ACONST; + + switch (iptr[1].opc) { + case ICMD_AASTORE: + /* We can only optimize for NULL values + * here because otherwise a checkcast is + * required. */ + if (iptr->sx.val.anyptr != NULL) + goto normal_ACONST; - switch (iptr[1].opc) { - case ICMD_PUTSTATIC: - iptr[0].opc = ICMD_PUTSTATICCONST; - iptr[0].op1 = TYPE_ADR; - SETDST; - break; - case ICMD_PUTFIELD: - iptr[0].opc = ICMD_PUTFIELDCONST; - iptr[0].op1 = TYPE_ADR; - OP1_0(TYPE_ADR); - break; - } + /* copy the constant (NULL) to s3 */ + iptr->sx.s23.s3.constval = 0; + iptr->opc = ICMD_AASTORECONST; + iptr->flags.bits |= INS_FLAG_CHECK; + OP2_0(TYPE_ADR, TYPE_INT); - iptr[1].opc = ICMD_NOP; - COUNT(count_pcmd_op); + iptr[1].opc = ICMD_NOP; + COUNT(count_pcmd_op); + break; + case ICMD_PUTSTATIC: + case ICMD_PUTFIELD: # if SUPPORT_CONST_STORE_ZERO_ONLY - } - else - /* no transformation */ - PUSHCONST(TYPE_ADR); + if (iptr->sx.val.anyptr != NULL) + goto normal_ACONST; # endif - break; + /* XXX check field type? */ + /* copy the constant to s2 */ + /* XXX constval -> fieldconstval? */ + iptr->sx.s23.s2.constval = (ptrint) iptr->sx.val.anyptr; - default: - aconst_no_transform: - /* no transformation */ - PUSHCONST(TYPE_ADR); - } - } - else { - /* no transformation */ - PUSHCONST(TYPE_ADR); - } -# if defined(ENABLE_INTRP) + goto putconst_tail; + + default: + goto normal_ACONST; } - else - PUSHCONST(TYPE_ADR); -# endif -#else /* SUPPORT_CONST_STORE */ - PUSHCONST(TYPE_ADR); + + /* if we get here the ACONST has been optimized */ + break; + +normal_ACONST: #endif /* SUPPORT_CONST_STORE */ + OP0_1(TYPE_ADR); break; + /* pop 0 push 1 load */ - + case ICMD_ILOAD: case ICMD_LLOAD: case ICMD_FLOAD: case ICMD_DLOAD: case ICMD_ALOAD: COUNT(count_load_instruction); - i = opcode - ICMD_ILOAD; -#if defined(ENABLE_INTRP) - if (!opt_intrp) + i = opcode - ICMD_ILOAD; /* type */ + + j = iptr->s1.varindex = + jd->local_map[iptr->s1.varindex * 5 + i]; + + if (sd.var[j].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 - rd->locals[iptr->op1][i].type = i; - LOAD(i, LOCALVAR, iptr->op1); break; /* pop 2 push 1 */ case ICMD_LALOAD: - case ICMD_IALOAD: case ICMD_FALOAD: case ICMD_DALOAD: case ICMD_AALOAD: + coalescing_boundary = sd.new; + iptr->flags.bits |= INS_FLAG_CHECK; COUNT(count_check_null); COUNT(count_check_bound); COUNT(count_pcmd_mem); - OP2IAT_1(opcode - ICMD_IALOAD); + OP2_1(TYPE_ADR, TYPE_INT, opcode - ICMD_IALOAD); break; + case ICMD_IALOAD: case ICMD_BALOAD: case ICMD_CALOAD: case ICMD_SALOAD: + coalescing_boundary = sd.new; + iptr->flags.bits |= INS_FLAG_CHECK; COUNT(count_check_null); COUNT(count_check_bound); COUNT(count_pcmd_mem); - OP2IAT_1(TYPE_INT); + OP2_1(TYPE_ADR, TYPE_INT, TYPE_INT); break; /* pop 0 push 0 iinc */ 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; + + iptr->s1.varindex = + jd->local_map[iptr->s1.varindex * 5 + TYPE_INT]; + + copy = curstack; + i = stackdepth - 1; + while (copy) { + if ((copy->varkind == LOCALVAR) && + (copy->varnum == iptr->s1.varindex)) + { + assert(IS_LOCALVAR(copy)); + SET_TEMPVAR(copy); + } + i--; + copy = copy->prev; + } +#if defined(ENABLE_SSA) + } +#endif + + iptr->dst.varindex = iptr->s1.varindex; + break; + + /* pop 1 push 0 store */ + + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + REQUIRE(1); + + i = opcode - ICMD_ISTORE; /* type */ + javaindex = iptr->dst.varindex; + j = iptr->dst.varindex = + jd->local_map[javaindex * 5 + i]; + + COPY_VAL_AND_TYPE(sd, curstack->varnum, j); + #if defined(ENABLE_STATISTICS) if (opt_stat) { - i = stackdepth; + count_pcmd_store++; + i = sd.new - curstack; + if (i >= 20) + count_store_length[20]++; + else + count_store_length[i]++; + i = stackdepth - 1; if (i >= 10) count_store_depth[10]++; else count_store_depth[i]++; } #endif - last_store[5 * iptr->op1 + TYPE_INT] = bptr->icount - len - 1; - copy = curstack; - i = stackdepth - 1; +#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 == iptr->op1)) { + (copy->varnum == j)) + { copy->varkind = TEMPVAR; - copy->varnum = i; + assert(IS_LOCALVAR(copy)); + SET_TEMPVAR(copy); } i--; copy = copy->prev; } - - SETDST; - break; - - /* pop 1 push 0 store */ - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - REQUIRE_1; + /* if the variable is already coalesced, don't bother */ - i = opcode - ICMD_ISTORE; -#if defined(ENABLE_INTRP) - if (!opt_intrp) -#endif - rd->locals[iptr->op1][i].type = i; -#if defined(ENABLE_STATISTICS) - if (opt_stat) { - count_pcmd_store++; - i = new - curstack; - if (i >= 20) - count_store_length[20]++; - else - count_store_length[i]++; - i = stackdepth - 1; - if (i >= 10) - count_store_depth[10]++; - else - count_store_depth[i]++; - } -#endif - /* check for conflicts as described in Figure 5.2 */ - copy = curstack->prev; - i = stackdepth - 2; - while (copy) { - if ((copy->varkind == LOCALVAR) && - (copy->varnum == iptr->op1)) { - copy->varkind = TEMPVAR; - copy->varnum = i; - } - i--; - copy = copy->prev; - } + /* We do not need to check against INOUT, as invars */ + /* are always before the coalescing boundary. */ - /* do not change instack Stackslots */ - /* it won't improve performance if we copy the interface */ - /* at the BB begin or here, and lsra relies that no */ - /* instack stackslot is marked LOCALVAR */ - if (curstack->varkind == STACKVAR) - goto _possible_conflict; - - /* check for a DUPX,SWAP while the lifetime of curstack */ - /* and as creator curstack */ - if (last_dupx != -1) { - /* we have to look at the dst stack of DUPX */ - /* == src Stack of PEI */ - copy = bptr->iinstr[last_dupx].dst; - /* - if (last_pei == 0) - copy = bptr->instack; - else - copy = bptr->iinstr[last_pei-1].dst; - */ - if ((copy != NULL) && (curstack <= copy)) { - /* curstack alive at or created by DUPX */ + if (curstack->varkind == LOCALVAR) + goto store_tail; - /* TODO:.... */ - /* now look, if there is a LOCALVAR at anyone of */ - /* the src stacklots used by DUPX */ + /* there is no STORE Lj while curstack is live */ - goto _possible_conflict; - } - } + if (curstack < last_store_boundary[javaindex]) + goto assume_conflict; - /* check for a PEI while the lifetime of curstack */ - if (last_pei != -1) { - /* && there are exception handler in this method */ - /* when this is checked prevent ARGVAR from */ - /* overwriting LOCALVAR!!! */ + /* curstack must be after the coalescing boundary */ - /* we have to look at the stack _before_ the PEI! */ - /* == src Stack of PEI */ - if (last_pei == 0) - copy = bptr->instack; - else - copy = bptr->iinstr[last_pei-1].dst; - if ((copy != NULL) && (curstack <= copy)) { - /* curstack alive at PEI */ - goto _possible_conflict; - } - } - - /* check if there is a possible conflicting XSTORE */ - if (last_store[5 * iptr->op1 + opcode - ICMD_ISTORE] != -1) { - /* we have to look at the stack _before_ the XSTORE! */ - /* == src Stack of XSTORE */ - if (last_store[5 * iptr->op1 + opcode - ICMD_ISTORE] == 0) - copy = bptr->instack; - else - copy = bptr->iinstr[last_store[5 * iptr->op1 + opcode - ICMD_ISTORE] - 1].dst; - if ((copy != NULL) && (curstack <= copy)) { - /* curstack alive at Last Store */ - goto _possible_conflict; - } - } + if (curstack < coalescing_boundary) + goto assume_conflict; - /* check if there is a conflict with a XLOAD */ - /* this is done indirectly by looking if a Stackslot is */ - /* marked LOCALVAR and is live while curstack is live */ - /* see figure 5.3 */ + /* there is no DEF LOCALVAR(j) while curstack is live */ - /* First check "above" stackslots of the instack */ - copy = curstack + 1; - for(;(copy <= bptr->instack); copy++) - if ((copy->varkind == LOCALVAR) && (copy->varnum == iptr->op1)) { - goto _possible_conflict; + copy = sd.new; /* most recent stackslot created + 1 */ + while (--copy > curstack) { + if (copy->varkind == LOCALVAR && copy->varnum == j) + goto assume_conflict; } - - /* "intra" Basic Block Stackslots are allocated above */ - /* bptr->stack (see doc/stack.txt), so if curstack + 1 */ - /* is an instack, copy could point now to the stackslots */ - /* of an inbetween analysed Basic Block */ - if (copy < bptr->stack) - copy = bptr->stack; - while (copy < new) { - if ((copy->varkind == LOCALVAR) && (copy->varnum == iptr->op1)) { - goto _possible_conflict; + + /* coalesce the temporary variable with Lj */ + assert((curstack->varkind == TEMPVAR) + || (curstack->varkind == UNDEFVAR)); + assert(!IS_LOCALVAR(curstack)); /* XXX correct? */ + assert(!IS_INOUT(curstack)); + assert(!IS_PREALLOC(curstack)); + + assert(curstack->creator); + assert(curstack->creator->dst.varindex == curstack->varnum); + RELEASE_INDEX(sd, curstack); + curstack->varkind = LOCALVAR; + curstack->varnum = j; + curstack->creator->dst.varindex = j; + goto store_tail; + + /* revert the coalescing, if it has been done earlier */ +assume_conflict: + if ((curstack->varkind == LOCALVAR) + && (curstack->varnum == j)) + { + assert(IS_LOCALVAR(curstack)); + SET_TEMPVAR(curstack); } - copy++; - } - /* If Stackslot is already marked as LOCALVAR, do not */ - /* change it! Conflict resolution works only, if xLOAD */ - /* has priority! */ - if (curstack->varkind == LOCALVAR) - goto _possible_conflict; - /* no conflict - mark the Stackslot as LOCALVAR */ - curstack->varkind = LOCALVAR; - curstack->varnum = iptr->op1; - - goto _local_join; - _possible_conflict: - if ((curstack->varkind == LOCALVAR) - && (curstack->varnum == iptr->op1)) { - curstack->varkind = TEMPVAR; - curstack->varnum = stackdepth-1; - } - _local_join: - last_store[5 * iptr->op1 + opcode - ICMD_ISTORE] = bptr->icount - len - 1; - STORE(opcode - ICMD_ISTORE); - break; + /* 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); + else + STORE(opcode - ICMD_ISTORE, j); + break; /* pop 3 push 0 */ case ICMD_AASTORE: + coalescing_boundary = sd.new; + iptr->flags.bits |= INS_FLAG_CHECK; COUNT(count_check_null); COUNT(count_check_bound); COUNT(count_pcmd_mem); @@ -4064,35 +3065,46 @@ bool stack_analyse(jitdata *jd) rd->memuse = md->memuse; if (md->argintreguse > rd->argintreguse) rd->argintreguse = md->argintreguse; + /* XXX non-leaf method? */ /* make all stack variables saved */ copy = curstack; while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; + /* in case copy->varnum is/will be a LOCALVAR */ + /* once and set back to a non LOCALVAR */ + /* the correct SAVEDVAR flag has to be */ + /* remembered in copy->flags, too */ copy->flags |= SAVEDVAR; copy = copy->prev; } - OP3TIA_0(TYPE_ADR); + OP3_0(TYPE_ADR, TYPE_INT, TYPE_ADR); break; - case ICMD_IASTORE: + case ICMD_LASTORE: case ICMD_FASTORE: case ICMD_DASTORE: + coalescing_boundary = sd.new; + iptr->flags.bits |= INS_FLAG_CHECK; COUNT(count_check_null); COUNT(count_check_bound); COUNT(count_pcmd_mem); - OP3TIA_0(opcode - ICMD_IASTORE); + OP3_0(TYPE_ADR, TYPE_INT, opcode - ICMD_IASTORE); break; + case ICMD_IASTORE: case ICMD_BASTORE: case ICMD_CASTORE: case ICMD_SASTORE: + coalescing_boundary = sd.new; + iptr->flags.bits |= INS_FLAG_CHECK; COUNT(count_check_null); COUNT(count_check_bound); COUNT(count_pcmd_mem); - OP3TIA_0(TYPE_INT); + OP3_0(TYPE_ADR, TYPE_INT, TYPE_INT); break; /* pop 1 push 0 */ @@ -4100,12 +3112,12 @@ bool stack_analyse(jitdata *jd) case ICMD_POP: #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_1; + REQUIRE(1); if (IS_2_WORD_TYPE(curstack->type)) goto throw_stack_category_error; } #endif - OP1_0ANY; + OP1_0_ANY; break; case ICMD_IRETURN: @@ -4113,28 +3125,30 @@ bool stack_analyse(jitdata *jd) case ICMD_FRETURN: case ICMD_DRETURN: case ICMD_ARETURN: -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (!opt_intrp) -# endif + coalescing_boundary = sd.new; + /* Assert here that no LOCAL or INOUTS get */ + /* preallocated, since tha macros are not */ + /* available in md-abi.c! */ + if (IS_TEMPVAR(curstack)) md_return_alloc(jd, curstack); -#endif COUNT(count_pcmd_return); OP1_0(opcode - ICMD_IRETURN); superblockend = true; break; case ICMD_ATHROW: + coalescing_boundary = sd.new; COUNT(count_check_null); OP1_0(TYPE_ADR); - STACKRESET; - SETDST; + curstack = NULL; stackdepth = 0; superblockend = true; break; case ICMD_PUTSTATIC: + coalescing_boundary = sd.new; COUNT(count_pcmd_mem); - OP1_0(iptr->op1); + INSTRUCTION_GET_FIELDREF(iptr, fmiref); + OP1_0(fmiref->parseddesc.fd->type); break; /* pop 1 push 0 branch */ @@ -4142,12 +3156,8 @@ bool stack_analyse(jitdata *jd) case ICMD_IFNULL: case ICMD_IFNONNULL: COUNT(count_pcmd_bra); - OP1_0(TYPE_ADR); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; - - MARKREACHED(tbptr, copy); + OP1_BRANCH(TYPE_ADR); + BRANCH(tbptr); break; case ICMD_IFEQ: @@ -4157,106 +3167,21 @@ bool stack_analyse(jitdata *jd) case ICMD_IFGT: case ICMD_IFLE: COUNT(count_pcmd_bra); -#if CONDITIONAL_LOADCONST && 0 -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif - tbptr = m->basicblocks + b_index; - - if ((b_count >= 3) && - ((b_index + 2) == m->basicblockindex[iptr[0].op1]) && - (tbptr[1].pre_count == 1) && - (tbptr[1].iinstr[0].opc == ICMD_ICONST) && - (tbptr[1].iinstr[1].opc == ICMD_GOTO) && - ((b_index + 3) == m->basicblockindex[tbptr[1].iinstr[1].op1]) && - (tbptr[2].pre_count == 1) && - (tbptr[2].iinstr[0].opc == ICMD_ICONST) && - (tbptr[2].icount==1)) { - /*printf("tbptr[2].icount=%d\n",tbptr[2].icount);*/ - OP1_1(TYPE_INT, TYPE_INT); - switch (iptr[0].opc) { - case ICMD_IFEQ: - iptr[0].opc = ICMD_IFNE_ICONST; - break; - case ICMD_IFNE: - iptr[0].opc = ICMD_IFEQ_ICONST; - break; - case ICMD_IFLT: - iptr[0].opc = ICMD_IFGE_ICONST; - break; - case ICMD_IFGE: - iptr[0].opc = ICMD_IFLT_ICONST; - break; - case ICMD_IFGT: - iptr[0].opc = ICMD_IFLE_ICONST; - break; - case ICMD_IFLE: - iptr[0].opc = ICMD_IFGT_ICONST; - break; - } -#if 1 - iptr[0].val.i = iptr[1].val.i; - iptr[1].opc = ICMD_ELSE_ICONST; - iptr[1].val.i = iptr[3].val.i; - iptr[2].opc = ICMD_NOP; - iptr[3].opc = ICMD_NOP; -#else - /* HACK: save compare value in iptr[1].op1 */ - iptr[1].op1 = iptr[0].val.i; - iptr[0].val.i = tbptr[1].iinstr[0].val.i; - iptr[1].opc = ICMD_ELSE_ICONST; - iptr[1].val.i = tbptr[2].iinstr[0].val.i; - tbptr[1].iinstr[0].opc = ICMD_NOP; - tbptr[1].iinstr[1].opc = ICMD_NOP; - tbptr[2].iinstr[0].opc = ICMD_NOP; -#endif - tbptr[1].flags = BBDELETED; - tbptr[2].flags = BBDELETED; - tbptr[1].icount = 0; - tbptr[2].icount = 0; - if (tbptr[3].pre_count == 2) { - len += tbptr[3].icount + 3; - bptr->icount += tbptr[3].icount + 3; - tbptr[3].flags = BBDELETED; - tbptr[3].icount = 0; - b_index++; - } - else { - bptr->icount++; - len ++; - } - b_index += 2; - break; - } -# if defined(ENABLE_INTRP) - } -# endif - -#endif /* CONDITIONAL_LOADCONST */ - - /* iptr->val.i is set implicitly in parse by + /* iptr->sx.val.i is set implicitly in parse by clearing the memory or from IF_ICMPxx optimization. */ - OP1_0(TYPE_INT); -/* iptr->val.i = 0; */ - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; - - MARKREACHED(tbptr, copy); + OP1_BRANCH(TYPE_INT); +/* iptr->sx.val.i = 0; */ + BRANCH(tbptr); break; /* pop 0 push 0 branch */ case ICMD_GOTO: COUNT(count_pcmd_bra); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; - - MARKREACHED(tbptr, copy); - SETDST; + OP0_BRANCH; + BRANCH(tbptr); superblockend = true; break; @@ -4264,63 +3189,45 @@ bool stack_analyse(jitdata *jd) case ICMD_TABLESWITCH: COUNT(count_pcmd_table); - OP1_0(TYPE_INT); - s4ptr = iptr->val.a; - tbptr = m->basicblocks + m->basicblockindex[*s4ptr++]; - MARKREACHED(tbptr, copy); - i = *s4ptr++; /* low */ - i = *s4ptr++ - i + 1; /* high */ + OP1_BRANCH(TYPE_INT); - tptr = DMNEW(void*, i+1); - iptr->target = (void *) tptr; + table = iptr->dst.table; + BRANCH_TARGET(*table, tbptr); + table++; - tptr[0] = (void *) tbptr; - tptr++; + i = iptr->sx.s23.s3.tablehigh + - iptr->sx.s23.s2.tablelow + 1; while (--i >= 0) { - tbptr = m->basicblocks + m->basicblockindex[*s4ptr++]; - - tptr[0] = (void *) tbptr; - tptr++; - - MARKREACHED(tbptr, copy); + BRANCH_TARGET(*table, tbptr); + table++; } - SETDST; superblockend = true; break; - + /* pop 1 push 0 table branch */ case ICMD_LOOKUPSWITCH: COUNT(count_pcmd_table); - OP1_0(TYPE_INT); - s4ptr = iptr->val.a; - tbptr = m->basicblocks + m->basicblockindex[*s4ptr++]; - MARKREACHED(tbptr, copy); - i = *s4ptr++; /* count */ + OP1_BRANCH(TYPE_INT); - tptr = DMNEW(void*, i+1); - iptr->target = (void *) tptr; + BRANCH_TARGET(iptr->sx.s23.s3.lookupdefault, tbptr); - tptr[0] = (void *) tbptr; - tptr++; + lookup = iptr->dst.lookup; - while (--i >= 0) { - tbptr = m->basicblocks + m->basicblockindex[s4ptr[1]]; + i = iptr->sx.s23.s2.lookupcount; - tptr[0] = (void *) tbptr; - tptr++; - - MARKREACHED(tbptr, copy); - s4ptr += 2; + while (--i >= 0) { + BRANCH_TARGET(lookup->target, tbptr); + lookup++; } - SETDST; superblockend = true; break; case ICMD_MONITORENTER: - COUNT(count_check_null); case ICMD_MONITOREXIT: + coalescing_boundary = sd.new; + COUNT(count_check_null); OP1_0(TYPE_ADR); break; @@ -4333,241 +3240,346 @@ bool stack_analyse(jitdata *jd) case ICMD_IF_ICMPGT: case ICMD_IF_ICMPLE: COUNT(count_pcmd_bra); - OP2_0(TYPE_INT); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; - - MARKREACHED(tbptr, copy); + OP2_BRANCH(TYPE_INT, TYPE_INT); + BRANCH(tbptr); break; case ICMD_IF_ACMPEQ: case ICMD_IF_ACMPNE: COUNT(count_pcmd_bra); - OP2_0(TYPE_ADR); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; - - MARKREACHED(tbptr, copy); + OP2_BRANCH(TYPE_ADR, TYPE_ADR); + BRANCH(tbptr); break; /* pop 2 push 0 */ case ICMD_PUTFIELD: + coalescing_boundary = sd.new; COUNT(count_check_null); COUNT(count_pcmd_mem); - OPTT2_0(iptr->op1,TYPE_ADR); + INSTRUCTION_GET_FIELDREF(iptr, fmiref); + OP2_0(TYPE_ADR, fmiref->parseddesc.fd->type); break; case ICMD_POP2: - REQUIRE_1; + REQUIRE(1); if (!IS_2_WORD_TYPE(curstack->type)) { /* ..., cat1 */ #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->prev->type)) goto throw_stack_category_error; } #endif - OP1_0ANY; /* second pop */ + OP2_0_ANY_ANY; /* pop two slots */ } - else + else { iptr->opc = ICMD_POP; - OP1_0ANY; + OP1_0_ANY; /* pop one (two-word) slot */ + } break; /* pop 0 push 1 dup */ - + case ICMD_DUP: #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_1; + REQUIRE(1); if (IS_2_WORD_TYPE(curstack->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif - last_dupx = bptr->icount - len - 1; COUNT(count_dup_instruction); - DUP; + +icmd_DUP: + src1 = curstack; + + COPY_UP(src1); + coalescing_boundary = sd.new - 1; break; case ICMD_DUP2: - last_dupx = bptr->icount - len - 1; - REQUIRE_1; + REQUIRE(1); if (IS_2_WORD_TYPE(curstack->type)) { /* ..., cat2 */ iptr->opc = ICMD_DUP; - DUP; + goto icmd_DUP; } else { - REQUIRE_2; + REQUIRE(2); /* ..., ????, cat1 */ #ifdef ENABLE_VERIFIER if (opt_verify) { if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif - copy = curstack; - NEWSTACK(copy->prev->type, copy->prev->varkind, - copy->prev->varnum); - NEWSTACK(copy->type, copy->varkind, - copy->varnum); - SETDST; - stackdepth += 2; + src1 = curstack->prev; + src2 = curstack; + + COPY_UP(src1); iptr++; len--; + COPY_UP(src2); + + coalescing_boundary = sd.new; } break; /* pop 2 push 3 dup */ - + case ICMD_DUP_X1: #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type) || IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif - last_dupx = bptr->icount - len - 1; - DUP_X1; + +icmd_DUP_X1: + src1 = curstack->prev; + src2 = curstack; + 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--; + MOVE_UP(src2); iptr++; len--; + + COPY_DOWN(curstack, dst1); + + coalescing_boundary = sd.new; break; case ICMD_DUP2_X1: - last_dupx = bptr->icount - len - 1; - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type)) { /* ..., ????, cat2 */ #ifdef ENABLE_VERIFIER if (opt_verify) { if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif iptr->opc = ICMD_DUP_X1; - DUP_X1; + goto icmd_DUP_X1; } else { /* ..., ????, cat1 */ #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_3; + REQUIRE(3); if (IS_2_WORD_TYPE(curstack->prev->type) || IS_2_WORD_TYPE(curstack->prev->prev->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif - DUP2_X1; + +icmd_DUP2_X1: + src1 = curstack->prev->prev; + src2 = curstack->prev; + src3 = curstack; + 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++; + + MOVE_UP(src1); iptr++; len--; + MOVE_UP(src2); iptr++; len--; + MOVE_UP(src3); iptr++; len--; + + COPY_DOWN(curstack, dst2); iptr++; len--; + COPY_DOWN(curstack->prev, dst1); + + coalescing_boundary = sd.new; } break; /* pop 3 push 4 dup */ - + case ICMD_DUP_X2: - last_dupx = bptr->icount - len - 1; - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->prev->type)) { /* ..., cat2, ???? */ #ifdef ENABLE_VERIFIER if (opt_verify) { if (IS_2_WORD_TYPE(curstack->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif iptr->opc = ICMD_DUP_X1; - DUP_X1; + goto icmd_DUP_X1; } else { /* ..., cat1, ???? */ #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_3; + REQUIRE(3); if (IS_2_WORD_TYPE(curstack->type) || IS_2_WORD_TYPE(curstack->prev->prev->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif - DUP_X2; +icmd_DUP_X2: + src1 = curstack->prev->prev; + src2 = curstack->prev; + src3 = curstack; + 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--; + MOVE_UP(src2); iptr++; len--; + MOVE_UP(src3); iptr++; len--; + + COPY_DOWN(curstack, dst1); + + coalescing_boundary = sd.new; } break; case ICMD_DUP2_X2: - last_dupx = bptr->icount - len - 1; - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type)) { /* ..., ????, cat2 */ if (IS_2_WORD_TYPE(curstack->prev->type)) { /* ..., cat2, cat2 */ iptr->opc = ICMD_DUP_X1; - DUP_X1; + goto icmd_DUP_X1; } else { /* ..., cat1, cat2 */ #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_3; + REQUIRE(3); if (IS_2_WORD_TYPE(curstack->prev->prev->type)) - goto throw_stack_category_error; + goto throw_stack_category_error; } #endif iptr->opc = ICMD_DUP_X2; - DUP_X2; + goto icmd_DUP_X2; } } - else { - REQUIRE_3; - /* ..., ????, ????, cat1 */ - if (IS_2_WORD_TYPE(curstack->prev->prev->type)) { - /* ..., cat2, ????, cat1 */ + + REQUIRE(3); + /* ..., ????, ????, cat1 */ + + if (IS_2_WORD_TYPE(curstack->prev->prev->type)) { + /* ..., cat2, ????, cat1 */ #ifdef ENABLE_VERIFIER - if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) - goto throw_stack_category_error; - } -#endif - iptr->opc = ICMD_DUP2_X1; - DUP2_X1; + if (opt_verify) { + if (IS_2_WORD_TYPE(curstack->prev->type)) + goto throw_stack_category_error; } - else { - /* ..., cat1, ????, cat1 */ +#endif + iptr->opc = ICMD_DUP2_X1; + goto icmd_DUP2_X1; + } + else { + /* ..., cat1, ????, cat1 */ #ifdef ENABLE_VERIFIER - if (opt_verify) { - REQUIRE_4; - if (IS_2_WORD_TYPE(curstack->prev->type) - || IS_2_WORD_TYPE(curstack->prev->prev->prev->type)) - goto throw_stack_category_error; - } + if (opt_verify) { + REQUIRE(4); + if (IS_2_WORD_TYPE(curstack->prev->type) + || IS_2_WORD_TYPE(curstack->prev->prev->prev->type)) + goto throw_stack_category_error; + } #endif - DUP2_X2; + + src1 = curstack->prev->prev->prev; + src2 = curstack->prev->prev; + src3 = curstack->prev; + src4 = curstack; + 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++; + + MOVE_UP(src1); iptr++; len--; + MOVE_UP(src2); iptr++; len--; + MOVE_UP(src3); iptr++; len--; + MOVE_UP(src4); iptr++; len--; + + COPY_DOWN(curstack, dst2); iptr++; len--; + COPY_DOWN(curstack->prev, dst1); + + coalescing_boundary = sd.new; } break; /* pop 2 push 2 swap */ - + case ICMD_SWAP: - last_dupx = bptr->icount - len - 1; #ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type) || IS_2_WORD_TYPE(curstack->prev->type)) goto throw_stack_category_error; } #endif - SWAP; + + src1 = curstack->prev; + src2 = curstack; + 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); + + coalescing_boundary = sd.new; break; /* pop 2 push 1 */ case ICMD_IDIV: case ICMD_IREM: + coalescing_boundary = sd.new; #if !SUPPORT_DIVISION - bte = (builtintable_entry *) iptr->val.a; + bte = iptr->sx.s23.s3.bte; md = bte->md; - i = iptr->op1; if (md->memuse > rd->memuse) rd->memuse = md->memuse; @@ -4578,11 +3590,12 @@ bool stack_analyse(jitdata *jd) copy = curstack; while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; copy->flags |= SAVEDVAR; copy = copy->prev; } + /* FALLTHROUGH */ - /* fall through */ #endif /* !SUPPORT_DIVISION */ case ICMD_ISHL: @@ -4595,30 +3608,32 @@ bool stack_analyse(jitdata *jd) case ICMD_IOR: case ICMD_IXOR: COUNT(count_pcmd_op); - OP2_1(TYPE_INT); + OP2_1(TYPE_INT, TYPE_INT, TYPE_INT); break; case ICMD_LDIV: case ICMD_LREM: + coalescing_boundary = sd.new; #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) - bte = (builtintable_entry *) iptr->val.a; + bte = iptr->sx.s23.s3.bte; md = bte->md; - i = iptr->op1; if (md->memuse > rd->memuse) rd->memuse = md->memuse; if (md->argintreguse > rd->argintreguse) rd->argintreguse = md->argintreguse; + /* XXX non-leaf method? */ /* make all stack variables saved */ copy = curstack; while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; copy->flags |= SAVEDVAR; copy = copy->prev; } + /* FALLTHROUGH */ - /* fall through */ #endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */ case ICMD_LMUL: @@ -4630,14 +3645,14 @@ bool stack_analyse(jitdata *jd) case ICMD_LXOR: #endif /* SUPPORT_LONG_LOGICAL */ COUNT(count_pcmd_op); - OP2_1(TYPE_LNG); + OP2_1(TYPE_LNG, TYPE_LNG, TYPE_LNG); break; case ICMD_LSHL: case ICMD_LSHR: case ICMD_LUSHR: COUNT(count_pcmd_op); - OP2IT_1(TYPE_LNG); + OP2_1(TYPE_LNG, TYPE_INT, TYPE_LNG); break; case ICMD_FADD: @@ -4646,7 +3661,7 @@ bool stack_analyse(jitdata *jd) case ICMD_FDIV: case ICMD_FREM: COUNT(count_pcmd_op); - OP2_1(TYPE_FLT); + OP2_1(TYPE_FLT, TYPE_FLT, TYPE_FLT); break; case ICMD_DADD: @@ -4655,239 +3670,232 @@ bool stack_analyse(jitdata *jd) case ICMD_DDIV: case ICMD_DREM: COUNT(count_pcmd_op); - OP2_1(TYPE_DBL); + OP2_1(TYPE_DBL, TYPE_DBL, TYPE_DBL); break; case ICMD_LCMP: COUNT(count_pcmd_op); #if SUPPORT_LONG_CMP_CONST - if ((len > 0) && (iptr[1].val.i == 0)) { - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr[0].opc = ICMD_IF_LCMPEQ; - icmd_lcmp_if_tail: - iptr[0].op1 = iptr[1].op1; - iptr[1].opc = ICMD_NOP; -/* len--; */ -/* bptr->icount--; */ + if ((len == 0) || (iptr[1].sx.val.i != 0)) + goto normal_LCMP; - OP2_0(TYPE_LNG); - tbptr = m->basicblocks + - m->basicblockindex[iptr[0].op1]; - - iptr[0].target = (void *) tbptr; + switch (iptr[1].opc) { + case ICMD_IFEQ: + iptr->opc = ICMD_IF_LCMPEQ; + icmd_lcmp_if_tail: + iptr->dst.insindex = iptr[1].dst.insindex; + iptr[1].opc = ICMD_NOP; - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr[0].opc = ICMD_IF_LCMPNE; - goto icmd_lcmp_if_tail; - case ICMD_IFLT: - iptr[0].opc = ICMD_IF_LCMPLT; - goto icmd_lcmp_if_tail; - case ICMD_IFGT: - iptr[0].opc = ICMD_IF_LCMPGT; - goto icmd_lcmp_if_tail; - case ICMD_IFLE: - iptr[0].opc = ICMD_IF_LCMPLE; - goto icmd_lcmp_if_tail; - case ICMD_IFGE: - iptr[0].opc = ICMD_IF_LCMPGE; - goto icmd_lcmp_if_tail; - default: - OPTT2_1(TYPE_LNG, TYPE_INT); - } + OP2_BRANCH(TYPE_LNG, TYPE_LNG); + BRANCH(tbptr); + + COUNT(count_pcmd_bra); + break; + case ICMD_IFNE: + iptr->opc = ICMD_IF_LCMPNE; + goto icmd_lcmp_if_tail; + case ICMD_IFLT: + iptr->opc = ICMD_IF_LCMPLT; + goto icmd_lcmp_if_tail; + case ICMD_IFGT: + iptr->opc = ICMD_IF_LCMPGT; + goto icmd_lcmp_if_tail; + case ICMD_IFLE: + iptr->opc = ICMD_IF_LCMPLE; + goto icmd_lcmp_if_tail; + case ICMD_IFGE: + iptr->opc = ICMD_IF_LCMPGE; + goto icmd_lcmp_if_tail; + default: + goto normal_LCMP; } - else + break; +normal_LCMP: #endif /* SUPPORT_LONG_CMP_CONST */ - OPTT2_1(TYPE_LNG, TYPE_INT); + 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].val.i == 0)) { - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr[0].opc = ICMD_IF_FCMPEQ; - icmd_if_fcmpl_tail: - iptr[0].op1 = iptr[1].op1; - iptr[1].opc = ICMD_NOP; + 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_0(TYPE_FLT); - tbptr = m->basicblocks + - m->basicblockindex[iptr[0].op1]; - - iptr[0].target = (void *) tbptr; + OP2_BRANCH(TYPE_FLT, TYPE_FLT); + BRANCH(tbptr); - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr[0].opc = ICMD_IF_FCMPNE; - goto icmd_if_fcmpl_tail; - case ICMD_IFLT: - iptr[0].opc = ICMD_IF_FCMPL_LT; - goto icmd_if_fcmpl_tail; - case ICMD_IFGT: - iptr[0].opc = ICMD_IF_FCMPL_GT; - goto icmd_if_fcmpl_tail; - case ICMD_IFLE: - iptr[0].opc = ICMD_IF_FCMPL_LE; - goto icmd_if_fcmpl_tail; - case ICMD_IFGE: - iptr[0].opc = ICMD_IF_FCMPL_GE; - goto icmd_if_fcmpl_tail; - default: - OPTT2_1(TYPE_FLT, TYPE_INT); - } + 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; } - else - OPTT2_1(TYPE_FLT, TYPE_INT); + break; + +normal_FCMPL: + OPTT2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); break; case ICMD_FCMPG: COUNT(count_pcmd_op); - if ((len > 0) && (iptr[1].val.i == 0)) { - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr[0].opc = ICMD_IF_FCMPEQ; - icmd_if_fcmpg_tail: - iptr[0].op1 = iptr[1].op1; - iptr[1].opc = ICMD_NOP; + 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_0(TYPE_FLT); - tbptr = m->basicblocks + - m->basicblockindex[iptr[0].op1]; - - iptr[0].target = (void *) tbptr; + OP2_BRANCH(TYPE_FLT, TYPE_FLT); + BRANCH(tbptr); - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr[0].opc = ICMD_IF_FCMPNE; - goto icmd_if_fcmpg_tail; - case ICMD_IFLT: - iptr[0].opc = ICMD_IF_FCMPG_LT; - goto icmd_if_fcmpg_tail; - case ICMD_IFGT: - iptr[0].opc = ICMD_IF_FCMPG_GT; - goto icmd_if_fcmpg_tail; - case ICMD_IFLE: - iptr[0].opc = ICMD_IF_FCMPG_LE; - goto icmd_if_fcmpg_tail; - case ICMD_IFGE: - iptr[0].opc = ICMD_IF_FCMPG_GE; - goto icmd_if_fcmpg_tail; - default: - OPTT2_1(TYPE_FLT, TYPE_INT); - } + 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; } - else - OPTT2_1(TYPE_FLT, TYPE_INT); + break; + +normal_FCMPG: + OP2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); break; case ICMD_DCMPL: COUNT(count_pcmd_op); - if ((len > 0) && (iptr[1].val.i == 0)) { - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr[0].opc = ICMD_IF_DCMPEQ; - icmd_if_dcmpl_tail: - iptr[0].op1 = iptr[1].op1; - iptr[1].opc = ICMD_NOP; + 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_0(TYPE_DBL); - tbptr = m->basicblocks + - m->basicblockindex[iptr[0].op1]; - - iptr[0].target = (void *) tbptr; + OP2_BRANCH(TYPE_DBL, TYPE_DBL); + BRANCH(tbptr); - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr[0].opc = ICMD_IF_DCMPNE; - goto icmd_if_dcmpl_tail; - case ICMD_IFLT: - iptr[0].opc = ICMD_IF_DCMPL_LT; - goto icmd_if_dcmpl_tail; - case ICMD_IFGT: - iptr[0].opc = ICMD_IF_DCMPL_GT; - goto icmd_if_dcmpl_tail; - case ICMD_IFLE: - iptr[0].opc = ICMD_IF_DCMPL_LE; - goto icmd_if_dcmpl_tail; - case ICMD_IFGE: - iptr[0].opc = ICMD_IF_DCMPL_GE; - goto icmd_if_dcmpl_tail; - default: - OPTT2_1(TYPE_DBL, TYPE_INT); - } + 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; } - else - OPTT2_1(TYPE_DBL, TYPE_INT); + break; + +normal_DCMPL: + OPTT2_1(TYPE_DBL, TYPE_INT); break; case ICMD_DCMPG: COUNT(count_pcmd_op); - if ((len > 0) && (iptr[1].val.i == 0)) { - switch (iptr[1].opc) { - case ICMD_IFEQ: - iptr[0].opc = ICMD_IF_DCMPEQ; - icmd_if_dcmpg_tail: - iptr[0].op1 = iptr[1].op1; - iptr[1].opc = ICMD_NOP; + 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_0(TYPE_DBL); - tbptr = m->basicblocks + - m->basicblockindex[iptr[0].op1]; - - iptr[0].target = (void *) tbptr; + OP2_BRANCH(TYPE_DBL, TYPE_DBL); + BRANCH(tbptr); - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); - break; - case ICMD_IFNE: - iptr[0].opc = ICMD_IF_DCMPNE; - goto icmd_if_dcmpg_tail; - case ICMD_IFLT: - iptr[0].opc = ICMD_IF_DCMPG_LT; - goto icmd_if_dcmpg_tail; - case ICMD_IFGT: - iptr[0].opc = ICMD_IF_DCMPG_GT; - goto icmd_if_dcmpg_tail; - case ICMD_IFLE: - iptr[0].opc = ICMD_IF_DCMPG_LE; - goto icmd_if_dcmpg_tail; - case ICMD_IFGE: - iptr[0].opc = ICMD_IF_DCMPG_GE; - goto icmd_if_dcmpg_tail; - default: - OPTT2_1(TYPE_DBL, TYPE_INT); - } + 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; } - else - OPTT2_1(TYPE_DBL, TYPE_INT); + break; + +normal_DCMPG: + OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); break; #else case ICMD_FCMPL: case ICMD_FCMPG: COUNT(count_pcmd_op); - OPTT2_1(TYPE_FLT, TYPE_INT); + OP2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); break; case ICMD_DCMPL: case ICMD_DCMPG: COUNT(count_pcmd_op); - OPTT2_1(TYPE_DBL, TYPE_INT); + OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); break; #endif /* pop 1 push 1 */ - + case ICMD_INEG: case ICMD_INT2BYTE: case ICMD_INT2CHAR: @@ -4958,7 +3966,8 @@ bool stack_analyse(jitdata *jd) break; case ICMD_CHECKCAST: - if (iptr->op1 == 0) { + coalescing_boundary = sd.new; + if (iptr->flags.bits & INS_FLAG_ARRAY) { /* array type cast-check */ bte = builtintable_get_internal(BUILTIN_arraycheckcast); @@ -4973,6 +3982,7 @@ bool stack_analyse(jitdata *jd) copy = curstack; while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; copy->flags |= SAVEDVAR; copy = copy->prev; } @@ -4982,59 +3992,67 @@ bool stack_analyse(jitdata *jd) case ICMD_INSTANCEOF: case ICMD_ARRAYLENGTH: + coalescing_boundary = sd.new; OP1_1(TYPE_ADR, TYPE_INT); break; case ICMD_NEWARRAY: case ICMD_ANEWARRAY: + coalescing_boundary = sd.new; OP1_1(TYPE_INT, TYPE_ADR); break; case ICMD_GETFIELD: + coalescing_boundary = sd.new; COUNT(count_check_null); COUNT(count_pcmd_mem); - OP1_1(TYPE_ADR, iptr->op1); + INSTRUCTION_GET_FIELDREF(iptr, fmiref); + OP1_1(TYPE_ADR, fmiref->parseddesc.fd->type); break; /* pop 0 push 1 */ - + case ICMD_GETSTATIC: + coalescing_boundary = sd.new; COUNT(count_pcmd_mem); - OP0_1(iptr->op1); + INSTRUCTION_GET_FIELDREF(iptr, fmiref); + OP0_1(fmiref->parseddesc.fd->type); break; case ICMD_NEW: + coalescing_boundary = sd.new; OP0_1(TYPE_ADR); break; case ICMD_JSR: - OP0_1(TYPE_ADR); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; + OP0_1(TYPE_RET); - /* This is a dirty hack. The typechecker - * needs it because the OP1_0ANY below - * overwrites iptr->dst. - */ - iptr->val.a = (void *) iptr->dst; + 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; + tbptr = stack_mark_reached(&sd, tbptr, curstack, stackdepth); + if (!tbptr) + return false; + + iptr->sx.s23.s3.jsrtarget.block = tbptr; + /* We need to check for overflow right here because - * the pushed value is poped after MARKREACHED. */ + * the pushed value is poped afterwards */ CHECKOVERFLOW; - MARKREACHED(tbptr, copy); - OP1_0ANY; + + superblockend = true; + /* XXX should not be marked as interface, as it does not need to be */ + /* allocated. Same for the invar of the target. */ break; /* pop many push any */ case ICMD_BUILTIN: -#if defined(USEBUILTINTABLE) - builtin: -#endif - bte = (builtintable_entry *) iptr->val.a; +icmd_BUILTIN: + bte = iptr->sx.s23.s3.bte; md = bte->md; goto _callhandling; @@ -5043,13 +4061,21 @@ bool stack_analyse(jitdata *jd) case ICMD_INVOKEVIRTUAL: case ICMD_INVOKEINTERFACE: COUNT(count_pcmd_met); - INSTRUCTION_GET_METHODDESC(iptr,md); + + /* Check for functions to replace with builtin + * functions. */ + + if (builtintable_replace_function(iptr)) + goto icmd_BUILTIN; + + INSTRUCTION_GET_METHODDESC(iptr, md); + /* XXX resurrect this COUNT? */ /* if (lm->flags & ACC_STATIC) */ -/* {COUNT(count_check_null);} */ +/* {COUNT(count_check_null);} */ _callhandling: - last_pei = bptr->icount - len - 1; + coalescing_boundary = sd.new; i = md->paramcount; @@ -5062,87 +4088,123 @@ bool stack_analyse(jitdata *jd) REQUIRE(i); + /* XXX optimize for <= 2 args */ + /* XXX not for ICMD_BUILTIN */ + iptr->s1.argcount = stackdepth; + iptr->sx.s23.s2.args = DMNEW(s4, stackdepth); + copy = curstack; for (i-- ; i >= 0; i--) { + iptr->sx.s23.s2.args[i] = copy->varnum; + + /* do not change STACKVARs or LOCALVARS to ARGVAR*/ + /* -> won't help anyway */ + if (!(IS_INOUT(copy) || IS_LOCALVAR(copy))) { + #if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) - /* If we pass float arguments in integer argument registers, we - * are not allowed to precolor them here. Floats have to be moved - * to this regs explicitly in codegen(). - * Only arguments that are passed by stack anyway can be precolored - * (michi 2005/07/24) */ - if (!(copy->flags & SAVEDVAR) && - (!IS_FLT_DBL_TYPE(copy->type) || md->params[i].inmemory)) { + /* If we pass float arguments in integer argument registers, we + * are not allowed to precolor them here. Floats have to be moved + * to this regs explicitly in codegen(). + * Only arguments that are passed by stack anyway can be precolored + * (michi 2005/07/24) */ + if (!(sd.var[copy->varnum].flags & SAVEDVAR) && + (!IS_FLT_DBL_TYPE(copy->type) + || md->params[i].inmemory)) { #else - if (!(copy->flags & SAVEDVAR)) { + if (!(sd.var[copy->varnum].flags & SAVEDVAR)) { #endif - copy->varkind = ARGVAR; - copy->varnum = i; -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif - if (md->params[i].inmemory) { - copy->flags = INMEMORY; - copy->regoff = md->params[i].regoff; - } - else { - copy->flags = 0; - if (IS_FLT_DBL_TYPE(copy->type)) + SET_PREALLOC(copy); + + 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 - copy->regoff = - rd->argfltregs[md->params[i].regoff]; -#endif - else { + sd.var[copy->varnum].vv.regoff = + rd->argfltregs[md->params[i].regoff]; +#endif /* SUPPORT_PASS_FLOATARGS_IN_INTREGS */ + } + else { #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(copy->type)) - copy->regoff = PACK_REGS( - rd->argintregs[GET_LOW_REG(md->params[i].regoff)], - rd->argintregs[GET_HIGH_REG(md->params[i].regoff)]); - else -#endif - copy->regoff = - rd->argintregs[md->params[i].regoff]; - } + 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)]); + + else +#endif /* SUPPORT_COMBINE_INTEGER_REGISTERS */ + sd.var[copy->varnum].vv.regoff = + rd->argintregs[md->params[i].regoff]; } -#if defined(ENABLE_INTRP) } -#endif + } } copy = copy->prev; } + /* 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 = copy->prev; } + /* pop the arguments */ + i = md->paramcount; - POPMANY(i); - if (md->returntype.type != TYPE_VOID) - OP0_1(md->returntype.type); + + stackdepth -= i; + while (--i >= 0) { + POPANY; + } + + /* push the return value */ + + if (md->returntype.type != TYPE_VOID) { + GET_NEW_VAR(sd, new_index, md->returntype.type); + DST(md->returntype.type, new_index); + stackdepth++; + } break; case ICMD_INLINE_START: case ICMD_INLINE_END: - SETDST; + CLR_S1; + CLR_DST; break; case ICMD_MULTIANEWARRAY: + coalescing_boundary = sd.new; if (rd->argintreguse < 3) rd->argintreguse = 3; - i = iptr->op1; + i = iptr->s1.argcount; REQUIRE(i); + + iptr->sx.s23.s2.args = DMNEW(s4, i); + #if defined(SPECIALMEMUSE) # if defined(__DARWIN__) - if (rd->memuse < (i + INT_ARG_CNT + LA_WORD_SIZE)) - rd->memuse = i + LA_WORD_SIZE + INT_ARG_CNT; + if (rd->memuse < (i + INT_ARG_CNT +LA_SIZE_IN_POINTERS)) + rd->memuse = i + LA_SIZE_IN_POINTERS + INT_ARG_CNT; # else - if (rd->memuse < (i + LA_WORD_SIZE + 3)) - rd->memuse = i + LA_WORD_SIZE + 3; + if (rd->memuse < (i + LA_SIZE_IN_POINTERS + 3)) + rd->memuse = i + LA_SIZE_IN_POINTERS + 3; # endif #else # if defined(__I386__) @@ -5158,36 +4220,48 @@ bool stack_analyse(jitdata *jd) #endif copy = curstack; while (--i >= 0) { - /* check INT type here? Currently typecheck does this. */ - if (!(copy->flags & SAVEDVAR)) { + /* check INT type here? Currently typecheck does this. */ + iptr->sx.s23.s2.args[i] = copy->varnum; + if (!(sd.var[copy->varnum].flags & SAVEDVAR) + && (!IS_INOUT(copy)) + && (!IS_LOCALVAR(copy)) ) { copy->varkind = ARGVAR; - copy->varnum = i + INT_ARG_CNT; - copy->flags |= INMEMORY; + sd.var[copy->varnum].flags |= + INMEMORY & PREALLOC; #if defined(SPECIALMEMUSE) # if defined(__DARWIN__) - copy->regoff = i + LA_WORD_SIZE + INT_ARG_CNT; + sd.var[copy->varnum].vv.regoff = i + + LA_SIZE_IN_POINTERS + INT_ARG_CNT; # else - copy->regoff = i + LA_WORD_SIZE + 3; + sd.var[copy->varnum].vv.regoff = i + + LA_SIZE_IN_POINTERS + 3; # endif #else # if defined(__I386__) - copy->regoff = i + 3; + sd.var[copy->varnum].vv.regoff = i + 3; # elif defined(__MIPS__) && SIZEOF_VOID_P == 4 - copy->regoff = i + 2; + sd.var[copy->varnum].vv.regoff = i + 2; # else - copy->regoff = i; + sd.var[copy->varnum].vv.regoff = i; # endif /* defined(__I386__) */ #endif /* defined(SPECIALMEMUSE) */ } copy = copy->prev; } while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; copy->flags |= SAVEDVAR; copy = copy->prev; } - i = iptr->op1; - POPMANY(i); - OP0_1(TYPE_ADR); + + i = iptr->s1.argcount; + stackdepth -= i; + while (--i >= 0) { + POPANY; + } + GET_NEW_VAR(sd, new_index, TYPE_ADR); + DST(TYPE_ADR, new_index); + stackdepth++; break; default: @@ -5200,70 +4274,120 @@ bool stack_analyse(jitdata *jd) iptr++; } /* while instructions */ - /* set out-stack of block */ - - bptr->outstack = curstack; - bptr->outdepth = stackdepth; - /* stack slots at basic block end become interfaces */ + sd.bptr->outdepth = stackdepth; + sd.bptr->outvars = DMNEW(s4, stackdepth); + i = stackdepth - 1; for (copy = curstack; copy; i--, copy = copy->prev) { - if ((copy->varkind == STACKVAR) && (copy->varnum > i)) - copy->varkind = TEMPVAR; + varinfo *v; + s4 t; + + /* with the new vars rd->interfaces will be removed */ + /* and all in and outvars have to be STACKVARS! */ + /* in the moment i.e. SWAP with in and out vars can */ + /* create an unresolvable conflict */ + + SET_TEMPVAR(copy); + t = copy->type; + if (t == TYPE_RET) + t = TYPE_ADR; + + v = sd.var + copy->varnum; + 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 { - copy->varkind = STACKVAR; - copy->varnum = i; + jd->interface_map[i*5 + t].flags |= v->flags; } - IF_NO_INTRP( - rd->interfaces[i][copy->type].type = copy->type; - rd->interfaces[i][copy->type].flags |= copy->flags; - ); + + sd.bptr->outvars[i] = copy->varnum; } /* check if interface slots at basic block begin must be saved */ - IF_NO_INTRP( - i = bptr->indepth - 1; - for (copy = bptr->instack; copy; i--, copy = copy->prev) { - rd->interfaces[i][copy->type].type = copy->type; - if (copy->varkind == STACKVAR) { - if (copy->flags & SAVEDVAR) - rd->interfaces[i][copy->type].flags |= SAVEDVAR; - } + 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; + + 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; } - ); + } - } /* if */ - else - superblockend = true; + /* store the number of this block's variables */ + + sd.bptr->varcount = sd.vartop - sd.bptr->varstart; + +#if defined(STACK_VERBOSE) + stack_verbose_block_exit(&sd, superblockend); +#endif + + /* reach the following block, if any */ + + if (!superblockend) + if (!stack_reach_next_block(&sd)) + return false; + + } /* for blocks */ + + } while (sd.repeat && !deadcode); + + /* XXX reset TYPE_RET to TYPE_ADR */ + + for (i=0; iexceptiontable; + for (; ex != NULL; ex = ex->down) { + if (ex->start == ex->end) { + assert(ex->end->next); + ex->end = ex->end->next; + } + } + + /* gather statistics *****************************************************/ #if defined(ENABLE_STATISTICS) if (opt_stat) { - if (m->basicblockcount > count_max_basic_blocks) - count_max_basic_blocks = m->basicblockcount; - count_basic_blocks += m->basicblockcount; - if (m->instructioncount > count_max_javainstr) count_max_javainstr = m->instructioncount; - count_javainstr += m->instructioncount; - if (m->stackcount > count_upper_bound_new_stack) - count_upper_bound_new_stack = m->stackcount; - if ((new - m->stack) > count_max_new_stack) - count_max_new_stack = (new - m->stack); - - b_count = m->basicblockcount; - bptr = m->basicblocks; - while (--b_count >= 0) { - if (bptr->flags > BBREACHED) { - if (bptr->indepth >= 10) + 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) count_block_stack[10]++; else - count_block_stack[bptr->indepth]++; - len = bptr->icount; - if (len < 10) + count_block_stack[sd.bptr->indepth]++; + len = sd.bptr->icount; + if (len < 10) count_block_size_distribution[len]++; else if (len <= 12) count_block_size_distribution[10]++; @@ -5282,58 +4406,54 @@ bool stack_analyse(jitdata *jd) else count_block_size_distribution[17]++; } - bptr++; } - if (loops == 1) + if (iteration_count == 1) count_analyse_iterations[0]++; - else if (loops == 2) + else if (iteration_count == 2) count_analyse_iterations[1]++; - else if (loops == 3) + else if (iteration_count == 3) count_analyse_iterations[2]++; - else if (loops == 4) + else if (iteration_count == 4) count_analyse_iterations[3]++; else count_analyse_iterations[4]++; - if (m->basicblockcount <= 5) + if (jd->basicblockcount <= 5) count_method_bb_distribution[0]++; - else if (m->basicblockcount <= 10) + else if (jd->basicblockcount <= 10) count_method_bb_distribution[1]++; - else if (m->basicblockcount <= 15) + else if (jd->basicblockcount <= 15) count_method_bb_distribution[2]++; - else if (m->basicblockcount <= 20) + else if (jd->basicblockcount <= 20) count_method_bb_distribution[3]++; - else if (m->basicblockcount <= 30) + else if (jd->basicblockcount <= 30) count_method_bb_distribution[4]++; - else if (m->basicblockcount <= 40) + else if (jd->basicblockcount <= 40) count_method_bb_distribution[5]++; - else if (m->basicblockcount <= 50) + else if (jd->basicblockcount <= 50) count_method_bb_distribution[6]++; - else if (m->basicblockcount <= 75) + else if (jd->basicblockcount <= 75) count_method_bb_distribution[7]++; else count_method_bb_distribution[8]++; } #endif /* defined(ENABLE_STATISTICS) */ - /* everything's ok */ + /* everything's ok *******************************************************/ return true; + /* goto labels for throwing verifier exceptions **************************/ + #if defined(ENABLE_VERIFIER) throw_stack_underflow: - *exceptionptr = - new_verifyerror(m, "Unable to pop operand off an empty stack"); + exceptions_throw_verifyerror(m, "Unable to pop operand off an empty stack"); return false; throw_stack_overflow: - *exceptionptr = new_verifyerror(m, "Stack size too large"); - return false; - -throw_stack_depth_error: - *exceptionptr = new_verifyerror(m,"Stack depth mismatch"); + exceptions_throw_verifyerror(m, "Stack size too large"); return false; throw_stack_type_error: @@ -5341,14 +4461,109 @@ throw_stack_type_error: return false; throw_stack_category_error: - *exceptionptr = - new_verifyerror(m, "Attempt to split long or double on the stack"); + exceptions_throw_verifyerror(m, "Attempt to split long or double on the stack"); return false; #endif } +/* 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) + printf("{L%03d}", v->vv.retaddr->nr); +} + + +static void stack_verbose_show_variable(stackdata_t *sd, s4 index) +{ + assert(index >= 0 && index < sd->vartop); + stack_verbose_show_varinfo(sd, sd->var + index); +} + + +static void stack_verbose_show_block(stackdata_t *sd, basicblock *bptr) +{ + s4 i; + + printf("L%03d type:%d in:%d [", bptr->nr, bptr->type, bptr->indepth); + if (bptr->invars) { + for (i=0; iindepth; ++i) { + if (i) + putchar(' '); + stack_verbose_show_variable(sd, bptr->invars[i]); + } + } + else + putchar('-'); + printf("] inlocals ["); + if (bptr->inlocals) { + for (i=0; ilocalcount; ++i) { + if (i) + putchar(' '); + stack_verbose_show_varinfo(sd, bptr->inlocals + i); + } + } + else + putchar('-'); + printf("] out:%d [", bptr->outdepth); + if (bptr->outvars) { + for (i=0; ioutdepth; ++i) { + if (i) + putchar(' '); + stack_verbose_show_variable(sd, bptr->outvars[i]); + } + } + else + putchar('-'); + printf("]"); + + if (bptr->original) + printf(" (clone of L%03d)", bptr->original->nr); + else { + basicblock *b = bptr->copied_to; + if (b) { + printf(" (copied to "); + for (; b; b = b->copied_to) + printf("L%03d ", b->nr); + printf(")"); + } + } +} + + +static void stack_verbose_block_enter(stackdata_t *sd, bool reanalyse) +{ + int i; + + printf("======================================== STACK %sANALYSE BLOCK ", + (reanalyse) ? "RE-" : ""); + stack_verbose_show_block(sd, sd->bptr); + printf("\n"); + + if (sd->handlers[0]) { + printf("HANDLERS: "); + for (i=0; sd->handlers[i]; ++i) { + printf("L%03d ", sd->handlers[i]->handler->nr); + } + printf("\n"); + } + printf("\n"); +} + + +static void stack_verbose_block_exit(stackdata_t *sd, bool superblockend) +{ + printf("%s ", (superblockend) ? "SUPERBLOCKEND" : "END"); + stack_verbose_show_block(sd, sd->bptr); + printf("\n"); +} +#endif + /* * These are local overrides for various environment variables in Emacs.