implemented subroutine verification (Coglio's method) + several verifier fixes
[cacao.git] / jit / stack.c
index 7b8aa2f28ec64e2f4f37c53c7563509a6aa52260..3c3db3367fd73895a16341e311f8b13fe9c1aba0 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: stack.c 803 2003-12-17 14:11:00Z edwin $
+   $Id: stack.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -37,6 +37,7 @@
 #include <string.h>
 #include "stack.h"
 #include "global.h"
+#include "main.h"
 #include "jit.h"
 #include "builtin.h"
 #include "disass.h"
@@ -84,14 +85,15 @@ extern int dseglen;
 #define REQUIRE_4     REQUIRE(4)
 
 /* overflow check */
-/* XXX we allow ACONST to exceed the maximum stack depth because it is
- * generated for builtin calls. Maybe we should check against maximum
- * stack depth only at block boundaries?
+/* XXX 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 CHECKOVERFLOW                                                  \
        do {                                                                            \
                if (stackdepth > maxstack) {                    \
-                       if (iptr[0].opc != ICMD_ACONST)         \
+                       if (iptr[0].opc != ICMD_ACONST          \
+                || iptr[0].op1 == 0)            \
                        {OVERFLOW;}                                                     \
                }                                                                               \
        } while(0)
@@ -136,6 +138,8 @@ extern int dseglen;
  *
  * 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!
  */
    
 #define PUSHCONST(s){NEWSTACKn(s,stackdepth);SETDST;stackdepth++;}
@@ -185,7 +189,10 @@ extern int dseglen;
                     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;}
-/******************************/
+
+/*--------------------------------------------------*/
+/* MACROS FOR HANDLING BASIC BLOCKS                 */
+/*--------------------------------------------------*/
 
 /* COPYCURSTACK makes a copy of the current operand stack (curstack)
  * and returns it in the variable copy.
@@ -218,6 +225,9 @@ extern int dseglen;
                copy=NULL;\
 }
 
+/* BBEND is called at the end of each basic block (after the last
+ * instruction of the block has been processed).
+ */
 
 #define BBEND(s,i){\
        i=stackdepth-1;\
@@ -268,6 +278,31 @@ extern int dseglen;
 }
 
 
+/**********************************************************************/
+/* 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]) XXX 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.
+ */
+
 void analyse_stack()
 {
        int b_count;
@@ -1039,6 +1074,13 @@ void analyse_stack()
                                                /* pop 1 push 0 */
 
                                        case ICMD_POP:
+#ifdef TYPECHECK_STACK_COMPCAT
+                                               if (opt_verify) {
+                                                       REQUIRE_1;
+                                                       if (IS_2_WORD_TYPE(curstack->type))
+                                                               panic("Illegal instruction: POP on category 2 type");
+                                               }
+#endif
                                                OP1_0ANY;
                                                break;
 
@@ -1267,6 +1309,14 @@ void analyse_stack()
                                        case ICMD_POP2:
                                                REQUIRE_1;
                                                if (! IS_2_WORD_TYPE(curstack->type)) {
+                                                       /* ..., cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                       if (opt_verify) {
+                                                               REQUIRE_2;
+                                                               if (IS_2_WORD_TYPE(curstack->prev->type))
+                                                                       panic("Illegal instruction: POP2 on cat2, cat1 types");
+                                                       }
+#endif
                                                        OP1_0ANY;                /* second pop */
                                                }
                                                else
@@ -1277,6 +1327,13 @@ void analyse_stack()
                                                /* pop 0 push 1 dup */
                                                
                                        case ICMD_DUP:
+#ifdef TYPECHECK_STACK_COMPCAT
+                                               if (opt_verify) {
+                                                       REQUIRE_1;
+                                                       if (IS_2_WORD_TYPE(curstack->type))
+                                                               panic("Illegal instruction: DUP on category 2 type");
+                                               }
+#endif
                                                COUNT(count_dup_instruction);
                                                DUP;
                                                break;
@@ -1284,11 +1341,19 @@ void analyse_stack()
                                        case ICMD_DUP2:
                                                REQUIRE_1;
                                                if (IS_2_WORD_TYPE(curstack->type)) {
+                                                       /* ..., cat2 */
                                                        iptr->opc = ICMD_DUP;
                                                        DUP;
                                                }
                                                else {
                                                        REQUIRE_2;
+                                                       /* ..., ????, cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                       if (opt_verify) {
+                                                               if (IS_2_WORD_TYPE(curstack->prev->type))
+                                                                       panic("Illegal instruction: DUP2 on cat2, cat1 types");
+                                                       }
+#endif
                                                        copy = curstack;
                                                        NEWSTACK(copy->prev->type, copy->prev->varkind,
                                                                         copy->prev->varnum);
@@ -1302,16 +1367,40 @@ void analyse_stack()
                                                /* pop 2 push 3 dup */
                                                
                                        case ICMD_DUP_X1:
+#ifdef TYPECHECK_STACK_COMPCAT
+                                               if (opt_verify) {
+                                                       REQUIRE_2;
+                                                       if (IS_2_WORD_TYPE(curstack->type) ||
+                                                               IS_2_WORD_TYPE(curstack->prev->type))
+                                                               panic("Illegal instruction: DUP_X1 on cat 2 type");
+                                               }
+#endif
                                                DUP_X1;
                                                break;
 
                                        case ICMD_DUP2_X1:
                                                REQUIRE_2;
                                                if (IS_2_WORD_TYPE(curstack->type)) {
+                                                       /* ..., ????, cat2 */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                       if (opt_verify) {
+                                                               if (IS_2_WORD_TYPE(curstack->prev->type))
+                                                                       panic("Illegal instruction: DUP2_X1 on cat2, cat2 types");
+                                                       }
+#endif
                                                        iptr->opc = ICMD_DUP_X1;
                                                        DUP_X1;
                                                }
                                                else {
+                                                       /* ..., ????, cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                       if (opt_verify) {
+                                                               REQUIRE_3;
+                                                               if (IS_2_WORD_TYPE(curstack->prev->type)
+                                                                       || IS_2_WORD_TYPE(curstack->prev->prev->type))
+                                                                       panic("Illegal instruction: DUP2_X1 on invalid types");
+                                                       }
+#endif
                                                        DUP2_X1;
                                                }
                                                break;
@@ -1321,10 +1410,26 @@ void analyse_stack()
                                        case ICMD_DUP_X2:
                                                REQUIRE_2;
                                                if (IS_2_WORD_TYPE(curstack->prev->type)) {
+                                                       /* ..., cat2, ???? */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                       if (opt_verify) {
+                                                               if (IS_2_WORD_TYPE(curstack->type))
+                                                                       panic("Illegal instruction: DUP_X2 on cat2, cat2 types");
+                                                       }
+#endif
                                                        iptr->opc = ICMD_DUP_X1;
                                                        DUP_X1;
                                                }
                                                else {
+                                                       /* ..., cat1, ???? */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                       if (opt_verify) {
+                                                               REQUIRE_3;
+                                                               if (IS_2_WORD_TYPE(curstack->type)
+                                                                       || IS_2_WORD_TYPE(curstack->prev->prev->type))
+                                                                       panic("Illegal instruction: DUP_X2 on invalid types");
+                                                       }
+#endif
                                                        DUP_X2;
                                                }
                                                break;
@@ -1332,22 +1437,49 @@ void analyse_stack()
                                        case ICMD_DUP2_X2:
                                                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;
                                                        }
                                                        else {
+                                                               /* ..., cat1, cat2 */
+#ifdef TYPECHECK_STACK_COMPCAT
+                                                               if (opt_verify) {
+                                                                       REQUIRE_3;
+                                                                       if (IS_2_WORD_TYPE(curstack->prev->prev->type))
+                                                                               panic("Illegal instruction: DUP2_X2 on invalid types");
+                                                               }
+#endif
                                                                iptr->opc = ICMD_DUP_X2;
                                                                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))
+                                                                               panic("Illegal instruction: DUP2_X2 on invalid types");
+                                                               }
+#endif
                                                                iptr->opc = ICMD_DUP2_X1;
                                                                DUP2_X1;
                                                        }
                                                        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))
+                                                                               panic("Illegal instruction: DUP2_X2 on invalid types");
+                                                               }
+#endif
                                                                DUP2_X2;
                                                        }
                                                }
@@ -1356,6 +1488,14 @@ void analyse_stack()
                                                /* pop 2 push 2 swap */
                                                
                                        case ICMD_SWAP:
+#ifdef TYPECHECK_STACK_COMPCAT
+                                               if (opt_verify) {
+                                                       REQUIRE_2;
+                                                       if (IS_2_WORD_TYPE(curstack->type)
+                                                               || IS_2_WORD_TYPE(curstack->prev->type))
+                                                               panic("Illegal instruction: SWAP on category 2 type");
+                                               }
+#endif
                                                SWAP;
                                                break;
 
@@ -1640,9 +1780,12 @@ void analyse_stack()
                                                 * needs it because the OP1_0ANY below
                                                 * overwrites iptr->dst.
                                                 */
-                                               iptr->val.a = (void*) iptr->dst;
+                                               iptr->val.a = (void *) iptr->dst;
+
+                                               tbptr->type = BBTYPE_SBR;
 
-                                               tbptr->type=BBTYPE_SBR;
+                                               /* We need to check for overflow right here because
+                                                * the pushed value is poped after MARKREACHED. */
                                                CHECKOVERFLOW;
                                                MARKREACHED(tbptr, copy);
                                                OP1_0ANY;
@@ -1777,6 +1920,7 @@ void analyse_stack()
                                                        arguments_num = i + intreg_argnum;
                                                copy = curstack;
                                                while (--i >= 0) {
+                                                       /* XXX check INT type here? Currently typecheck does this. */
                                                        if (! (copy->flags & SAVEDVAR)) {
                                                                copy->varkind = ARGVAR;
                                                                copy->varnum = i + intreg_argnum;
@@ -1912,6 +2056,10 @@ void analyse_stack()
 }
 
 
+/**********************************************************************/
+/* DEBUGGING HELPERS                                                  */
+/**********************************************************************/
+
 void icmd_print_stack(stackptr s)
 {
        int i, j;
@@ -2301,14 +2449,11 @@ void show_icmd(instruction *iptr,bool deadcode)
        case ICMD_PUTSTATIC:
        case ICMD_GETSTATIC:
                printf(" ");
-               utf_fprint(stdout,
-                                  ((fieldinfo *) iptr->val.a)->class->name);
+               utf_fprint(stdout, ((fieldinfo *) iptr->val.a)->class->name);
                printf(".");
-               utf_fprint(stdout,
-                                  ((fieldinfo *) iptr->val.a)->name);
+               utf_fprint(stdout, ((fieldinfo *) iptr->val.a)->name);
                printf(" (type ");
-               utf_fprint(stdout,
-                                  ((fieldinfo *) iptr->val.a)->descriptor);
+               utf_fprint(stdout, ((fieldinfo *) iptr->val.a)->descriptor);
                printf(")");
                break;