GNU header update.
[cacao.git] / src / vm / jit / verify / typecheck.c
index 98bd6cc445ed77e23e6226a9a03ed5a218960594..900262a3512d3c92cffcbffb930e3ca1dfa70732 100644 (file)
@@ -1,9 +1,9 @@
-/* jit/typecheck.c - typechecking (part of bytecode verification)
+/* vm/jit/verify/typecheck.c - typechecking (part of bytecode verification)
 
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
-   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
-   P. Tomsich, J. Wenninger
+   Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
+   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
+   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
+   Institut f. Computersprachen - TU Wien
 
    This file is part of CACAO.
 
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 701 2003-12-07 16:26:58Z edwin $
+   $Id: typecheck.c 1735 2004-12-07 14:33:27Z twisti $
 
 */
 
-#include "global.h" /* must be here because of CACAO_TYPECHECK */
+#include <string.h>
+
+#include "vm/global.h" /* must be here because of CACAO_TYPECHECK */
 
 #ifdef CACAO_TYPECHECK
 
-#include "jit.h"
-#include "builtin.h"
-#include "tables.h"
-#include "loader.h"
 #include "types.h"
-#include "toolbox/loging.h"
-#include "toolbox/memory.h"
-
-#define TOUCHED_YES    0x01
-#define TOUCHED_NO     0x02
-#define TOUCHED_MAYBE  (TOUCHED_YES | TOUCHED_NO)
+/*  #include "main.h" */
+#include "mm/memory.h"
+#include "toolbox/logging.h"
+#include "native/native.h"
+#include "vm/builtin.h"
+#include "vm/loader.h"
+#include "vm/options.h"
+#include "vm/tables.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/stack.h"
 
-#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                                                            */
@@ -69,10 +67,10 @@ 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(get_logfile(),info);log_plain("\n");} while(0))
+#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))
@@ -95,7 +93,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)
@@ -105,29 +103,14 @@ bool typecheckverbose = false;
 
 #if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
 
-static
-void
-typeinfo_print_locals(FILE *file,u1 *vtype,typeinfo *vinfo,u1 *touched,int num)
-{
-    int i;
-
-    for (i=0; i<num; ++i) {
-        if (touched)
-            fprintf(file," %d%s=",i,
-                    (touched[i]==TOUCHED_YES) ? "*"
-                    : ((touched[i]==TOUCHED_NO) ? "" : "~"));
-        else
-            fprintf(file," %d=",i);
-        typeinfo_print_type(file,vtype[i],vinfo+i);
-    }
-}
+#include <stdio.h>
 
 static
 void
-typeinfo_print_stack(FILE *file,stackptr stack)
+typestack_print(FILE *file,stackptr stack)
 {
     while (stack) {
-        typeinfo_print_type(file,stack->type,&stack->typeinfo);
+        typeinfo_print_stacktype(file,stack->type,&stack->typeinfo);
         stack = stack->prev;
         if (stack) fprintf(file," ");
     }
@@ -135,305 +118,646 @@ typeinfo_print_stack(FILE *file,stackptr stack)
 
 static
 void
-typeinfo_print_block(FILE *file,stackptr instack,
-                     u1 *vtype,typeinfo *vinfo,u1 *touched)
+typestate_print(FILE *file,stackptr instack,typevector *localset,int size)
 {
     fprintf(file,"Stack: ");
-    typeinfo_print_stack(file,instack);
+    typestack_print(file,instack);
     fprintf(file," Locals:");
-    typeinfo_print_locals(file,vtype,vinfo,touched,maxlocals);
+    typevectorset_print(file,localset,size);
 }
 
+#endif
 
-static
-void
-typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+/****************************************************************************/
+/* STATISTICS                                                               */
+/****************************************************************************/
+
+#ifdef TYPECHECK_DEBUG
+/*#define TYPECHECK_STATISTICS*/
+#endif
+
+#ifdef TYPECHECK_STATISTICS
+#define STAT_ITERATIONS  10
+#define STAT_BLOCKS      10
+#define STAT_LOCALS      16
+
+static int stat_typechecked = 0;
+static int stat_typechecked_jsr = 0;
+static int stat_iterations[STAT_ITERATIONS+1] = { 0 };
+static int stat_reached = 0;
+static int stat_copied = 0;
+static int stat_merged = 0;
+static int stat_merging_changed = 0;
+static int stat_backwards = 0;
+static int stat_blocks[STAT_BLOCKS+1] = { 0 };
+static int stat_locals[STAT_LOCALS+1] = { 0 };
+static int stat_ins = 0;
+static int stat_ins_field = 0;
+static int stat_ins_invoke = 0;
+static int stat_ins_primload = 0;
+static int stat_ins_aload = 0;
+static int stat_ins_builtin = 0;
+static int stat_ins_builtin_gen = 0;
+static int stat_ins_branch = 0;
+static int stat_ins_switch = 0;
+static int stat_ins_unchecked = 0;
+static int stat_handlers_reached = 0;
+static int stat_savedstack = 0;
+
+#define TYPECHECK_COUNT(cnt)  (cnt)++
+#define TYPECHECK_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
+#define TYPECHECK_COUNT_FREQ(array,val,limit) \
+       do {                                                                      \
+               if ((val) < (limit)) (array)[val]++;  \
+               else (array)[limit]++;                            \
+       } while (0)
+
+static void print_freq(FILE *file,int *array,int limit)
 {
-    int bi;
-    /*    int j;*/
+       int i;
+       for (i=0; i<limit; ++i)
+               fprintf(file,"      %3d: %8d\n",i,array[i]);
+       fprintf(file,"    =>%3d: %8d\n",limit,array[limit]);
+}
 
-    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);
-        fprintf(file,"\n");
+void typecheck_print_statistics(FILE *file) {
+       fprintf(file,"typechecked methods: %8d\n",stat_typechecked);
+       fprintf(file,"methods with JSR   : %8d\n",stat_typechecked_jsr);
+       fprintf(file,"reached blocks     : %8d\n",stat_reached);
+       fprintf(file,"copied states      : %8d\n",stat_copied);
+       fprintf(file,"merged states      : %8d\n",stat_merged);
+       fprintf(file,"merging changed    : %8d\n",stat_merging_changed);
+       fprintf(file,"backwards branches : %8d\n",stat_backwards);
+       fprintf(file,"handlers reached   : %8d\n",stat_handlers_reached);
+       fprintf(file,"saved stack (times): %8d\n",stat_savedstack);
+       fprintf(file,"instructions       : %8d\n",stat_ins);
+       fprintf(file,"    field access   : %8d\n",stat_ins_field);
+       fprintf(file,"    invocations    : %8d\n",stat_ins_invoke);
+       fprintf(file,"    load primitive : %8d\n",stat_ins_primload);
+       fprintf(file,"    load address   : %8d\n",stat_ins_aload);
+       fprintf(file,"    builtins       : %8d\n",stat_ins_builtin);
+       fprintf(file,"        generic    : %8d\n",stat_ins_builtin_gen);
+       fprintf(file,"    unchecked      : %8d\n",stat_ins_unchecked);
+       fprintf(file,"    branches       : %8d\n",stat_ins_branch);
+       fprintf(file,"    switches       : %8d\n",stat_ins_switch);
+       fprintf(file,"iterations used:\n");
+       print_freq(file,stat_iterations,STAT_ITERATIONS);
+       fprintf(file,"basic blocks per method / 10:\n");
+       print_freq(file,stat_blocks,STAT_BLOCKS);
+       fprintf(file,"locals:\n");
+       print_freq(file,stat_locals,STAT_LOCALS);
+}
+                                                  
+#else
+                                                  
+#define TYPECHECK_COUNT(cnt)
+#define TYPECHECK_COUNTIF(cond,cnt)
+#define TYPECHECK_COUNT_FREQ(array,val,limit)
+#endif
 
-/*         for (j=0; j<block[bi].icount; ++j) { */
-/*             fprintf(file,"\t%s\n",icmd_names[block[bi].iinstr[j].opc]); */
-/*         } */
+/****************************************************************************/
+/* TYPESTACK FUNCTIONS                                                      */
+/****************************************************************************/
 
-        show_icmd_block(block+bi);
-    }
+#define TYPESTACK_IS_RETURNADDRESS(sptr) \
+            TYPE_IS_RETURNADDRESS((sptr)->type,(sptr)->typeinfo)
+
+#define TYPESTACK_IS_REFERENCE(sptr) \
+            TYPE_IS_REFERENCE((sptr)->type,(sptr)->typeinfo)
+
+#define TYPESTACK_RETURNADDRESSSET(sptr) \
+            ((typeinfo_retaddr_set*)TYPEINFO_RETURNADDRESS((sptr)->typeinfo))
+
+#define RETURNADDRESSSET_SEEK(set,pos) \
+            do {int i; for (i=pos;i--;) set=set->alt;} while(0)
+
+#define TYPESTACK_COPY(sp,copy)                                                                        \
+               do {for(; sp; sp=sp->prev, copy=copy->prev) {           \
+                                       copy->type = sp->type;                                          \
+                                       TYPEINFO_COPY(sp->typeinfo,copy->typeinfo);     \
+                               }} while (0)                                                                    \
+
+static void
+typestack_copy(stackptr dst,stackptr y,typevector *selected)
+{
+       typevector *sel;
+       typeinfo_retaddr_set *sety;
+       typeinfo_retaddr_set *new;
+       typeinfo_retaddr_set **next;
+       int k;
+       
+       for (;dst; dst=dst->prev, y=y->prev) {
+               if (!y) panic("Stack depth mismatch 1");
+               if (dst->type != y->type)
+                       panic("Stack type mismatch 1");
+               LOG3("copy %p -> %p (type %d)",y,dst,dst->type);
+               if (dst->type == TYPE_ADDRESS) {
+                       if (TYPEINFO_IS_PRIMITIVE(y->typeinfo)) {
+                               /* We copy the returnAddresses from the selected
+                                * states only. */
+
+                               LOG("copying returnAddress");
+                               sety = TYPESTACK_RETURNADDRESSSET(y);
+                               next = &new;
+                               for (k=0,sel=selected; sel; sel=sel->alt) {
+                                       LOG1("selected k=%d",sel->k);
+                                       while (k<sel->k) {
+                                               sety = sety->alt;
+                                               k++;
+                                       }
+                                       *next = DNEW(typeinfo_retaddr_set);
+                                       (*next)->addr = sety->addr;
+                                       next = &((*next)->alt);
+                               }
+                               *next = NULL;
+                               TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,new);
+                       }
+                       else {
+                               TYPEINFO_CLONE(y->typeinfo,dst->typeinfo);
+                       }
+               }
+       }
+       if (y) panic("Stack depth mismatch 2");
+}
+
+static void
+typestack_put_retaddr(stackptr dst,void *retaddr,typevector *loc)
+{
+#ifdef TYPECHECK_DEBUG
+       if (dst->type != TYPE_ADDRESS)
+               panic("Internal error: Storing returnAddress in non-address slot");
+#endif
+       
+       TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,NULL);
+       for (;loc; loc=loc->alt) {
+               typeinfo_retaddr_set *set = DNEW(typeinfo_retaddr_set);
+               set->addr = retaddr;
+               set->alt = TYPESTACK_RETURNADDRESSSET(dst);
+               TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,set);
+       }
+}
+
+static void
+typestack_collapse(stackptr dst)
+{
+       for (; dst; dst = dst->prev) {
+               if (TYPESTACK_IS_RETURNADDRESS(dst))
+                       TYPESTACK_RETURNADDRESSSET(dst)->alt = NULL;
+       }
+}
+
+static bool
+typestack_merge(stackptr dst,stackptr y)
+{
+       bool changed = false;
+       for (; dst; dst = dst->prev, y=y->prev) {
+               if (!y)
+                       panic("Stack depth mismatch 3");
+               if (dst->type != y->type) panic("Stack type mismatch 2");
+               if (dst->type == TYPE_ADDRESS) {
+                       if (TYPEINFO_IS_PRIMITIVE(dst->typeinfo)) {
+                               /* dst has returnAddress type */
+                               if (!TYPEINFO_IS_PRIMITIVE(y->typeinfo))
+                                       panic("Merging returnAddress with reference");
+                       }
+                       else {
+                               /* dst has reference type */
+                               if (TYPEINFO_IS_PRIMITIVE(y->typeinfo))
+                                       panic("Merging reference with returnAddress");
+                               changed |= typeinfo_merge(&(dst->typeinfo),&(y->typeinfo));
+                       }
+               }
+       }
+       if (y) panic("Stack depth mismatch 4");
+       return changed;
+}
+
+static void
+typestack_add(stackptr dst,stackptr y,int ky)
+{
+       typeinfo_retaddr_set *setd;
+       typeinfo_retaddr_set *sety;
+       
+       for (; dst; dst = dst->prev, y=y->prev) {
+               if (TYPESTACK_IS_RETURNADDRESS(dst)) {
+                       setd = TYPESTACK_RETURNADDRESSSET(dst);
+                       sety = TYPESTACK_RETURNADDRESSSET(y);
+                       RETURNADDRESSSET_SEEK(sety,ky);
+                       while (setd->alt)
+                               setd=setd->alt;
+                       setd->alt = DNEW(typeinfo_retaddr_set);
+                       setd->alt->addr = sety->addr;
+                       setd->alt->alt = NULL;
+               }
+       }
+}
+
+/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_separable_with(stackptr a,stackptr b,int kb)
+{
+       typeinfo_retaddr_set *seta;
+       typeinfo_retaddr_set *setb;
+       
+       for (; a; a = a->prev, b = b->prev) {
+#ifdef TYPECHECK_DEBUG
+               if (!b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+               if (TYPESTACK_IS_RETURNADDRESS(a)) {
+#ifdef TYPECHECK_DEBUG
+                       if (!TYPESTACK_IS_RETURNADDRESS(b))
+                               panic("Internal error: typestack_separable_from: unmergable stacks");
+#endif
+                       seta = TYPESTACK_RETURNADDRESSSET(a);
+                       setb = TYPESTACK_RETURNADDRESSSET(b);
+                       RETURNADDRESSSET_SEEK(setb,kb);
+
+                       for (;seta;seta=seta->alt)
+                               if (seta->addr != setb->addr) return true;
+               }
+       }
+#ifdef TYPECHECK_DEBUG
+       if (b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+       return false;
 }
 
+/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_separable_from(stackptr a,int ka,stackptr b,int kb)
+{
+       typeinfo_retaddr_set *seta;
+       typeinfo_retaddr_set *setb;
+
+       for (; a; a = a->prev, b = b->prev) {
+#ifdef TYPECHECK_DEBUG
+               if (!b) panic("Internal error: typestack_separable_from: different depth");
 #endif
+               if (TYPESTACK_IS_RETURNADDRESS(a)) {
+#ifdef TYPECHECK_DEBUG
+                       if (!TYPESTACK_IS_RETURNADDRESS(b))
+                               panic("Internal error: typestack_separable_from: unmergable stacks");
+#endif
+                       seta = TYPESTACK_RETURNADDRESSSET(a);
+                       setb = TYPESTACK_RETURNADDRESSSET(b);
+                       RETURNADDRESSSET_SEEK(seta,ka);
+                       RETURNADDRESSSET_SEEK(setb,kb);
+
+                       if (seta->addr != setb->addr) return true;
+               }
+       }
+#ifdef TYPECHECK_DEBUG
+       if (b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+       return false;
+}
 
 /****************************************************************************/
-/* INTERNAL DATA STRUCTURES                                                 */
+/* TYPESTATE FUNCTIONS                                                      */
 /****************************************************************************/
 
-typedef struct jsr_record jsr_record;
+static bool
+typestate_merge(stackptr deststack,typevector *destloc,
+                               stackptr ystack,typevector *yloc,
+                               int locsize,bool jsrencountered)
+{
+       typevector *dvec,*yvec;
+       int kd,ky;
+       bool changed = false;
+       
+       LOG("merge:");
+       LOGSTR("dstack: "); DOLOG(typestack_print(get_logfile(),deststack)); LOGNL;
+       LOGSTR("ystack: "); DOLOG(typestack_print(get_logfile(),ystack)); LOGNL;
+       LOGSTR("dloc  : "); DOLOG(typevectorset_print(get_logfile(),destloc,locsize)); LOGNL;
+       LOGSTR("yloc  : "); DOLOG(typevectorset_print(get_logfile(),yloc,locsize)); LOGNL;
+       LOGFLUSH;
+
+       /* The stack is always merged. If there are returnAddresses on
+        * the stack they are ignored in this step. */
+
+       changed |= typestack_merge(deststack,ystack);
+
+       if (!jsrencountered)
+               return typevector_merge(destloc,yloc,locsize);
+
+       for (yvec=yloc; yvec; yvec=yvec->alt) {
+               ky = yvec->k;
+
+               /* Check if the typestates (deststack,destloc) will be
+                * separable when (ystack,yvec) is added. */
+
+               if (!typestack_separable_with(deststack,ystack,ky)
+                       && !typevectorset_separable_with(destloc,yvec,locsize))
+               {
+                       /* No, the resulting set won't be separable, thus we
+                        * may merge all states in (deststack,destloc) and
+                        * (ystack,yvec). */
+
+                       typestack_collapse(deststack);
+                       typevectorset_collapse(destloc,locsize);
+                       typevector_merge(destloc,yvec,locsize);
+               }
+               else {
+                       /* Yes, the resulting set will be separable. Thus we check
+                        * if we may merge (ystack,yvec) with a single state in
+                        * (deststack,destloc). */
+               
+                       for (dvec=destloc,kd=0; dvec; dvec=dvec->alt, kd++) {
+                               if (!typestack_separable_from(ystack,ky,deststack,kd)
+                                       && !typevector_separable_from(yvec,dvec,locsize))
+                               {
+                                       /* The typestate (ystack,yvec) is not separable from
+                                        * (deststack,dvec) by any returnAddress. Thus we may
+                                        * merge the states. */
+                                       
+                                       changed |= typevector_merge(dvec,yvec,locsize);
+                                       
+                                       goto merged;
+                               }
+                       }
+
+                       /* The typestate (ystack,yvec) is separable from all typestates
+                        * (deststack,destloc). Thus we must add this state to the
+                        * result set. */
+
+                       typestack_add(deststack,ystack,ky);
+                       typevectorset_add(destloc,yvec,locsize);
+                       changed = true;
+               }
+                  
+       merged:
+               ;
+       }
+       
+       LOG("result:");
+       LOGSTR("dstack: "); DOLOG(typestack_print(get_logfile(),deststack)); LOGNL;
+       LOGSTR("dloc  : "); DOLOG(typevectorset_print(get_logfile(),destloc,locsize)); LOGNL;
+       LOGFLUSH;
+       
+       return changed;
+}
 
-/*
- * For each basic block we store the chain of JSR instructions which
- * were used to reach the block (usually zero or one). For more
- * details on verifying JSR and RET instructions see the Java VM
- * Specification.
- *
- * CAUTION: The fields starting with sbr_ are only valid for the
- * jsr_record of the first block of the subroutine.
- */
-struct jsr_record {
-    basicblock *target;      /* target of the JSR instruction (first block of subroutine) */
-    jsr_record *next;        /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
-    u1         *sbr_touched; /* specifies which variables the subroutine touches */
-    u1         *sbr_vtype;   /* Types of local variables after RET */
-    typeinfo   *sbr_vinfo;   /* Types of local variables after RET */
-    u1          touched[1];  /* touched flags for local variables */
-};
+
+static bool
+typestate_reach(codegendata *cd, registerdata *rd,void *localbuf,
+                               basicblock *current,
+                               basicblock *destblock,
+                               stackptr ystack,typevector *yloc,
+                               int locsize,bool jsrencountered)
+{
+       typevector *destloc;
+       int destidx;
+       bool changed = false;
+
+       LOG1("reaching block L%03d",destblock->debug_nr);
+       TYPECHECK_COUNT(stat_reached);
+       
+       destidx = destblock - cd->method->basicblocks;
+       destloc = MGET_TYPEVECTOR(localbuf,destidx,locsize);
+
+       /* When branching backwards we have to check for uninitialized objects */
+       
+       if (destblock <= current) {
+               stackptr sp;
+               int i;
+#if defined(__GNUC__)
+#warning FIXME FOR INLINING
+#endif
+               if (!useinlining) {
+                       TYPECHECK_COUNT(stat_backwards);
+                       LOG("BACKWARDS!");
+                       for (sp = ystack; sp; sp=sp->prev)
+                               if (sp->type == TYPE_ADR &&
+                               TYPEINFO_IS_NEWOBJECT(sp->typeinfo)) {
+                                       show_icmd_method(cd->method,cd,rd);
+                               printf("current: %ld, dest: %ld\n",current->debug_nr,destblock->debug_nr);
+                               panic("Branching backwards with uninitialized object on stack");
+                       }
+
+                       for (i=0; i<locsize; ++i)
+                               if (yloc->td[i].type == TYPE_ADR &&
+                               TYPEINFO_IS_NEWOBJECT(yloc->td[i].info))
+                                       panic("Branching backwards with uninitialized object in local variable");
+               }
+       }
+       
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               TYPECHECK_COUNT(stat_copied);
+               LOG1("block (index %04d) reached first time",destidx);
+               
+               typestack_copy(destblock->instack,ystack,yloc);
+               COPY_TYPEVECTORSET(yloc,destloc,locsize);
+               changed = true;
+       }
+       else {
+               /* The destblock has already been reached before */
+               
+               TYPECHECK_COUNT(stat_merged);
+               LOG1("block (index %04d) reached before",destidx);
+               
+               changed = typestate_merge(destblock->instack,destloc,
+                                                                 ystack,yloc,locsize,
+                                                                 jsrencountered);
+               TYPECHECK_COUNTIF(changed,stat_merging_changed);
+       }
+
+       if (changed) {
+               LOG("changed!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               if (destblock <= current) {LOG("REPEAT!"); return true;}
+       }
+       return false;
+}
+
+
+static bool
+typestate_ret(codegendata *cd,registerdata *rd, void *localbuf,
+                         basicblock *current,
+                         stackptr ystack,typevector *yloc,
+                         int retindex,int locsize)
+{
+       typevector *yvec;
+       typevector *selected;
+       basicblock *destblock;
+       bool repeat = false;
+
+       for (yvec=yloc; yvec; ) {
+               if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+                       panic("Illegal instruction: RET on non-returnAddress");
+
+               destblock = (basicblock*) TYPEINFO_RETURNADDRESS(yvec->td[retindex].info);
+
+               selected = typevectorset_select(&yvec,retindex,destblock);
+               
+               repeat |= typestate_reach(cd, rd,  localbuf,current,destblock,
+                                                                 ystack,selected,locsize,true);
+       }
+       return repeat;
+}
 
 /****************************************************************************/
-/* MACROS USED INTERNALLY IN typecheck()                                    */
+/* HELPER FUNCTIONS                                                         */
 /****************************************************************************/
 
-#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)
+/* If a field is checked, definingclass == implementingclass */
+static bool
+is_accessible(int flags,classinfo *definingclass,classinfo *implementingclass, classinfo *methodclass,
+                         typeinfo *instance)
+{
+       /* check access rights */
+       if (methodclass != definingclass) {
+               switch (flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)) {
+                 case ACC_PUBLIC:
+                         break;
+                         
+                         /* In the cases below, definingclass cannot be an interface */
+                         
+                 case 0:
+                         if (definingclass->packagename != methodclass->packagename)
+                                 return false;
+                         break;
+                 case ACC_PROTECTED:
+                         if (definingclass->packagename != methodclass->packagename) {
+                                 if (!builtin_isanysubclass(methodclass,implementingclass))
+                                         return false;
+                                 
+                                 /* For protected access of super class members in another
+                                  * package the instance must be a subclass of or the same
+                                  * as the current class. */
+                                 LOG("protected access into other package");
+                                 implementingclass = methodclass;
+                         }
+                         break;
+                 case ACC_PRIVATE:
+                         if (definingclass != methodclass) {
+                                 LOG("private access");
+                                 return false;
+                         }
+                         break;
+                 default:
+                         panic("Invalid access flags");
+               }
+       }
+
+       if (instance) {
+               if ((flags & ACC_STATIC) != 0) {
+                       LOG("accessing STATIC member with instance");
+                       return false;
+               }
+               
+               if (implementingclass
+                       && !TYPEINFO_IS_NULLTYPE(*instance)
+                       && !TYPEINFO_IS_NEWOBJECT(*instance))
+               {
+                       if (!typeinfo_is_assignable_to_classinfo(instance,
+                                                                                                        implementingclass))
+                       {
+                               LOG("instance not assignable");
+                               LOGINFO(instance);
+                               LOGSTRu(implementingclass->name); LOGNL; LOGFLUSH;
+                               return false;
+                       }
+               }
+       }
+       else {
+               if ((flags & ACC_STATIC) == 0) {
+                       LOG("accessing non-STATIC member without instance");
+                       return false;
+               }
+       }
+       
+       return true;
+}
 
-/* 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);}
+/****************************************************************************/
+/* MACROS FOR LOCAL VARIABLE CHECKING                                       */
+/****************************************************************************/
 
-#define CHECKVARTYPE(num,type)  \
-            {if (vtype[(num)] != (type)) panic("Variable type mismatch"); TOUCH_VARIABLE(num);}
+#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 STORE_ONEWORD(num,type)                                                                        \
+       do {typevectorset_store(localset,num,type,NULL);} while(0)
+
+#define STORE_TWOWORD(num,type)                                                                                \
+       do {typevectorset_store_twoword(localset,num,type);} while(0)
+
+
+#define WORDCHECKFAULT \
+       do { \
+               show_icmd_method(m, cd, rd); \
+               dolog("localset->td index: %ld\ninstruction belongs to:%s.%s, outermethod:%s.%s\n", \
+               iptr->op1,iptr->method->class->name->text, \
+                       iptr->method->name->text,m->class->name->text,m->name->text); \
+               show_icmd(iptr++, false); \
+               show_icmd(iptr, false); \
+       } while (0)
+
+
+#define CHECK_ONEWORD(num,tp)                                                                                  \
+       do {TYPECHECK_COUNT(stat_ins_primload);                                                         \
+               if (jsrencountered) {                                                                                   \
+                       if (!typevectorset_checktype(localset,num,tp)) {                                \
+                               WORDCHECKFAULT; \
+                               panic("Variable type mismatch");                                                \
+                       }       \
+               }                                                                                                                               \
+               else {                                                                                                                  \
+                       if (localset->td[num].type != tp) {                                                     \
+                               panic("Variable type mismatch");                                                \
+                               WORDCHECKFAULT; \
+                       } \
+               }                                                                                                                               \
+               } while(0)
+
+#define CHECK_TWOWORD(num,type)                                                                                        \
+       do {TYPECHECK_COUNT(stat_ins_primload);                                                         \
+               if (!typevectorset_checktype(localset,num,type)) {                \
+                       WORDCHECKFAULT; \
+                       panic("Variable type mismatch");                                \
+               } \
+       } while(0)
 
-/* XXX maybe it's faster to copy always */
-#define COPYTYPE(source,dest)   \
-            {if ((source)->type == TYPE_ADR) \
-                 TYPEINFO_COPY((source)->typeinfo,(dest)->typeinfo);}
+/****************************************************************************/
+/* MACROS FOR STACK TYPE CHECKING                                           */
+/****************************************************************************/
 
-#define ISBUILTIN(v)   (iptr->val.a == (functionptr)(v))
+/* These macros are for basic typechecks which were not done in stack.c */
 
-/* TYPECHECK_COPYVARS: copy the types and typeinfos of the current local
- *     variables to the local variables of the target block.
- * Input:
- *     vtype......current local variable types
- *     vinfo......current local variable typeinfos
- *     ttype......local variable types of target block
- *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
- * Used:
- *     macro_i
- */
-#define TYPECHECK_COPYVARS                                      \
-    do {                                                        \
-    LOG("TYPECHECK_COPYVARS");                                  \
-    for (macro_i=0; macro_i<maxlocals; ++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.
- * Input:
- *     vtype......current local variable types
- *     vinfo......current local variable typeinfos
- *     ttype......local variable types of target block
- *     tinfo......local variable typeinfos of target block
- *     maxlocals..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) {                     \
-        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;                                 \
-            changed = true;                                             \
-        } else if (ttype[macro_i] == TYPE_ADR) {                        \
-            if ( ((TYPEINFO_IS_PRIMITIVE(tinfo[macro_i])) ? 1 : 0)      \
-                 ^                                                      \
-                 ((TYPEINFO_IS_PRIMITIVE(vinfo[macro_i])) ? 1 : 0)) {   \
-                LOG1("var %d: primitive + reference merge",macro_i);    \
-                ttype[macro_i] = TYPE_VOID;                             \
-                changed = true;                                         \
-            }                                                           \
-            else {                                                      \
-                LOG1("var %d:",macro_i);                                \
-                LOGINFO(tinfo+macro_i);                                 \
-                LOGINFO(vinfo+macro_i);                                 \
-                changed |= typeinfo_merge(tinfo+macro_i,vinfo+macro_i); \
-                LOGINFO(tinfo+macro_i);                                 \
-                LOGIF(changed,"vars have changed");                     \
-            }                                                           \
-        };                                                              \
-    } } while (0)
-
-/* TYPECHECK_MERGEJSR:
- *
- * Input:
- * Ouput:
- *     tbptr......target block
- *     changed....set to true if any typeinfo has changed
- *     maxlocals..number of local variables
- *     touched....current touched flags of local variables
- * Used:
- *     macro_i, jsrtemp, jsrtemp2
- */
-#define TYPECHECK_MERGEJSR                                              \
-    do {                                                                \
-        LOG("TYPECHECK_MERGEJSR");                                      \
-    jsrtemp = jsrbuffer[tbptr-block];                                   \
-    jsrtemp2 = jsrchain;                                                \
-    while (jsrtemp || jsrtemp2) {                                       \
-        if (!jsrtemp || !jsrtemp2)                                      \
-            panic("Merging JSR subroutines of different depth");        \
-        if (jsrtemp->target != jsrtemp2->target)                        \
-            panic("Merging different JSR subroutines");                 \
-        jsrtemp = jsrtemp->next;                                        \
-        jsrtemp2 = jsrtemp2->next;                                      \
-    }                                                                   \
-    jsrtemp = jsrbuffer[tbptr-block];                                   \
-    if (jsrtemp)                                                        \
-        for (macro_i=0; macro_i<maxlocals; ++macro_i) {                 \
-            jsrtemp->touched[i] |= touched[i];                          \
-    } } while (0)
-
-/* TYPECHECK_COPYSTACK: copy the typeinfos of the current stack to
- *     the input stack of the target block.
- * Input:
- *     srcstack...current stack
- *     dststack...input stack of target block
- */
-#define TYPECHECK_COPYSTACK                                             \
-    do {                                                                \
-    LOG("TYPECHECK_COPYSTACK");                                         \
-    while (srcstack) {                                                  \
-        LOG1("copy %d",srcstack->type);                                 \
-        if (!dststack) panic("Stack depth mismatch");                   \
-        if (srcstack->type != dststack->type)                           \
-            panic("Type mismatch on stack");                            \
-        if (srcstack->type == TYPE_ADR) {                               \
-            TYPEINFO_CLONE(srcstack->typeinfo,dststack->typeinfo);      \
-        }                                                               \
-        dststack = dststack->prev;                                      \
-        srcstack = srcstack->prev;                                      \
-    }                                                                   \
-    if (dststack) panic("Stack depth mismatch");                        \
-    } while (0)
+#define TYPECHECK_STACK(sp,tp)                                                         \
+       do { if ((sp)->type != (tp))                                                    \
+                       panic("Wrong data type on stack"); } while(0)
 
-/* TYPECHECK_MERGESTACK: merge the input stack of the target block
- *     with the current stack.
- * Input:
- *     srcstack...current stack
- *     dststack...input stack of target block
- * Ouput:
- *     changed....set to true if any typeinfo has changed
- */
-#define TYPECHECK_MERGESTACK                                            \
-    do {                                                                \
-    LOG("TYPECHECK_MERGESTACK");                                        \
-    while (srcstack) {                                                  \
-        if (!dststack) panic("Stack depth mismatch");                   \
-        if (srcstack->type != dststack->type)                           \
-            panic("Type mismatch on stack");                            \
-        if (srcstack->type == TYPE_ADR) {                               \
-            LOGINFO(&dststack->typeinfo);                               \
-            LOGINFO(&srcstack->typeinfo);  LOGFLUSH;                    \
-            changed |= typeinfo_merge(&dststack->typeinfo,              \
-                                      &srcstack->typeinfo);             \
-            LOGINFO(&dststack->typeinfo);                               \
-            LOG((changed)?"CHANGED!\n":"not changed.\n");               \
-        }                                                               \
-        dststack = dststack->prev;                                      \
-        srcstack = srcstack->prev;                                      \
-    }                                                                   \
-    if (dststack) panic("Stack depth mismatch");                        \
-    } 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_CHECK_JSR_CHAIN: checks if the target block is reached by
- *     the same JSR targets on all control paths.
- *
- * Input:
- *     tbptr......target block
- *     jsrchain...current JSR target chain
- *     jsrbuffer..JSR target chain for each basic block
- * Output:
- *     panic if the JSR target chains don't match
- * Used:
- *     jsrtemp, jsrtemp2
- */
-#define TYPECHECK_CHECK_JSR_CHAIN                                       \
-    do {                                                                \
-    jsrtemp = jsrbuffer[tbptr-block];                                   \
-    if (!jsrtemp) panic("non-subroutine called by JSR");                \
-    if (jsrtemp->target != tbptr)                                       \
-        panic("Merging different JSR subroutines");                     \
-    jsrtemp = jsrtemp->next;                                            \
-    jsrtemp2 = jsrchain;                                                \
-    while (jsrtemp || jsrtemp2) {                                       \
-        if (!jsrtemp || !jsrtemp2)                                      \
-            panic("Merging JSR subroutines of different depth");        \
-        if (jsrtemp->target != jsrtemp2->target)                        \
-            panic("Merging different JSR subroutines");                 \
-        jsrtemp = jsrtemp->next;                                        \
-        jsrtemp2 = jsrtemp2->next;                                      \
-    } } while (0)
-
-/* TYPECHECK_ADD_JSR: add a JSR target to the current JSR target chain
- *     and store the resulting chain in the target block.
- *
- * Input:
- *     jsrchain...current JSR target chain
- *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
- *     jsrbuffer..JSR target chain for each basic block
- * Used:
- *     jsrtemp
- */
-#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->target = (tbptr);                                          \
-    jsrtemp->next = jsrchain;                                           \
-    jsrtemp->sbr_touched = NULL;                                        \
-    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals);          \
-    jsrbuffer[tbptr-block] = jsrtemp;                                   \
-    } while (0)
+/****************************************************************************/
+/* MISC MACROS                                                              */
+/****************************************************************************/
 
-/* TYPECHECK_COPYJSR: copy the current JSR chain to the target block.
- *
- * Input:
- *     chain......current JSR target chain
- *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
- *     jsrbuffer..JSR target chain for each basic block
- *     touched....current touched flags of local variables
- * Used:
- *     jsrtemp
- */
-#define TYPECHECK_COPYJSR(chain)                                        \
-    do {                                                                \
-        LOG("TYPECHECK_COPYJSR");                                       \
-        if (chain) {                                                    \
-            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
-            jsrtemp->target = (chain)->target;                          \
-            jsrtemp->next = (chain)->next;                              \
-            jsrtemp->sbr_touched = NULL;                                \
-            memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals);     \
-            jsrbuffer[tbptr-block] = jsrtemp;                           \
-        }                                                               \
-        else                                                            \
-            jsrbuffer[tbptr-block] = NULL;                              \
-    } while (0)
+#define COPYTYPE(source,dest)   \
+       {if ((source)->type == TYPE_ADR)                                                                \
+                       TYPEINFO_COPY((source)->typeinfo,(dest)->typeinfo);}
+
+#define ISBUILTIN(v)   (iptr->val.fp == (functionptr) (v))
 
 /* TYPECHECK_REACH: executed, when the target block (tbptr) can be reached
  *     from the current block (bptr). The types of local variables and
@@ -441,56 +765,39 @@ struct jsr_record {
  * Input:
  *     bptr.......current block
  *     tbptr......target block
- *     dst........current output stack pointer (not needed for REACH_THROW)
- *     vtype......current local variable types
- *     vinfo......current local variable typeinfos
- *     jsrchain...current JSR target chain
- *     jsrbuffer..JSR target chain for each basic block
- *     way........in which way the block is reached (REACH_ constant)
- *     touched....current touched flags of local variables
+ *     dst........current output stack pointer
+ *     numlocals..number of local variables
+ *     localset...current local variable vectorset
+ *     localbuf...local variable vectorset buffer
+ *     jsrencountered...true if a JSR has been seen
  * Output:
  *     repeat.....changed to true if a block before the current
  *                block has changed
- * Used:
- *     ttype, tinfo, srcstack, dststack, changed, macro_i
  */
-#define TYPECHECK_REACH(way)                                            \
+#define TYPECHECK_REACH                                                 \
     do {                                                                \
-    LOG2("reaching block %04d (%d)",tbptr-block,way);                   \
-    srcstack = dst;                                                     \
-    dststack = tbptr->instack;                                          \
-    ttype = vartype + maxlocals*(tbptr-block);                          \
-    tinfo = vartypeinfo + maxlocals*(tbptr-block);                      \
-    if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
-        /* This block is reached for the first time */                  \
-        if (way == REACH_JSR) {                                         \
-            TYPECHECK_ADD_JSR;                                          \
-            TYPECHECK_COPYVARS;                                         \
-        }                                                               \
-        else {                                                          \
-            TYPECHECK_COPYJSR(jsrchain);                                \
-            TYPECHECK_COPYVARS;                                         \
-        }                                                               \
-        if (way != REACH_THROW) TYPECHECK_COPYSTACK;                    \
-        changed = true;                                                 \
-    } else {                                                            \
-        /* This block has been reached before */                        \
-        changed = false;                                                \
-        if (way == REACH_JSR)                                           \
-            TYPECHECK_CHECK_JSR_CHAIN;                                  \
-        else                                                            \
-            TYPECHECK_MERGEJSR;                                         \
-        TYPECHECK_MERGEVARS;                                            \
-        if (way != REACH_THROW) TYPECHECK_MERGESTACK;                   \
-    }                                                                   \
-    if (changed) {                                                      \
-        LOG("REACHED!");                                                \
-        tbptr->flags = BBTYPECHECK_REACHED;                             \
-        if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");}        \
-    }                                                                   \
+    repeat |= typestate_reach(cd,rd, localbuf,bptr,tbptr,dst,               \
+                                                         localset,numlocals,jsrencountered);       \
     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
+ *     localset.....current local variable vectorset
+ *     initmethod...true if this is an <init> method
+ */
+#define TYPECHECK_LEAVE                                                 \
+    do {                                                                \
+        if (initmethod && m->class != class_java_lang_Object) {         \
+            /* check the marker variable */                             \
+            LOG("Checking <init> marker");                              \
+            if (!typevectorset_checktype(localset,numlocals-1,TYPE_INT))\
+                panic("<init> method does not initialize 'this'");      \
+        }                                                               \
+    } while (0)
+
 /****************************************************************************/
 /* typecheck()                                                              */
 /****************************************************************************/
@@ -498,45 +805,57 @@ struct jsr_record {
 #define MAXPARAMS 255
 
 /* typecheck is called directly after analyse_stack */
-void
-typecheck()
+
+methodinfo *typecheck(methodinfo *m, codegendata *cd, registerdata *rd)
 {
     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;                                      /* current opcode */
-    int macro_i, i;                              /* temporary counters */
+    int i;                                        /* temporary counter */
     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;                                    /* used in macros */
     instruction *iptr;               /* pointer to current instruction */
     basicblock *bptr;                /* pointer to current basic block */
     basicblock *tbptr;                   /* temporary for target block */
-    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 */
-    typeinfo *vinfo;     /* type of each local for current instruction */
-    u1 *ttype;                                    /* temporary pointer */
-    typeinfo *tinfo;                              /* temporary pointer */
-    typeinfo tempinfo;                                    /* temporary */
-    int returntype;                   /* return type of current method */
-    typeinfo returntypeinfo;               /* typeinfo for return type */
+       
+    int numlocals;                        /* number of local variables */
+       int validlocals;         /* number of valid local variable indices */
+       void *localbuf;       /* local variable types for each block start */
+       typevector *localset;        /* typevector set for local variables */
+       typevector *lset;                             /* temporary pointer */
+       typedescriptor *td;                           /* temporary pointer */
+
+       stackptr savedstackbuf = NULL;      /* buffer for saving the stack */
+       stackptr savedstack = NULL;      /* saved instack of current block */
+
+       stackelement excstack;           /* instack for exception handlers */
+                                                                                                         
+       typedescriptor returntype;        /* return type of current method */
     u1 *ptype;                     /* parameter types of called method */
     typeinfo *pinfo;           /* parameter typeinfos of called method */
     int rtype;                         /* return type of called method */
     typeinfo rinfo;       /* typeinfo for return type of called method */
+       
     stackptr dst;               /* output stack of current instruction */
-    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;              /* temporary variables */
-    jsr_record *subroutine;    /* jsr_record of the current subroutine */
-    u1 *touched;                  /* touched flags for local variables */
-    xtable **handlers;                    /* active exception handlers */
+    basicblock **tptr;    /* pointer into target list of switch instr. */
+    exceptiontable **handlers;            /* active exception handlers */
     classinfo *cls;                                       /* temporary */
     bool maythrow;               /* true if this instruction may throw */
+    static utf *name_init;                                 /* "<init>" */
+    bool initmethod;             /* true if this is an "<init>" method */
+       builtin_descriptor *builtindesc;    /* temp. descriptor of builtin */
+       bool jsrencountered = false;         /* true if we there was a JSR */
+
+    classinfo *myclass;
+
+#ifdef TYPECHECK_STATISTICS
+       int count_iterations = 0;
+       TYPECHECK_COUNT(stat_typechecked);
+       TYPECHECK_COUNT_FREQ(stat_locals,m->codegendata->maxlocals,STAT_LOCALS);
+       TYPECHECK_COUNT_FREQ(stat_blocks,m->basicblockcount/10,STAT_BLOCKS);
+#endif
 
     LOGSTR("\n==============================================================================\n");
     DOLOG(show_icmd_method());
@@ -548,16 +867,22 @@ typecheck()
     LOGimpSTR("    (class ");
     LOGimpSTRu(method->class->name);
     LOGimpSTR(")\n");
+       LOGFLUSH;
+
+       if (!name_init)
+               name_init = utf_new_char("<init>");
+    initmethod = (m->name == name_init);
 
-    /* XXX allocate buffers for method arguments */
+       /* Allocate buffer for method arguments */
+       
     ptype = DMNEW(u1,MAXPARAMS);
     pinfo = DMNEW(typeinfo,MAXPARAMS);
     
     LOG("Buffer allocated.\n");
 
     /* reset all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
-    b_count = block_count;
-    bptr = block;
+    b_count = m->basicblockcount;
+    bptr = m->basicblocks;
     while (--b_count >= 0) {
 #ifdef TYPECHECK_DEBUG
         if (bptr->flags != BBFINISHED && bptr->flags != BBDELETED
@@ -575,71 +900,81 @@ typecheck()
     }
 
     /* The first block is always reached */
-    if (block_count && block[0].flags == BBTYPECHECK_UNDEF)
-        block[0].flags = BBTYPECHECK_REACHED;
+    if (m->basicblockcount && m->basicblocks[0].flags == BBTYPECHECK_UNDEF)
+        m->basicblocks[0].flags = BBTYPECHECK_REACHED;
 
     LOG("Blocks reset.\n");
 
-    /* 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));
-
-    LOG("Variable buffer initialized.\n");
-
-    /* allocate the buffer for storing JSR target chains */
-    jsrbuffer = DMNEW(jsr_record*,block_count);
-    memset(jsrbuffer,0,block_count * sizeof(jsr_record*));
-    jsrchain = NULL;
+    /* number of local variables */
     
-    LOG("jsrbuffer initialized.\n");
+    /* In <init> methods we use an extra local variable to signal if
+     * the 'this' reference has been initialized. */
+    numlocals = cd->maxlocals;
+       validlocals = numlocals;
+    if (initmethod) numlocals++;
+
+    /* allocate the buffers for local variables */
+       localbuf = DMNEW_TYPEVECTOR(m->basicblockcount+1, numlocals);
+       localset = MGET_TYPEVECTOR(localbuf,m->basicblockcount,numlocals);
+
+    LOG("Variable buffer allocated.\n");
 
     /* allocate the buffer of active exception handlers */
-    handlers = DMNEW(xtable*,method->exceptiontablelength + 1);
+    handlers = DMNEW(exceptiontable*, cd->exceptiontablelength + 1);
 
     /* initialize the variable types of the first block */
     /* to the types of the arguments */
-    ttype = vartype;
-    tinfo = vartypeinfo;
+       lset = MGET_TYPEVECTOR(localbuf,0,numlocals);
+       lset->k = 0;
+       lset->alt = NULL;
+       td = lset->td;
+       i = validlocals;
 
     /* if this is an instance method initialize the "this" ref type */
-    if (!(method->flags & ACC_STATIC)) {
-        *ttype++ = TYPE_ADDRESS;
-        TYPEINFO_INIT_CLASSINFO(*tinfo,class);
-        tinfo++;
+    if (!(m->flags & ACC_STATIC)) {
+               if (!i)
+                       panic("Not enough local variables for method arguments");
+        td->type = TYPE_ADDRESS;
+        if (initmethod)
+            TYPEINFO_INIT_NEWOBJECT(td->info,NULL);
+        else
+            TYPEINFO_INIT_CLASSINFO(td->info, m->class);
+        td++;
+               i--;
     }
 
     LOG("'this' argument set.\n");
 
     /* the rest of the arguments and the return type */
-    typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
-                                   maxlocals - (tinfo-vartypeinfo),
-                                   true, /* two word types use two slots */
-                                   &returntype,&returntypeinfo);
+    i = typedescriptors_init_from_method_args(td, m->descriptor,
+                                                                                         i,
+                                                                                         true, /* two word types use two slots */
+                                                                                         &returntype);
+       td += i;
+       i = numlocals - (td - lset->td);
+       while (i--) {
+               td->type = TYPE_VOID;
+               td++;
+       }
 
     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);
-    }
+       excstack.prev = NULL;
+       excstack.type = TYPE_ADR;
+       TYPEINFO_INIT_CLASSINFO(excstack.typeinfo,
+                                                       class_java_lang_Throwable); /* changed later */
 
     LOG("Exception handler stacks set.\n");
 
     /* loop while there are still blocks to be checked */
     do {
+               TYPECHECK_COUNT(count_iterations);
 
         repeat = false;
         
-        b_count = block_count;
-        bptr = block;
+        b_count = m->basicblockcount;
+        bptr = m->basicblocks;
 
         while (--b_count >= 0) {
             LOGSTR1("---- BLOCK %04d, ",bptr-block);
@@ -652,66 +987,51 @@ typecheck()
                 
                 superblockend = false;
                 bptr->flags = BBFINISHED;
-                b_index = bptr - block;
+                b_index = bptr - m->basicblocks;
 
                 /* init stack at the start of this block */
                 curstack = bptr->instack;
                                        
-                /* 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]);
-                }
-
-                /* init JSR target chain */
-                if ((jsrchain = jsrbuffer[b_index]) != NULL) {
-#ifdef TYPECHECK_VERBOSE
-                    if (typecheckverbose) {
-                        LOGSTR("jsr chain:");
-                        jsrtemp = jsrchain;
-                        while (jsrtemp) {
-                            LOGSTR1(" L%03d",jsrtemp->target->debug_nr);
-                            jsrtemp = jsrtemp->next;
-                        }
-                        LOGNL;
-                        LOGFLUSH;
-                    }
-#endif
-
-                    subroutine = jsrbuffer[jsrchain->target - block];
-                    memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
-                }
-                else
-                    subroutine = NULL;
-#ifdef TYPECHECK_VERBOSE
-                if (typecheckverbose) {
-                    if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
-                    typeinfo_print_block(get_logfile(),curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
-                    LOGNL; LOGFLUSH;
-                }
-#endif
-
                 /* 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;
+                for (i = 0; i < cd->exceptiontablelength; ++i) {
+                    if ((cd->exceptiontable[i].start <= bptr) && (cd->exceptiontable[i].end > bptr)) {
+                        LOG1("active handler L%03d", cd->exceptiontable[i].handler->debug_nr);
+                        handlers[len++] = cd->exceptiontable + i;
                     }
                 }
                 handlers[len] = NULL;
                                        
+                /* init variable types at the start of this block */
+                               COPY_TYPEVECTORSET(MGET_TYPEVECTOR(localbuf,b_index,numlocals),
+                                                                  localset,numlocals);
+#if defined(__GNUC__)
+#warning FIXME FOR INLINING
+#endif
+               if(!useinlining) {
+                               if (handlers[0])
+                                       for (i=0; i<numlocals; ++i)
+                                               if (localset->td[i].type == TYPE_ADR
+                                                       && TYPEINFO_IS_NEWOBJECT(localset->td[i].info)) {
+                                                               show_icmd_method(m, cd, rd);
+                                                               printf("Uninitialized variale:%ld, block:%ld\n",i,bptr->debug_nr);
+                                                               panic("Uninitialized object in local variable inside try block");
+                                                       }
+               }
+                               DOLOG(typestate_print(get_logfile(),curstack,localset,numlocals));
+                               LOGNL; LOGFLUSH;
+
                 /* loop over the instructions */
                 len = bptr->icount;
                 iptr = bptr->iinstr;
                 while (--len >= 0)  {
-                    DOLOG(show_icmd(iptr,false));
-                    LOGNL;
-                    LOGFLUSH;
+                                       TYPECHECK_COUNT(stat_ins);
+                    DOLOG(show_icmd(iptr,false)); LOGNL; LOGFLUSH;
                         
                     opcode = iptr->opc;
+                   myclass = iptr->method->class;
                     dst = iptr->dst;
                     maythrow = false;
                                                
@@ -723,6 +1043,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;
@@ -767,33 +1093,68 @@ typecheck()
                           COPYTYPE(curstack->prev,dst);
                           break;
 
-                          /* XXX only add these cases in debug mode? */
-                      case ICMD_POP:
-                          break;
-                                                       
-                      case ICMD_POP2:
-                          break;
+                          /****************************************/
+
+
+
 
+
+
+
+
+
+                          /* PRIMITIVE VARIABLE ACCESS            */
+
+                      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_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;
+                          
                           /****************************************/
                           /* LOADING ADDRESS FROM VARIABLE        */
 
                       case ICMD_ALOAD:
-                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                                                 TYPECHECK_COUNT(stat_ins_aload);
                           
                           /* loading a returnAddress is not allowed */
-                          if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
-                              panic("illegal instruction: ALOAD loading returnAddress");
-
-                          TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+                                                 if (jsrencountered) {
+                                                         if (!typevectorset_checkreference(localset,iptr->op1))
+                                                                 panic("illegal instruction: ALOAD loading non-reference");
+
+                                                         typevectorset_copymergedtype(localset,iptr->op1,&(dst->typeinfo));
+                                                 }
+                                                 else {
+                                                         if (!TYPEDESC_IS_REFERENCE(localset->td[iptr->op1])) {
+                                                                 show_icmd_method(m, cd, rd);
+                                                                 dolog("localset->td index: %ld\ninstruction belongs to:%s.%s, outermethod:%s.%s\n",
+                                                                       iptr->op1,iptr->method->class->name->text,
+                                                                       iptr->method->name->text,m->class->name->text,m->name->text);
+                                                                 show_icmd(iptr, false);
+                                                                 panic("illegal instruction: ALOAD loading non-reference");
+                                                         }
+                                                         TYPEINFO_COPY(localset->td[iptr->op1].info,dst->typeinfo);
+                                                 }
                           break;
                                                        
                           /****************************************/
                           /* STORING ADDRESS TO VARIABLE          */
 
                       case ICMD_ASTORE:
-                          /* TYPE_ADR has already been checked. */
-                          STORE_TYPE(iptr->op1,TYPE_ADDRESS);
-                          TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+                          if (handlers[0] &&
+                              TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
+                              panic("Storing uninitialized object in local variable inside try block");
+
+                                                 if (TYPESTACK_IS_RETURNADDRESS(curstack))
+                                                         typevectorset_store_retaddr(localset,iptr->op1,&(curstack->typeinfo));
+                                                 else
+                                                         typevectorset_store(localset,iptr->op1,TYPE_ADDRESS,
+                                                                                                 &(curstack->typeinfo));
                           break;
                           
                           /****************************************/
@@ -807,44 +1168,73 @@ typecheck()
                           maythrow = true;
                           break;
                                                          
-                          /****************************************/
-                          /* STORING ADDRESS TO ARRAY             */
-
-                      case ICMD_AASTORE:
-                          /* XXX also handled by builtin3 */
-                          /* XXX move this to unexpected instructions? */
-                          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");
-                          */
-                          maythrow = true;
-                          break;
-
                           /****************************************/
                           /* FIELD ACCESS                         */
 
                       case ICMD_PUTFIELD:
+                                                 TYPECHECK_COUNT(stat_ins_field);
                           if (!TYPEINFO_IS_REFERENCE(curstack->prev->typeinfo))
                               panic("illegal instruction: PUTFIELD on non-reference");
-                          if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo)) /* XXX arraystub */
+                          if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo))
                               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_NEWOBJECT(curstack->prev->typeinfo)) {
+                                                                 if (initmethod
+                                                                         && !TYPEINFO_NEWOBJECT_INSTRUCTION(curstack->prev->typeinfo))
+                                                                 {
+                                                                         /* uninitialized "this" instance */
+                                                                         if (fi->class != m->class || (fi->flags & ACC_STATIC) != 0)
+                                                                                 panic("Setting unaccessible field in uninitialized object");
+                                                                 }
+                                                                 else {
+                                                                         panic("PUTFIELD on uninitialized object");
+                                                                 }
+                                                         }
+                                                         else {
+                                                                 if (!is_accessible(fi->flags,fi->class,fi->class, myclass,
+                                                                                                        &(curstack->prev->typeinfo)))
+                                                                         panic("PUTFIELD: field is not accessible");
+                                                         }
+
+                                                         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 */
-                          maythrow = true; /* XXX ? */
+                                                 TYPECHECK_COUNT(stat_ins_field);
+                          /* check if the value is assignable to the field */
+                                                 {
+                                                         fieldinfo *fi = (fieldinfo*) iptr[0].val.a;
+
+                                                         if (!is_accessible(fi->flags,fi->class,fi->class,myclass,NULL))
+                                                                 panic("PUTSTATIC: field is not accessible");
+
+                                                         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:
+                                                 TYPECHECK_COUNT(stat_ins_field);
                           if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
                               panic("illegal instruction: GETFIELD on non-reference");
                           if (TYPEINFO_IS_ARRAY(curstack->typeinfo))
@@ -852,43 +1242,51 @@ typecheck()
                           
                           {
                               fieldinfo *fi = (fieldinfo *)(iptr->val.a);
-                              /* XXX check non-static? */
+
+                                                         if (!is_accessible(fi->flags,fi->class,fi->class,myclass,
+                                                                                                &(curstack->typeinfo)))
+                                                                 panic("GETFIELD: field is not accessible");
+                                                         
                               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:
+                                                 TYPECHECK_COUNT(stat_ins_field);
                           {
                               fieldinfo *fi = (fieldinfo *)(iptr->val.a);
-                              /* XXX check static? */
+                                                         
+                                                         if (!is_accessible(fi->flags,fi->class,fi->class,myclass,NULL)) {
+                                                               printf("---------\n");
+                                                                 utf_display(fi->class->name);
+                                                               printf("\n");
+                                                                 utf_display(myclass->name);
+                                                               printf("\n");
+
+
+                                                                 panic("GETSTATIC: field is not accessible");
+                                                       }
+
                               if (dst->type == TYPE_ADR) {
                                   TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
                               }
-                              else {
-                                  /* XXX check field type? */
-                                  TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
-                              }
                           }
-                          /* XXX may throw? */
+                          maythrow = true;
                           break;
 
                           /****************************************/
                           /* PRIMITIVE ARRAY ACCESS               */
 
                       case ICMD_ARRAYLENGTH:
-                          /* XXX should this also work on arraystubs? */
-                          if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo))
+                          if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo)
+                                                         && curstack->typeinfo.typeclass != pseudo_class_Arraystub)
                               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))
@@ -963,37 +1361,69 @@ typecheck()
                           maythrow = true;
                           break;
 
+                      case ICMD_IASTORECONST:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo, ARRAYTYPE_INT))
+                              panic("Array type mismatch");
+                          maythrow = true;
+                          break;
+
+                      case ICMD_LASTORECONST:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo, ARRAYTYPE_LONG))
+                              panic("Array type mismatch");
+                          maythrow = true;
+                          break;
+
+                      case ICMD_BASTORECONST:
+                          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_CASTORECONST:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo, ARRAYTYPE_CHAR))
+                              panic("Array type mismatch");
+                          maythrow = true;
+                          break;
+
+                      case ICMD_SASTORECONST:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo, ARRAYTYPE_SHORT))
+                              panic("Array type mismatch");
+                          maythrow = true;
+                          break;
+
+
+                          /****************************************/
+                          /* ADDRESS CONSTANTS                    */
+
+                      case ICMD_ACONST:
+                          if (iptr->val.a == NULL)
+                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
+                          else
+                              /* string constants (or constant for builtin function) */
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
+                          break;
+
                           /****************************************/
-                          /* OPERATIONS WITH UNCHECKED INPUT      */
+                          /* CHECKCAST AND INSTANCEOF             */
 
                       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 may throw ? */
                           break;
                           
-                      case ICMD_ACONST:
-                          if (iptr->val.a == NULL)
-                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo)
-                          else
-                              /* XXX constants for builtin functions */
-                              /* string constants */
-                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
-                          break;
-
                           /****************************************/
                           /* BRANCH INSTRUCTIONS                  */
 
@@ -1028,30 +1458,32 @@ typecheck()
                       case ICMD_IF_LCMPGE:
                       case ICMD_IF_LCMPGT:
                       case ICMD_IF_LCMPLE:
+                                                 TYPECHECK_COUNT(stat_ins_branch);
                           tbptr = (basicblock *) iptr->target;
 
                           /* propagate stack and variables to the target block */
-                          TYPECHECK_REACH(REACH_STD);
-                          /* XXX */
+                          TYPECHECK_REACH;
                           break;
 
                           /****************************************/
                           /* SWITCHES                             */
                           
                       case ICMD_TABLESWITCH:
+                                                 TYPECHECK_COUNT(stat_ins_switch);
                           {
                               s4 *s4ptr = iptr->val.a;
-                              s4ptr++; /* skip default */
-                              i = *s4ptr++; /* low */
+                              s4ptr++;              /* skip default */
+                              i = *s4ptr++;         /* low */
                               i = *s4ptr++ - i + 2; /* +1 for default target */
                           }
                           goto switch_instruction_tail;
                           
                       case ICMD_LOOKUPSWITCH:
+                                                 TYPECHECK_COUNT(stat_ins_switch);
                           {
                               s4 *s4ptr = iptr->val.a;
-                              s4ptr++; /* skip default */
-                              i = *s4ptr++ + 1; /* count +1 for default target */
+                              s4ptr++;              /* skip default */
+                              i = *s4ptr++ + 1;     /* count +1 for default */
                           }
                     switch_instruction_tail:
                           tptr = (basicblock **)iptr->target;
@@ -1059,7 +1491,7 @@ typecheck()
                           while (--i >= 0) {
                               tbptr = *tptr++;
                               LOG2("target %d is block %04d",(tptr-(basicblock **)iptr->target)-1,tbptr-block);
-                              TYPECHECK_REACH(REACH_STD);
+                              TYPECHECK_REACH;
                           }
                           LOG("switch done");
                           superblockend = true;
@@ -1069,8 +1501,8 @@ typecheck()
                           /* RETURNS AND THROW                    */
 
                       case ICMD_ATHROW:
-                          TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
-                          if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                          if (!typeinfo_is_assignable_to_classinfo(
+                                   &curstack->typeinfo,class_java_lang_Throwable))
                               panic("illegal instruction: ATHROW on non-Throwable");
                           superblockend = true;
                           maythrow = true;
@@ -1080,37 +1512,33 @@ typecheck()
                           if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
                               panic("illegal instruction: ARETURN on non-reference");
 
-                          if (returntype != TYPE_ADDRESS
-                              || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+                          if (returntype.type != TYPE_ADDRESS
+                              || !typeinfo_is_assignable(&curstack->typeinfo,&(returntype.info)))
                               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 != 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 != 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 != 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 != TYPE_DOUBLE) panic("Return type mismatch");
+                                                 goto return_tail;
+                                                 
                       case ICMD_RETURN:
-                          if (returntype != TYPE_VOID)
-                              panic("Return type mismatch");
+                          if (returntype.type != TYPE_VOID) panic("Return type mismatch");
+                                         return_tail:
+                          TYPECHECK_LEAVE;
                           superblockend = true;
+                          maythrow = true;
                           break;
                                                     
                           /****************************************/
@@ -1118,112 +1546,32 @@ typecheck()
 
                       case ICMD_JSR:
                           LOG("jsr");
+                                                 jsrencountered = true;
 
-                          /* XXX This is a dirty hack. It is needed
-                           * because of the special handling of ICMD_JSR in stack.c
+                          /* This is a dirty hack. It is needed
+                           * because of the special handling of
+                           * ICMD_JSR in stack.c
                            */
                           dst = (stackptr) iptr->val.a;
                           
-                          /* push return address */
-                          TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
-
-                          LOG("reaching block...");
-                          
-                          /* add the target to the JSR target chain and */
-                          /* propagate stack and variables to the target block */
                           tbptr = (basicblock *) iptr->target;
-                          TYPECHECK_REACH(REACH_JSR);
-
-                          /* set dst to the stack after the subroutine execution */
-                          /* XXX We assume (as in stack.c) that the
-                           * subroutine returns the stack as it was
-                           * before the JSR instruction. Is this
-                           * correct?
-                           */
-                          dst = iptr->dst;
-
-                          /* Find the jsr_record of the called subroutine */
-                          jsrtemp = jsrbuffer[tbptr - block];
-
-                          /* Check if we already calculated (at least
-                           * for one RET) which variables the
-                           * subroutine touches.
-                           */
-                          if (jsrtemp->sbr_touched) {
-                              /* Calculate the local variables after the subroutine call */
-                              for (i=0; i<maxlocals; ++i)
-                                  if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
-                                      TOUCH_VARIABLE(i);
-                                      if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
-                                          TYPEINFO_CLONE(jsrtemp->sbr_vinfo[i],vinfo[i]);
-                                  }
+                                                 if (bptr + 1 == (m->basicblocks + m->basicblockcount + 1))
+                                                         panic("Illegal instruction: JSR at end of bytecode");
+                                                 typestack_put_retaddr(dst,bptr+1,localset);
+                                                 repeat |= typestate_reach(cd, rd,localbuf,bptr,tbptr,dst,
+                                                                                                       localset,numlocals,true);
 
-                              /* continue after the JSR call */
-                              superblockend = false;
-                          }
-                          else {
-                              /* We cannot proceed until the subroutine has been typechecked. */
-                              /* XXX actually we would not have to check this block again */
-                              bptr->flags = BBTYPECHECK_REACHED;
-                              repeat = true;
-                              superblockend = true;
-                          }
-                          /* XXX may throw? */
+                                                 superblockend = true;
                           break;
                           
                       case ICMD_RET:
                           /* check returnAddress variable */
-                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
-                          
-                          if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                                                 if (!typevectorset_checkretaddr(localset,iptr->op1))
                               panic("illegal instruction: RET using non-returnAddress variable");
 
-                          /* check if we are inside a subroutine */
-                          if (!subroutine)
-                              panic("RET outside of subroutine");
-
-                          /* determine which variables are touched by this subroutine */
-                          /* and their types */
-                          if (subroutine->sbr_touched) {
-                              for (i=0; i<maxlocals; ++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)
-                                  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(get_logfile(),subroutine->sbr_vtype,subroutine->sbr_vinfo,
-                                                      subroutine->sbr_touched,maxlocals));
-                          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;
-                              LOG("ends with JSR");
-                              if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != subroutine->target)
-                                  continue;
-                              tbptr++;
-
-                              LOG1("RET reaches block %04d",tbptr-block);
-
-                              /*TYPECHECK_REACH(REACH_RET);*/
-                          }
-                          
+                                                 repeat |= typestate_ret(cd,rd, localbuf,bptr,curstack,
+                                                                                                 localset,iptr->op1,numlocals);
+
                           superblockend = true;
                           break;
                                                          
@@ -1234,15 +1582,28 @@ typecheck()
                       case ICMD_INVOKESPECIAL:
                       case ICMD_INVOKESTATIC:
                       case ICMD_INVOKEINTERFACE:
+                                                 TYPECHECK_COUNT(stat_ins_invoke);
                           {
-                              /* XXX check access rights */
-                              
                               methodinfo *mi = (methodinfo*) iptr->val.a;
-
-                              /* XXX for INVOKESPECIAL: check if the invokation is done at all */
+                                                         bool specialmethod = (mi->name->text[0] == '<');
+                              bool callinginit = (opcode == ICMD_INVOKESPECIAL && mi->name == name_init);
+                              instruction *ins;
+                              classinfo *initclass;
+
+                                                         if (specialmethod && !callinginit)
+                                                                 panic("Invalid invocation of special method");
+
+                                                         if (opcode == ICMD_INVOKESPECIAL) {
+                                                                 /* XXX for INVOKESPECIAL: check if the invokation is done at all */
+                                                                 
+                                                                 /* (If callinginit the class is checked later.) */
+                                                                 if (!callinginit) { 
+                                                                         if (!builtin_isanysubclass(myclass,mi->class)) 
+                                                                                 panic("Illegal instruction: INVOKESPECIAL calling non-superclass method"); 
+                                                                 } 
+                                                         }
 
                               /* fetch parameter types and return type */
-                              /* XXX might use dst->typeinfo directly if non void */
                               i = 0;
                               if (opcode != ICMD_INVOKESTATIC) {
                                   ptype[0] = TYPE_ADR;
@@ -1263,170 +1624,365 @@ typecheck()
                                   if (srcstack->type == TYPE_ADR) {
                                       LOGINFO(&(srcstack->typeinfo));
                                       LOGINFO(pinfo + i);
-                                      if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
-                                          panic("Parameter reference type mismatch in method invocation");
+                                      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 : m->class;
+                                          LOGSTR("class: "); LOGSTRu(initclass->name); LOGNL;
+
+                                                                                 /* check type */
+                                                                                 /* (This is checked below.) */
+/*                                                                               TYPEINFO_INIT_CLASSINFO(tempinfo,initclass); */
+/*                                           if (!typeinfo_is_assignable(&tempinfo,pinfo+0)) */
+/*                                               panic("Parameter reference type mismatch in <init> invocation"); */
+                                      }
+                                      else {
+                                          if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
+                                              panic("Parameter reference type mismatch in method invocation");
+                                      }
                                   }
                                   LOG("ok");
 
-                                  srcstack = srcstack->prev;
+                                  if (i) srcstack = srcstack->prev;
                               }
 
+                                                         /* XXX We should resolve the method and pass its
+                                                          * class as implementingclass to is_accessible. */
+                                                         if (!is_accessible(mi->flags,mi->class,NULL, myclass,
+                                                                                                (opcode == ICMD_INVOKESTATIC) ? NULL
+                                                                                                : &(srcstack->typeinfo)))
+                                                                 panic("Invoking unaccessible method");
+
+                                                         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");
+
+                                                                                 /* If this stackslot is in the instack of
+                                                                                  * this basic block we must save the type(s)
+                                                                                  * we are going to replace.
+                                                                                  */
+                                                                                 if (srcstack <= bptr->instack && !savedstack)
+                                                                                 {
+                                                                                         stackptr sp;
+                                                                                         stackptr copy;
+                                                                                         LOG("saving input stack types");
+                                                                                         if (!savedstackbuf) {
+                                                                                                 LOG("allocating savedstack buffer");
+                                                                                                 savedstackbuf = DMNEW(stackelement, cd->maxstack);
+                                                                                                 savedstackbuf->prev = NULL;
+                                                                                                 for (i = 1; i < cd->maxstack; ++i)
+                                                                                                         savedstackbuf[i].prev = savedstackbuf+(i-1);
+                                                                                         }
+                                                                                         sp = savedstack = bptr->instack;
+                                                                                         copy = bptr->instack = savedstackbuf + (bptr->indepth-1);
+                                                                                         TYPESTACK_COPY(sp,copy);
+                                                                                 }
+                                                                                 
+                                          TYPEINFO_INIT_CLASSINFO(srcstack->typeinfo,initclass);
+                                      }
+                                      srcstack = srcstack->prev;
+                                  }
+                                  /* replace uninitialized object type in locals */
+                                                                 typevectorset_init_object(localset,ins,initclass,numlocals);
+
+                                  /* initializing the 'this' reference? */
+                                  if (!ins) {
+#ifdef TYPECHECK_DEBUG
+                                                                         if (!initmethod)
+                                                                                 panic("Internal error: calling <init> on this in non-<init> method.");
+#endif
+                                                                         /* must be <init> of current class or direct superclass */
+                                                                         if (mi->class != m->class && mi->class != m->class->super)
+                                                                                 panic("<init> calling <init> of the wrong class");
+                                                                         
+                                      /* set our marker variable to type int */
+                                      LOG("setting <init> marker");
+                                                                         typevectorset_store(localset,numlocals-1,TYPE_INT,NULL);
+                                  }
+                                                                 else {
+                                                                         /* initializing an instance created with NEW */
+                                                                         /* XXX is this strictness ok? */
+                                                                         if (mi->class != initclass)
+                                                                                 panic("Calling <init> method of the wrong class");
+                                                                 }
+                              }
                           }
                           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_t *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_t*) 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 */
+                                                 TYPECHECK_COUNT(stat_ins_builtin);
+                          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");
-
-                              /* XXX optimize */
-                              /*
-                                typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
-                                if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
-                                panic("illegal instruction: AASTORE to incompatible type");
-                              */
                           }
-                          /* XXX check for missed builtins in debug mode? */
-                          maythrow = true; /* XXX better safe than sorry */
+                                                 else {
+                                                         /* XXX put these checks in a function */
+                                                         TYPECHECK_COUNT(stat_ins_builtin_gen);
+                                                         builtindesc = builtin_desc;
+                                                         while (builtindesc->opcode && builtindesc->builtin
+                                                                        != iptr->val.fp) builtindesc++;
+                                                         if (!builtindesc->opcode) {
+                                                                 dolog("Builtin not in table: %s",icmd_builtin_name(iptr->val.fp));
+                                                                 panic("Internal error: builtin not found in table");
+                                                         }
+                                                         TYPECHECK_ARGS3(builtindesc->type_s3,builtindesc->type_s2,builtindesc->type_s1);
+                                                 }
+                          maythrow = true;
                           break;
                           
                       case ICMD_BUILTIN2:
-                          if (
-#if defined(__I386__)
-                              ISBUILTIN(asm_builtin_newarray)
-#else
-                              ISBUILTIN(builtin_newarray)
-#endif
-                              )
+                                                 TYPECHECK_COUNT(stat_ins_builtin);
+                          if (ISBUILTIN(BUILTIN_newarray))
                           {
+                                                         vftbl_t *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_t *)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_t *vft;
+                                                         TYPECHECK_ADR(curstack->prev);
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: builtin_arrayinstanceof without classinfo");
+                                                         vft = (vftbl_t *)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_t *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_t *)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? */
-                          maythrow = true; /* XXX better safe than sorry */
+                                                 else {
+                                                         TYPECHECK_COUNT(stat_ins_builtin_gen);
+                                                         builtindesc = builtin_desc;
+                                                         while (builtindesc->opcode && builtindesc->builtin
+                                                                        != iptr->val.fp) builtindesc++;
+                                                         if (!builtindesc->opcode) {
+                                                                 dolog("Builtin not in table: %s",icmd_builtin_name(iptr->val.fp));
+                                                                 panic("Internal error: builtin not found in table");
+                                                         }
+                                                         TYPECHECK_ARGS2(builtindesc->type_s2,builtindesc->type_s1);
+                                                 }
+                          maythrow = true;
                           break;
                           
                       case ICMD_BUILTIN1:
-                          if (ISBUILTIN(builtin_new)) {
+                                                 TYPECHECK_COUNT(stat_ins_builtin);
+                          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);
+                                                         cls = (classinfo *) iptr[-1].val.a;
+                                                         if (!cls->linked)
+                                                                 panic("Internal error: NEW with unlinked class");
+                                                         /* The following check also forbids array classes and interfaces: */
+                                                         if ((cls->flags & ACC_ABSTRACT) != 0)
+                                                                 panic("Invalid instruction: NEW creating instance of abstract class");
+                              TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
                           }
-                          else if (ISBUILTIN(builtin_newarray_boolean)) {
+                          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? */
-                          maythrow = true; /* XXX better safe than sorry */
+                                                 else {
+                                                         TYPECHECK_COUNT(stat_ins_builtin_gen);
+                                                         builtindesc = builtin_desc;
+                                                         while (builtindesc->opcode && builtindesc->builtin
+                                                                        != iptr->val.fp) builtindesc++;
+                                                         if (!builtindesc->opcode) {
+                                                                 dolog("Builtin not in table: %s",icmd_builtin_name(iptr->val.fp));
+                                                                 panic("Internal error: builtin not found in table");
+                                                         }
+                                                         TYPECHECK_ARGS1(builtindesc->type_s1);
+                                                 }
+                          maythrow = true;
                           break;
                                                      
                           /****************************************/
-                          /* PRIMITIVE VARIABLE ACCESS            */
+                          /* SIMPLE EXCEPTION THROWING TESTS      */
+
+                      case ICMD_CHECKASIZE:
+                                                 /* The argument to CHECKASIZE is typechecked by
+                                                  * typechecking the array creation instructions. */
+
+                                                 /* FALLTHROUGH! */
+                      case ICMD_NULLCHECKPOP:
+                                                 /* NULLCHECKPOP just requires that the stack top
+                                                  * is an address. This is checked in stack.c */
+                                                 
+                          maythrow = true;
+                          break;
 
-                      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_FSTORE: STORE_PRIMITIVE(iptr->op1,TYPE_FLOAT); break;
-                      case ICMD_ISTORE: STORE_PRIMITIVE(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;
-                          
                           /****************************************/
                           /* INSTRUCTIONS WHICH SHOULD HAVE BEEN  */
-                          /* REPLACED BY BUILTIN CALLS            */
+                          /* REPLACED BY OTHER OPCODES            */
 
+#ifdef TYPECHECK_DEBUG
                       case ICMD_NEW:
                       case ICMD_NEWARRAY:
                       case ICMD_ANEWARRAY:
                       case ICMD_MONITORENTER:
                       case ICMD_MONITOREXIT:
-                          /* XXX only check this in debug mode? */
-                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                      case ICMD_AASTORE:
+                          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;
                                                      
+                      case ICMD_READONLY_ARG:
+                      case ICMD_CLEAR_ARGREN:
+                          LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                                                 LOG("Should have been replaced in stack.c.");
+                          panic("Internal error: unexpected pseudo instruction encountered");
+                          break;
+#endif
+                                                 
                           /****************************************/
                           /* UNCHECKED OPERATIONS                 */
 
-                          /* These ops have no input or output to be checked */
-                          /* (apart from the checks done in analyse_stack).  */
-                                                /* XXX only add cases for them in debug mode? */
-
-                      case ICMD_NOP:
-                      case ICMD_READONLY_ARG: /* XXX ? */
-                      case ICMD_CLEAR_ARGREN: /* XXX ? */
-                          break;
-
-                      case ICMD_CHECKASIZE:
-                      case ICMD_NULLCHECKPOP:
+                                                 /*********************************************
+                                                  * Instructions below...
+                                                  *     *) don't operate on local variables,
+                                                  *     *) don't operate on references,
+                                                  *     *) don't operate on returnAddresses.
+                                                  *
+                                                  * (These instructions are typechecked in
+                                                  *  analyse_stack.)
+                                                  ********************************************/
+
+                          /* Instructions which may throw a runtime exception: */
+                          
+                      case ICMD_IDIV:
+                      case ICMD_IREM:
+                      case ICMD_LDIV:
+                      case ICMD_LREM:
+                          
                           maythrow = true;
                           break;
+                          
+                          /* Instructions which never throw a runtime exception: */
+#if defined(TYPECHECK_DEBUG) || defined(TYPECHECK_STATISTICS)
+                      case ICMD_NOP:
+                      case ICMD_POP:
+                      case ICMD_POP2:
 
-                          /****************************************/
-                          /* ARITHMETIC AND CONVERSION            */
+                      case ICMD_ICONST:
+                      case ICMD_LCONST:
+                      case ICMD_FCONST:
+                      case ICMD_DCONST:
 
-                          /* These instructions are typechecked in analyse_stack. */
-                                                /* XXX only add cases for them in debug mode? */
+                      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:
@@ -1437,8 +1993,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:
@@ -1471,6 +2025,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:
@@ -1491,46 +2061,16 @@ 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:
-
-                          maythrow = true; /* XXX be more selective here */
-                          break;
-                          
-                      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:
-
+                                                 TYPECHECK_COUNT(stat_ins_unchecked);
                           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");
-                    }
+#endif
+                                       }
 
                     /* the output of this instruction becomes the current stack */
                     curstack = dst;
@@ -1540,18 +2080,25 @@ typecheck()
                         LOG("reaching exception handlers");
                         i = 0;
                         while (handlers[i]) {
-                            tbptr = handlers[i]->handler;
-                            TYPECHECK_REACH(REACH_THROW); /* XXX jsr chain? */
+                                                       TYPECHECK_COUNT(stat_handlers_reached);
+                                                       cls = handlers[i]->catchtype;
+                                                       excstack.typeinfo.typeclass = (cls) ? cls
+                                                               : class_java_lang_Throwable;
+                                                       repeat |= typestate_reach(cd,rd, localbuf,bptr,
+                                                                                                         handlers[i]->handler,
+                                                                                                         &excstack,localset,
+                                                                                                         numlocals,
+                                                                                                         jsrencountered);
                             i++;
                         }
                     }
-                    
+
                     iptr++;
                 } /* while instructions */
 
                 LOG("instructions done");
                 LOGSTR("RESULT=> ");
-                DOLOG(typeinfo_print_block(get_logfile(),curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+                DOLOG(typestate_print(get_logfile(),curstack,localset,numlocals));
                 LOGNL; LOGFLUSH;
                 
                 /* propagate stack and variables to the following block */
@@ -1561,31 +2108,82 @@ typecheck()
                     while (tbptr->flags == BBDELETED) {
                         tbptr++;
 #ifdef TYPECHECK_DEBUG
-                        if ((tbptr-block) >= block_count)
+                        if ((tbptr-block) >= m->basicblockcount)
                             panic("Control flow falls off the last block");
 #endif
                     }
-                    TYPECHECK_REACH(REACH_STD);
+                    TYPECHECK_REACH;
                 }
+
+                               /* We may have to restore the types of the instack slots. They
+                                * have been saved if an <init> call inside the block has
+                                * modified the instack types. (see INVOKESPECIAL) */
+                               
+                               if (savedstack) {
+                                       stackptr sp = bptr->instack;
+                                       stackptr copy = savedstack;
+                                       TYPECHECK_COUNT(stat_savedstack);
+                                       LOG("restoring saved instack");
+                                       TYPESTACK_COPY(sp,copy);
+                                       bptr->instack = savedstack;
+                                       savedstack = NULL;
+                               }
                 
             } /* if block has to be checked */
             bptr++;
         } /* while blocks */
-        
+
         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);
+       TYPECHECK_COUNT_FREQ(stat_iterations,count_iterations,STAT_ITERATIONS);
+       TYPECHECK_COUNTIF(jsrencountered,stat_typechecked_jsr);
+#endif
 
+#ifdef TYPECHECK_DEBUG
+       for (i=0; i<m->basicblockcount; ++i) {
+               if (m->basicblocks[i].flags != BBDELETED
+                       && m->basicblocks[i].flags != BBUNDEF
+                       && m->basicblocks[i].flags != BBFINISHED
+                       && m->basicblocks[i].flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
+                                                                                                        * some exception handlers,
+                                                                                                        * that's ok. */
+               {
+                       LOG2("block L%03d has invalid flags after typecheck: %d",
+                                m->basicblocks[i].debug_nr,m->basicblocks[i].flags);
+                       panic("Invalid block flags after typecheck");
+               }
+       }
+#endif
+       
+       /* Reset blocks we never reached */
+       for (i=0; i<m->basicblockcount; ++i) {
+               if (m->basicblocks[i].flags == BBTYPECHECK_UNDEF)
+                       m->basicblocks[i].flags = BBFINISHED;
+       }
+               
     LOGimp("exiting typecheck");
+
+       /* just return methodinfo* to signal everything was ok */
+
+       return m;
 }
 
 #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:
+ */