fixed loging crash caused by printf
[cacao.git] / src / vm / jit / verify / typecheck.c
index 44ffacf24f18f38ea95db9b94af132fa9404dba9..1de7717cbb825827388ca6a5f467a8fdf9b932c8 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 696 2003-12-06 20:10:05Z edwin $
+   $Id: typecheck.c 730 2003-12-11 21:23:31Z edwin $
 
 */
 
@@ -34,6 +34,7 @@
 
 #ifdef CACAO_TYPECHECK
 
+#include <string.h>
 #include "jit.h"
 #include "builtin.h"
 #include "tables.h"
 #define TOUCHED_NO     0x02
 #define TOUCHED_MAYBE  (TOUCHED_YES | TOUCHED_NO)
 
-#define REACH_STD      0
-#define REACH_JSR      1
-#define REACH_RET      2
+#define REACH_STD      0  /* reached by branch or fallthrough */
+#define REACH_JSR      1  /* reached by JSR */
+#define REACH_RET      2  /* reached by RET */ /* XXX ? */
+#define REACH_THROW    3  /* reached by THROW (exception handler) */
 
 /****************************************************************************/
 /* DEBUG HELPERS                                                            */
@@ -68,14 +70,14 @@ bool typecheckverbose = false;
 #define LOG2(str,a,b)      DOLOG(dolog(str,a,b))
 #define LOG3(str,a,b,c)    DOLOG(dolog(str,a,b,c))
 #define LOGIF(cond,str)    DOLOG(do {if (cond) log_text(str);} while(0))
-#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,info);printf("\n");} while(0))
-#define LOGFLUSH           DOLOG(fflush(stdout))
-#define LOGNL              DOLOG(printf("\n"))
-#define LOGSTR(str)        DOLOG(printf(str))
-#define LOGSTR1(str,a)     DOLOG(printf(str,a))
-#define LOGSTR2(str,a,b)   DOLOG(printf(str,a,b))
-#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
-#define LOGSTRu(utf)       DOLOG(utf_display(utf))
+#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(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))
+#define LOGSTRu(utf)       DOLOG(log_plain_utf(utf))
 #else
 #define LOG(str)
 #define LOG1(str,a)
@@ -89,12 +91,13 @@ bool typecheckverbose = false;
 #define LOGSTR1(str,a)
 #define LOGSTR2(str,a,b)
 #define LOGSTR3(str,a,b,c)
+#define LOGSTRu(utf)
 #endif
 
 #ifdef TYPECHECK_VERBOSE_IMPORTANT
 #define LOGimp(str)     DOLOG(log_text(str))
-#define LOGimpSTR(str)  DOLOG(printf(str))
-#define LOGimpSTRu(utf) DOLOG(utf_display(utf))
+#define LOGimpSTR(str)  DOLOG(log_plain(str))
+#define LOGimpSTRu(utf) DOLOG(log_plain_utf(utf))
 #else
 #define LOGimp(str)
 #define LOGimpSTR(str)
@@ -103,6 +106,8 @@ bool typecheckverbose = false;
 
 #if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
 
+#include <stdio.h>
+
 static
 void
 typeinfo_print_locals(FILE *file,u1 *vtype,typeinfo *vinfo,u1 *touched,int num)
@@ -134,18 +139,18 @@ typeinfo_print_stack(FILE *file,stackptr stack)
 static
 void
 typeinfo_print_block(FILE *file,stackptr instack,
-                     u1 *vtype,typeinfo *vinfo,u1 *touched)
+                     int vnum,u1 *vtype,typeinfo *vinfo,u1 *touched)
 {
     fprintf(file,"Stack: ");
     typeinfo_print_stack(file,instack);
     fprintf(file," Locals:");
-    typeinfo_print_locals(file,vtype,vinfo,touched,maxlocals);
+    typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
 }
 
 
 static
 void
-typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+typeinfo_print_blocks(FILE *file,int vnum,u1 *vtype,typeinfo *vinfo)
 {
     int bi;
     /*    int j;*/
@@ -153,7 +158,7 @@ typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
     for (bi=0; bi<block_count; ++bi) {
         fprintf(file,"%04d: (%3d) ",bi,block[bi].flags);
         typeinfo_print_block(file,block[bi].instack,
-                             vtype+maxlocals*bi,vinfo+maxlocals*bi,NULL);
+                             vnum,vtype+vnum*bi,vinfo+vnum*bi,NULL);
         fprintf(file,"\n");
 
 /*         for (j=0; j<block[bi].icount; ++j) { */
@@ -166,6 +171,20 @@ typeinfo_print_blocks(FILE *file,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                                                 */
 /****************************************************************************/
@@ -194,18 +213,46 @@ struct jsr_record {
 /* MACROS USED INTERNALLY IN typecheck()                                    */
 /****************************************************************************/
 
-#define TOUCH_VARIABLE(num) do {if (jsrchain) touched[num] = TOUCHED_YES;} while (0)
-#define TOUCH_TWOWORD(num)  do {TOUCH_VARIABLE(num);TOUCH_VARIABLE((num)+1);} while (0)
-
-/* XXX should check num in range? */
-/* XXX invalidate two word variables on store in second half! */
-#define STORE_TYPE(num,type)       do {vtype[(num)] = (type); TOUCH_VARIABLE(num);} while(0)
-#define STORE_INVALID(num)         STORE_TYPE((num),TYPE_VOID)
-#define STORE_PRIMITIVE(num,type)  STORE_TYPE((num),(type))
-#define STORE_TWOWORD(num,type)    {STORE_PRIMITIVE((num),(type));STORE_INVALID((num)+1);}
-
-#define CHECKVARTYPE(num,type)  \
-            {if (vtype[(num)] != (type)) panic("Variable type mismatch"); TOUCH_VARIABLE(num);}
+#define TOUCH_VARIABLE(num)                                                                            \
+       do {if (jsrchain) touched[num] = TOUCHED_YES;} while (0)
+#define TOUCH_TWOWORD(num)                                                                             \
+       do {TOUCH_VARIABLE(num);TOUCH_VARIABLE((num)+1);} while (0)
+
+#define INDEX_ONEWORD(num)                                                                             \
+       do { if((num)<0 || (num)>=validlocals)                                          \
+                       panic("Invalid local variable index"); } while (0)
+#define INDEX_TWOWORD(num)                                                                             \
+       do { if((num)<0 || ((num)+1)>=validlocals)                                      \
+                       panic("Invalid local variable index"); } while (0)
+
+#define SET_VARIABLE(num,type)                                                                 \
+       do {vtype[num] = (type);                                                                        \
+               if ((num)>0 && IS_2_WORD_TYPE(vtype[(num)-1])) {                \
+                       vtype[(num)-1] = TYPE_VOID;                                                     \
+                       TOUCH_VARIABLE((num)-1);                                                        \
+               }                                                                                                               \
+               TOUCH_VARIABLE(num);} while(0)
+
+#define STORE_ONEWORD(num,type)                                                                        \
+       do {INDEX_ONEWORD(num);                                                                         \
+               SET_VARIABLE(num,type);} while(0)
+
+#define STORE_TWOWORD(num,type)                                                                        \
+       do {INDEX_TWOWORD(num);                                                                         \
+               SET_VARIABLE(num,type);                                                                 \
+               vtype[(num)+1] = TYPE_VOID;                                                             \
+               TOUCH_VARIABLE((num)+1);} while(0)
+
+#define CHECK_ONEWORD(num,type)                                                                                        \
+       do {INDEX_ONEWORD(num);                                                                                         \
+               if (vtype[(num)] != (type)) panic("Variable type mismatch");    \
+               TOUCH_VARIABLE(num);} while(0)
+
+#define CHECK_TWOWORD(num,type)                                                                                        \
+       do {INDEX_TWOWORD(num);                                                                                         \
+               if (vtype[(num)] != (type)) panic("Variable type mismatch");    \
+               TOUCH_VARIABLE(num);                                                                                    \
+               TOUCH_VARIABLE((num)+1);} while(0)
 
 /* XXX maybe it's faster to copy always */
 #define COPYTYPE(source,dest)   \
@@ -214,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:
@@ -221,16 +287,17 @@ struct jsr_record {
  *     vinfo......current local variable typeinfos
  *     ttype......local variable types of target block
  *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  * Used:
  *     macro_i
  */
 #define TYPECHECK_COPYVARS                                      \
+    do {                                                        \
     LOG("TYPECHECK_COPYVARS");                                  \
-    for (macro_i=0; macro_i<maxlocals; ++macro_i) {             \
+    for (macro_i=0; macro_i<numlocals; ++macro_i) {             \
         if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR)      \
             TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]);      \
-    }
+    } } while(0)
 
 /* TYPECHECK_MERGEVARS: merge the local variables of the target block
  *     with the current local variables.
@@ -239,15 +306,16 @@ struct jsr_record {
  *     vinfo......current local variable typeinfos
  *     ttype......local variable types of target block
  *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  * Ouput:
  *     changed....set to true if any typeinfo has changed
  * Used:
  *     macro_i
  */
 #define TYPECHECK_MERGEVARS                                             \
+    do {                                                                \
     LOG("TYPECHECK_MERGEVARS");                                         \
-    for (macro_i=0; macro_i<maxlocals; ++macro_i) {                     \
+    for (macro_i=0; macro_i<numlocals; ++macro_i) {                     \
         if ((ttype[macro_i] != TYPE_VOID) && (vtype[macro_i] != ttype[macro_i])) { \
             LOG3("var %d: type %d + type %d = void",macro_i,ttype[macro_i],vtype[macro_i]); \
             ttype[macro_i] = TYPE_VOID;                                 \
@@ -269,7 +337,7 @@ struct jsr_record {
                 LOGIF(changed,"vars have changed");                     \
             }                                                           \
         };                                                              \
-    }
+    } } while (0)
 
 /* TYPECHECK_MERGEJSR:
  *
@@ -277,7 +345,7 @@ struct jsr_record {
  * Ouput:
  *     tbptr......target block
  *     changed....set to true if any typeinfo has changed
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     touched....current touched flags of local variables
  * Used:
  *     macro_i, jsrtemp, jsrtemp2
@@ -297,7 +365,7 @@ struct jsr_record {
     }                                                                   \
     jsrtemp = jsrbuffer[tbptr-block];                                   \
     if (jsrtemp)                                                        \
-        for (macro_i=0; macro_i<maxlocals; ++macro_i) {                 \
+        for (macro_i=0; macro_i<numlocals; ++macro_i) {                 \
             jsrtemp->touched[i] |= touched[i];                          \
     } } while (0)
 
@@ -308,6 +376,7 @@ struct jsr_record {
  *     dststack...input stack of target block
  */
 #define TYPECHECK_COPYSTACK                                             \
+    do {                                                                \
     LOG("TYPECHECK_COPYSTACK");                                         \
     while (srcstack) {                                                  \
         LOG1("copy %d",srcstack->type);                                 \
@@ -320,7 +389,8 @@ struct jsr_record {
         dststack = dststack->prev;                                      \
         srcstack = srcstack->prev;                                      \
     }                                                                   \
-    if (dststack) panic("Stack depth mismatch");
+    if (dststack) panic("Stack depth mismatch");                        \
+    } while (0)
 
 /* TYPECHECK_MERGESTACK: merge the input stack of the target block
  *     with the current stack.
@@ -331,6 +401,7 @@ struct jsr_record {
  *     changed....set to true if any typeinfo has changed
  */
 #define TYPECHECK_MERGESTACK                                            \
+    do {                                                                \
     LOG("TYPECHECK_MERGESTACK");                                        \
     while (srcstack) {                                                  \
         if (!dststack) panic("Stack depth mismatch");                   \
@@ -347,7 +418,8 @@ struct jsr_record {
         dststack = dststack->prev;                                      \
         srcstack = srcstack->prev;                                      \
     }                                                                   \
-    if (dststack) panic("Stack depth mismatch");
+    if (dststack) panic("Stack depth mismatch");                        \
+    } while(0)
 
 
 /* TYPECHECK_CHECK_JSR_CHAIN: checks if the target block is reached by
@@ -385,7 +457,7 @@ struct jsr_record {
  * Input:
  *     jsrchain...current JSR target chain
  *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     jsrbuffer..JSR target chain for each basic block
  * Used:
  *     jsrtemp
@@ -393,11 +465,11 @@ struct jsr_record {
 #define TYPECHECK_ADD_JSR                                               \
     do {                                                                \
         LOG1("adding JSR to block %04d",(tbptr)-block);                 \
-    jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+    jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(numlocals-1)*sizeof(u1)); \
     jsrtemp->target = (tbptr);                                          \
     jsrtemp->next = jsrchain;                                           \
     jsrtemp->sbr_touched = NULL;                                        \
-    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals);          \
+    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*numlocals);          \
     jsrbuffer[tbptr-block] = jsrtemp;                                   \
     } while (0)
 
@@ -406,7 +478,7 @@ struct jsr_record {
  * Input:
  *     chain......current JSR target chain
  *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     jsrbuffer..JSR target chain for each basic block
  *     touched....current touched flags of local variables
  * Used:
@@ -416,24 +488,51 @@ struct jsr_record {
     do {                                                                \
         LOG("TYPECHECK_COPYJSR");                                       \
         if (chain) {                                                    \
-            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(numlocals-1)*sizeof(u1)); \
             jsrtemp->target = (chain)->target;                          \
             jsrtemp->next = (chain)->next;                              \
             jsrtemp->sbr_touched = NULL;                                \
-            memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals);     \
+            memcpy(&jsrtemp->touched,touched,sizeof(u1)*numlocals);     \
             jsrbuffer[tbptr-block] = jsrtemp;                           \
         }                                                               \
         else                                                            \
             jsrbuffer[tbptr-block] = NULL;                              \
     } while (0)
 
+/* TYPECHECK_BRANCH_BACKWARDS: executed when control flow moves
+ *     backwards. Checks if there are uninitialized objects on the
+ *     stack or in local variables.
+ * Input:
+ *     dst........current output stack pointer (not needed for REACH_THROW)
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ * Used:
+ *     srcstack, macro_i
+ */
+#define TYPECHECK_BRANCH_BACKWARDS                                      \
+    do {                                                                \
+        LOG("BACKWARDS!");                                              \
+        srcstack = dst;                                                 \
+        while (srcstack) {                                              \
+            if (srcstack->type == TYPE_ADR &&                           \
+                TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo))              \
+                panic("Branching backwards with uninitialized object on stack"); \
+            srcstack = srcstack->prev;                                  \
+        }                                                               \
+        for (macro_i=0; macro_i<numlocals; ++macro_i)                   \
+            if (vtype[macro_i] == TYPE_ADR &&                           \
+                TYPEINFO_IS_NEWOBJECT(vinfo[macro_i]))                  \
+                panic("Branching backwards with uninitialized object in local variable"); \
+    } while(0)
+
 /* TYPECHECK_REACH: executed, when the target block (tbptr) can be reached
  *     from the current block (bptr). The types of local variables and
  *     stack slots are propagated to the target block.
  * Input:
  *     bptr.......current block
  *     tbptr......target block
- *     dst........current output stack pointer
+ *     dst........current output stack pointer (not needed for REACH_THROW)
+ *     numlocals..number of local variables
  *     vtype......current local variable types
  *     vinfo......current local variable typeinfos
  *     jsrchain...current JSR target chain
@@ -447,11 +546,14 @@ struct jsr_record {
  *     ttype, tinfo, srcstack, dststack, changed, macro_i
  */
 #define TYPECHECK_REACH(way)                                            \
-    LOG1("reaching block %04d",tbptr-block);                            \
+    do {                                                                \
+    LOG2("reaching block %04d (%d)",tbptr-block,way);                   \
+    if (tbptr <= bptr && way != REACH_THROW)                            \
+        TYPECHECK_BRANCH_BACKWARDS;                                     \
     srcstack = dst;                                                     \
     dststack = tbptr->instack;                                          \
-    ttype = vartype + maxlocals*(tbptr-block);                          \
-    tinfo = vartypeinfo + maxlocals*(tbptr-block);                      \
+    ttype = vartype + numlocals*(tbptr-block);                          \
+    tinfo = vartypeinfo + numlocals*(tbptr-block);                      \
     if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
         /* This block is reached for the first time */                  \
         if (way == REACH_JSR) {                                         \
@@ -462,7 +564,7 @@ struct jsr_record {
             TYPECHECK_COPYJSR(jsrchain);                                \
             TYPECHECK_COPYVARS;                                         \
         }                                                               \
-        TYPECHECK_COPYSTACK;                                            \
+        if (way != REACH_THROW) TYPECHECK_COPYSTACK;                    \
         changed = true;                                                 \
     } else {                                                            \
         /* This block has been reached before */                        \
@@ -471,17 +573,34 @@ struct jsr_record {
             TYPECHECK_CHECK_JSR_CHAIN;                                  \
         else                                                            \
             TYPECHECK_MERGEJSR;                                         \
-        LOGIF(changed,"changed jsr");                                   \
         TYPECHECK_MERGEVARS;                                            \
-        LOGIF(changed,"changed vars");                                  \
-        TYPECHECK_MERGESTACK;                                           \
-        LOGIF(changed,"changed stack");                                 \
+        if (way != REACH_THROW) TYPECHECK_MERGESTACK;                   \
     }                                                                   \
     if (changed) {                                                      \
         LOG("REACHED!");                                                \
         tbptr->flags = BBTYPECHECK_REACHED;                             \
-        if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");}        \
-    } LOG("done.");
+        if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");}             \
+    }                                                                   \
+    LOG("done.");                                                       \
+    } while (0)
+
+/* TYPECHECK_LEAVE: executed when the method is exited non-abruptly
+ * Input:
+ *     class........class of the current method
+ *     numlocals....number of local variables
+ *     vtype........current local variable types
+ *     vinfo........current local variable typeinfos
+ *     initmethod...true if this is an <init> method
+ */
+#define TYPECHECK_LEAVE                                                 \
+    do {                                                                \
+        if (initmethod && class != class_java_lang_Object) {            \
+            /* check the marker variable */                             \
+            LOG("Checking <init> marker");                              \
+            if (vtype[numlocals-1] == TYPE_VOID)                        \
+                panic("<init> method does not initialize 'this'");      \
+        }                                                               \
+    } while (0)
 
 /****************************************************************************/
 /* typecheck()                                                              */
@@ -495,15 +614,19 @@ typecheck()
 {
     int b_count, b_index;
     stackptr curstack;      /* input stack top for current instruction */
-    stackptr srcstack;       /* source stack for copying and merging */
-    stackptr dststack;       /* target stack for copying and merging */
-    int opcode, macro_i, len, i;
+    stackptr srcstack;         /* source stack for copying and merging */
+    stackptr dststack;         /* target stack for copying and merging */
+    int opcode;                                      /* current opcode */
+    int macro_i, i;                              /* temporary counters */
+    int len;                        /* for counting instructions, etc. */
     bool superblockend;        /* true if no fallthrough to next block */
     bool repeat;            /* if true, blocks are iterated over again */
-    bool changed;
-    instruction *iptr = instr;       /* pointer to current instruction */
+    bool changed;                                    /* used in macros */
+    instruction *iptr;               /* pointer to current instruction */
     basicblock *bptr;                /* pointer to current basic block */
-    basicblock *tbptr;
+    basicblock *tbptr;                   /* temporary for target block */
+    int numlocals;                        /* number of local variables */
+       int validlocals;         /* number of valid local variable indices */
     u1 *vartype;            /* type of each local for each basic block */
     typeinfo *vartypeinfo;  /* type of each local for each basic block */
     u1 *vtype;           /* type of each local for current instruction */
@@ -518,14 +641,22 @@ typecheck()
     int rtype;                         /* return type of called method */
     typeinfo rinfo;       /* typeinfo for return type of called method */
     stackptr dst;               /* output stack of current instruction */
-    int changeddepth;          /* depth to which the stack has changed */ /* XXX */
-    bool fulltypecheck;           /* false == check only changed types */ /* XXX */
     basicblock **tptr;    /* pointer into target list of switch instructions */
     jsr_record **jsrbuffer;   /* JSR target chain for each basic block */
     jsr_record *jsrchain;               /* JSR chain for current block */
-    jsr_record *jsrtemp,*jsrtemp2,*jsrold;      /* temporary variables */
+    jsr_record *jsrtemp,*jsrtemp2;              /* temporary variables */
     jsr_record *subroutine;    /* jsr_record of the current subroutine */
     u1 *touched;                  /* touched flags for local variables */
+    xtable **handlers;                    /* active exception handlers */
+    classinfo *cls;                                       /* temporary */
+    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());
@@ -538,7 +669,9 @@ typecheck()
     LOGimpSTRu(method->class->name);
     LOGimpSTR(")\n");
 
-    /* XXX allocate buffers for method arguments */
+    name_init = utf_new_char("<init>");
+    initmethod = (method->name == name_init);
+
     ptype = DMNEW(u1,MAXPARAMS);
     pinfo = DMNEW(typeinfo,MAXPARAMS);
     
@@ -569,14 +702,22 @@ typecheck()
 
     LOG("Blocks reset.\n");
 
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to signal if
+     * the 'this' reference has been initialized. */
+    numlocals = maxlocals;
+       validlocals = numlocals;
+    if (initmethod) numlocals++;
+
     /* allocate the buffers for local variables */
-    vartype = DMNEW(u1,maxlocals * (block_count+1));
-    vartypeinfo = DMNEW(typeinfo,maxlocals * (block_count+1));
-    touched = DMNEW(u1,maxlocals);
-    vtype = vartype + maxlocals * block_count;
-    vinfo = vartypeinfo + maxlocals * block_count;
-    memset(vartype,TYPE_VOID,maxlocals * (block_count+1) * sizeof(typeinfo));
-    memset(vartypeinfo,0,maxlocals * (block_count+1) * sizeof(typeinfo));
+    vartype = DMNEW(u1,numlocals * (block_count+1));
+    vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
+    touched = DMNEW(u1,numlocals);
+    vtype = vartype + numlocals * block_count;
+    vinfo = vartypeinfo + numlocals * block_count;
+    memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(typeinfo));
+    memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
 
     LOG("Variable buffer initialized.\n");
 
@@ -587,6 +728,9 @@ typecheck()
     
     LOG("jsrbuffer initialized.\n");
 
+    /* allocate the buffer of active exception handlers */
+    handlers = DMNEW(xtable*,method->exceptiontablelength + 1);
+
     /* initialize the variable types of the first block */
     /* to the types of the arguments */
     ttype = vartype;
@@ -595,7 +739,10 @@ typecheck()
     /* if this is an instance method initialize the "this" ref type */
     if (!(method->flags & ACC_STATIC)) {
         *ttype++ = TYPE_ADDRESS;
-        TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+        if (initmethod)
+            TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+        else
+            TYPEINFO_INIT_CLASSINFO(*tinfo,class);
         tinfo++;
     }
 
@@ -603,15 +750,25 @@ typecheck()
 
     /* the rest of the arguments and the return type */
     typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
-                                   maxlocals - (tinfo-vartypeinfo),
+                                   numlocals - (tinfo-vartypeinfo),
                                    true, /* two word types use two slots */
                                    &returntype,&returntypeinfo);
 
     LOG("Arguments set.\n");
 
+    /* initialize the input stack of exception handlers */
+    for (i=0; i<method->exceptiontablelength; ++i) {
+        cls = extable[i].catchtype;
+        if (!cls) cls = class_java_lang_Throwable;
+        LOGSTR1("handler %i: ",i); LOGSTRu(cls->name); LOGNL;
+        TYPEINFO_INIT_CLASSINFO(extable[i].handler->instack->typeinfo,cls);
+    }
+
+    LOG("Exception handler stacks set.\n");
+
     /* loop while there are still blocks to be checked */
-    fulltypecheck = true; /* XXX */
     do {
+               TYPECHECK_COUNT(count_iterations);
 
         repeat = false;
         
@@ -634,10 +791,26 @@ typecheck()
                 /* init stack at the start of this block */
                 curstack = bptr->instack;
                                        
+                /* determine the active exception handlers for this block */
+                /* XXX could use a faster algorithm with sorted lists or
+                 * something? */
+                len = 0;
+                for (i=0; i<method->exceptiontablelength; ++i) {
+                    if ((extable[i].start <= bptr) && (extable[i].end > bptr)) {
+                        LOG1("active handler L%03d",extable[i].handler->debug_nr);
+                        handlers[len++] = extable + i;
+                    }
+                }
+                handlers[len] = NULL;
+                                       
                 /* init variable types at the start of this block */
-                for (i=0; i<maxlocals; ++i) {
-                    vtype[i] = vartype[maxlocals*b_index + i];
-                    TYPEINFO_COPY(vartypeinfo[maxlocals*b_index + i],vinfo[i]);
+                for (i=0; i<numlocals; ++i) {
+                    vtype[i] = vartype[numlocals*b_index + i];
+                    TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
+
+                    if (handlers[0] &&
+                        vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
+                        panic("Uninitialized object in local variable inside try block");
                 }
 
                 /* init JSR target chain */
@@ -656,18 +829,18 @@ typecheck()
 #endif
 
                     subroutine = jsrbuffer[jsrchain->target - block];
-                    memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+                    memcpy(touched,jsrchain->touched,sizeof(u1)*numlocals);
                 }
                 else
                     subroutine = NULL;
 #ifdef TYPECHECK_VERBOSE
                 if (typecheckverbose) {
                     if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
-                    typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
                     LOGNL; LOGFLUSH;
                 }
 #endif
-                                       
+
                 /* loop over the instructions */
                 len = bptr->icount;
                 iptr = bptr->iinstr;
@@ -678,6 +851,7 @@ typecheck()
                         
                     opcode = iptr->opc;
                     dst = iptr->dst;
+                    maythrow = false;
                                                
                     switch (opcode) {
 
@@ -687,6 +861,12 @@ typecheck()
                         /* We just need to copy the typeinfo */
                         /* for slots containing addresses.   */
 
+                        /* XXX We assume that the destination stack
+                         * slots were continuously allocated in
+                         * memory.  (The current implementation in
+                         * stack.c)
+                         */
+
                       case ICMD_DUP:
                           COPYTYPE(curstack,dst);
                           break;
@@ -731,18 +911,11 @@ typecheck()
                           COPYTYPE(curstack->prev,dst);
                           break;
 
-                          /* XXX only add these cases in debug mode? */
-                      case ICMD_POP:
-                          break;
-                                                       
-                      case ICMD_POP2:
-                          break;
-
                           /****************************************/
                           /* LOADING ADDRESS FROM VARIABLE        */
 
                       case ICMD_ALOAD:
-                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                          CHECK_ONEWORD(iptr->op1,TYPE_ADR);
                           
                           /* loading a returnAddress is not allowed */
                           if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
@@ -755,8 +928,11 @@ typecheck()
                           /* STORING ADDRESS TO VARIABLE          */
 
                       case ICMD_ASTORE:
-                          /* TYPE_ADR has already been checked. */
-                          STORE_TYPE(iptr->op1,TYPE_ADDRESS);
+                          if (handlers[0] &&
+                              TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
+                              panic("Storing uninitialized object in local variable inside try block");
+                          
+                          STORE_ONEWORD(iptr->op1,TYPE_ADDRESS);
                           TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
                           break;
                           
@@ -768,24 +944,9 @@ typecheck()
                               panic("illegal instruction: AALOAD on non-reference array");
 
                           typeinfo_init_component(&curstack->prev->typeinfo,&dst->typeinfo);
+                          maythrow = true;
                           break;
                                                          
-                          /****************************************/
-                          /* STORING ADDRESS TO ARRAY             */
-
-                      case ICMD_AASTORE:
-                          /* XXX also handled by builtin3 */
-                          if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
-                              panic("illegal instruction: AASTORE to non-reference array");
-
-                          /* XXX optimize */
-                          /*
-                            typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
-                            if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
-                            panic("illegal instruction: AASTORE to incompatible type");
-                          */
-                          break;
-
                           /****************************************/
                           /* FIELD ACCESS                         */
 
@@ -795,12 +956,54 @@ 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;
 
                       case ICMD_GETFIELD:
@@ -811,27 +1014,41 @@ 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);
                               }
                               else {
+                                  /* XXX check field type? */
                                   TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
                               }
                           }
+                          maythrow = true;
                           break;
 
                       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);
                               }
                               else {
+                                  /* XXX check field type? */
                                   TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
                               }
                           }
+                          maythrow = true;
                           break;
 
                           /****************************************/
@@ -841,92 +1058,110 @@ typecheck()
                           /* XXX should this also work on arraystubs? */
                           if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo))
                               panic("illegal instruction: ARRAYLENGTH on non-array");
+                          maythrow = true;
                           break;
                                                          
                       case ICMD_BALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
                               && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_CALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_CHAR))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_DALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_DOUBLE))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_FALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_FLOAT))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_IALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_INT))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_SALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_SHORT))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_LALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_LONG))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
 
                       case ICMD_BASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BOOLEAN)
                               && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BYTE))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_CASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_CHAR))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_DASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_DOUBLE))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_FASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_FLOAT))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_IASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_INT))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_SASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_SHORT))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
                       case ICMD_LASTORE:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_LONG))
                               panic("Array type mismatch");
+                          maythrow = true;
                           break;
 
                           /****************************************/
                           /* 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);
                           /* XXX */
+                          maythrow = true;
                           break;
 
                       case ICMD_INSTANCEOF:
+                                                 TYPECHECK_ADR(curstack);
                           /* returnAddress is not allowed */
                           if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
                               panic("Illegal instruction: INSTANCEOF on non-reference");
                           
-                          /* XXX */
+                          /* XXX optimize statically? */
                           break;
                           
                       case ICMD_ACONST:
                           if (iptr->val.a == NULL)
-                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo)
+                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
                           else
                               /* XXX constants for builtin functions */
                               /* string constants */
@@ -1012,6 +1247,7 @@ typecheck()
                           if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
                               panic("illegal instruction: ATHROW on non-Throwable");
                           superblockend = true;
+                          maythrow = true;
                           break;
 
                       case ICMD_ARETURN:
@@ -1021,34 +1257,30 @@ typecheck()
                           if (returntype != TYPE_ADDRESS
                               || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
                               panic("Return type mismatch");
-                                                         
-                          superblockend = true;
-                          break;
-
+                                                 goto return_tail;
+                                                 
                       case ICMD_IRETURN:
-                          if (returntype != TYPE_INT)
-                              panic("Return type mismatch");
-                          superblockend = true;
-                          break;                           
+                          if (returntype != TYPE_INT) panic("Return type mismatch");
+                                                 goto return_tail;
+                                                 
                       case ICMD_LRETURN:
-                          if (returntype != TYPE_LONG)
-                              panic("Return type mismatch");
-                          superblockend = true;
-                          break;
+                          if (returntype != TYPE_LONG) panic("Return type mismatch");
+                                                 goto return_tail;
+                                                 
                       case ICMD_FRETURN:
-                          if (returntype != TYPE_FLOAT)
-                              panic("Return type mismatch");
-                          superblockend = true;
-                          break;
+                          if (returntype != TYPE_FLOAT) panic("Return type mismatch");
+                                                 goto return_tail;
+                                                 
                       case ICMD_DRETURN:
-                          if (returntype != TYPE_DOUBLE)
-                              panic("Return type mismatch");
-                          superblockend = true;
-                          break;
+                          if (returntype != TYPE_DOUBLE) panic("Return type mismatch");
+                                                 goto return_tail;
+                                                 
                       case ICMD_RETURN:
-                          if (returntype != TYPE_VOID)
-                              panic("Return type mismatch");
+                          if (returntype != TYPE_VOID) panic("Return type mismatch");
+                                         return_tail:
+                          TYPECHECK_LEAVE;
                           superblockend = true;
+                          maythrow = true;
                           break;
                                                     
                           /****************************************/
@@ -1089,7 +1321,7 @@ typecheck()
                            */
                           if (jsrtemp->sbr_touched) {
                               /* Calculate the local variables after the subroutine call */
-                              for (i=0; i<maxlocals; ++i)
+                              for (i=0; i<numlocals; ++i)
                                   if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
                                       TOUCH_VARIABLE(i);
                                       if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
@@ -1106,11 +1338,12 @@ typecheck()
                               repeat = true;
                               superblockend = true;
                           }
+                          /* XXX may throw? I don't think. */
                           break;
                           
                       case ICMD_RET:
                           /* check returnAddress variable */
-                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                          CHECK_ONEWORD(iptr->op1,TYPE_ADR);
                           
                           if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
                               panic("illegal instruction: RET using non-returnAddress variable");
@@ -1122,34 +1355,37 @@ typecheck()
                           /* determine which variables are touched by this subroutine */
                           /* and their types */
                           if (subroutine->sbr_touched) {
-                              for (i=0; i<maxlocals; ++i)
+                              for (i=0; i<numlocals; ++i)
                                   subroutine->sbr_touched[i] |= touched[i];
                               ttype = subroutine->sbr_vtype;
                               tinfo = subroutine->sbr_vinfo;
                               TYPECHECK_MERGEVARS;
                           }
                           else {
-                              subroutine->sbr_touched = DMNEW(u1,maxlocals);
-                              memcpy(subroutine->sbr_touched,touched,sizeof(u1)*maxlocals);
-                              subroutine->sbr_vtype = DMNEW(u1,maxlocals);
-                              memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*maxlocals);
-                              subroutine->sbr_vinfo = DMNEW(typeinfo,maxlocals);
-                              for (i=0; i<maxlocals; ++i)
+                              subroutine->sbr_touched = DMNEW(u1,numlocals);
+                              memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
+                              subroutine->sbr_vtype = DMNEW(u1,numlocals);
+                              memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*numlocals);
+                              subroutine->sbr_vinfo = DMNEW(typeinfo,numlocals);
+                              for (i=0; i<numlocals; ++i)
                                   if (vtype[i] == TYPE_ADR)
                                       TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
                           }
+                          /* XXX check if subroutine changed types? */
 
                           LOGSTR("subroutine touches:");
-                          DOLOG(typeinfo_print_locals(stdout,subroutine->sbr_vtype,subroutine->sbr_vinfo,
-                                                      subroutine->sbr_touched,maxlocals));
+                          DOLOG(typeinfo_print_locals(get_logfile(),subroutine->sbr_vtype,subroutine->sbr_vinfo,
+                                                      subroutine->sbr_touched,numlocals));
                           LOGNL; LOGFLUSH;
 
                           /* reach blocks after JSR statements */
                           for (i=0; i<block_count; ++i) {
                               tbptr = block + i;
+                              LOG1("block L%03d",tbptr->debug_nr);
                               if (tbptr->iinstr[tbptr->icount - 1].opc != ICMD_JSR)
                                   continue;
-                              if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != jsrold->target)
+                              LOG("ends with JSR");
+                              if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != subroutine->target)
                                   continue;
                               tbptr++;
 
@@ -1169,40 +1405,142 @@ typecheck()
                       case ICMD_INVOKESTATIC:
                       case ICMD_INVOKEINTERFACE:
                           {
+                                                         /* XXX check if this opcode may invoke this method */
                               /* XXX check access rights */
                               
                               methodinfo *mi = (methodinfo*) iptr->val.a;
+                              bool callinginit = (opcode == ICMD_INVOKESPECIAL && mi->name == name_init);
+                              instruction *ins;
+                              classinfo *initclass;
+
+                              /* XXX for INVOKESPECIAL: check if the invokation is done at all */
+
+                              /* fetch parameter types and return type */
                               /* XXX might use dst->typeinfo directly if non void */
-                              typeinfo_init_from_method_args(mi->descriptor,ptype,pinfo,MAXPARAMS,false,
+                              i = 0;
+                              if (opcode != ICMD_INVOKESTATIC) {
+                                  ptype[0] = TYPE_ADR;
+                                  TYPEINFO_INIT_CLASSINFO(pinfo[0],mi->class);
+                                  i++;
+                              }
+                              typeinfo_init_from_method_args(mi->descriptor,ptype+i,pinfo+i,
+                                                             MAXPARAMS-i,false,
                                                              &rtype,&rinfo);
 
-                              /* XXX compare rtype and dst->type? */
+                              /* check parameter types */
+                              srcstack = curstack;
+                              i = mi->paramcount; /* number of parameters including 'this'*/
+                              while (--i >= 0) {
+                                  LOG1("param %d",i);
+                                  if (srcstack->type != ptype[i])
+                                      panic("Parameter type mismatch in method invocation");
+                                  if (srcstack->type == TYPE_ADR) {
+                                      LOGINFO(&(srcstack->typeinfo));
+                                      LOGINFO(pinfo + i);
+                                      if (i==0 && callinginit)
+                                      {
+                                          /* first argument to <init> method */
+                                          if (!TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo))
+                                              panic("Calling <init> on initialized object");
+                                          
+                                          /* get the address of the NEW instruction */
+                                          LOGINFO(&(srcstack->typeinfo));
+                                          ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(srcstack->typeinfo);
+                                          initclass = (ins) ? (classinfo*)ins[-1].val.a : method->class;
+                                          LOGSTR("class: "); LOGSTRu(initclass->name); LOGNL;
+
+                                          /* XXX check type */
+                                      }
+                                      else {
+                                          if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
+                                              panic("Parameter reference type mismatch in method invocation");
+                                      }
+                                  }
+                                  LOG("ok");
+
+                                  srcstack = srcstack->prev;
+                              }
+
+                                                         LOG("checking return type");
                               if (rtype != TYPE_VOID) {
+                                  if (rtype != dst->type)
+                                      panic("Return type mismatch in method invocation");
                                   TYPEINFO_COPY(rinfo,dst->typeinfo);
                               }
+
+                              if (callinginit) {
+                                                                 LOG("replacing uninitialized object");
+                                  /* replace uninitialized object type on stack */
+                                  srcstack = dst;
+                                  while (srcstack) {
+                                      if (srcstack->type == TYPE_ADR
+                                          && TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo)
+                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(srcstack->typeinfo) == ins)
+                                      {
+                                          LOG("replacing uninitialized type on stack");
+                                          TYPEINFO_INIT_CLASSINFO(srcstack->typeinfo,initclass);
+                                      }
+                                      srcstack = srcstack->prev;
+                                  }
+                                  /* replace uninitialized object type in locals */
+                                  for (i=0; i<numlocals; ++i) {
+                                      if (vtype[i] == TYPE_ADR
+                                          && TYPEINFO_IS_NEWOBJECT(vinfo[i])
+                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
+                                      {
+                                          LOG1("replacing uninitialized type in local %d",i);
+                                          TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
+                                      }
+                                  }
+
+                                  /* initializing the 'this' reference? */
+                                  if (initmethod && !ins) {
+                                      /* set our marker variable to type int */
+                                      LOG("setting <init> marker");
+                                                                         vtype[numlocals-1] = TYPE_INT;
+                                  }
+                              }
                           }
+                          maythrow = true;
                           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)) {
-                              /* XXX also handled by ICMD_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");
 
@@ -1213,74 +1551,134 @@ 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_CLASSINFO(dst->typeinfo,(classinfo *)iptr[-1].val.a);
+                              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;
                                                      
                           /****************************************/
                           /* PRIMITIVE VARIABLE ACCESS            */
 
-                      case ICMD_ILOAD: CHECKVARTYPE(iptr->op1,TYPE_INT); break;
-                      case ICMD_LLOAD: CHECKVARTYPE(iptr->op1,TYPE_LONG); break;
-                      case ICMD_FLOAD: CHECKVARTYPE(iptr->op1,TYPE_FLOAT); break;
-                      case ICMD_DLOAD: CHECKVARTYPE(iptr->op1,TYPE_DOUBLE); break;
-                      case ICMD_IINC:  CHECKVARTYPE(iptr->op1,TYPE_INT); /*TOUCH_VARIABLE(iptr->op1);*/ break;
+                      case ICMD_ILOAD: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
+                      case ICMD_FLOAD: CHECK_ONEWORD(iptr->op1,TYPE_FLOAT); break;
+                      case ICMD_IINC:  CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
+                      case ICMD_LLOAD: CHECK_TWOWORD(iptr->op1,TYPE_LONG); break;
+                      case ICMD_DLOAD: CHECK_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
                           
-                      case ICMD_FSTORE: STORE_PRIMITIVE(iptr->op1,TYPE_FLOAT); break;
-                      case ICMD_ISTORE: STORE_PRIMITIVE(iptr->op1,TYPE_INT); break;                           
+                      case ICMD_FSTORE: STORE_ONEWORD(iptr->op1,TYPE_FLOAT); break;
+                      case ICMD_ISTORE: STORE_ONEWORD(iptr->op1,TYPE_INT); break;
                       case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
                       case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
                           
@@ -1293,8 +1691,10 @@ typecheck()
                       case ICMD_ANEWARRAY:
                       case ICMD_MONITORENTER:
                       case ICMD_MONITOREXIT:
+                      case ICMD_AASTORE:
                           /* XXX only check this in debug mode? */
-                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                          LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                                                 LOG("Should have been converted to builtin function call.");
                           panic("Internal error: unexpected instruction encountered");
                           break;
                                                      
@@ -1306,23 +1706,50 @@ typecheck()
                                                 /* XXX only add cases for them in debug mode? */
 
                       case ICMD_NOP:
-                      case ICMD_CHECKASIZE: /* XXX ? */
-                      case ICMD_NULLCHECKPOP: /* XXX ? */
+                      case ICMD_POP:
+                      case ICMD_POP2:
                       case ICMD_READONLY_ARG: /* XXX ? */
                       case ICMD_CLEAR_ARGREN: /* XXX ? */
                           break;
 
+                      case ICMD_CHECKASIZE:
+                      case ICMD_NULLCHECKPOP:
+                          maythrow = true;
+                          break;
+
                           /****************************************/
                           /* ARITHMETIC AND CONVERSION            */
+                          /* (These instructions are typechecked in analyse_stack.) */
 
-                          /* These instructions are typechecked in analyse_stack. */
-                                                /* XXX only add cases for them in debug mode? */
+                          /* The following instructions may throw a runtime exception: */
+                          
+                      case ICMD_IDIV:
+                      case ICMD_IREM:
+                      case ICMD_LDIV:
+                      case ICMD_LREM:
+                          
+                          maythrow = true;
+                          break;
+                          
+                          /* The following instructions never throw a runtime exception: */
+                          /* XXX only add cases for them in debug mode? */
+                          
+                      case ICMD_ICONST:
+                      case ICMD_LCONST:
+                      case ICMD_FCONST:
+                      case ICMD_DCONST:
+
+                      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:
 
                       case ICMD_IADD:
                       case ICMD_ISUB:
                       case ICMD_IMUL:
-                      case ICMD_IDIV:
-                      case ICMD_IREM:
                       case ICMD_INEG:
                       case ICMD_IAND:
                       case ICMD_IOR:
@@ -1333,8 +1760,6 @@ typecheck()
                       case ICMD_LADD:
                       case ICMD_LSUB:
                       case ICMD_LMUL:
-                      case ICMD_LDIV:
-                      case ICMD_LREM:
                       case ICMD_LNEG:
                       case ICMD_LAND:
                       case ICMD_LOR:
@@ -1367,6 +1792,22 @@ typecheck()
                       case ICMD_LUSHRCONST:
                       case ICMD_LREMPOW2:
                           
+                      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:
+                      case ICMD_INT2BYTE:
+                      case ICMD_INT2CHAR:
+                      case ICMD_INT2SHORT:
+
                       case ICMD_LCMP:
                       case ICMD_LCMPCONST:
                       case ICMD_FCMPL:
@@ -1387,53 +1828,40 @@ typecheck()
                       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:
-                      case ICMD_INT2BYTE:
-                      case ICMD_INT2CHAR:
-                      case ICMD_INT2SHORT:
-
-                      case ICMD_ICONST:
-                      case ICMD_LCONST:
-                      case ICMD_FCONST:
-                      case ICMD_DCONST:
-
-                      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:
-
                           break;
                           
                           /****************************************/
 
                       default:
-                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                          LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
                           panic("Missing ICMD code during typecheck");
                     }
-                    
+
                     /* the output of this instruction becomes the current stack */
                     curstack = dst;
                     
+                    /* reach exception handlers for this instruction */
+                    if (maythrow) {
+                        LOG("reaching exception handlers");
+                        i = 0;
+                        while (handlers[i]) {
+                            tbptr = handlers[i]->handler;
+                            TYPECHECK_REACH(REACH_THROW); /* XXX jsr chain? */
+                            i++;
+                        }
+                    }
+
+                    /*
+                      DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+                      LOGNL; LOGFLUSH;
+                    */
+                    
                     iptr++;
                 } /* while instructions */
 
                 LOG("instructions done");
                 LOGSTR("RESULT=> ");
-                DOLOG(typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+                DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
                 LOGNL; LOGFLUSH;
                 
                 /* propagate stack and variables to the following block */
@@ -1454,23 +1882,51 @@ typecheck()
             bptr++;
         } /* while blocks */
         
-        /* the following iterations only check if any types changed */
-        fulltypecheck = false; /* XXX */
-
         LOGIF(repeat,"repeat=true");
     } while (repeat);
 
-    /* XXX reset BB... to BBFINISHED */
-    
-    /* XXX free vartype */
-    /* XXX free vartypeinfo */
-            /* XXX free buffers for method arguments. */
-
-    /* XXX add debug check if all non-dead blocks have been checked */
+#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 != 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("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");
 }
 
 #undef COPYTYPE
 
 #endif /* CACAO_TYPECHECK */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */