X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstack.h;h=eceb2db2204fd84ca3b6256b58a5a471c9d559a9;hb=777a728b1d476cd762c1e8943f9c6412b027b43d;hp=3e3bc6834830f7f34c40476c583f7860d2b13a81;hpb=5c912e4f542be4b673465c498339779269c4da41;p=cacao.git diff --git a/src/vm/jit/stack.h b/src/vm/jit/stack.h index 3e3bc6834..eceb2db22 100644 --- a/src/vm/jit/stack.h +++ b/src/vm/jit/stack.h @@ -1,9 +1,7 @@ -/* vm/jit/stack.h - stack analysis header +/* src/vm/jit/stack.h - stack analysis header - 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, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -19,14 +17,8 @@ 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. - - Contact: cacao@complang.tuwien.ac.at - - Authors: Christian Thalinger - - $Id: stack.h 2497 2005-05-23 08:06:46Z twisti $ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ @@ -34,333 +26,147 @@ #ifndef _STACK_H #define _STACK_H -#include "vm/global.h" -#include "vm/exceptions.h" -#include "vm/jit/reg.h" +/* forward typedefs ***********************************************************/ +typedef struct stackelement_t stackelement_t; -/**********************************************************************/ -/* Macros used internally by analyse_stack */ -/**********************************************************************/ -#ifdef STATISTICS -#define COUNT(cnt) cnt++ -#else -#define COUNT(cnt) -#endif - -/* convenient abbreviations */ -#define CURKIND curstack->varkind -#define CURTYPE curstack->type +#include "config.h" -/*--------------------------------------------------*/ -/* SIGNALING ERRORS */ -/*--------------------------------------------------*/ +#include -#define TYPE_VERIFYERROR(t) \ - do { \ - char *type; \ - switch ((t)) { \ - case TYPE_INT: \ - type = "integer"; \ - break; \ - case TYPE_LNG: \ - type = "long"; \ - break; \ - case TYPE_FLT: \ - type = "float"; \ - break; \ - case TYPE_DBL: \ - type = "double"; \ - break; \ - case TYPE_ADR: \ - type = "object/array"; \ - break; \ - } \ - *exceptionptr = new_verifyerror(m, \ - "Expecting to find %s on stack", \ - type); \ - return NULL; \ - } while (0) +#include "vm/types.h" +#include "vm/exceptions.h" +#include "vm/global.h" -/*--------------------------------------------------*/ -/* STACK UNDERFLOW/OVERFLOW CHECKS */ -/*--------------------------------------------------*/ +#include "vm/jit/jit.h" +#include "vm/jit/reg.h" -/* underflow checks */ -#define REQUIRE(num) \ - do { \ - if (stackdepth < (num)) { \ - *exceptionptr = \ - new_verifyerror(m, "Unable to pop operand off an empty stack"); \ - return NULL; \ - } \ - } while(0) +/* stack element structure ****************************************************/ -#define REQUIRE_1 REQUIRE(1) -#define REQUIRE_2 REQUIRE(2) -#define REQUIRE_3 REQUIRE(3) -#define REQUIRE_4 REQUIRE(4) +/* flags */ +#define SAVEDVAR 1 /* variable has to survive method invocations */ +#define INMEMORY 2 /* variable stored in memory */ +#define SAVREG 4 /* allocated to a saved register */ +#define ARGREG 8 /* allocated to an arg register */ +#define PASSTHROUGH 32 /* stackslot was passed-through by an ICMD */ +#define PREALLOC 64 /* preallocated var like for ARGVARS. Used */ + /* with the new var system */ +#define INOUT 128 /* variable is an invar or/and an outvar */ -/* overflow check */ -/* We allow ACONST instructions inserted as arguments to builtin - * functions to exceed the maximum stack depth. Maybe we should check - * against maximum stack depth only at block boundaries? - */ +#define IS_SAVEDVAR(x) ((x) & SAVEDVAR) +#define IS_INMEMORY(x) ((x) & INMEMORY) -#define CHECKOVERFLOW \ - do { \ - if (stackdepth > m->maxstack) { \ - if (iptr[0].opc != ICMD_ACONST || iptr[0].op1 == 0) { \ - *exceptionptr = new_verifyerror(m, "Stack size too large"); \ - return NULL; \ - } \ - } \ - } while(0) +/* variable kinds */ -/*--------------------------------------------------*/ -/* ALLOCATING STACK SLOTS */ -/*--------------------------------------------------*/ +#define UNDEFVAR 0 /* stack slot will become temp during regalloc*/ +#define TEMPVAR 1 /* stack slot is temp register */ +#define STACKVAR 2 /* stack slot is numbered stack slot */ +#define LOCALVAR 3 /* stack slot is local variable */ +#define ARGVAR 4 /* stack slot is argument variable */ -#define NEWSTACK_(s,v,n) {new->prev=curstack;new->type=s;new->flags=0; \ - new->varkind=v;new->varnum=n;curstack=new;new++;} - /* Initialize regoff, so -sia can show regnames even before reg.inc */ - /* regs[rd->intregargnum has to be set for this */ - /* new->regoff = (IS_FLT_DBL_TYPE(s))?-1:rd->intreg_argnum; }*/ -#ifdef LSRA - #define NEWSTACK(s,v,n) {NEWSTACK_(s,v,n); m->maxlifetimes++;} -#else - #define NEWSTACK(s,v,n) NEWSTACK_(s,v,n) -#endif -#define NEWSTACKn(s,n) NEWSTACK(s,UNDEFVAR,n) -#define NEWSTACK0(s) NEWSTACK(s,UNDEFVAR,0) +struct stackelement_t { + stackelement_t *prev; /* pointer to next element towards bottom */ + instruction *creator; /* instruction that created this element */ + s4 type; /* slot type of stack element */ + s4 flags; /* flags (SAVED, INMEMORY) */ + s4 varkind; /* kind of variable or register */ + s4 varnum; /* number of variable */ +}; -/* allocate the input stack for an exception handler */ -#define NEWXSTACK {NEWSTACK(TYPE_ADR,STACKVAR,0);curstack=0;} +/* macros used internally by analyse_stack ************************************/ /*--------------------------------------------------*/ -/* STACK MANIPULATION */ +/* BASIC TYPE CHECKING */ /*--------------------------------------------------*/ -/* resetting to an empty operand stack */ +/* XXX would be nice if we did not have to pass the expected type */ -#define STACKRESET \ - do { \ - curstack = 0; \ - stackdepth = 0; \ +#if defined(ENABLE_VERIFIER) +#define CHECK_BASIC_TYPE(expected,actual) \ + do { \ + if ((actual) != (expected)) { \ + expectedtype = (expected); \ + goto throw_stack_type_error; \ + } \ } while (0) +#else /* !ENABLE_VERIFIER */ +#define CHECK_BASIC_TYPE(expected,actual) +#endif /* ENABLE_VERIFIER */ +/*--------------------------------------------------*/ +/* STACK UNDERFLOW/OVERFLOW CHECKS */ +/*--------------------------------------------------*/ -/* set the output stack of the current instruction */ - -#define SETDST iptr->dst = curstack; - - -/* The following macros do NOT check stackdepth, set stackdepth or iptr->dst */ - -#define POP(s) \ - do { \ - if ((s) != curstack->type) { \ - TYPE_VERIFYERROR((s)); \ - } \ - if (curstack->varkind == UNDEFVAR) \ - curstack->varkind = TEMPVAR; \ - curstack = curstack->prev; \ - } while (0) - -#define POPANY \ - do { \ - if (curstack->varkind == UNDEFVAR) \ - curstack->varkind = TEMPVAR; \ - curstack = curstack->prev; \ - } while (0) +/* underflow checks */ -#define COPY(s,d) \ - do { \ - (d)->flags = 0; \ - (d)->type = (s)->type; \ - (d)->varkind = (s)->varkind; \ - (d)->varnum = (s)->varnum; \ +#if defined(ENABLE_VERIFIER) +#define REQUIRE(num) \ + do { \ + if (stackdepth < (num)) \ + goto throw_stack_underflow; \ } while (0) +#else /* !ENABLE_VERIFIER */ +#define REQUIRE(num) +#endif /* ENABLE_VERIFIER */ -/*--------------------------------------------------*/ -/* STACK OPERATIONS MODELING */ -/*--------------------------------------------------*/ - -/* The following macros are used to model the stack manipulations of - * different kinds of instructions. - * - * These macros check the input stackdepth and they set the output - * stackdepth and the output stack of the instruction (iptr->dst). - * - * These macros do *not* check for stack overflows! +/* overflow check */ +/* We allow ACONST instructions inserted as arguments to builtin + * functions to exceed the maximum stack depth. Maybe we should check + * against maximum stack depth only at block boundaries? */ - -#define PUSHCONST(s){NEWSTACKn(s,stackdepth);SETDST;stackdepth++;} -#define LOAD(s,v,n) {NEWSTACK(s,v,n);SETDST;stackdepth++;} -#define STORE(s) {REQUIRE_1;POP(s);SETDST;stackdepth--;} -#define OP1_0(s) {REQUIRE_1;POP(s);SETDST;stackdepth--;} -#define OP1_0ANY {REQUIRE_1;POPANY;SETDST;stackdepth--;} -#define OP0_1(s) {NEWSTACKn(s,stackdepth);SETDST;stackdepth++;} -#define OP1_1(s,d) {REQUIRE_1;POP(s);NEWSTACKn(d,stackdepth-1);SETDST;} -#define OP2_0(s) {REQUIRE_2;POP(s);POP(s);SETDST;stackdepth-=2;} -#define OPTT2_0(t,b){REQUIRE_2;POP(t);POP(b);SETDST;stackdepth-=2;} -#define OP2_1(s) {REQUIRE_2;POP(s);POP(s);NEWSTACKn(s,stackdepth-2);SETDST;stackdepth--;} -#define OP2IAT_1(s) {REQUIRE_2;POP(TYPE_INT);POP(TYPE_ADR);NEWSTACKn(s,stackdepth-2);\ - SETDST;stackdepth--;} -#define OP2IT_1(s) {REQUIRE_2;POP(TYPE_INT);POP(s);NEWSTACKn(s,stackdepth-2);\ - SETDST;stackdepth--;} -#define OPTT2_1(s,d){REQUIRE_2;POP(s);POP(s);NEWSTACKn(d,stackdepth-2);SETDST;stackdepth--;} -#define OP2_2(s) {REQUIRE_2;POP(s);POP(s);NEWSTACKn(s,stackdepth-2);\ - NEWSTACKn(s,stackdepth-1);SETDST;} -#define OP3TIA_0(s) {REQUIRE_3;POP(s);POP(TYPE_INT);POP(TYPE_ADR);SETDST;stackdepth-=3;} -#define OP3_0(s) {REQUIRE_3;POP(s);POP(s);POP(s);SETDST;stackdepth-=3;} -#define POPMANY(i) {REQUIRE(i);stackdepth-=i;while(--i>=0){POPANY;}SETDST;} -#define DUP {REQUIRE_1;NEWSTACK(CURTYPE,CURKIND,curstack->varnum);SETDST; \ - stackdepth++;} -#define SWAP {REQUIRE_2;COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\ - new[0].prev=curstack;new[1].prev=new;\ - curstack=new+1;new+=2;SETDST;} -#define DUP_X1 {REQUIRE_2;COPY(curstack,new);COPY(curstack,new+2);POPANY;\ - COPY(curstack,new+1);POPANY;new[0].prev=curstack;\ - new[1].prev=new;new[2].prev=new+1;\ - curstack=new+2;new+=3;SETDST;stackdepth++;} -#define DUP2_X1 {REQUIRE_3;COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\ - COPY(curstack,new);COPY(curstack,new+3);POPANY;\ - COPY(curstack,new+2);POPANY;new[0].prev=curstack;\ - new[1].prev=new;new[2].prev=new+1;\ - new[3].prev=new+2;new[4].prev=new+3;\ - curstack=new+4;new+=5;SETDST;stackdepth+=2;} -#define DUP_X2 {REQUIRE_3;COPY(curstack,new);COPY(curstack,new+3);POPANY;\ - COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\ - new[0].prev=curstack;new[1].prev=new;\ - new[2].prev=new+1;new[3].prev=new+2;\ - curstack=new+3;new+=4;SETDST;stackdepth++;} -#define DUP2_X2 {REQUIRE_4;COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\ - COPY(curstack,new);COPY(curstack,new+4);POPANY;\ - COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\ - new[0].prev=curstack;new[1].prev=new;\ - new[2].prev=new+1;new[3].prev=new+2;\ - new[4].prev=new+3;new[5].prev=new+4;\ - curstack=new+5;new+=6;SETDST;stackdepth+=2;} +/* XXX we should find a way to remove the opc/op1 check */ +#if defined(ENABLE_VERIFIER) +#define CHECKOVERFLOW \ + do { \ + if (stackdepth > m->maxstack) \ + if ((iptr->opc != ICMD_ACONST) || INSTRUCTION_MUST_CHECK(iptr))\ + goto throw_stack_overflow; \ + } while(0) +#else /* !ENABLE_VERIFIER */ +#define CHECKOVERFLOW +#endif /* ENABLE_VERIFIER */ /*--------------------------------------------------*/ -/* MACROS FOR HANDLING BASIC BLOCKS */ +/* ALLOCATING STACK SLOTS */ /*--------------------------------------------------*/ -/* COPYCURSTACK makes a copy of the current operand stack (curstack) - * and returns it in the variable copy. - * - * This macro is used to propagate the operand stack from one basic - * block to another. The destination block receives the copy as its - * input stack. - */ -#define COPYCURSTACK(copy) {\ - int d;\ - stackptr s;\ - if(curstack){\ - s=curstack;\ - new+=stackdepth;\ - d=stackdepth;\ - copy=new;\ - while(s){\ - copy--;d--;\ - copy->prev=copy-1;\ - copy->type=s->type;\ - copy->flags=0;\ - copy->varkind=STACKVAR;\ - copy->varnum=d;\ - s=s->prev;\ - }\ - copy->prev=NULL;\ - copy=new-1;\ - }\ - else\ - copy=NULL;\ -} - -/* BBEND is called at the end of each basic block (after the last - * instruction of the block has been processed). - */ +#define NEWSTACK(s,v,n) \ + do { \ + sd.new->prev = curstack; \ + sd.new->type = (s); \ + sd.new->flags = 0; \ + sd.new->varkind = (v); \ + sd.new->varnum = (n); \ + curstack = sd.new; \ + sd.var[(n)].type = (s); \ + sd.var[(n)].flags = 0; \ + sd.new++; \ + } while (0) -#define BBEND(s,i){ \ - i = stackdepth - 1; \ - copy = s; \ - while (copy) { \ - if ((copy->varkind == STACKVAR) && (copy->varnum > i)) \ - copy->varkind = TEMPVAR; \ - else { \ - copy->varkind = STACKVAR; \ - copy->varnum = i;\ - } \ - rd->interfaces[i][copy->type].type = copy->type; \ - rd->interfaces[i][copy->type].flags |= copy->flags; \ - i--; copy = copy->prev; \ - } \ - i = bptr->indepth - 1; \ - copy = bptr->instack; \ - while (copy) { \ - rd->interfaces[i][copy->type].type = copy->type; \ - if (copy->varkind == STACKVAR) { \ - if (copy->flags & SAVEDVAR) \ - rd->interfaces[i][copy->type].flags |= SAVEDVAR; \ - } \ - i--; copy = copy->prev; \ - } \ -} - - -/* MARKREACHED marks the destination block as reached. If this - * block has been reached before we check if stack depth and types - * match. Otherwise the destination block receives a copy of the - * current stack as its input stack. - * - * b...destination block - * c...current stack - */ +/* Initialize regoff, so -sia can show regnames even before reg.inc */ +/* regs[rd->intregargnum] has to be set for this */ +/* new->regoff = (IS_FLT_DBL_TYPE(s))?-1:rd->intreg_argnum; } */ -#define MARKREACHED(b,c) \ - do { \ - if ((b)->flags < 0) { \ - COPYCURSTACK((c)); \ - (b)->flags = 0; \ - (b)->instack = (c); \ - (b)->indepth = stackdepth; \ - } else { \ - stackptr s = curstack; \ - stackptr t = (b)->instack; \ - if ((b)->indepth != stackdepth) { \ - show_icmd_method(m, cd, rd); \ - log_text("Stack depth mismatch"); \ - assert(0); \ - } \ - while (s) { \ - if (s->type != t->type) \ - TYPE_VERIFYERROR(t->type); \ - s = s->prev; \ - t = t->prev; \ - } \ - } \ - } while (0) +#define NEWSTACKn(s,n) NEWSTACK(s,UNDEFVAR,n) +#define NEWSTACK0(s) NEWSTACK(s,UNDEFVAR,0) /* function prototypes ********************************************************/ -methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd); +bool stack_init(void); + +bool stack_analyse(jitdata *jd); -void icmd_print_stack(codegendata *cd, stackptr s); -char *icmd_builtin_name(functionptr bptr); -void show_icmd_method(methodinfo *m, codegendata *cd, registerdata *rd); -void show_icmd_block(methodinfo *m, codegendata *cd, basicblock *bptr); -void show_icmd(instruction *iptr, bool deadcode); +void stack_javalocals_store(instruction *iptr, s4 *javalocals); #endif /* _STACK_H */ @@ -376,4 +182,5 @@ void show_icmd(instruction *iptr, bool deadcode); * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */