Merge from subtype.
[cacao.git] / src / vm / jit / stack.h
index 49aee25e1ec479fe5b03dba6cc66aca59695430e..803d2db11d83ed7ae3d5c3e5c561e6554613e1bd 100644 (file)
@@ -1,9 +1,7 @@
-/* vm/jit/stack.h - stack analysis header
+/* src/vm/jit/stack.h - stack analysis header
 
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
-   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
-   P. Tomsich, J. Wenninger
+   Copyright (C) 1996-2005, 2006, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
 
    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 1621 2004-11-30 13:06:55Z twisti $
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
 */
 
 #ifndef _STACK_H
 #define _STACK_H
 
-#include "vm/exceptions.h"
-#include "vm/global.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 <stdint.h>
 
-#define TYPEPANIC  {panic("Stack type mismatch");}
+#include "vm/types.h"
 
+#include "vm/global.h"
 
-/*--------------------------------------------------*/
-/* STACK UNDERFLOW/OVERFLOW CHECKS                  */
-/*--------------------------------------------------*/
+#include "vm/jit/jit.hpp"
+#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++;}
-#define NEWSTACKn(s,n)  NEWSTACK(s,UNDEFVAR,n)
-#define NEWSTACK0(s)    NEWSTACK(s,UNDEFVAR,0)
 
-/* allocate the input stack for an exception handler */
-#define NEWXSTACK   {NEWSTACK(TYPE_ADR,STACKVAR,0);curstack=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                         */
+};
+
 
+/* macros used internally by analyse_stack ************************************/
 
 /*--------------------------------------------------*/
-/* STACK MANIPULATION                               */
+/* BASIC TYPE CHECKING                              */
 /*--------------------------------------------------*/
 
-/* resetting to an empty operand stack */
-#define STACKRESET {curstack=0;stackdepth=0;}
-
-/* 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)      {if(s!=curstack->type){TYPEPANIC;}                                                                         \
-                     if(curstack->varkind==UNDEFVAR)curstack->varkind=TEMPVAR;\
-                     curstack=curstack->prev;}
-#define POPANY      {if(curstack->varkind==UNDEFVAR)curstack->varkind=TEMPVAR; \
-                     curstack=curstack->prev;}
-#define COPY(s,d)   {(d)->flags=0;(d)->type=(s)->type;\
-                     (d)->varkind=(s)->varkind;(d)->varnum=(s)->varnum;}
+/* XXX would be nice if we did not have to pass the expected type */
 
+#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 OPERATIONS MODELING                        */
+/* STACK UNDERFLOW/OVERFLOW CHECKS                  */
 /*--------------------------------------------------*/
 
-/* 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!
+/* underflow checks */
+
+#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 */
+
+
+/* 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;\
-}
+#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)
 
-/* BBEND is called at the end of each basic block (after the last
- * instruction of the block has been processed).
- */
+/* 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 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; \
-       } \
-}
+#define NEWSTACKn(s,n)  NEWSTACK(s,UNDEFVAR,n)
+#define NEWSTACK0(s)    NEWSTACK(s,UNDEFVAR,0)
 
 
-/* MARKREACHED marks the destination block <b> 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
- */
+/* function prototypes ********************************************************/
 
-#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); \
-                panic("Stack depth mismatch"); \
-            } \
-                   while (s) { \
-                if (s->type != t->type) \
-                                   TYPEPANIC; \
-                           s = s->prev; \
-                t = t->prev; \
-                       } \
-               } \
-    } while (0)
+#ifdef __cplusplus
+extern "C" {
+#endif
 
+bool stack_init(void);
 
-/* function prototypes */
+bool stack_analyse(jitdata *jd);
 
-methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd);
+void stack_javalocals_store(instruction *iptr, s4 *javalocals);
 
-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);
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _STACK_H */
 
@@ -316,4 +189,5 @@ void show_icmd(instruction *iptr, bool deadcode);
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */