fixed loging crash caused by printf
[cacao.git] / src / vm / jit / verify / typecheck.c
index 7d7a20eef872a2c29a9c9b2a53652f63c43d2735..1de7717cbb825827388ca6a5f467a8fdf9b932c8 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 725 2003-12-10 00:24:36Z edwin $
+   $Id: typecheck.c 730 2003-12-11 21:23:31Z edwin $
 
 */
 
@@ -73,7 +73,7 @@ bool typecheckverbose = false;
 #define LOGINFO(info)      DOLOG(do {typeinfo_print_short(get_logfile(),info);log_plain("\n");} while(0))
 #define LOGFLUSH           DOLOG(fflush(get_logfile()))
 #define LOGNL              DOLOG(log_plain("\n"))
-#define LOGSTR(str)        DOLOG(dolog_plain(str))
+#define LOGSTR(str)        DOLOG(log_plain(str))
 #define LOGSTR1(str,a)     DOLOG(dolog_plain(str,a))
 #define LOGSTR2(str,a,b)   DOLOG(dolog_plain(str,a,b))
 #define LOGSTR3(str,a,b,c) DOLOG(dolog_plain(str,a,b,c))
@@ -96,7 +96,7 @@ bool typecheckverbose = false;
 
 #ifdef TYPECHECK_VERBOSE_IMPORTANT
 #define LOGimp(str)     DOLOG(log_text(str))
-#define LOGimpSTR(str)  DOLOG(dolog_plain(str))
+#define LOGimpSTR(str)  DOLOG(log_plain(str))
 #define LOGimpSTRu(utf) DOLOG(log_plain_utf(utf))
 #else
 #define LOGimp(str)
@@ -171,6 +171,20 @@ typeinfo_print_blocks(FILE *file,int vnum,u1 *vtype,typeinfo *vinfo)
 
 #endif
 
+/****************************************************************************/
+/* STATISTICS                                                               */
+/****************************************************************************/
+
+#ifdef TYPECHECK_DEBUG
+/*#define TYPECHECK_STATISTICS*/
+#endif
+
+#ifdef TYPECHECK_STATISTICS
+#define TYPECHECK_COUNT(cnt)  (cnt)++
+#else
+#define TYPECHECK_COUNT(cnt)
+#endif
+
 /****************************************************************************/
 /* INTERNAL DATA STRUCTURES                                                 */
 /****************************************************************************/
@@ -247,6 +261,25 @@ struct jsr_record {
 
 #define ISBUILTIN(v)   (iptr->val.a == (functionptr)(v))
 
+#define TYPECHECK_STACK(sp,tp)                                                                                 \
+       do { if ((sp)->type != (tp))                                                                            \
+                       panic("Wrong data type on stack"); } while(0)
+
+#define TYPECHECK_ADR(sp)  TYPECHECK_STACK(sp,TYPE_ADR)
+#define TYPECHECK_INT(sp)  TYPECHECK_STACK(sp,TYPE_INT)
+#define TYPECHECK_LNG(sp)  TYPECHECK_STACK(sp,TYPE_LNG)
+#define TYPECHECK_FLT(sp)  TYPECHECK_STACK(sp,TYPE_FLT)
+#define TYPECHECK_DBL(sp)  TYPECHECK_STACK(sp,TYPE_DBL)
+
+#define TYPECHECK_ARGS1(t1)                                                                \
+       do {TYPECHECK_STACK(curstack,t1);} while (0)
+#define TYPECHECK_ARGS2(t1,t2)                                                     \
+       do {TYPECHECK_ARGS1(t1);                                                                        \
+               TYPECHECK_STACK(curstack->prev,t2);} while (0)
+#define TYPECHECK_ARGS3(t1,t2,t3)                                                              \
+       do {TYPECHECK_ARGS2(t1,t2);                                                                     \
+               TYPECHECK_STACK(curstack->prev->prev,t3);} while (0)
+
 /* TYPECHECK_COPYVARS: copy the types and typeinfos of the current local
  *     variables to the local variables of the target block.
  * Input:
@@ -619,6 +652,11 @@ typecheck()
     bool maythrow;               /* true if this instruction may throw */
     utf *name_init;                                        /* "<init>" */
     bool initmethod;             /* true if this is an "<init>" method */
+       builtin_descriptor *builtindesc;
+
+#ifdef TYPECHECK_STATISTICS
+       int count_iterations = 0;
+#endif
 
     LOGSTR("\n==============================================================================\n");
     DOLOG(show_icmd_method());
@@ -730,6 +768,7 @@ typecheck()
 
     /* loop while there are still blocks to be checked */
     do {
+               TYPECHECK_COUNT(count_iterations);
 
         repeat = false;
         
@@ -889,8 +928,6 @@ typecheck()
                           /* STORING ADDRESS TO VARIABLE          */
 
                       case ICMD_ASTORE:
-                          /* TYPE_ADR has already been checked. */
-                          
                           if (handlers[0] &&
                               TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
                               panic("Storing uninitialized object in local variable inside try block");
@@ -919,13 +956,53 @@ typecheck()
                           if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo)) /* XXX arraystub */
                               panic("illegal instruction: PUTFIELD on array");
 
-                          
-                          /* XXX */
+                          /* check if the value is assignable to the field */
+                                                 {
+                                                         fieldinfo *fi = (fieldinfo*) iptr[0].val.a;
+                                                         
+                                                         if (!TYPEINFO_IS_NULLTYPE(curstack->prev->typeinfo)) {
+                                                                 cls = fi->class;
+                                                                 /* XXX treat uinitialized objects specially? */
+                                                                 if (!class_issubclass(curstack->prev->typeinfo.typeclass,
+                                                                                                               cls))
+                                                                         panic("PUTFIELD reference type does not support field");
+                                                         }
+
+                                                         /* XXX check flags */
+
+                                                         /* XXX ---> unify with ICMD_PUTSTATIC? */
+                                                         
+                                                         /* XXX check access rights */
+                                                         
+                                                         if (curstack->type != fi->type)
+                                                                 panic("PUTFIELD type mismatch");
+                                                         if (fi->type == TYPE_ADR) {
+                                                                 TYPEINFO_INIT_FROM_FIELDINFO(rinfo,fi);
+                                                                 if (!typeinfo_is_assignable(&(curstack->typeinfo),
+                                                                                                                         &rinfo))
+                                                                         panic("PUTFIELD reference type not assignable");
+                                                         }
+                                                 }
                           maythrow = true;
                           break;
 
                       case ICMD_PUTSTATIC:
-                          /* XXX */
+                          /* check if the value is assignable to the field */
+                                                 {
+                                                         fieldinfo *fi = (fieldinfo*) iptr[0].val.a;
+
+                                                         /* check flags */
+                                                         /* XXX check access rights */
+                                                         
+                                                         if (curstack->type != fi->type)
+                                                                 panic("PUTSTATIC type mismatch");
+                                                         if (fi->type == TYPE_ADR) {
+                                                                 TYPEINFO_INIT_FROM_FIELDINFO(rinfo,fi);
+                                                                 if (!typeinfo_is_assignable(&(curstack->typeinfo),
+                                                                                                                         &rinfo))
+                                                                         panic("PUTSTATIC reference type not assignable");
+                                                         }
+                                                 }
                           maythrow = true;
                           break;
 
@@ -937,7 +1014,16 @@ typecheck()
                           
                           {
                               fieldinfo *fi = (fieldinfo *)(iptr->val.a);
-                              /* XXX check non-static? */
+
+                                                         if (!TYPEINFO_IS_NULLTYPE(curstack->typeinfo)) {
+                                                                 cls = fi->class;
+                                                                 if (!class_issubclass(curstack->typeinfo.typeclass,
+                                                                                                               cls))
+                                                                         panic("GETFIELD reference type does not support field");
+                                                         }
+
+                                                         /* XXX check flags */
+                                                         /* XXX check access rights */
                               if (dst->type == TYPE_ADR) {
                                   TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
                               }
@@ -952,7 +1038,8 @@ typecheck()
                       case ICMD_GETSTATIC:
                           {
                               fieldinfo *fi = (fieldinfo *)(iptr->val.a);
-                              /* XXX check static? */
+                              /* XXX check flags */
+                                                         /* XXX check access rights */
                               if (dst->type == TYPE_ADR) {
                                   TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
                               }
@@ -1052,9 +1139,10 @@ typecheck()
                           /* OPERATIONS WITH UNCHECKED INPUT      */
 
                       case ICMD_CHECKCAST:
+                                                 TYPECHECK_ADR(curstack);
                           /* returnAddress is not allowed */
                           if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
-                              panic("Illegal instruction: INSTANCEOF on non-reference");
+                              panic("Illegal instruction: CHECKCAST on non-reference");
 
                           /* XXX check if the cast can be done statically */
                           TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[0].val.a);
@@ -1063,6 +1151,7 @@ typecheck()
                           break;
 
                       case ICMD_INSTANCEOF:
+                                                 TYPECHECK_ADR(curstack);
                           /* returnAddress is not allowed */
                           if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
                               panic("Illegal instruction: INSTANCEOF on non-reference");
@@ -1416,25 +1505,42 @@ typecheck()
                           break;
                           
                       case ICMD_MULTIANEWARRAY:
-                          /* check the array lengths on the stack */
-                          i = iptr[0].op1;
-                          if (i<1) panic("MULTIANEWARRAY with dimensions < 1");
-                          srcstack = curstack;
-                          while (i--) {
-                              if (!srcstack)
-                                  panic("MULTIANEWARRAY missing array length");
-                              if (srcstack->type != TYPE_INT)
-                                  panic("MULTIANEWARRAY using non-int as array length");
-                              srcstack = srcstack->prev;
-                          }
-                          
-                          /* set the array type of the result */
-                          TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[0].val.a)->class);
+                                                 {
+                                                         vftbl *arrayvftbl;
+                                                         arraydescriptor *desc;
+                                                         
+                                                         /* check the array lengths on the stack */
+                                                         i = iptr[0].op1;
+                                                         if (i<1) panic("MULTIANEWARRAY with dimensions < 1");
+                                                         srcstack = curstack;
+                                                         while (i--) {
+                                                                 if (!srcstack)
+                                                                         panic("MULTIANEWARRAY missing array length");
+                                                                 if (srcstack->type != TYPE_INT)
+                                                                         panic("MULTIANEWARRAY using non-int as array length");
+                                                                 srcstack = srcstack->prev;
+                                                         }
+                                                         
+                                                         /* check array descriptor */
+                                                         arrayvftbl = (vftbl*) iptr[0].val.a;
+                                                         if (!arrayvftbl)
+                                                                 panic("MULTIANEWARRAY with unlinked class");
+                                                         if ((desc = arrayvftbl->arraydesc) == NULL)
+                                                                 panic("MULTIANEWARRAY with non-array class");
+                                                         if (desc->dimension < iptr[0].op1)
+                                                                 panic("MULTIANEWARRAY dimension to high");
+                                                         
+                                                         /* set the array type of the result */
+                                                         TYPEINFO_INIT_CLASSINFO(dst->typeinfo,arrayvftbl->class);
+                                                 }
                           maythrow = true;
                           break;
                           
                       case ICMD_BUILTIN3:
-                          if (ISBUILTIN(asm_builtin_aastore)) {
+                          if (ISBUILTIN(BUILTIN_aastore)) {
+                                                         TYPECHECK_ADR(curstack);
+                                                         TYPECHECK_INT(curstack->prev);
+                                                         TYPECHECK_ADR(curstack->prev->prev);
                               if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
                                   panic("illegal instruction: AASTORE to non-reference array");
 
@@ -1445,63 +1551,120 @@ typecheck()
                                 panic("illegal instruction: AASTORE to incompatible type");
                               */
                           }
-                          /* XXX check for missed builtins in debug mode? */
+                                                 else {
+                                                         builtindesc = builtin_desc;
+                                                         while (builtindesc->opcode && builtindesc->builtin
+                                                                        != (functionptr) iptr->val.a) builtindesc++;
+                                                         if (!builtindesc->opcode) {
+                                                                 dolog("Builtin not in table: %s",icmd_builtin_name((functionptr) iptr->val.a));
+                                                                 panic("Internal error: builtin not found in table");
+                                                         }
+                                                         TYPECHECK_ARGS3(builtindesc->type_s3,builtindesc->type_s2,builtindesc->type_s1);
+                                                 }
                           maythrow = true; /* XXX better safe than sorry */
                           break;
                           
                       case ICMD_BUILTIN2:
-                          if (
-#if defined(__I386__)
-                              ISBUILTIN(asm_builtin_newarray)
-#else
-                              ISBUILTIN(builtin_newarray)
-#endif
-                              )
+                                                 /* XXX use BUILTIN_ macros */
+                          if (ISBUILTIN(BUILTIN_newarray))
                           {
+                                                         vftbl *vft;
+                                                         TYPECHECK_INT(curstack->prev);
                               if (iptr[-1].opc != ICMD_ACONST)
                                   panic("illegal instruction: builtin_newarray without classinfo");
-                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+                                                         vft = (vftbl *)iptr[-1].val.a;
+                                                         if (!vft)
+                                                                 panic("ANEWARRAY with unlinked class");
+                                                         if (!vft->arraydesc)
+                                                                 panic("ANEWARRAY with non-array class");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,vft->class);
                           }
-                          else if (ISBUILTIN(asm_builtin_checkarraycast)) {
+                          else if (ISBUILTIN(BUILTIN_arrayinstanceof))
+                          {
+                                                         vftbl *vft;
+                                                         TYPECHECK_ADR(curstack->prev);
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: builtin_arrayinstanceof without classinfo");
+                                                         vft = (vftbl *)iptr[-1].val.a;
+                                                         if (!vft)
+                                                                 panic("INSTANCEOF with unlinked class");
+                                                         if (!vft->arraydesc)
+                                                                 panic("internal error: builtin_arrayinstanceof with non-array class");
+                                                 }
+                          else if (ISBUILTIN(BUILTIN_checkarraycast)) {
+                                                         vftbl *vft;
+                                                         TYPECHECK_ADR(curstack->prev);
                               if (iptr[-1].opc != ICMD_ACONST)
-                                  panic("illegal instruction: asm_builtin_checkarraycast without classinfo");
-                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+                                  panic("illegal instruction: BUILTIN_checkarraycast without classinfo");
+                                                         vft = (vftbl *)iptr[-1].val.a;
+                                                         if (!vft)
+                                                                 panic("CHECKCAST with unlinked class");
+                                                         if (!vft->arraydesc)
+                                                                 panic("internal error: builtin_checkarraycast with non-array class");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,vft->class);
                           }
-                          /* XXX check for missed builtins in debug mode? */
+                                                 else {
+                                                         builtindesc = builtin_desc;
+                                                         while (builtindesc->opcode && builtindesc->builtin
+                                                                        != (functionptr) iptr->val.a) builtindesc++;
+                                                         if (!builtindesc->opcode) {
+                                                                 dolog("Builtin not in table: %s",icmd_builtin_name((functionptr) iptr->val.a));
+                                                                 panic("Internal error: builtin not found in table");
+                                                         }
+                                                         TYPECHECK_ARGS2(builtindesc->type_s2,builtindesc->type_s1);
+                                                 }
                           maythrow = true; /* XXX better safe than sorry */
                           break;
                           
                       case ICMD_BUILTIN1:
-                          if (ISBUILTIN(builtin_new)) {
+                          if (ISBUILTIN(BUILTIN_new)) {
                               if (iptr[-1].opc != ICMD_ACONST)
                                   panic("illegal instruction: builtin_new without classinfo");
                               TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
                           }
-                          else if (ISBUILTIN(builtin_newarray_boolean)) {
+                                                 /* XXX unify the following cases */
+                          else if (ISBUILTIN(BUILTIN_newarray_boolean)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
                           }
-                          else if (ISBUILTIN(builtin_newarray_char)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_char)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_CHAR);
                           }
-                          else if (ISBUILTIN(builtin_newarray_float)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_float)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_FLOAT);
                           }
-                          else if (ISBUILTIN(builtin_newarray_double)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_double)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_DOUBLE);
                           }
-                          else if (ISBUILTIN(builtin_newarray_byte)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_byte)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BYTE);
                           }
-                          else if (ISBUILTIN(builtin_newarray_short)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_short)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_SHORT);
                           }
-                          else if (ISBUILTIN(builtin_newarray_int)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_int)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_INT);
                           }
-                          else if (ISBUILTIN(builtin_newarray_long)) {
+                          else if (ISBUILTIN(BUILTIN_newarray_long)) {
+                                                         TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_LONG);
                           }
-                          /* XXX check for missed builtins in debug mode? */
+                                                 else {
+                                                         builtindesc = builtin_desc;
+                                                         while (builtindesc->opcode && builtindesc->builtin
+                                                                        != (functionptr) iptr->val.a) builtindesc++;
+                                                         if (!builtindesc->opcode) {
+                                                                 dolog("Builtin not in table: %s",icmd_builtin_name((functionptr) iptr->val.a));
+                                                                 panic("Internal error: builtin not found in table");
+                                                         }
+                                                         TYPECHECK_ARGS1(builtindesc->type_s1);
+                                                 }
                           maythrow = true; /* XXX better safe than sorry */
                           break;
                                                      
@@ -1722,19 +1885,32 @@ typecheck()
         LOGIF(repeat,"repeat=true");
     } while (repeat);
 
+#ifdef TYPECHECK_STATISTICS
+       dolog("Typechecker did %4d iterations",count_iterations);
+#endif
+
 #ifdef TYPECHECK_DEBUG
        for (i=0; i<block_count; ++i) {
                if (block[i].flags != BBDELETED
                        && block[i].flags != BBUNDEF
-                       && block[i].flags != BBFINISHED)
+                       && block[i].flags != BBFINISHED
+                       && block[i].flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
+                                                                                                        * some exception handlers,
+                                                                                                        * that's ok. */
                {
                        LOG2("block L%03d has invalid flags after typecheck: %d",
                                 block[i].debug_nr,block[i].flags);
-                       panic("Inalid block flags after typecheck");
+                       panic("Invalid block flags after typecheck");
                }
        }
 #endif
-
+       
+       /* Reset blocks we never reached */
+       for (i=0; i<block_count; ++i) {
+               if (block[i].flags == BBTYPECHECK_UNDEF)
+                       block[i].flags = BBFINISHED;
+       }
+               
     LOGimp("exiting typecheck");
 }