+ 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;
+ dv = sd->var + index;
+ sv = sd->var + sp->varnum;
+ dv->flags = INOUT;
+ COPY_VAL_AND_TYPE_VAR(sv, dv);
+ }
+
+ stack_create_locals(sd, b);
+}
+
+
+/* stack_create_invars_from_outvars ********************************************
+
+ 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.
+
+ IN:
+ sd...........stack analysis data
+ b............block to create the invars for
+
+*******************************************************************************/
+
+static void stack_create_invars_from_outvars(stackdata_t *sd, basicblock *b)
+{
+ int i;
+ int n;
+ varinfo *sv, *dv;
+
+ n = sd->bptr->outdepth;
+ assert(sd->vartop + n <= sd->varcount);
+
+ b->indepth = n;
+ b->invars = DMNEW(s4, n);
+
+ if (n) {
+ dv = sd->var + sd->vartop;
+
+ /* allocate the invars */
+
+ for (i=0; i<n; ++i, ++dv) {
+ sv = sd->var + sd->bptr->outvars[i];
+ b->invars[i] = sd->vartop++;
+ dv->flags = INOUT;
+ COPY_VAL_AND_TYPE_VAR(sv, dv);
+ }
+ }
+
+ stack_create_locals(sd, b);
+}
+
+
+/* stack_check_invars **********************************************************
+
+ Check the current stack against the invars of the given basic block.
+ Depth and types must match.
+
+ IN:
+ sd...........stack analysis data
+ b............block which invars to check against
+ curstack.....current stack top
+ stackdepth...current stack depth
+
+ RETURN VALUE:
+ the destinaton block
+ NULL.........a VerifyError has been thrown
+
+*******************************************************************************/
+
+static basicblock * stack_check_invars(stackdata_t *sd, basicblock *b,
+ stackelement_t * curstack, int stackdepth)
+{
+ int i;
+ stackelement_t * sp;
+ basicblock *orig;
+ bool separable;
+ varinfo *sv;
+ varinfo *dv;
+
+#if defined(STACK_VERBOSE)
+ printf("stack_check_invars(L%03d)\n", b->nr);
+#endif
+
+ /* find original of b */
+ if (b->original)
+ b = b->original;
+ orig = b;
+
+#if defined(STACK_VERBOSE)
+ printf("original is L%03d\n", orig->nr);
+#endif
+
+ i = orig->indepth;
+
+#if defined(ENABLE_VERIFIER)
+ if (i != stackdepth) {
+ exceptions_throw_verifyerror(sd->m, "Stack depth mismatch");
+ return NULL;
+ }
+#endif
+
+ do {
+ separable = false;
+
+#if defined(STACK_VERBOSE)
+ printf("checking against ");
+ stack_verbose_show_block(sd, b); printf("\n");
+#endif
+
+ sp = curstack;
+ for (i = orig->indepth; i--; sp = sp->prev) {
+ dv = sd->var + b->invars[i];
+ sv = sd->var + sp->varnum;
+
+#if defined(ENABLE_VERIFIER)
+ if (dv->type != sp->type) {
+ exceptions_throw_verifyerror_for_stack(sd->m, dv->type);
+ return NULL;
+ }
+#endif
+
+ if (sp->type == TYPE_RET) {
+#if defined(ENABLE_VERIFIER)
+ if (dv->SBRSTART != sv->SBRSTART) {
+ exceptions_throw_verifyerror(sd->m, "Mismatched stack types");
+ return NULL;
+ }
+#endif
+ if (dv->vv.retaddr != sv->vv.retaddr) {
+ separable = true;
+ /* don't break! have to check the remaining stackslots */
+ }
+ }
+ }
+
+ if (b->inlocals) {
+ for (i=0; i<sd->localcount; ++i) {
+ dv = b->inlocals + i;
+ sv = sd->var + i;
+ if (sv->type == TYPE_RET && dv->type == TYPE_RET) {
+ if (
+#if defined(ENABLE_VERIFIER)
+ (sv->SBRSTART == dv->SBRSTART) &&
+#endif
+ (sv->vv.retaddr != dv->vv.retaddr))
+ {
+ separable = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!separable) {
+ /* XXX cascading collapse? */
+
+ stack_merge_locals(sd, b);
+
+#if defined(STACK_VERBOSE)
+ printf("------> using L%03d\n", b->nr);
+#endif
+ return b;
+ }
+ } while ((b = b->copied_to) != NULL);
+
+ b = stack_clone_block(sd, orig);
+ if (!b)
+ return NULL;
+
+ stack_create_invars(sd, b, curstack, stackdepth);
+ return b;
+}
+
+
+/* stack_check_invars_from_outvars *********************************************
+
+ Check the outvars of the current block against the invars of the given block.
+ Depth and types must match.
+
+ IN:
+ sd...........stack analysis data
+ b............block which invars to check against
+
+ RETURN VALUE:
+ the destinaton block
+ NULL.........a VerifyError has been thrown
+
+*******************************************************************************/
+
+static basicblock * stack_check_invars_from_outvars(stackdata_t *sd, basicblock *b)
+{
+ int i;
+ int n;
+ varinfo *sv, *dv;
+ basicblock *orig;
+ bool separable;
+
+#if defined(STACK_VERBOSE)
+ printf("stack_check_invars_from_outvars(L%03d)\n", b->nr);
+#endif
+
+ /* find original of b */
+ if (b->original)
+ b = b->original;
+ orig = b;
+
+#if defined(STACK_VERBOSE)
+ printf("original is L%03d\n", orig->nr);
+#endif
+
+ i = orig->indepth;
+ n = sd->bptr->outdepth;
+
+#if defined(ENABLE_VERIFIER)
+ if (i != n) {
+ exceptions_throw_verifyerror(sd->m, "Stack depth mismatch");
+ return NULL;
+ }
+#endif
+
+ do {
+ separable = false;
+
+#if defined(STACK_VERBOSE)
+ printf("checking against ");
+ stack_verbose_show_block(sd, b); printf("\n");
+#endif
+
+ if (n) {
+ dv = sd->var + b->invars[0];
+
+ for (i=0; i<n; ++i, ++dv) {
+ sv = sd->var + sd->bptr->outvars[i];
+
+#if defined(ENABLE_VERIFIER)
+ if (sv->type != dv->type) {
+ exceptions_throw_verifyerror_for_stack(sd->m, dv->type);
+ return NULL;
+ }
+#endif
+
+ if (dv->type == TYPE_RET) {
+#if defined(ENABLE_VERIFIER)
+ if (sv->SBRSTART != dv->SBRSTART) {
+ exceptions_throw_verifyerror(sd->m, "Mismatched stack types");
+ return NULL;
+ }
+#endif
+ if (sv->vv.retaddr != dv->vv.retaddr) {
+ separable = true;
+ /* don't break! have to check the remaining stackslots */
+ }
+ }
+ }
+ }
+
+ if (b->inlocals) {
+ for (i=0; i<sd->localcount; ++i) {
+ dv = b->inlocals + i;
+ sv = sd->var + i;
+ if (
+#if defined(ENABLE_VERIFIER)
+ (sv->SBRSTART == dv->SBRSTART) &&
+#endif
+ (sv->type == TYPE_RET && dv->type == TYPE_RET))
+ {
+ if (sv->vv.retaddr != dv->vv.retaddr) {
+ separable = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!separable) {
+ /* XXX cascading collapse? */
+
+ stack_merge_locals(sd, b);
+
+#if defined(STACK_VERBOSE)
+ printf("------> using L%03d\n", b->nr);
+#endif
+ return b;
+ }
+ } while ((b = b->copied_to) != NULL);
+
+ b = stack_clone_block(sd, orig);
+ if (!b)
+ return NULL;
+
+ stack_create_invars_from_outvars(sd, b);
+ return b;
+}
+
+
+/* stack_create_instack ********************************************************
+
+ Create the instack of the current basic block.
+
+ IN:
+ sd...........stack analysis data
+
+ RETURN VALUE:
+ the current stack top at the start of the basic block.
+
+*******************************************************************************/
+
+static stackelement_t * stack_create_instack(stackdata_t *sd)
+{
+ stackelement_t * 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;
+
+ /* return the top of the created stack */
+ return sd->new - 1;
+}
+
+
+/* stack_mark_reached **********************************************************
+
+ 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.
+
+ IN:
+ sd...........stack analysis data
+ b............the block to reach
+ curstack.....the current stack top
+ stackdepth...the current stack depth
+
+ RETURN VALUE:
+ a pointer to (a specialized version of) the target
+ NULL.........a VerifyError has been thrown
+
+*******************************************************************************/
+
+static basicblock *stack_mark_reached(stackdata_t *sd, basicblock *b, stackelement_t * curstack, int stackdepth)
+{
+ assert(b != NULL);
+
+#if defined(STACK_VERBOSE)
+ printf("stack_mark_reached(L%03d from L%03d)\n", b->nr, sd->bptr->nr);
+#endif
+
+ /* mark targets of backward branches */
+
+ if (b->nr <= sd->bptr->nr)
+ b->bitflags |= BBFLAG_REPLACEMENT;
+
+ if (b->flags < BBREACHED) {
+ /* b is reached for the first time. Create its invars. */
+
+#if defined(STACK_VERBOSE)
+ printf("reached L%03d for the first time\n", b->nr);
+#endif
+
+ stack_create_invars(sd, b, curstack, stackdepth);
+
+ b->flags = BBREACHED;
+
+ return b;
+ }
+ else {
+ /* b has been reached before. Check that its invars match. */
+
+ return stack_check_invars(sd, b, curstack, stackdepth);
+ }
+}
+
+
+/* stack_mark_reached_from_outvars *********************************************
+
+ 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.
+
+ IN:
+ sd...........stack analysis data
+ b............the block to reach
+
+ RETURN VALUE:
+ a pointer to (a specialized version of) the target
+ NULL.........a VerifyError has been thrown
+
+*******************************************************************************/
+
+static basicblock *stack_mark_reached_from_outvars(stackdata_t *sd, basicblock *b)
+{
+ assert(b != NULL);
+
+#if defined(STACK_VERBOSE)
+ printf("stack_mark_reached_from_outvars(L%03d from L%03d)\n", b->nr, sd->bptr->nr);
+#endif
+
+ /* mark targets of backward branches */
+
+ if (b->nr <= sd->bptr->nr)
+ b->bitflags |= BBFLAG_REPLACEMENT;
+
+ if (b->flags < BBREACHED) {
+ /* b is reached for the first time. Create its invars. */
+
+#if defined(STACK_VERBOSE)
+ printf("reached L%03d for the first time\n", b->nr);
+#endif
+
+ stack_create_invars_from_outvars(sd, b);
+
+ 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 == NULL)
+ return false;
+
+ if (tbptr != sd->bptr->next) {
+#if defined(STACK_VERBOSE)
+ printf("NEXT IS NON-CONSEQUITIVE L%03d\n", tbptr->nr);
+#endif
+ iptr = sd->bptr->iinstr + sd->bptr->icount - 1;
+ assert(iptr->opc == ICMD_NOP);
+ iptr->opc = ICMD_GOTO;
+ iptr->dst.block = tbptr;
+#if defined(STACK_VERBOSE)
+ if (iptr->line == 0) printf("goto with line 0 in L%03d\n", sd->bptr->nr);
+#endif
+
+ if (tbptr->flags < BBFINISHED)
+ sd->repeat = true; /* XXX check if we really need to repeat */
+ }
+
+ return true;
+}
+
+
+/* stack_reach_handlers ********************************************************
+
+ Reach the exception handlers for the current block.
+
+ IN:
+ sd...........stack analysis data
+
+ RETURN VALUE:
+ true.........everything ok
+ false........a VerifyError has been thrown
+
+*******************************************************************************/
+
+static bool stack_reach_handlers(stackdata_t *sd)
+{
+ s4 i;
+ basicblock *tbptr;
+
+#if defined(STACK_VERBOSE)
+ printf("reaching exception handlers...\n");
+#endif
+
+ for (i=0; sd->handlers[i]; ++i) {
+ tbptr = sd->handlers[i]->handler;
+
+ tbptr->type = BBTYPE_EXH;
+ tbptr->predecessorcount = CFG_UNKNOWN_PREDECESSORS;
+
+ /* reach (and specialize) the handler block */
+
+ tbptr = stack_mark_reached(sd, tbptr, &(sd->exstack), 1);
+
+ if (tbptr == NULL)
+ return false;
+
+ sd->handlers[i]->handler = tbptr;
+ }
+
+ return true;
+}
+
+
+/* stack_reanalyse_block ******************************************************
+
+ 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.).
+
+ IN:
+ sd...........stack analysis data
+
+ RETURN VALUE:
+ true.........everything ok
+ false........a VerifyError has been thrown
+
+*******************************************************************************/
+
+#define RELOCATE(index) \
+ do { \
+ if ((index) >= blockvarstart) \
+ (index) += blockvarshift; \
+ else if ((index) >= invarstart) \
+ (index) += invarshift; \
+ } while (0)
+
+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, varindex;
+ s4 *argp;
+ branch_target_t *table;
+ lookup_target_t *lookup;
+ bool superblockend;
+ bool cloneinstructions;
+ exception_entry *ex;
+
+#if defined(STACK_VERBOSE)
+ stack_verbose_block_enter(sd, true);
+#endif
+
+ b = sd->bptr;
+
+ if (!b->iinstr) {
+ orig = b->original;
+ assert(orig != NULL);
+
+ /* clone the instruction list */
+
+ cloneinstructions = true;
+
+ assert(orig->iinstr);
+ len = orig->icount;
+ iptr = DMNEW(instruction, len + 1);
+
+ MCOPY(iptr, orig->iinstr, instruction, len);
+ iptr[len].opc = ICMD_NOP;
+ iptr[len].line = 0;
+ iptr[len].flags.bits = 0;
+ b->iinstr = iptr;
+ b->icount = ++len;
+
+ /* reserve space for the clone's block variables */
+
+ stack_grow_variable_array(sd, orig->varcount);
+
+ /* we already have the invars set */
+
+ assert(b->indepth == orig->indepth);
+
+ /* calculate relocation shifts for invars and block variables */
+
+ 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;
+
+ /* copy block variables */
+
+ 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);
+
+ /* clone exception handlers */
+
+ for (i=0; sd->handlers[i]; ++i) {
+ ex = DNEW(exception_entry);
+ 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;
+
+ assert(sd->extableend->down == NULL);
+ sd->extableend->down = ex;
+ sd->extableend = ex;
+ sd->jd->exceptiontablelength++;
+
+ sd->handlers[i] = ex;
+ }
+ }
+ else {
+ cloneinstructions = false;
+ invarshift = 0;
+ blockvarshift = 0;
+ invarstart = sd->vartop;
+ blockvarstart = sd->vartop;
+ iptr = b->iinstr;
+ }
+
+ if (b->original) {
+ /* find exception handlers for the cloned block */
+ len = 0;
+ ex = sd->jd->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
+
+ /* mark block as finished */
+
+ b->flags = BBFINISHED;
+
+ /* initialize locals at the start of this block */
+
+ if (b->inlocals)
+ MCOPY(sd->var, b->inlocals, varinfo, sd->localcount);
+
+ MCOPY(sd->javalocals, b->javalocals, s4, sd->maxlocals);
+
+ /* reach exception handlers for this block */
+
+ if (!stack_reach_handlers(sd))
+ return false;
+
+ superblockend = false;
+
+ for (len = b->icount; len--; iptr++) {
+#if defined(STACK_VERBOSE)
+ show_icmd(sd->jd, iptr, false, SHOW_STACK);
+ printf("\n");
+#endif
+
+ switch (iptr->opc) {
+ case ICMD_RET:
+ varindex = iptr->s1.varindex;
+
+#if defined(ENABLE_VERIFIER)
+ if (sd->var[varindex].type != TYPE_RET) {
+ exceptions_throw_verifyerror(sd->m, "RET with non-returnAddress value");
+ return false;
+ }
+#endif
+
+ iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[varindex].vv.retaddr);
+ superblockend = true;
+ break;
+
+ case ICMD_JSR:
+ iptr->sx.s23.s3.jsrtarget.block = stack_mark_reached_from_outvars(sd, iptr->sx.s23.s3.jsrtarget.block);
+ RELOCATE(iptr->dst.varindex);
+ superblockend = true;
+ break;
+
+ case ICMD_RETURN:
+ superblockend = true;
+ break;
+
+ case ICMD_CHECKNULL:
+ case ICMD_PUTSTATICCONST:
+ break;
+
+ case ICMD_NOP:
+ case ICMD_IINC:
+ break;
+
+ case ICMD_GOTO:
+ iptr->dst.block = stack_mark_reached_from_outvars(sd, iptr->dst.block);
+ superblockend = true;
+ break;
+
+ /* pop 0 push 1 const */
+
+ case ICMD_ACONST:
+ case ICMD_ICONST:
+ case ICMD_LCONST:
+ case ICMD_FCONST:
+ case ICMD_DCONST:
+
+ /* pop 0 push 1 load */
+
+ case ICMD_ILOAD:
+ case ICMD_LLOAD:
+ case ICMD_FLOAD:
+ case ICMD_DLOAD:
+ case ICMD_ALOAD:
+ RELOCATE(iptr->dst.varindex);
+ break;
+
+ /* 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);
+ break;
+
+ /* 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);
+ break;
+
+ /* pop 1 push 0 store */
+
+ case ICMD_ISTORE:
+ case ICMD_LSTORE:
+ case ICMD_FSTORE:
+ case ICMD_DSTORE:
+ case ICMD_ASTORE:
+ RELOCATE(iptr->s1.varindex);
+
+ varindex = iptr->dst.varindex;
+ COPY_VAL_AND_TYPE(*sd, iptr->s1.varindex, varindex);
+ i = iptr->sx.s23.s3.javaindex;
+ if (iptr->flags.bits & INS_FLAG_RETADDR) {
+ iptr->sx.s23.s2.retaddrnr =
+ JAVALOCAL_FROM_RETADDR(sd->var[varindex].vv.retaddr->nr);
+ sd->javalocals[i] = iptr->sx.s23.s2.retaddrnr;
+ }
+ else
+ sd->javalocals[i] = varindex;
+ if (iptr->flags.bits & INS_FLAG_KILL_PREV)
+ sd->javalocals[i-1] = UNUSED;
+ if (iptr->flags.bits & INS_FLAG_KILL_NEXT)
+ sd->javalocals[i+1] = UNUSED;
+ break;
+
+ /* pop 1 push 0 */
+
+ case ICMD_ARETURN:
+ case ICMD_ATHROW:
+ case ICMD_IRETURN:
+ case ICMD_LRETURN:
+ case ICMD_FRETURN:
+ case ICMD_DRETURN:
+ RELOCATE(iptr->s1.varindex);
+ superblockend = true;
+ break;
+
+ case ICMD_PUTSTATIC:
+ case ICMD_PUTFIELDCONST:
+ case ICMD_POP:
+ RELOCATE(iptr->s1.varindex);
+ break;
+
+ /* pop 1 push 0 branch */
+
+ case ICMD_IFNULL:
+ case ICMD_IFNONNULL:
+
+ case ICMD_IFEQ:
+ case ICMD_IFNE:
+ case ICMD_IFLT:
+ case ICMD_IFGE:
+ case ICMD_IFGT:
+ case ICMD_IFLE:
+
+ 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;
+
+ /* pop 1 push 0 table branch */
+
+ case ICMD_TABLESWITCH:
+ i = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1 + 1;
+
+ 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);
+ break;
+
+ /* pop 2 push 0 branch */
+
+ 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_LCMPEQ:
+ case ICMD_IF_LCMPNE:
+ case ICMD_IF_LCMPLT:
+ case ICMD_IF_LCMPGE:
+ case ICMD_IF_LCMPGT:
+ case ICMD_IF_LCMPLE:
+
+ 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;
+
+ /* 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:
+ case ICMD_POP2:
+ RELOCATE(iptr->sx.s23.s2.varindex);
+ RELOCATE(iptr->s1.varindex);
+ break;
+
+ /* pop 0 push 1 copy */
+
+ 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;
+
+ /* pop 2 push 1 */
+
+ case ICMD_IDIV:
+ case ICMD_IREM:
+ case ICMD_LDIV:
+ case ICMD_LREM:
+ 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;
+
+ /* pop 1 push 1 */
+
+ case ICMD_CHECKCAST:
+ case ICMD_ARRAYLENGTH:
+ case ICMD_INSTANCEOF:
+ case ICMD_NEWARRAY:
+ case ICMD_ANEWARRAY:
+ 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;
+
+ /* pop 0 push 1 */
+
+ case ICMD_GETSTATIC:
+ case ICMD_NEW:
+ RELOCATE(iptr->dst.varindex);
+ break;
+
+ /* 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;
+ }
+
+ while (--i >= 0) {
+ RELOCATE(*argp);
+ argp++;
+ }
+ RELOCATE(iptr->dst.varindex);
+ break;
+
+ default:
+ exceptions_throw_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
+ }
+
+ /* relocate outvars */
+
+ for (i=0; i<b->outdepth; ++i) {
+ RELOCATE(b->outvars[i]);
+ }
+
+#if defined(STACK_VERBOSE)
+ stack_verbose_block_exit(sd, superblockend);
+#endif
+
+ /* propagate to the next block */
+
+ if (!superblockend)
+ if (!stack_reach_next_block(sd))
+ return false;
+
+ return true;
+}
+
+
+/* stack_change_to_tempvar *****************************************************
+
+ Change the given stackslot to a TEMPVAR. This includes creating a new
+ temporary variable and changing the dst.varindex of the creator of the
+ stacklot to the new variable index. If this stackslot has been passed
+ through ICMDs between the point of its creation and the current point,
+ then the variable index is also changed in these ICMDs.
+
+ IN:
+ sd...........stack analysis data
+ sp...........stackslot to change
+ ilimit.......instruction up to which to look for ICMDs passing-through
+ the stackslot (exclusive). This may point exactly after the
+ last instruction, in which case the search is done to the
+ basic block end.
+
+*******************************************************************************/
+
+static void stack_change_to_tempvar(stackdata_t *sd, stackelement_t * sp,
+ instruction *ilimit)
+{
+ s4 newindex;
+ s4 oldindex;
+ instruction *iptr;
+ s4 depth;
+ s4 i;
+
+ oldindex = sp->varnum;
+
+ /* create a new temporary variable */
+
+ GET_NEW_VAR(*sd, newindex, sp->type);
+
+ sd->var[newindex].flags = sp->flags;
+
+ /* change the stackslot */
+
+ sp->varnum = newindex;
+ sp->varkind = TEMPVAR;
+
+ /* change the dst.varindex of the stackslot's creator */
+
+ if (sp->creator)
+ sp->creator->dst.varindex = newindex;
+
+ /* handle ICMDs this stackslot passed through, if any */
+
+ if (sp->flags & PASSTHROUGH) {
+ iptr = (sp->creator) ? (sp->creator + 1) : sd->bptr->iinstr;
+
+ /* assert that the limit points to an ICMD, or after the last one */
+
+ assert(ilimit >= sd->bptr->iinstr);
+ assert(ilimit <= sd->bptr->iinstr + sd->bptr->icount);
+
+ /* find the stackdepth under sp plus one */
+ /* Note: This number is usually known when this function is called, */
+ /* but calculating it here is less error-prone and should not be */
+ /* a performance problem. */
+
+ for (depth = 0; sp != NULL; sp = sp->prev)
+ depth++;
+
+ /* iterate over all instructions in the range and replace */
+
+ for (; iptr < ilimit; ++iptr) {
+ switch (iptr->opc) {
+ case ICMD_INVOKESTATIC:
+ case ICMD_INVOKESPECIAL:
+ case ICMD_INVOKEVIRTUAL:
+ case ICMD_INVOKEINTERFACE:
+ case ICMD_BUILTIN:
+ i = iptr->s1.argcount - depth;
+ if (iptr->sx.s23.s2.args[i] == oldindex) {
+ iptr->sx.s23.s2.args[i] = newindex;
+ }
+ break;
+ /* IMPORTANT: If any ICMD sets the PASSTHROUGH flag of a */
+ /* stackslot, it must be added in this switch! */
+ }
+ }
+ }
+}
+
+
+/* stack_init_javalocals *******************************************************
+
+ Initialize the mapping from Java locals to cacao variables at method entry.
+
+ IN:
+ sd...........stack analysis data
+
+*******************************************************************************/
+
+static void stack_init_javalocals(stackdata_t *sd)
+{
+ s4 *jl;
+ s4 type,i,j;
+ methoddesc *md;
+ jitdata *jd;
+
+ jd = sd->jd;
+
+ jl = DMNEW(s4, sd->maxlocals);
+ jd->basicblocks[0].javalocals = jl;
+
+ for (i=0; i<sd->maxlocals; ++i)
+ jl[i] = UNUSED;
+
+ md = jd->m->parseddesc;
+ j = 0;
+ for (i=0; i<md->paramcount; ++i) {
+ type = md->paramtypes[i].type;
+ jl[j] = jd->local_map[5*j + type];
+ j++;
+ if (IS_2_WORD_TYPE(type))
+ j++;
+ }
+}
+
+
+/* stack_analyse ***************************************************************
+
+ Analyse_stack uses the intermediate code created by parse.c to
+ 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.
+
+*******************************************************************************/
+
+bool stack_analyse(jitdata *jd)
+{
+ methodinfo *m; /* method being analyzed */
+ codeinfo *code;
+ registerdata *rd;
+ stackdata_t sd;
+ int stackdepth;
+ stackelement_t *curstack; /* current stack top */
+ stackelement_t *copy;
+ int opcode; /* opcode of current instruction */
+ int i, varindex;
+ int javaindex;
+ int type; /* operand type */
+ int len; /* # of instructions after the current one */
+ bool superblockend; /* if true, no fallthrough to next block */
+ bool deadcode; /* true if no live code has been reached */
+ instruction *iptr; /* the current instruction */
+ basicblock *tbptr;
+ basicblock *original;
+ exception_entry *ex;
+
+ stackelement_t **last_store_boundary;
+ stackelement_t *coalescing_boundary;
+
+ stackelement_t *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 */
+#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 - initialization */
+
+ m = jd->m;
+ code = jd->code;
+ rd = jd->rd;
+
+ /* 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.varsallocated = sd.varcount;
+ sd.maxlocals = m->maxlocals;
+ sd.javalocals = DMNEW(s4, sd.maxlocals);
+ sd.handlers = DMNEW(exception_entry *, jd->exceptiontablelength + 1);
+
+ /* prepare the variable for exception handler stacks */
+ /* (has been reserved by STACK_EXTRA_VARS, or VERIFIER_EXTRA_VARS) */
+
+ sd.exstack.type = TYPE_ADR;
+ sd.exstack.prev = NULL;
+ sd.exstack.varnum = sd.localcount;
+ sd.var[sd.exstack.varnum].type = TYPE_ADR;
+
+#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 (jd->exceptiontablelength)
+ sd.extableend = jd->exceptiontable + jd->exceptiontablelength - 1;
+ else
+ sd.extableend = NULL;
+
+ /* init jd->interface_map */
+
+ jd->maxinterfaces = m->maxstack;
+ jd->interface_map = DMNEW(interface_info, m->maxstack * 5);
+ for (i = 0; i < m->maxstack * 5; i++)
+ jd->interface_map[i].flags = UNUSED;
+
+ last_store_boundary = DMNEW(stackelement_t *, m->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);
+
+ /* initialize java local mapping of first block */
+
+ stack_init_javalocals(&sd);
+
+ /* stack analysis loop (until fixpoint reached) **************************/