X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstack.c;h=23188765ba5c144359a41c6fb62f156bfbbcfaa7;hb=5ffbb605195638d15affc2bacff833c59de6445e;hp=f8608d766b6e6c43cfe911546df493c1abc27bb9;hpb=e8632958988ec3cdeba05a40c1330c07f280d0f3;p=cacao.git diff --git a/src/vm/jit/stack.c b/src/vm/jit/stack.c index f8608d766..23188765b 100644 --- a/src/vm/jit/stack.c +++ b/src/vm/jit/stack.c @@ -1,9 +1,9 @@ /* src/vm/jit/stack.c - stack analysis - Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -19,10 +19,10 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - Contact: cacao@complang.tuwien.ac.at + Contact: cacao@cacaojvm.org Authors: Andreas Krall @@ -30,7 +30,7 @@ Christian Thalinger Christian Ullrich - $Id: stack.c 4168 2006-01-12 22:32:06Z twisti $ + $Id: stack.c 5481 2006-09-12 21:23:56Z edwin $ */ @@ -40,6 +40,7 @@ #include #include #include +#include #include "vm/types.h" @@ -55,18 +56,445 @@ #include "vm/resolve.h" #include "vm/statistics.h" #include "vm/stringlocal.h" +#include "vm/jit/cfg.h" #include "vm/jit/codegen-common.h" -#include "vm/jit/disass.h" +#include "vm/jit/abi.h" +#include "vm/jit/show.h" + +#if defined(ENABLE_DISASSEMBLER) +# include "vm/jit/disass.h" +#endif + #include "vm/jit/jit.h" -#include "vm/jit/reg.h" #include "vm/jit/stack.h" -#include "vm/jit/allocator/lsra.h" +#if defined(ENABLE_LSRA) +# include "vm/jit/allocator/lsra.h" +#endif + +/*#define STACK_VERBOSE*/ + + +/* 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) +#else /* !defined(ENABLE_STATISTICS) */ +#define STATISTICS_STACKDEPTH_DISTRIBUTION(distr) +#endif + +/* stackdata_t ***************************************************************** + + This struct holds internal data during stack analysis. + +*******************************************************************************/ + +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 */ +}; -/* global variables ***********************************************************/ -#if defined(USE_THREADS) -static java_objectheader *lock_show_icmd; +/* 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) + +/* 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_OUTVAR(sp) \ + (sd.var[(sp)->varnum].flags & OUTVAR) + +#define IS_PREALLOC(sp) \ + (sd.var[(sp)->varnum].flags & PREALLOC) + +#define IS_TEMPVAR(sp) \ + ( ((sp)->varnum >= sd.localcount) \ + && !(sd.var[(sp)->varnum].flags & (OUTVAR | PREALLOC)) ) + +#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 &= ~(OUTVAR | PREALLOC); \ + } while (0); + +#define SET_PREALLOC(sp) \ + do { \ + assert(!IS_LOCALVAR((sp))); \ + sd.var[(sp)->varnum].flags |= PREALLOC; \ + } while (0); + + +/* macros for source operands ***************************************/ + +#define CLR_S1 \ + (iptr->s1.varindex = -1) + +#define USE_S1(type1) \ + do { \ + REQUIRE(1); \ + CHECK_BASIC_TYPE(type1, curstack->type); \ + iptr->s1.varindex = curstack->varnum; \ + } while (0) + +#define USE_S1_ANY \ + do { \ + REQUIRE(1); \ + iptr->s1.varindex = curstack->varnum; \ + } while (0) + +#define USE_S1_S2(type1, type2) \ + do { \ + REQUIRE(2); \ + CHECK_BASIC_TYPE(type1, curstack->prev->type); \ + CHECK_BASIC_TYPE(type2, curstack->type); \ + 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.varindex = curstack->varnum; \ + iptr->s1.varindex = curstack->prev->varnum; \ + } while (0) + +#define USE_S1_S2_S3(type1, type2, type3) \ + do { \ + 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.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) \ + do { \ + USE_S1(type1); \ + if (curstack->varkind == UNDEFVAR) \ + curstack->varkind = TEMPVAR; \ + curstack = curstack->prev; \ + } while (0) + +#define POP_S1_ANY \ + do { \ + USE_S1_ANY; \ + if (curstack->varkind == UNDEFVAR) \ + curstack->varkind = TEMPVAR; \ + curstack = curstack->prev; \ + } while (0) + +#define POP_S1_S2(type1, type2) \ + do { \ + USE_S1_S2(type1, type2); \ + if (curstack->varkind == UNDEFVAR) \ + curstack->varkind = TEMPVAR; \ + if (curstack->prev->varkind == UNDEFVAR) \ + curstack->prev->varkind = TEMPVAR; \ + curstack = curstack->prev->prev; \ + } while (0) + +#define POP_S1_S2_ANY_ANY \ + do { \ + USE_S1_S2_ANY_ANY; \ + if (curstack->varkind == UNDEFVAR) \ + curstack->varkind = TEMPVAR; \ + if (curstack->prev->varkind == UNDEFVAR) \ + curstack->prev->varkind = TEMPVAR; \ + curstack = curstack->prev->prev; \ + } while (0) + +#define POP_S1_S2_S3(type1, type2, type3) \ + do { \ + USE_S1_S2_S3(type1, type2, type3); \ + if (curstack->varkind == UNDEFVAR) \ + curstack->varkind = TEMPVAR; \ + if (curstack->prev->varkind == UNDEFVAR) \ + curstack->prev->varkind = TEMPVAR; \ + if (curstack->prev->prev->varkind == UNDEFVAR) \ + curstack->prev->prev->varkind = TEMPVAR; \ + curstack = curstack->prev->prev->prev; \ + } while (0) + +#define CLR_SX \ + (iptr->sx.val.l = 0) + + +/* macros for setting the destination operand ***********************/ + +#define CLR_DST \ + (iptr->dst.varindex = -1) + +#define DST(typed, index) \ + do { \ + NEWSTACKn((typed),(index)); \ + curstack->creator = iptr; \ + iptr->dst.varindex = (index); \ + } while (0) + +#define DST_LOCALVAR(typed, index) \ + do { \ + NEWSTACK((typed), LOCALVAR, (index)); \ + curstack->creator = iptr; \ + iptr->dst.varindex = (index); \ + } while (0) + + +/* macro for propagating constant values ****************************/ + +#define COPY_VAL_AND_TYPE(sd, sindex, dindex) \ + do { \ + (sd).var[(dindex)].type = (sd).var[(sindex)].type; \ + (sd).var[(dindex)].vv = (sd).var[(sindex)].vv; \ + } while (0) \ + + +/* stack modelling macros *******************************************/ + +#define OP0_1(typed) \ + do { \ + CLR_S1; \ + GET_NEW_VAR(sd, new_index, (typed)); \ + DST(typed, new_index); \ + stackdepth++; \ + } while (0) + +#define OP1_0_ANY \ + do { \ + POP_S1_ANY; \ + CLR_DST; \ + stackdepth--; \ + } while (0) + +#define OP1_BRANCH(type1) \ + do { \ + POP_S1(type1); \ + stackdepth--; \ + } while (0) + +#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 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); \ + CLR_DST; \ + stackdepth--; \ + } while (0) + +#define OP2_0(type1, type2) \ + do { \ + POP_S1_S2(type1, type2); \ + CLR_DST; \ + stackdepth -= 2; \ + } while (0) + +#define OP2_BRANCH(type1, type2) \ + do { \ + POP_S1_S2(type1, type2); \ + stackdepth -= 2; \ + } while (0) + +#define OP2_0_ANY_ANY \ + do { \ + POP_S1_S2_ANY_ANY; \ + CLR_DST; \ + stackdepth -= 2; \ + } while (0) + +#define OP3_0(type1, type2, type3) \ + do { \ + POP_S1_S2_S3(type1, type2, type3); \ + CLR_DST; \ + stackdepth -= 3; \ + } while (0) + +#define LOAD(type1, index) \ + do { \ + DST_LOCALVAR(type1, index); \ + stackdepth++; \ + } while (0) + +#define STORE(type1, index) \ + do { \ + POP_S1(type1); \ + stackdepth--; \ + } while (0) + + +/* 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 { \ + iptr->opc = ICMD_MOVE; \ + iptr->s1.varindex = (sp)->varnum; \ + DUP_SLOT(sp); \ + curstack->creator = iptr; \ + iptr->dst.varindex = curstack->varnum; \ + stackdepth++; \ + } while (0) + +/* does not check input stackdepth */ +#define COPY_UP(sp) \ + do { \ + 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 COPY_DOWN(s, d) \ + do { \ + SET_TEMPVAR((s)); \ + iptr->opc = ICMD_COPY; \ + iptr->s1.varindex = (s)->varnum; \ + iptr->dst.varindex = (d)->varnum; \ + (d)->creator = iptr; \ + } while (0) + + +/* macros for branching / reaching basic blocks *********************/ + +#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) + +#define BRANCH(tempbptr) \ + BRANCH_TARGET(iptr->dst, tempbptr) + + +/* 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 @@ -78,516 +506,1845 @@ static java_objectheader *lock_show_icmd; bool stack_init(void) { -#if defined(USE_THREADS) - /* initialize the show lock */ + return true; +} - lock_show_icmd = NEW(java_objectheader); -# if defined(NATIVE_THREADS) - initObjectLock(lock_show_icmd); -# endif +/* stack_grow_variable_array *************************************************** + + Grow the variable array so the given number of additional variables fits in. + + IN: + sd...........stack analysis data + num..........number of additional variables + +*******************************************************************************/ + +static void stack_grow_variable_array(stackdata_t *sd, s4 num) +{ + s4 newcount; + + assert(num >= 0); + + if (num == 0) + return; + + /* XXX avoid too many reallocations */ + newcount = sd->varcount + num; + + sd->var = DMREALLOC(sd->var, varinfo, sd->varcount, newcount); + sd->varcount = newcount; + sd->jd->var = sd->var; + sd->jd->varcount = newcount; +} + + +/* stack_append_block ********************************************************** + + Append the given block after the last real block of the method (before + the pseudo-block at the end). + + IN: + sd...........stack analysis data + b............the block to append + +*******************************************************************************/ + +static void stack_append_block(stackdata_t *sd, basicblock *b) +{ +#if defined(STACK_VERBOSE) + printf("APPENDING BLOCK L%0d\n", b->nr); +#endif + + b->next = sd->last_real_block->next; + sd->last_real_block->next = b; + sd->last_real_block = b; + sd->jd->new_basicblockcount++; +} + + +/* stack_clone_block *********************************************************** + + Create a copy of the given block and insert it at the end of the method. + + 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. + + IN: + sd...........stack analysis data + b............the block to clone + + RETURN VALUE: + a pointer to the copy + +*******************************************************************************/ + +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_debug_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); + +#if defined(STACK_VERBOSE) + printf("cloning block L%03d ------> L%03d\n", b->nr, clone->nr); +#endif + + return clone; +} + + +/* stack_create_invars ********************************************************* + + Create the invars for the given basic block. Also make a copy of the locals. + + IN: + sd...........stack analysis data + b............block to create the invars for + curstack.....current stack top + stackdepth...current stack depth + + This function creates STACKDEPTH invars and sets their types to the + types to the types of the corresponding slot in the current stack. + +*******************************************************************************/ + +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 = OUTVAR; + v->vv = sd->var[sp->varnum].vv; +#if defined(STACK_VERBOSE) && 0 + printf("\tinvar[%d]: %d\n", i, sd->var[b->invars[i]]); +#endif + } + + /* copy the current state of the local variables */ + + v = DMNEW(varinfo, sd->localcount); + b->inlocals = v; + for (i=0; ilocalcount; ++i) + *v++ = sd->var[i]; +} + + +/* 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; ivar + sd->bptr->outvars[i]; + b->invars[i] = sd->vartop++; + dv->type = sv->type; + dv->flags = OUTVAR; + dv->vv = sv->vv; + } + } + + /* copy the current state of the local variables */ + + dv = DMNEW(varinfo, sd->localcount); + b->inlocals = dv; + for (i=0; ilocalcount; ++i) + *dv++ = sd->var[i]; +} + + +/* 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, + stackptr curstack, int stackdepth) +{ + int i; + stackptr sp; + basicblock *orig; + bool separable; + +#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 (i != stackdepth) { + exceptions_throw_verifyerror(sd->m, "Stack depth mismatch"); + return NULL; + } + + 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) { + if (sd->var[b->invars[i]].type != sp->type) { + exceptions_throw_verifyerror_for_stack(sd->m, + sd->var[b->invars[i]].type); + return NULL; + } + + if (sp->type == TYPE_RET) { + if (sd->var[b->invars[i]].vv.retaddr != sd->var[sp->varnum].vv.retaddr) { + separable = true; + break; + } + } + } + + 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; + } + } + } + } + + 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); + + 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 (i != n) { + exceptions_throw_verifyerror(sd->m, "Stack depth mismatch"); + return NULL; + } + + 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; ivar + sd->bptr->outvars[i]; + if (sv->type != dv->type) { + exceptions_throw_verifyerror_for_stack(sd->m, dv->type); + return NULL; + } + + if (dv->type == TYPE_RET) { + if (sv->vv.retaddr != dv->vv.retaddr) { + separable = true; + break; + } + } + } + } + + 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; + } + } + } + } + + 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); + + 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 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; + + /* 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, stackptr curstack, int stackdepth) +{ +#if defined(STACK_VERBOSE) + printf("stack_mark_reached(L%03d from L%03d)\n", b->nr, sd->bptr->nr); +#endif + /* mark targets of backward branches */ + if (b <= sd->bptr) + 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) +{ +#if defined(STACK_VERBOSE) + printf("stack_mark_reached_from_outvars(L%03d from L%03d)\n", b->nr, sd->bptr->nr); +#endif + /* mark targets of backward branches */ + if (b <= sd->bptr) + 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) + 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; - /* everything's ok */ + if (tbptr->flags < BBFINISHED) + sd->repeat = true; /* XXX check if we really need to repeat */ + } return true; } -/**********************************************************************/ -/* analyse_stack */ -/**********************************************************************/ - -/* 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. - */ +/* 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 -methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) +*******************************************************************************/ + +static bool stack_reach_handlers(stackdata_t *sd) { - int b_count; - int b_index; - int stackdepth; - stackptr curstack; - stackptr new; - stackptr copy; - int opcode, i, len, loops; - int superblockend, repeat, deadcode; - instruction *iptr; - basicblock *bptr; + 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, j; + s4 *argp; + branch_target_t *table; + lookup_target_t *lookup; + bool superblockend; + bool maythrow; + bool cloneinstructions; + exceptiontable *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; + b->iinstr = iptr; + b->icount = ++len; + + /* allocate 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(exceptiontable); + ex->handler = sd->handlers[i]->handler; + ex->start = b; + ex->end = b; /* XXX hack, see end of new_stack_analyse */ + ex->catchtype = sd->handlers[i]->catchtype; + ex->down = NULL; + + assert(sd->extableend->down == NULL); + sd->extableend->down = ex; + sd->extableend = ex; + sd->jd->cd->exceptiontablelength++; + + sd->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->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 + + /* 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); + + /* 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) + new_show_icmd(sd->jd, iptr, false, SHOW_STACK); + printf("\n"); +#endif + + maythrow = false; + + switch (iptr->opc) { + case ICMD_RET: + j = iptr->s1.varindex; + + if (sd->var[j].type != TYPE_RET) { + exceptions_throw_verifyerror(sd->m, "RET with non-returnAddress value"); + return false; + } + + iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[j].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); + superblockend = true; + break; + + case ICMD_RETURN: + superblockend = true; + break; + + case ICMD_CHECKNULL: + case ICMD_PUTSTATICCONST: + maythrow = true; + break; + + case ICMD_NOP: + case ICMD_IINC: + case ICMD_INLINE_START: + case ICMD_INLINE_END: + case ICMD_INLINE_GOTO: + break; + + case ICMD_GOTO: + iptr->dst.block = stack_mark_reached_from_outvars(sd, iptr->dst.block); + superblockend = true; + break; + + /* pop 0 push 1 const */ + + case ICMD_ACONST: + maythrow = true; + 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); + maythrow = true; + 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); + maythrow = true; + 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); + + j = iptr->dst.varindex; + COPY_VAL_AND_TYPE(*sd, iptr->s1.varindex, j); + break; + + /* pop 1 push 0 */ + + 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; + + case ICMD_PUTSTATIC: + case ICMD_PUTFIELDCONST: + maythrow = true; + 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); + maythrow = true; + 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_FCMPEQ: + case ICMD_IF_FCMPNE: + + case ICMD_IF_FCMPL_LT: + case ICMD_IF_FCMPL_GE: + case ICMD_IF_FCMPL_GT: + case ICMD_IF_FCMPL_LE: + + case ICMD_IF_FCMPG_LT: + case ICMD_IF_FCMPG_GE: + case ICMD_IF_FCMPG_GT: + case ICMD_IF_FCMPG_LE: + + case ICMD_IF_DCMPEQ: + case ICMD_IF_DCMPNE: + + case ICMD_IF_DCMPL_LT: + case ICMD_IF_DCMPL_GE: + case ICMD_IF_DCMPL_GT: + case ICMD_IF_DCMPL_LE: + + case ICMD_IF_DCMPG_LT: + case ICMD_IF_DCMPG_GE: + case ICMD_IF_DCMPG_GT: + case ICMD_IF_DCMPG_LE: + + case ICMD_IF_ACMPEQ: + case ICMD_IF_ACMPNE: + RELOCATE(iptr->sx.s23.s2.varindex); + 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: + maythrow = true; + 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: + 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; + + /* 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; + + /* pop 0 push 1 */ + + case ICMD_GETSTATIC: + case ICMD_NEW: + maythrow = true; + 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; + } + + maythrow = true; + while (--i >= 0) { + RELOCATE(*argp); + argp++; + } + RELOCATE(iptr->dst.varindex); + break; + + default: + *exceptionptr = + new_internalerror("Unknown ICMD %d during stack re-analysis", + iptr->opc); + return false; + } /* switch */ + +#if defined(STACK_VERBOSE) + new_show_icmd(sd->jd, iptr, false, SHOW_STACK); + printf("\n"); +#endif + } + + /* relocate outvars */ + + for (i=0; ioutdepth; ++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_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 new_stack_analyse(jitdata *jd) +{ + methodinfo *m; /* method being analyzed */ + codeinfo *code; + codegendata *cd; + registerdata *rd; + stackdata_t sd; + int b_index; /* basic block index */ + int stackdepth; + stackptr curstack; /* current stack top */ + stackptr copy; + 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 *argren; + 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 */ +#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) + new_show_method(jd, SHOW_PARSE); +#endif + + /* get required compiler data - initialization */ + + m = jd->m; + code = jd->code; + cd = jd->cd; + 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.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->new_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->new_basicblocks[0].flags = BBREACHED; + jd->new_basicblocks[0].invars = NULL; + jd->new_basicblocks[0].indepth = 0; + + /* stack analysis loop (until fixpoint reached) **************************/ + + do { +#if defined(ENABLE_STATISTICS) + iteration_count++; +#endif + + /* initialize loop over basic blocks */ + + sd.bptr = jd->new_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; + } - builtintable_entry *bte; - unresolved_method *um; - methoddesc *md; + 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. */ -#if defined(ENABLE_LSRA) - m->maxlifetimes = 0; -#endif + sd.repeat = true; + continue; + } - argren = DMNEW(s4, cd->maxlocals); /* table for argument renaming */ - for (i = 0; i < cd->maxlocals; i++) - argren[i] = i; - - 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; - } + /* This block has to be analysed now. */ -#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; + /* XXX The rest of this block is still indented one level too */ + /* much in order to avoid a giant diff by changing that. */ - case ICMD_IFEQ: - case ICMD_IFNE: - case ICMD_IFLT: - case ICMD_IFGE: - case ICMD_IFGT: - case ICMD_IFLE: + /* We know that sd.bptr->flags == BBREACHED. */ + /* This block has been reached before. */ - case ICMD_IFNULL: - case ICMD_IFNONNULL: + assert(sd.bptr->flags == BBREACHED); + stackdepth = sd.bptr->indepth; - case ICMD_IF_ICMPEQ: - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: + /* find exception handlers for this block */ - case ICMD_IF_ACMPEQ: - case ICMD_IF_ACMPNE: - bptr[1].pre_count++; - case ICMD_GOTO: - m->basicblocks[m->basicblockindex[iptr->op1]].pre_count++; - break; + /* determine the active exception handlers for this block */ + /* XXX could use a faster algorithm with sorted lists or */ + /* something? */ - 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++; + original = (sd.bptr->original) ? sd.bptr->original : sd.bptr; + + len = 0; + ex = cd->exceptiontable; + for (; ex != NULL; ex = ex->down) { + if ((ex->start <= original) && (ex->end > original)) { + sd.handlers[len++] = ex; + } } - 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; + sd.handlers[len] = NULL; + + + /* reanalyse cloned block */ + + if (sd.bptr->original) { + if (!stack_reanalyse_block(&sd)) + return false; + continue; } - break; - default: - bptr[1].pre_count++; - break; - } - } - bptr++; - } -#endif /* CONDITIONAL_LOADCONST */ + /* reset the new pointer for allocating stackslots */ - do { - loops++; - b_count = m->basicblockcount; - bptr = m->basicblocks; - superblockend = true; - repeat = false; - STACKRESET; - deadcode = true; + sd.new = jd->new_stack; - while (--b_count >= 0) { - if (bptr->flags == BBDELETED) { - /* do nothing */ + /* create the instack of this block */ - } else if (superblockend && (bptr->flags < BBREACHED)) { - repeat = true; + curstack = stack_create_instack(&sd); - } else if (bptr->flags <= BBREACHED) { - if (superblockend) { - stackdepth = bptr->indepth; + /* initialize locals at the start of this block */ - } else if (bptr->flags < BBREACHED) { - COPYCURSTACK(copy); - bptr->instack = copy; - bptr->indepth = stackdepth; + if (sd.bptr->inlocals) + MCOPY(sd.var, sd.bptr->inlocals, varinfo, sd.localcount); - } else if (bptr->indepth != stackdepth) { - /*show_icmd_method(m, cd, rd); - printf("Block: %d, required depth: %d, current depth: %d\n", - bptr->debug_nr, bptr->indepth, stackdepth);*/ - *exceptionptr = new_verifyerror(m,"Stack depth mismatch"); - return NULL; - } + /* set up local variables for analyzing this block */ - curstack = bptr->instack; 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->new_basicblocks; + + /* mark the block as analysed */ + + sd.bptr->flags = BBFINISHED; + + /* reset variables for dependency checking */ + + coalescing_boundary = sd.new; + for( i = 0; i < cd->maxlocals; i++) + last_store_boundary[i] = sd.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) + new_show_icmd(jd, iptr, false, SHOW_PARSE); printf("\n"); + for( copy = curstack; copy; copy = copy->prev ) { + printf("%2d(%d", copy->varnum, copy->type); + if (IS_OUTVAR(copy)) + printf("S"); + if (IS_PREALLOC(copy)) + printf("A"); + printf(") "); + } + printf("\n"); +#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 + IF_NO_INTRP( 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; - m->isleafmethod = false; - goto builtin; + 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; } -# if defined(ENABLE_INTRP) - } -# endif + ); #endif /* defined(USEBUILTINTABLE) */ - + + /* 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) + 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); +#if 0 + IF_NO_INTRP( rd->locals[iptr->s1.localindex/*XXX invalid here*/][TYPE_ADR].type = TYPE_ADR; ); #endif - rd->locals[iptr->op1][TYPE_ADR].type = TYPE_ADR; + 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[0].opc = ICMD_IFEQ; - icmd_if_icmp_tail: - iptr[0].op1 = iptr[1].op1; - /* IF_ICMPxx is the last instruction in the */ - /* basic block, just remove it */ - /* iptr[1].opc = ICMD_NOP; */ - bptr->icount--; - len--; + iptr[1].opc = ICMD_IFEQ; + /* FALLTHROUGH */ - OP1_0(TYPE_INT); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; + icmd_if_icmp_tail: + /* set the constant for the following icmd */ + iptr[1].sx.val.i = iptr->sx.val.i; - iptr[0].target = (void *) tbptr; + /* this instruction becomes a nop */ + iptr->opc = ICMD_NOP; + goto icmd_NOP; - MARKREACHED(tbptr, copy); - COUNT(count_pcmd_bra); - break; case ICMD_IF_ICMPLT: - iptr[0].opc = ICMD_IFLT; + iptr[1].opc = ICMD_IFLT; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPLE: - iptr[0].opc = ICMD_IFLE; + iptr[1].opc = ICMD_IFLE; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPNE: - iptr[0].opc = ICMD_IFNE; + iptr[1].opc = ICMD_IFNE; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPGT: - iptr[0].opc = ICMD_IFGT; + iptr[1].opc = ICMD_IFGT; goto icmd_if_icmp_tail; + case ICMD_IF_ICMPGE: - iptr[0].opc = ICMD_IFGE; + iptr[1].opc = ICMD_IFGE; goto icmd_if_icmp_tail; #if SUPPORT_CONST_STORE @@ -595,529 +2352,568 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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) { -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ - 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; - } - - iptr[1].opc = ICMD_NOP; - OPTT2_0(TYPE_INT, TYPE_ADR); - COUNT(count_pcmd_op); + IF_INTRP( goto normal_ICONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY - } else - PUSHCONST(TYPE_INT); -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ -# if defined(ENABLE_INTRP) - } else - PUSHCONST(TYPE_INT); + if (iptr->sx.val.i != 0) + goto normal_ICONST; # endif + 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; + + /* 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) { -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ - 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; - } - - iptr[1].opc = ICMD_NOP; - iptr[0].op1 = TYPE_INT; - COUNT(count_pcmd_op); + IF_INTRP( goto normal_ICONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY - } else - PUSHCONST(TYPE_INT); -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ -# if defined(ENABLE_INTRP) - } else - PUSHCONST(TYPE_INT); + 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.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 +#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; -#endif /* SUPPORT_LONG_DIV */ + 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; - icmd_lconst_lcmp_tail: - iptr[0].op1 = iptr[2].op1; - bptr->icount -= 2; - len -= 2; - /* iptr[1].opc = ICMD_NOP; - iptr[2].opc = ICMD_NOP; */ - OP1_0(TYPE_LNG); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; + iptr->opc = ICMD_IF_LEQ; + /* FALLTHROUGH */ - iptr[0].target = (void *) tbptr; + 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; - 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 /* SUPPORT_CONST_STORE_ZERO_ONLY */ - iptr[0].opc = ICMD_LASTORECONST; - iptr[1].opc = ICMD_NOP; - OPTT2_0(TYPE_INT, TYPE_ADR); - COUNT(count_pcmd_op); + IF_INTRP( goto normal_LCONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY - } else - PUSHCONST(TYPE_LNG); -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ -# 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) { -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ - 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; - } - - iptr[1].opc = ICMD_NOP; - iptr[0].op1 = TYPE_LNG; - COUNT(count_pcmd_op); + IF_INTRP( goto normal_LCONST; ) # if SUPPORT_CONST_STORE_ZERO_ONLY - } else - PUSHCONST(TYPE_LNG); -# endif /* SUPPORT_CONST_STORE_ZERO_ONLY */ -# if defined(ENABLE_INTRP) - } else - PUSHCONST(TYPE_LNG); + if (iptr->sx.val.l != 0) + goto normal_LCONST; # endif - 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; + #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 - if ((len > 0) && (iptr->val.a == 0)) { - switch (iptr[1].opc) { - case ICMD_AASTORE: - case ICMD_PUTSTATIC: - case ICMD_PUTFIELD: - switch (iptr[1].opc) { - case ICMD_AASTORE: - iptr[0].opc = ICMD_AASTORECONST; - OPTT2_0(TYPE_INT, TYPE_ADR); - break; - 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; - } + IF_INTRP( goto normal_ACONST; ) - iptr[1].opc = ICMD_NOP; - COUNT(count_pcmd_op); - break; + /* We can only optimize if the ACONST is resolved + * and there is an instruction after it. */ - default: - PUSHCONST(TYPE_ADR); - } + 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; - } else - PUSHCONST(TYPE_ADR); -# if defined(ENABLE_INTRP) - } else - PUSHCONST(TYPE_ADR); + /* 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); + break; + + case ICMD_PUTSTATIC: + case ICMD_PUTFIELD: +# if SUPPORT_CONST_STORE_ZERO_ONLY + if (iptr->sx.val.anyptr != NULL) + goto normal_ACONST; # endif -#else /* SUPPORT_CONST_STORE */ - PUSHCONST(TYPE_ADR); + /* XXX check field type? */ + /* copy the constant to s2 */ + /* XXX constval -> fieldconstval? */ + iptr->sx.s23.s2.constval = (ptrint) iptr->sx.val.anyptr; + + goto putconst_tail; + + default: + goto normal_ACONST; + } + + /* 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; - iptr->op1 = argren[iptr->op1]; -#if defined(ENABLE_INTRP) - if (!opt_intrp) -#endif - rd->locals[iptr->op1][i].type = i; - LOAD(i, LOCALVAR, iptr->op1); + 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; + } + + LOAD(i, j); 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: -#if defined(ENABLE_STATISTICS) - if (opt_stat) { - i = stackdepth; - if (i >= 10) - count_store_depth[10]++; - else - count_store_depth[i]++; - } -#endif + STATISTICS_STACKDEPTH_DISTRIBUTION(count_store_depth); + + 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->op1)) { - copy->varkind = TEMPVAR; - copy->varnum = i; + (copy->varnum == iptr->s1.varindex)) + { + assert(IS_LOCALVAR(copy)); + SET_TEMPVAR(copy); } i--; copy = copy->prev; } - /* allocate a dummy stack slot to keep ISTORE from */ - /* marking its input stack as a LOCALVAR, since we */ - /* change the value of the local variable here. */ - NEWSTACK0(TYPE_INT); - POP(TYPE_INT); - - SETDST; + iptr->dst.varindex = iptr->s1.varindex; break; /* pop 1 push 0 store */ @@ -1127,50 +2923,108 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) case ICMD_FSTORE: case ICMD_DSTORE: case ICMD_ASTORE: - icmd_store: - REQUIRE_1; + 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); - 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]++; - } + if (opt_stat) { + 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 - copy = curstack->prev; - i = stackdepth - 2; - while (copy) { - if ((copy->varkind == LOCALVAR) && - (copy->varnum == iptr->op1)) { - copy->varkind = TEMPVAR; - copy->varnum = i; + /* check for conflicts as described in Figure 5.2 */ + + copy = curstack->prev; + i = stackdepth - 2; + while (copy) { + if ((copy->varkind == LOCALVAR) && + (copy->varnum == j)) + { + copy->varkind = TEMPVAR; + assert(IS_LOCALVAR(copy)); + SET_TEMPVAR(copy); + } + i--; + copy = copy->prev; } - i--; - copy = copy->prev; - } - if ((new - curstack) == 1) { + + /* if the variable is already coalesced, don't bother */ + + /* We do not need to check against OUTVAR, as invars */ + /* are always before the coalescing boundary. */ + + if (curstack->varkind == LOCALVAR) + goto store_tail; + + /* there is no STORE Lj while curstack is live */ + + if (curstack < last_store_boundary[javaindex]) + goto assume_conflict; + + /* curstack must be after the coalescing boundary */ + + if (curstack < coalescing_boundary) + goto assume_conflict; + + /* there is no DEF LOCALVAR(j) while curstack is live */ + + copy = sd.new; /* most recent stackslot created + 1 */ + while (--copy > curstack) { + if (copy->varkind == LOCALVAR && copy->varnum == j) + goto assume_conflict; + } + + /* coalesce the temporary variable with Lj */ + assert((curstack->varkind == TEMPVAR) + || (curstack->varkind == UNDEFVAR)); + assert(!IS_LOCALVAR(curstack)); /* XXX correct? */ + assert(!IS_OUTVAR(curstack)); + assert(!IS_PREALLOC(curstack)); + + assert(curstack->creator); + assert(curstack->creator->dst.varindex == curstack->varnum); + RELEASE_INDEX(sd, curstack); curstack->varkind = LOCALVAR; - curstack->varnum = iptr->op1; - }; - STORE(opcode - ICMD_ISTORE); - break; + 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); + } + + /* remember the stack boundary at this store */ +store_tail: + last_store_boundary[javaindex] = sd.new; + + 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); @@ -1182,50 +3036,59 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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 */ case ICMD_POP: -#ifdef TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_1; - if (IS_2_WORD_TYPE(curstack->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + REQUIRE(1); + if (IS_2_WORD_TYPE(curstack->type)) + goto throw_stack_category_error; } #endif - OP1_0ANY; + OP1_0_ANY; break; case ICMD_IRETURN: @@ -1233,29 +3096,26 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) case ICMD_FRETURN: case ICMD_DRETURN: case ICMD_ARETURN: -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (!opt_intrp) -# endif - md_return_alloc(m, rd, opcode - ICMD_IRETURN, - curstack); -#endif + coalescing_boundary = sd.new; + IF_JIT( md_return_alloc(jd, curstack); ) 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 */ @@ -1263,12 +3123,8 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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: @@ -1278,101 +3134,21 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) case ICMD_IFGT: case ICMD_IFLE: COUNT(count_pcmd_bra); -#if CONDITIONAL_LOADCONST -# 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->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; @@ -1380,63 +3156,45 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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; @@ -1449,258 +3207,309 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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 TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_2; - if (IS_2_WORD_TYPE(curstack->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + 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 TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_1; - if (IS_2_WORD_TYPE(curstack->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + REQUIRE(1); + if (IS_2_WORD_TYPE(curstack->type)) + goto throw_stack_category_error; } #endif COUNT(count_dup_instruction); - DUP; + +icmd_DUP: + src1 = curstack; + + COPY_UP(src1); + coalescing_boundary = sd.new - 1; break; case ICMD_DUP2: - 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 TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + if (IS_2_WORD_TYPE(curstack->prev->type)) + 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 TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type) || - IS_2_WORD_TYPE(curstack->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + IS_2_WORD_TYPE(curstack->prev->type)) + goto throw_stack_category_error; } #endif - DUP_X1; + +icmd_DUP_X1: + src1 = curstack->prev; + src2 = curstack; + POPANY; POPANY; + stackdepth -= 2; + + 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: - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type)) { /* ..., ????, cat2 */ -#ifdef TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + if (IS_2_WORD_TYPE(curstack->prev->type)) + goto throw_stack_category_error; } #endif iptr->opc = ICMD_DUP_X1; - DUP_X1; + goto icmd_DUP_X1; } else { /* ..., ????, cat1 */ -#ifdef TYPECHECK_STACK_COMPCAT +#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)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + || IS_2_WORD_TYPE(curstack->prev->prev->type)) + 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; + + 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: - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->prev->type)) { /* ..., cat2, ???? */ -#ifdef TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + if (IS_2_WORD_TYPE(curstack->type)) + goto throw_stack_category_error; } #endif iptr->opc = ICMD_DUP_X1; - DUP_X1; + goto icmd_DUP_X1; } else { /* ..., cat1, ???? */ -#ifdef TYPECHECK_STACK_COMPCAT +#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)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + || IS_2_WORD_TYPE(curstack->prev->prev->type)) + 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; + + 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: - 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 TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_3; - if (IS_2_WORD_TYPE(curstack->prev->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + REQUIRE(3); + if (IS_2_WORD_TYPE(curstack->prev->prev->type)) + 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 */ -#ifdef TYPECHECK_STACK_COMPCAT - if (opt_verify) { - if (IS_2_WORD_TYPE(curstack->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } - } -#endif - iptr->opc = ICMD_DUP2_X1; - DUP2_X1; + + 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; } - else { - /* ..., cat1, ????, cat1 */ -#ifdef TYPECHECK_STACK_COMPCAT - if (opt_verify) { - REQUIRE_4; - if (IS_2_WORD_TYPE(curstack->prev->type) - || IS_2_WORD_TYPE(curstack->prev->prev->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } - } #endif - DUP2_X2; + 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; } +#endif + + src1 = curstack->prev->prev->prev; + src2 = curstack->prev->prev; + src3 = curstack->prev; + src4 = curstack; + POPANY; POPANY; POPANY; POPANY; + stackdepth -= 4; + + 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: -#ifdef TYPECHECK_STACK_COMPCAT +#ifdef ENABLE_VERIFIER if (opt_verify) { - REQUIRE_2; + REQUIRE(2); if (IS_2_WORD_TYPE(curstack->type) - || IS_2_WORD_TYPE(curstack->prev->type)) { - *exceptionptr = new_verifyerror(m, "Attempt to split long or double on the stack"); - return NULL; - } + || IS_2_WORD_TYPE(curstack->prev->type)) + goto throw_stack_category_error; } #endif - SWAP; + + src1 = curstack->prev; + src2 = curstack; + POPANY; POPANY; + stackdepth -= 2; + + 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; @@ -1711,11 +3520,12 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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: @@ -1728,30 +3538,32 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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: @@ -1763,14 +3575,14 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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: @@ -1779,7 +3591,7 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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: @@ -1788,65 +3600,232 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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; - len--; - bptr->icount--; - /* iptr[1].opc = ICMD_NOP; */ - OP2_0(TYPE_LNG); - tbptr = m->basicblocks + m->basicblockindex[iptr->op1]; - - iptr[0].target = (void *) tbptr; - - 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); - } + if ((len == 0) || (iptr[1].sx.val.i != 0)) + goto normal_LCMP; + + 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; + + 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].sx.val.i != 0)) + goto normal_FCMPL; + + switch (iptr[1].opc) { + case ICMD_IFEQ: + iptr->opc = ICMD_IF_FCMPEQ; + icmd_if_fcmpl_tail: + iptr->dst.insindex = iptr[1].dst.insindex; + iptr[1].opc = ICMD_NOP; + + OP2_BRANCH(TYPE_FLT, TYPE_FLT); + BRANCH(tbptr); + + COUNT(count_pcmd_bra); + break; + case ICMD_IFNE: + iptr->opc = ICMD_IF_FCMPNE; + goto icmd_if_fcmpl_tail; + case ICMD_IFLT: + iptr->opc = ICMD_IF_FCMPL_LT; + goto icmd_if_fcmpl_tail; + case ICMD_IFGT: + iptr->opc = ICMD_IF_FCMPL_GT; + goto icmd_if_fcmpl_tail; + case ICMD_IFLE: + iptr->opc = ICMD_IF_FCMPL_LE; + goto icmd_if_fcmpl_tail; + case ICMD_IFGE: + iptr->opc = ICMD_IF_FCMPL_GE; + goto icmd_if_fcmpl_tail; + default: + goto normal_FCMPL; + } + break; + +normal_FCMPL: + OPTT2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); + break; + + case ICMD_FCMPG: + COUNT(count_pcmd_op); + if ((len == 0) || (iptr[1].sx.val.i != 0)) + goto normal_FCMPG; + + switch (iptr[1].opc) { + case ICMD_IFEQ: + iptr->opc = ICMD_IF_FCMPEQ; + icmd_if_fcmpg_tail: + iptr->dst.insindex = iptr[1].dst.insindex; + iptr[1].opc = ICMD_NOP; + + OP2_BRANCH(TYPE_FLT, TYPE_FLT); + BRANCH(tbptr); + + COUNT(count_pcmd_bra); + break; + case ICMD_IFNE: + iptr->opc = ICMD_IF_FCMPNE; + goto icmd_if_fcmpg_tail; + case ICMD_IFLT: + iptr->opc = ICMD_IF_FCMPG_LT; + goto icmd_if_fcmpg_tail; + case ICMD_IFGT: + iptr->opc = ICMD_IF_FCMPG_GT; + goto icmd_if_fcmpg_tail; + case ICMD_IFLE: + iptr->opc = ICMD_IF_FCMPG_LE; + goto icmd_if_fcmpg_tail; + case ICMD_IFGE: + iptr->opc = ICMD_IF_FCMPG_GE; + goto icmd_if_fcmpg_tail; + default: + goto normal_FCMPG; + } + break; + +normal_FCMPG: + OP2_1(TYPE_FLT, TYPE_FLT, TYPE_INT); + break; + + case ICMD_DCMPL: + COUNT(count_pcmd_op); + if ((len == 0) || (iptr[1].sx.val.i != 0)) + goto normal_DCMPL; + + switch (iptr[1].opc) { + case ICMD_IFEQ: + iptr->opc = ICMD_IF_DCMPEQ; + icmd_if_dcmpl_tail: + iptr->dst.insindex = iptr[1].dst.insindex; + iptr[1].opc = ICMD_NOP; + + OP2_BRANCH(TYPE_DBL, TYPE_DBL); + BRANCH(tbptr); + + COUNT(count_pcmd_bra); + break; + case ICMD_IFNE: + iptr->opc = ICMD_IF_DCMPNE; + goto icmd_if_dcmpl_tail; + case ICMD_IFLT: + iptr->opc = ICMD_IF_DCMPL_LT; + goto icmd_if_dcmpl_tail; + case ICMD_IFGT: + iptr->opc = ICMD_IF_DCMPL_GT; + goto icmd_if_dcmpl_tail; + case ICMD_IFLE: + iptr->opc = ICMD_IF_DCMPL_LE; + goto icmd_if_dcmpl_tail; + case ICMD_IFGE: + iptr->opc = ICMD_IF_DCMPL_GE; + goto icmd_if_dcmpl_tail; + default: + goto normal_DCMPL; + } + break; + +normal_DCMPL: + OPTT2_1(TYPE_DBL, TYPE_INT); + break; + + case ICMD_DCMPG: + COUNT(count_pcmd_op); + if ((len == 0) || (iptr[1].sx.val.i != 0)) + goto normal_DCMPG; + + switch (iptr[1].opc) { + case ICMD_IFEQ: + iptr->opc = ICMD_IF_DCMPEQ; + icmd_if_dcmpg_tail: + iptr->dst.insindex = iptr[1].dst.insindex; + iptr[1].opc = ICMD_NOP; + + OP2_BRANCH(TYPE_DBL, TYPE_DBL); + BRANCH(tbptr); + + COUNT(count_pcmd_bra); + break; + case ICMD_IFNE: + iptr->opc = ICMD_IF_DCMPNE; + goto icmd_if_dcmpg_tail; + case ICMD_IFLT: + iptr->opc = ICMD_IF_DCMPG_LT; + goto icmd_if_dcmpg_tail; + case ICMD_IFGT: + iptr->opc = ICMD_IF_DCMPG_GT; + goto icmd_if_dcmpg_tail; + case ICMD_IFLE: + iptr->opc = ICMD_IF_DCMPG_LE; + goto icmd_if_dcmpg_tail; + case ICMD_IFGE: + iptr->opc = ICMD_IF_DCMPG_GE; + goto icmd_if_dcmpg_tail; + default: + goto normal_DCMPG; + } + break; + +normal_DCMPG: + OP2_1(TYPE_DBL, TYPE_DBL, TYPE_INT); break; +#else case ICMD_FCMPL: case ICMD_FCMPG: COUNT(count_pcmd_op); - 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: @@ -1917,7 +3896,8 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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); @@ -1932,6 +3912,7 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) copy = curstack; while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; copy->flags |= SAVEDVAR; copy = copy->prev; } @@ -1941,59 +3922,67 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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]; + OP0_1(TYPE_RET); - iptr[0].target = (void *) tbptr; - - /* 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; @@ -2002,12 +3991,22 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) case ICMD_INVOKEVIRTUAL: case ICMD_INVOKEINTERFACE: COUNT(count_pcmd_met); - um = iptr->target; - md = um->methodref->parseddesc.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: + + coalescing_boundary = sd.new; + i = md->paramcount; if (md->memuse > rd->memuse) @@ -2019,86 +4018,128 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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_OUTVAR(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; + + SET_PREALLOC(copy); #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)) + 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? */ #else - copy->regoff = - rd->argfltregs[md->params[i].regoff]; -#endif + 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)]); + 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 - copy->regoff = - rd->argintregs[md->params[i].regoff]; +#endif /* SUPPORT_COMBINE_INTEGER_REGISTERS */ + sd.var[copy->varnum].vv.regoff = + rd->argintregs[md->params[i].regoff]; } } #if defined(ENABLE_INTRP) - } + } /* end if (!opt_intrp) */ #endif + } } copy = copy->prev; } + /* deal with live-through stack slots "under" the */ + /* arguments */ + /* XXX not for ICMD_BUILTIN */ + + i = md->paramcount; + while (copy) { - copy->flags |= SAVEDVAR; + SET_TEMPVAR(copy); + iptr->sx.s23.s2.args[i++] = copy->varnum; + sd.var[copy->varnum].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__) @@ -2114,104 +4155,174 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) #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_OUTVAR(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) { - copy->flags |= SAVEDVAR; - copy = copy->prev; + while (copy) { + sd.var[copy->varnum].flags |= SAVEDVAR; + copy = copy->prev; + } + + 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: + *exceptionptr = + new_internalerror("Unknown ICMD %d", opcode); + return false; + } /* switch */ + + CHECKOVERFLOW; + iptr++; + } /* while instructions */ + + /* 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) { + 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 |= OUTVAR; + + 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; + } + + sd.bptr->outvars[i] = copy->varnum; + } + + /* check if interface slots at basic block begin must be saved */ + IF_NO_INTRP( + for (i=0; iindepth; ++i) { + varinfo *v = sd.var + sd.bptr->invars[i]; + s4 t; + + t = v->type; + if (t == TYPE_RET) + t = TYPE_ADR; + + 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; } - i = iptr->op1; - POPMANY(i); - OP0_1(TYPE_ADR); - break; + } + ); - case ICMD_CLEAR_ARGREN: - for (i = iptr->op1; i < cd->maxlocals; i++) - argren[i] = i; - iptr->opc = opcode = ICMD_NOP; - SETDST; - break; - - case ICMD_READONLY_ARG: - case ICMD_READONLY_ARG+1: - case ICMD_READONLY_ARG+2: - case ICMD_READONLY_ARG+3: - case ICMD_READONLY_ARG+4: - - REQUIRE_1; - if (curstack->varkind == LOCALVAR) { - i = curstack->varnum; - argren[iptr->op1] = i; - iptr->op1 = i; - } - opcode = iptr->opc = opcode - ICMD_READONLY_ARG + ICMD_ISTORE; - goto icmd_store; + /* store the number of this block's variables */ - break; + sd.bptr->varcount = sd.vartop - sd.bptr->varstart; - default: - *exceptionptr = - new_internalerror("Unknown ICMD %d", opcode); - return NULL; - } /* switch */ +#if defined(STACK_VERBOSE) + stack_verbose_block_exit(&sd, superblockend); +#endif - CHECKOVERFLOW; - iptr++; - } /* while instructions */ + /* reach the following block, if any */ - bptr->outstack = curstack; - bptr->outdepth = stackdepth; - BBEND(curstack, i); - } /* if */ - else - superblockend = true; - bptr++; - } /* while blocks */ - } while (repeat && !deadcode); + 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->new_basicblockcount > count_max_basic_blocks) + count_max_basic_blocks = jd->new_basicblockcount; + count_basic_blocks += jd->new_basicblockcount; + if (jd->new_instructioncount > count_max_javainstr) + count_max_javainstr = jd->new_instructioncount; + count_javainstr += jd->new_instructioncount; + if (jd->new_stackcount > count_upper_bound_new_stack) + count_upper_bound_new_stack = jd->new_stackcount; + if ((sd.new - jd->new_stack) > count_max_new_stack) + count_max_new_stack = (sd.new - jd->new_stack); + + sd.bptr = jd->new_basicblocks; + 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]++; @@ -2230,926 +4341,167 @@ methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd) 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->new_basicblockcount <= 5) count_method_bb_distribution[0]++; - else if (m->basicblockcount <= 10) + else if (jd->new_basicblockcount <= 10) count_method_bb_distribution[1]++; - else if (m->basicblockcount <= 15) + else if (jd->new_basicblockcount <= 15) count_method_bb_distribution[2]++; - else if (m->basicblockcount <= 20) + else if (jd->new_basicblockcount <= 20) count_method_bb_distribution[3]++; - else if (m->basicblockcount <= 30) + else if (jd->new_basicblockcount <= 30) count_method_bb_distribution[4]++; - else if (m->basicblockcount <= 40) + else if (jd->new_basicblockcount <= 40) count_method_bb_distribution[5]++; - else if (m->basicblockcount <= 50) + else if (jd->new_basicblockcount <= 50) count_method_bb_distribution[6]++; - else if (m->basicblockcount <= 75) + else if (jd->new_basicblockcount <= 75) count_method_bb_distribution[7]++; else count_method_bb_distribution[8]++; } #endif /* defined(ENABLE_STATISTICS) */ - /* just return methodinfo* to signal everything was ok */ - - return m; -} - + /* everything's ok *******************************************************/ -/* debugging helpers **********************************************************/ + return true; -void icmd_print_stack(codegendata *cd, stackptr s) -{ - int i, j; - stackptr t; + /* goto labels for throwing verifier exceptions **************************/ - i = cd->maxstack; - t = s; - - while (t) { - i--; - t = t->prev; - } - j = cd->maxstack - i; - while (--i >= 0) - printf(" "); - - while (s) { - j--; - if (s->flags & SAVEDVAR) - switch (s->varkind) { - case TEMPVAR: - if (s->flags & INMEMORY) - printf(" M%02d", s->regoff); -#ifdef HAS_ADDRESS_REGISTER_FILE - else if (s->type == TYPE_ADR) - printf(" R%02d", s->regoff); -#endif - else if (IS_FLT_DBL_TYPE(s->type)) - printf(" F%02d", s->regoff); - else { -#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(s->type)) - printf(" %3s/%3s", regs[GET_LOW_REG(s->regoff)], - regs[GET_HIGH_REG(s->regoff)]); - else -#endif - { -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (opt_intrp) - printf(" %3d", s->regoff); - else -# endif - printf(" %3s", regs[s->regoff]); -#else - printf(" %3d", s->regoff); -#endif - } - } - break; - case STACKVAR: - printf(" I%02d", s->varnum); - break; - case LOCALVAR: - printf(" L%02d", s->varnum); - break; - case ARGVAR: - if (s->varnum == -1) { - /* Return Value */ - /* varkind ARGVAR "misused for this special case */ - printf(" V0"); - } else /* "normal" Argvar */ - printf(" A%02d", s->varnum); - break; - default: - printf(" !%02d", j); - } - else - switch (s->varkind) { - case TEMPVAR: - if (s->flags & INMEMORY) - printf(" m%02d", s->regoff); -#ifdef HAS_ADDRESS_REGISTER_FILE - else if (s->type == TYPE_ADR) - printf(" r%02d", s->regoff); -#endif - else if (IS_FLT_DBL_TYPE(s->type)) - printf(" f%02d", s->regoff); - else { -#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(s->type)) - printf(" %3s/%3s", regs[GET_LOW_REG(s->regoff)], - regs[GET_HIGH_REG(s->regoff)]); - else -#endif - { -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (opt_intrp) - printf(" %3d", s->regoff); - else -# endif - printf(" %3s", regs[s->regoff]); -#else - printf(" %3d", s->regoff); -#endif - } - } - break; - case STACKVAR: - printf(" i%02d", s->varnum); - break; - case LOCALVAR: - printf(" l%02d", s->varnum); - break; - case ARGVAR: - if (s->varnum == -1) { - /* Return Value */ - /* varkind ARGVAR "misused for this special case */ - printf(" v0"); - } else /* "normal" Argvar */ - printf(" a%02d", s->varnum); - break; - default: - printf(" ?%02d", j); - } - s = s->prev; - } -} +#if defined(ENABLE_VERIFIER) +throw_stack_underflow: + exceptions_throw_verifyerror(m, "Unable to pop operand off an empty stack"); + return false; -#if 0 -static void print_reg(stackptr s) { - if (s) { - if (s->flags & SAVEDVAR) - switch (s->varkind) { - case TEMPVAR: - if (s->flags & INMEMORY) - printf(" tm%02d", s->regoff); - else - printf(" tr%02d", s->regoff); - break; - case STACKVAR: - printf(" s %02d", s->varnum); - break; - case LOCALVAR: - printf(" l %02d", s->varnum); - break; - case ARGVAR: - printf(" a %02d", s->varnum); - break; - default: - printf(" ! %02d", s->varnum); - } - else - switch (s->varkind) { - case TEMPVAR: - if (s->flags & INMEMORY) - printf(" Tm%02d", s->regoff); - else - printf(" Tr%02d", s->regoff); - break; - case STACKVAR: - printf(" S %02d", s->varnum); - break; - case LOCALVAR: - printf(" L %02d", s->varnum); - break; - case ARGVAR: - printf(" A %02d", s->varnum); - break; - default: - printf(" ? %02d", s->varnum); - } - } - else - printf(" "); - -} -#endif +throw_stack_overflow: + exceptions_throw_verifyerror(m, "Stack size too large"); + return false; +throw_stack_depth_error: + exceptions_throw_verifyerror(m,"Stack depth mismatch"); + return false; -static char *jit_type[] = { - "int", - "lng", - "flt", - "dbl", - "adr" -}; +throw_stack_type_error: + exceptions_throw_verifyerror_for_stack(m, expectedtype); + return false; +throw_stack_category_error: + exceptions_throw_verifyerror(m, "Attempt to split long or double on the stack"); + return false; -/* show_icmd_method ************************************************************ +#endif +} - XXX -*******************************************************************************/ +/* functions for verbose stack analysis output ********************************/ -#if !defined(NDEBUG) -void show_icmd_method(methodinfo *m, codegendata *cd, registerdata *rd) +#if defined(STACK_VERBOSE) +static void stack_verbose_show_varinfo(stackdata_t *sd, varinfo *v) { - basicblock *bptr; - exceptiontable *ex; - s4 i, j; - u1 *u1ptr; + printf("%c", show_jit_type_letters[v->type]); + if (v->type == TYPE_RET) + printf("{L%03d}", v->vv.retaddr->nr); +} -#if defined(USE_THREADS) - /* We need to enter a lock here, since the binutils disassembler - is not reentrant-able and we could not read functions printed - at the same time. */ - builtin_monitorenter(lock_show_icmd); -#endif +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); +} - printf("\n"); - utf_fprint_classname(stdout, m->class->name); - printf("."); - utf_fprint(stdout, m->name); - utf_fprint(stdout, m->descriptor); - printf("\n\nMax locals: %d\n", (int) cd->maxlocals); - printf("Max stack: %d\n", (int) cd->maxstack); - printf("Line number table length: %d\n", m->linenumbercount); - - printf("Exceptions (Number: %d):\n", cd->exceptiontablelength); - for (ex = cd->exceptiontable; ex != NULL; ex = ex->down) { - printf(" L%03d ... ", ex->start->debug_nr ); - printf("L%03d = ", ex->end->debug_nr); - printf("L%03d", ex->handler->debug_nr); - printf(" (catchtype: "); - if (ex->catchtype.any) - if (IS_CLASSREF(ex->catchtype)) - utf_display_classname(ex->catchtype.ref->name); - else - utf_display_classname(ex->catchtype.cls->name); - else - printf("ANY"); - printf(")\n"); - } - - printf("Local Table:\n"); - for (i = 0; i < cd->maxlocals; i++) { - printf(" %3d: ", i); -#if defined(ENABLE_JIT) - for (j = TYPE_INT; j <= TYPE_ADR; j++) { -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif - if (rd->locals[i][j].type >= 0) { - printf(" (%s) ", jit_type[j]); - if (rd->locals[i][j].flags & INMEMORY) - printf("m%2d", rd->locals[i][j].regoff); -# ifdef HAS_ADDRESS_REGISTER_FILE - else if (j == TYPE_ADR) - printf("r%02d", rd->locals[i][j].regoff); -# endif - else if ((j == TYPE_FLT) || (j == TYPE_DBL)) - printf("f%02d", rd->locals[i][j].regoff); - else { -# if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(j)) - printf(" %3s/%3s", - regs[GET_LOW_REG(rd->locals[i][j].regoff)], - regs[GET_HIGH_REG(rd->locals[i][j].regoff)]); - else -# endif - printf("%3s", regs[rd->locals[i][j].regoff]); - } - } -# if defined(ENABLE_INTRP) - } -# endif +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]); } -#endif /* defined(ENABLE_JIT) */ - - printf("\n"); } - printf("\n"); - -#if defined(ENABLE_LSRA) - if (!opt_lsra) { -#endif -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif - printf("Interface Table:\n"); - for (i = 0; i < cd->maxstack; i++) { - if ((rd->interfaces[i][0].type >= 0) || - (rd->interfaces[i][1].type >= 0) || - (rd->interfaces[i][2].type >= 0) || - (rd->interfaces[i][3].type >= 0) || - (rd->interfaces[i][4].type >= 0)) { - printf(" %3d: ", i); - -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (!opt_intrp) { -# endif - for (j = TYPE_INT; j <= TYPE_ADR; j++) { - if (rd->interfaces[i][j].type >= 0) { - printf(" (%s) ", jit_type[j]); - if (rd->interfaces[i][j].flags & SAVEDVAR) { - if (rd->interfaces[i][j].flags & INMEMORY) - printf("M%2d", rd->interfaces[i][j].regoff); -#ifdef HAS_ADDRESS_REGISTER_FILE - else if (j == TYPE_ADR) - printf("R%02d", rd->interfaces[i][j].regoff); -#endif - else if ((j == TYPE_FLT) || (j == TYPE_DBL)) - printf("F%02d", rd->interfaces[i][j].regoff); - else { -#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(j)) - printf(" %3s/%3s", - regs[GET_LOW_REG(rd->interfaces[i][j].regoff)], - regs[GET_HIGH_REG(rd->interfaces[i][j].regoff)]); - else -#endif - printf("%3s",regs[rd->interfaces[i][j].regoff]); - } - } - else { - if (rd->interfaces[i][j].flags & INMEMORY) - printf("m%2d", rd->interfaces[i][j].regoff); -#ifdef HAS_ADDRESS_REGISTER_FILE - else if (j == TYPE_ADR) - printf("r%02d", rd->interfaces[i][j].regoff); -#endif - else if ((j == TYPE_FLT) || (j == TYPE_DBL)) - printf("f%02d", rd->interfaces[i][j].regoff); - else { -#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS) - if (IS_2_WORD_TYPE(j)) - printf(" %3s/%3s", - regs[GET_LOW_REG(rd->interfaces[i][j].regoff)], - regs[GET_HIGH_REG(rd->interfaces[i][j].regoff)]); - else -#endif - printf("%3s",regs[rd->interfaces[i][j].regoff]); - } - } - } - } - printf("\n"); -# if defined(ENABLE_INTRP) - } -# endif -#endif /* defined(ENABLE_JIT) */ - + else + putchar('-'); + printf("] inlocals ["); + if (bptr->inlocals) { + for (i=0; ilocalcount; ++i) { + if (i) + putchar(' '); + stack_verbose_show_varinfo(sd, bptr->inlocals + i); } } - printf("\n"); - -#if defined(ENABLE_INTRP) + 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]); } -#endif -#if defined(ENABLE_LSRA) - } -#endif - - /* show code before first basic block */ - - if (opt_showdisassemble) { - u1ptr = (u1 *) ((ptrint) m->mcode + cd->dseglen); - - for (; u1ptr < (u1 *) ((ptrint) m->mcode + cd->dseglen + m->basicblocks[0].mpc);) - DISASSINSTR(u1ptr); - - printf("\n"); - } - - /* show code of all basic blocks */ - - for (bptr = m->basicblocks; bptr != NULL; bptr = bptr->next) { - show_icmd_block(m, cd, bptr); } - - /* show stubs code */ - - if (opt_showdisassemble && opt_showexceptionstubs) { - printf("\nException stubs code:\n"); - printf("Length: %d\n\n", (s4) (m->mcodelength - - ((ptrint) cd->dseglen + - m->basicblocks[m->basicblockcount].mpc))); - - u1ptr = (u1 *) ((ptrint) m->mcode + cd->dseglen + - m->basicblocks[m->basicblockcount].mpc); - - for (; (ptrint) u1ptr < ((ptrint) m->mcode + m->mcodelength);) - DISASSINSTR(u1ptr); - - printf("\n"); + 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(")"); + } } - -#if defined(USE_THREADS) - builtin_monitorexit(lock_show_icmd); -#endif } -#endif /* !defined(NDEBUG) */ -/* show_icmd_block ************************************************************* - - XXX - -*******************************************************************************/ - -#if !defined(NDEBUG) -void show_icmd_block(methodinfo *m, codegendata *cd, basicblock *bptr) +static void stack_verbose_block_enter(stackdata_t *sd, bool reanalyse) { - s4 i, j; - bool deadcode; - instruction *iptr; - u1 *u1ptr; - - if (bptr->flags != BBDELETED) { - deadcode = bptr->flags <= BBREACHED; - printf("["); - if (deadcode) - for (j = cd->maxstack; j > 0; j--) - printf(" ? "); - else - icmd_print_stack(cd, bptr->instack); - printf("] L%03d(%d - %d) flags=%d:\n", bptr->debug_nr, bptr->icount, bptr->pre_count,bptr->flags); - iptr = bptr->iinstr; - - for (i = 0; i < bptr->icount; i++, iptr++) { - printf("["); - if (deadcode) { - for (j = cd->maxstack; j > 0; j--) - printf(" ? "); - } - else - icmd_print_stack(cd, iptr->dst); - printf("] %5d (line: %5d) ", i, iptr->line); - - show_icmd(iptr, deadcode); - printf("\n"); - } - - if (opt_showdisassemble && (!deadcode)) { - printf("\n"); - u1ptr = (u1 *) ((ptrint) m->mcode + cd->dseglen + bptr->mpc); + int i; - if (bptr->next != NULL) { - for (; u1ptr < (u1 *) ((ptrint) m->mcode + cd->dseglen + bptr->next->mpc);) - DISASSINSTR(u1ptr); + printf("======================================== STACK %sANALYSE BLOCK ", + (reanalyse) ? "RE-" : ""); + stack_verbose_show_block(sd, sd->bptr); + printf("\n"); - } else { - for (; u1ptr < (u1 *) ((ptrint) m->mcode + m->mcodelength);) - DISASSINSTR(u1ptr); - } - 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"); } -#endif /* !defined(NDEBUG) */ - - -/* show_icmd ******************************************************************* - XXX -*******************************************************************************/ - -#if !defined(NDEBUG) -void show_icmd(instruction *iptr, bool deadcode) +static void stack_verbose_block_exit(stackdata_t *sd, bool superblockend) { - int j; - s4 *s4ptr; - void **tptr = NULL; - - printf("%s", icmd_names[iptr->opc]); - - switch (iptr->opc) { - 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_LSHLCONST: - case ICMD_LSHRCONST: - case ICMD_LUSHRCONST: - case ICMD_ICONST: - case ICMD_ELSE_ICONST: - case ICMD_IASTORECONST: - case ICMD_BASTORECONST: - case ICMD_CASTORECONST: - case ICMD_SASTORECONST: - printf(" %d (0x%08x)", iptr->val.i, iptr->val.i); - 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: - printf("(%d) %d", iptr[1].op1, iptr->val.i); - break; - - 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_LCONST: - case ICMD_LASTORECONST: -#if SIZEOF_VOID_P == 4 - printf(" %lld (0x%016llx)", iptr->val.l, iptr->val.l); -#else - printf(" %ld (0x%016lx)", iptr->val.l, iptr->val.l); -#endif - break; - - case ICMD_FCONST: - printf(" %f (0x%08x)", iptr->val.f, iptr->val.i); - break; - - case ICMD_DCONST: -#if SIZEOF_VOID_P == 4 - printf(" %g (0x%016llx)", iptr->val.d, iptr->val.l); -#else - printf(" %g (0x%016lx)", iptr->val.d, iptr->val.l); -#endif - break; - - case ICMD_ACONST: - case ICMD_AASTORECONST: - /* check if this is a constant string or a class reference */ - - if (iptr->target) { - if (iptr->val.a) - printf(" %p", iptr->val.a); - else - printf(" (NOT RESOLVED)"); - - printf(", Class = \""); - utf_display(((constant_classref *) iptr->target)->name); - printf("\""); - - } else { - printf(" %p", iptr->val.a); - if (iptr->val.a) { - printf(", String = \""); - utf_display(javastring_toutf(iptr->val.a, false)); - printf("\""); - } - } - break; - - case ICMD_GETFIELD: - case ICMD_PUTFIELD: - if (iptr->val.a) - printf(" %d, ", ((fieldinfo *) iptr->val.a)->offset); - else - printf(" (NOT RESOLVED), "); - utf_display_classname(((unresolved_field *) iptr->target)->fieldref->classref->name); - printf("."); - utf_display(((unresolved_field *) iptr->target)->fieldref->name); - printf(" (type "); - utf_display(((unresolved_field *) iptr->target)->fieldref->descriptor); - printf(")"); - break; - - case ICMD_PUTSTATIC: - case ICMD_GETSTATIC: - if (iptr->val.a) { - if (!(((fieldinfo *) iptr->val.a)->class->state & CLASS_INITIALIZED)) - printf(" (NOT INITIALIZED) "); - else - printf(" "); - } else - printf(" (NOT RESOLVED) "); - utf_display_classname(((unresolved_field *) iptr->target)->fieldref->classref->name); - printf("."); - utf_display(((unresolved_field *) iptr->target)->fieldref->name); - printf(" (type "); - utf_display(((unresolved_field *) iptr->target)->fieldref->descriptor); - printf(")"); - break; - - case ICMD_PUTSTATICCONST: - case ICMD_PUTFIELDCONST: - switch (iptr[1].op1) { - case TYPE_INT: - printf(" %d (0x%08x),", iptr->val.i, iptr->val.i); - break; - case TYPE_LNG: -#if SIZEOF_VOID_P == 4 - printf(" %lld (0x%016llx),", iptr->val.l, iptr->val.l); -#else - printf(" %ld (0x%016lx),", iptr->val.l, iptr->val.l); -#endif - break; - case TYPE_ADR: - printf(" %p,", iptr->val.a); - break; - case TYPE_FLT: - printf(" %g (0x%08x),", iptr->val.f, iptr->val.i); - break; - case TYPE_DBL: -#if SIZEOF_VOID_P == 4 - printf(" %g (0x%016llx),", iptr->val.d, iptr->val.l); -#else - printf(" %g (0x%016lx),", iptr->val.d, iptr->val.l); -#endif - break; - } - if (iptr->opc == ICMD_PUTFIELDCONST) { - if (iptr[1].val.a) - printf(" %d,", ((fieldinfo *) iptr[1].val.a)->offset); - else - printf(" (NOT RESOLVED),"); - } - printf(" "); - utf_display_classname(((unresolved_field *) iptr[1].target)->fieldref->classref->name); - printf("."); - utf_display(((unresolved_field *) iptr[1].target)->fieldref->name); - printf(" (type "); - utf_display(((unresolved_field *) iptr[1].target)->fieldref->descriptor); - printf(")"); - break; - - case ICMD_IINC: - printf(" %d + %d", iptr->op1, iptr->val.i); - break; - - case ICMD_IASTORE: - case ICMD_SASTORE: - case ICMD_BASTORE: - case ICMD_CASTORE: - case ICMD_LASTORE: - case ICMD_DASTORE: - case ICMD_FASTORE: - case ICMD_AASTORE: - - case ICMD_IALOAD: - case ICMD_SALOAD: - case ICMD_BALOAD: - case ICMD_CALOAD: - case ICMD_LALOAD: - case ICMD_DALOAD: - case ICMD_FALOAD: - case ICMD_AALOAD: - if (iptr->op1 != 0) - printf("(opt.)"); - break; - - case ICMD_RET: - case ICMD_ILOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ALOAD: - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - printf(" %d", iptr->op1); - break; - - case ICMD_NEW: - printf(" "); - utf_display_classname(((classinfo *) iptr->val.a)->name); - break; - - case ICMD_NEWARRAY: - switch (iptr->op1) { - case 4: - printf(" boolean"); - break; - case 5: - printf(" char"); - break; - case 6: - printf(" float"); - break; - case 7: - printf(" double"); - break; - case 8: - printf(" byte"); - break; - case 9: - printf(" short"); - break; - case 10: - printf(" int"); - break; - case 11: - printf(" long"); - break; - } - break; - - case ICMD_ANEWARRAY: - if (iptr->op1) { - printf(" "); - utf_display_classname(((classinfo *) iptr->val.a)->name); - } - break; - - case ICMD_MULTIANEWARRAY: - if (iptr->target) { - printf(" (NOT RESOLVED) %d ",iptr->op1); - utf_display(((constant_classref *) iptr->val.a)->name); - } else { - printf(" %d ",iptr->op1); - utf_display_classname(((vftbl_t *) iptr->val.a)->class->name); - } - break; - - case ICMD_CHECKCAST: - case ICMD_INSTANCEOF: - { - classinfo *c = iptr->val.a; - if (c) { - if (c->flags & ACC_INTERFACE) - printf(" (INTERFACE) "); - else - printf(" (CLASS,%3d) ", c->vftbl->diffval); - } else { - printf(" (NOT RESOLVED) "); - } - utf_display_classname(((constant_classref *) iptr->target)->name); - } - break; - - case ICMD_INLINE_START: - printf(" "); - utf_display_classname(iptr->method->class->name); - printf("."); - utf_display_classname(iptr->method->name); - utf_display_classname(iptr->method->descriptor); - printf(", depth=%i", iptr->op1); - break; - - case ICMD_INLINE_END: - break; - - case ICMD_BUILTIN: - printf(" %s", ((builtintable_entry *) iptr->val.a)->name); - break; - - case ICMD_INVOKEVIRTUAL: - case ICMD_INVOKESPECIAL: - case ICMD_INVOKESTATIC: - case ICMD_INVOKEINTERFACE: - if (!iptr->val.a) - printf(" (NOT RESOLVED) "); - else - printf(" "); - utf_display_classname(((unresolved_method *) iptr->target)->methodref->classref->name); - printf("."); - utf_display(((unresolved_method *) iptr->target)->methodref->name); - utf_display(((unresolved_method *) iptr->target)->methodref->descriptor); - break; - - case ICMD_IFEQ: - case ICMD_IFNE: - case ICMD_IFLT: - case ICMD_IFGE: - case ICMD_IFGT: - case ICMD_IFLE: - if (deadcode || !iptr->target) - printf(" %d (0x%08x) op1=%d", iptr->val.i, iptr->val.i, iptr->op1); - else - printf(" %d (0x%08x) L%03d", iptr->val.i, iptr->val.i, ((basicblock *) iptr->target)->debug_nr); - break; - - case ICMD_IF_LEQ: - case ICMD_IF_LNE: - case ICMD_IF_LLT: - case ICMD_IF_LGE: - case ICMD_IF_LGT: - case ICMD_IF_LLE: - if (deadcode || !iptr->target) -#if SIZEOF_VOID_P == 4 - printf("(%lld) op1=%d", iptr->val.l, iptr->op1); -#else - printf("(%ld) op1=%d", iptr->val.l, iptr->op1); -#endif - else -#if SIZEOF_VOID_P == 4 - printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr); -#else - printf("(%ld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr); -#endif - break; - - case ICMD_JSR: - case ICMD_GOTO: - 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_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: - if (deadcode || !iptr->target) - printf(" op1=%d", iptr->op1); - else - printf(" L%03d", ((basicblock *) iptr->target)->debug_nr); - break; - - case ICMD_TABLESWITCH: - s4ptr = (s4*)iptr->val.a; - - if (deadcode || !iptr->target) { - printf(" %d;", *s4ptr); - } - else { - tptr = (void **) iptr->target; - printf(" L%03d;", ((basicblock *) *tptr)->debug_nr); - tptr++; - } - - s4ptr++; /* skip default */ - j = *s4ptr++; /* low */ - j = *s4ptr++ - j; /* high */ - while (j >= 0) { - if (deadcode || !*tptr) - printf(" %d", *s4ptr++); - else { - printf(" L%03d", ((basicblock *) *tptr)->debug_nr); - tptr++; - } - j--; - } - break; - - case ICMD_LOOKUPSWITCH: - s4ptr = (s4*)iptr->val.a; - - if (deadcode || !iptr->target) { - printf(" %d;", *s4ptr); - } - else { - tptr = (void **) iptr->target; - printf(" L%03d;", ((basicblock *) *tptr)->debug_nr); - tptr++; - } - s4ptr++; /* default */ - j = *s4ptr++; /* count */ - - while (--j >= 0) { - if (deadcode || !*tptr) { - s4ptr++; /* skip value */ - printf(" %d",*s4ptr++); - } - else { - printf(" L%03d", ((basicblock *) *tptr)->debug_nr); - tptr++; - } - } - break; - - case ICMD_ARETURN: - if (iptr->val.a) { - printf(" (NOT RESOLVED), Class = \""); - utf_display(((unresolved_class *) iptr->val.a)->classref->name); - printf("\""); - } - } + printf("%s ", (superblockend) ? "SUPERBLOCKEND" : "END"); + stack_verbose_show_block(sd, sd->bptr); + printf("\n"); } -#endif /* !defined(NDEBUG) */ +#endif /* @@ -3163,4 +4515,5 @@ void show_icmd(instruction *iptr, bool deadcode) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */