* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / vm / jit / verify / typecheck.c
index c9e0bd2208ec537ec2815d1dc4d20cb17a3885ce..5d21065fb217f3bfebe1e580b310c638c8ad20d1 100644 (file)
@@ -1,9 +1,9 @@
 /* src/vm/jit/verify/typecheck.c - typechecking (part of bytecode verification)
 
-   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
+   Copyright (C) 1996-2005, 2006 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.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   Contact: cacao@cacaojvm.org
 
    Authors: Edwin Steiner
 
    Changes: Christian Thalinger
 
-   $Id: typecheck.c 3333 2005-10-04 18:55:12Z twisti $
+   $Id: typecheck.c 4357 2006-01-22 23:33:38Z twisti $
 
 */
 
+/*
+
+What's the purpose of the `typechecker`?
+----------------------------------------
+
+The typechecker analyses (the intermediate repr. of) the bytecode of
+each method and ensures that for each instruction the values on the
+stack and in local variables are of the correct type whenever the
+instruction is executed.
+
+type checking is a mandatory part of bytecode verification.
+
+
+How does the typechecker work?
+------------------------------
+
+The JVM stack and the local variables are not statically typed, so the
+typechecker has to *infer* the static types of stack slots and local
+variables at each point of the method. The JVM spec imposes a lot of
+restrictions on the bytecode in order to guarantee that this is always
+possible.
+
+Basically the typechecker solves the data flow equations of the method.
+This is done in the usual way for a forward data flow analysis: Starting
+from the entry point of the method the typechecker follows the CFG and
+records the type of each stack slot and local variable at each point[1].
+When two or more control flow paths merge at a point, the union of the
+types for each slot/variable is taken. The algorithm continues to follow
+all possible paths[2] until the recorded types do not change anymore (ie.
+the equations have been solved).
+
+If the solution has been reached and the resulting types are valid for
+all instructions, then type checking terminates with success, otherwise
+an exception is thrown.
+
+
+Why is this code so damn complicated?
+-------------------------------------
+
+Short answer: The devil's in the details.
+
+While the basic operation of the typechecker is no big deal, there are
+many properties of Java bytecode which make type checking hard. Some of
+them are not even addressed in the JVM spec. Some problems and their
+solutions:
+
+*) Finding a good representation of the union of two reference types is
+difficult because of multiple inheritance of interfaces. 
+
+       Solution: The typeinfo system can represent such "merged" types by a
+       list of proper subclasses of a class. Example:
+
+               typeclass=java.lang.Object merged={ InterfaceA, InterfaceB }
+       
+       represents the result of merging two interface types "InterfaceA"
+       and "InterfaceB".
+
+*) When the code of a method is verified, there may still be unresolved
+references to classes/methods/fields in the code, which we may not force
+to be resolved eagerly. (A similar problem arises because of the special
+checks for protected members.)
+
+       Solution: The typeinfo system knows how to deal with unresolved
+       class references. Whenever a check has to be performed for an
+       unresolved type, the type is annotated with constraints representing
+       the check. Later, when the type is resolved, the constraints are
+       checked. (See the constrain_unresolved_... and the resolve_...
+       methods.)[3]
+
+*) The boundaries of jsr subroutines are not well-defined. For a given
+instruction it may be impossible to tell whether it is part of a
+subroutine, or to which subroutine it belongs.
+
+       Solution: The typechecker implements a method developed by
+       Alessandro Coglio[4] which treats each returnAddress as a distinct
+       type that is not merged with other returnAddresses. This way, when a
+       RET instruction is reached, we know exactly which types to propagate
+       to which return target among the possible targets of the RET. The
+       downside of this method is, that for each slot/variable we must
+       store not just one type, but one type *for each possible use of the
+       returnAddresses* that currently are in a slot/variable.[5]
+
+*) Checks for uninitialized object instances are hard because after the
+invocation of <init> on an uninitialized object *all* slots/variables
+referring to this object (and exactly those slots/variables) must be
+marked as initialized.
+
+       Solution: The JVM spec describes a solution, which has been
+       implemented in this typechecker.
+
+
+--- Footnotes
+
+[1] Actually only the types of slots/variables at the start of each
+basic block are remembered. Within a basic block the algorithm only keeps
+the types of the slots/variables for the "current" instruction which is
+being analysed. 
+
+[2] Actually the algorithm iterates through the basic block list until
+there are no more changes. Theoretically it would be wise to sort the
+basic blocks topologically beforehand, but the number of average/max
+iterations observed is so low, that this was not deemed necessary.
+
+[3] This is similar to a method proposed by: Alessandro Coglio et al., A
+Formal Specification of Java Class Loading, Technical Report, Kestrel
+Institute April 2000, revised July 2000 
+http://www.kestrel.edu/home/people/coglio/loading.pdf
+An important difference is that Coglio's subtype constraints are checked
+after loading, while our constraints are checked when the field/method
+is accessed for the first time, so we can guarantee lexically correct
+error reporting.
+
+[4] Alessandro Coglio, Simple Verification Technique for Complex Java
+Bytecode Subroutines, 4th ECOOP Workshop on Formal Techniques for
+Java-like Programs, June 2002
+http://www.kestrel.edu/home/people/coglio/ftjp02.pdf
+
+[5] This is a major source of code complexity. The main data structures
+dealing with this are the "typevector set" and the typestack. The
+"typevector set" is a set of alternative typevectors, such that each
+typevector specifies the types of the local variables for a single
+combination of returnAddresses used. Thus we support full polymorphism
+of subroutines over the types of local variables. The typestack,
+however, does not support polymorphism, both for historical and JVM-spec
+reasons. A slot of the typestack may, however, contain multiple
+alternative returnAddresses, which is realized by a linked list hanging
+of the typeinfo of the stack slot.
+
+*/
 
 #include <assert.h>
 #include <string.h>
 
+#include "config.h"
 #include "vm/types.h"
+#include "vm/global.h"
 
-#include "vm/global.h" /* must be here because of CACAO_TYPECHECK */
-
-#ifdef CACAO_TYPECHECK
+#ifdef ENABLE_VERIFIER
 
 #include "mm/memory.h"
 #include "toolbox/logging.h"
 #include "vm/jit/patcher.h"
 #include "vm/loader.h"
 #include "vm/options.h"
-#include "vm/tables.h"
 #include "vm/jit/jit.h"
 #include "vm/jit/stack.h"
 #include "vm/access.h"
@@ -166,6 +294,8 @@ typestate_print(FILE *file,stackptr instack,typevector *localset,int size)
 
 static int stat_typechecked = 0;
 static int stat_typechecked_jsr = 0;
+static int stat_methods_with_handlers = 0;
+static int stat_methods_maythrow = 0;
 static int stat_iterations[STAT_ITERATIONS+1] = { 0 };
 static int stat_reached = 0;
 static int stat_copied = 0;
@@ -175,18 +305,29 @@ 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_maythrow = 0;
+static int stat_ins_stack = 0;
 static int stat_ins_field = 0;
+static int stat_ins_field_unresolved = 0;
+static int stat_ins_field_uninitialized = 0;
 static int stat_ins_invoke = 0;
+static int stat_ins_invoke_unresolved = 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_primitive_return = 0;
+static int stat_ins_areturn = 0;
+static int stat_ins_areturn_unresolved = 0;
+static int stat_ins_athrow = 0;
+static int stat_ins_athrow_unresolved = 0;
 static int stat_ins_unchecked = 0;
 static int stat_handlers_reached = 0;
 static int stat_savedstack = 0;
 
+#define TYPECHECK_MARK(var)   ((var) = true)
 #define TYPECHECK_COUNT(cnt)  (cnt)++
 #define TYPECHECK_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
 #define TYPECHECK_COUNT_FREQ(array,val,limit) \
@@ -205,7 +346,9 @@ static void print_freq(FILE *file,int *array,int limit)
 
 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,"    with JSR       : %8d\n",stat_typechecked_jsr);
+       fprintf(file,"    with handler(s): %8d\n",stat_methods_with_handlers);
+       fprintf(file,"    with throw(s)  : %8d\n",stat_methods_maythrow);
        fprintf(file,"reached blocks     : %8d\n",stat_reached);
        fprintf(file,"copied states      : %8d\n",stat_copied);
        fprintf(file,"merged states      : %8d\n",stat_merged);
@@ -214,15 +357,25 @@ void typecheck_print_statistics(FILE *file) {
        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,"    stack          : %8d\n",stat_ins_stack);
        fprintf(file,"    field access   : %8d\n",stat_ins_field);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_field_unresolved);
+       fprintf(file,"      (uninit.)    : %8d\n",stat_ins_field_uninitialized);
        fprintf(file,"    invocations    : %8d\n",stat_ins_invoke);
-       fprintf(file,"    load primitive : %8d\n",stat_ins_primload);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_invoke_unresolved);
+       fprintf(file,"    load primitive : (currently not counted) %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,"    prim. return   : %8d\n",stat_ins_primitive_return);
+       fprintf(file,"    areturn        : %8d\n",stat_ins_areturn);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_areturn_unresolved);
+       fprintf(file,"    athrow         : %8d\n",stat_ins_athrow);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_athrow_unresolved);
+       fprintf(file,"    unchecked      : %8d\n",stat_ins_unchecked);
+       fprintf(file,"    maythrow       : %8d\n",stat_ins_maythrow);
        fprintf(file,"iterations used:\n");
        print_freq(file,stat_iterations,STAT_ITERATIONS);
        fprintf(file,"basic blocks per method / 10:\n");
@@ -234,13 +387,13 @@ void typecheck_print_statistics(FILE *file) {
 #else
                                                   
 #define TYPECHECK_COUNT(cnt)
+#define TYPECHECK_MARK(var)
 #define TYPECHECK_COUNTIF(cond,cnt)
 #define TYPECHECK_COUNT_FREQ(array,val,limit)
 #endif
 
-
 /****************************************************************************/
-/* MACROS FOR STACK TYPE CHECKING                                           */
+/* MACROS FOR THROWING EXCEPTIONS                                           */
 /****************************************************************************/
 
 #define TYPECHECK_VERIFYERROR_ret(m,msg,retval) \
@@ -252,6 +405,10 @@ void typecheck_print_statistics(FILE *file) {
 #define TYPECHECK_VERIFYERROR_main(msg)  TYPECHECK_VERIFYERROR_ret(state.m,(msg),NULL)
 #define TYPECHECK_VERIFYERROR_bool(msg)  TYPECHECK_VERIFYERROR_ret(state->m,(msg),false)
 
+/****************************************************************************/
+/* MACROS FOR STACK SLOT TYPE CHECKING                                      */
+/****************************************************************************/
+
 #define TYPECHECK_CHECK_TYPE(sp,tp,msg) \
     do { \
                if ((sp)->type != (tp)) { \
@@ -297,6 +454,10 @@ typedef struct verifier_state {
     bool repeat;            /* if true, blocks are iterated over again */
     bool initmethod;             /* true if this is an "<init>" method */
        bool jsrencountered;                 /* true if we there was a JSR */
+
+#ifdef TYPECHECK_STATISTICS
+       bool stat_maythrow;          /* at least one instruction may throw */
+#endif
 } verifier_state;
 
 /****************************************************************************/
@@ -315,21 +476,12 @@ typedef struct verifier_state {
 #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)                                                                    \
-
 /* typestack_copy **************************************************************
  
    Copy the types on the given stack to the destination stack.
@@ -362,6 +514,7 @@ typestack_copy(verifier_state *state,stackptr dst,stackptr y,typevector *selecte
        int k;
        
        for (;dst; dst=dst->prev, y=y->prev) {
+               /* XXX only check the following two in debug mode? */
                if (!y) {
                        *exceptionptr = new_verifyerror(state->m,"Stack depth mismatch");
                        return false;
@@ -550,7 +703,30 @@ typestack_add(stackptr dst,stackptr y,int ky)
        }
 }
 
-/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+/* typestack_separable_with ****************************************************
+   This function answers the question: If variant 'kb' of typestack 'b' is
+   added to typestack 'a', will the result be separable?
+
+   A typestack is called 'separable' if it has at least one slot of type
+   returnAddress that contains at least two different return addresses.
+   (ie. a RET using the value in this slot could go to more than one target)
+   
+   IN:
+          a................the first typestack
+          b................the second typestack
+          kb...............the k-index of the variant that should be selected
+                           from typestack 'b'
+
+   OUT:
+       true.............the result would be separable
+          false............the result would not be separable
+
+   PRE-CONDITION:
+       'a' and 'b' are assumed to have passed typestack_canmerge!
+
+*******************************************************************************/
+
 static bool
 typestack_separable_with(stackptr a,stackptr b,int kb)
 {
@@ -573,7 +749,33 @@ typestack_separable_with(stackptr a,stackptr b,int kb)
        return false;
 }
 
-/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+/* typestack_separable_from ****************************************************
+   This function answers the question: Is variant 'ka' of typestack 'a'
+   separable from variant 'kb' of typestack 'b'?
+
+   Two variants of typestacks are called 'separable' from each other, if there
+   is at least one slot for which the variants contain different return addresses.
+   (ie. a RET using the value in this slot would go to one target in the first
+   variant and to another target in the second variant)
+   
+   IN:
+          a................the first typestack
+          ka...............the k-index of the variant that should be selected
+                           from typestack 'a'
+          b................the second typestack
+          kb...............the k-index of the variant that should be selected
+                           from typestack 'b'
+
+   OUT:
+       true.............the variants are separable
+          false............the variants are not separable
+
+   PRE-CONDITION:
+       'a' and 'b' are assumed to have passed typestack_canmerge!
+
+*******************************************************************************/
+
 static bool
 typestack_separable_from(stackptr a,int ka,stackptr b,int kb)
 {
@@ -793,7 +995,7 @@ typestate_reach(verifier_state *state,
                
                if (!typestack_copy(state,destblock->instack,ystack,yloc))
                        return false;
-               COPY_TYPEVECTORSET(yloc,destloc,state->numlocals);
+               typevectorset_copy_inplace(yloc,destloc,state->numlocals);
                changed = true;
        }
        else {
@@ -861,62 +1063,76 @@ typestate_ret(verifier_state *state,int retindex)
        return true;
 }
 
-/****************************************************************************/
-/* MACROS FOR LOCAL VARIABLE CHECKING                                       */
-/****************************************************************************/
+/* typestate_save_instack ******************************************************
+   Save the input stack of the current basic block in the "savedstackbuf"
+   of the verifier state.
 
-#define INDEX_ONEWORD(num)                                                                             \
-       do { if((num)<0 || (num)>=state->validlocals)                           \
-                       TYPECHECK_VERIFYERROR_bool("Invalid local variable index"); } while (0)
-#define INDEX_TWOWORD(num)                                                                             \
-       do { if((num)<0 || ((num)+1)>=state->validlocals)                       \
-                       TYPECHECK_VERIFYERROR_bool("Invalid local variable index"); } while (0)
+   This function must be called before an instruction modifies a stack slot
+   that happens to be part of the instack of the current block. In such
+   cases the instack of the block must be saved, and restored at the end
+   of the analysis of this basic block, so that the instack again reflects
+   the *input* to this basic block (and does not randomly contain types
+   that appear within the block).
 
-#define STORE_ONEWORD(num,type)                                                                        \
-       do {typevectorset_store(state->localset,num,type,NULL);} while(0)
+   IN:
+       state............current state of the verifier
 
-#define STORE_TWOWORD(num,type)                                                                                \
-       do {typevectorset_store_twoword(state->localset,num,type);} while(0)
+*******************************************************************************/
 
+static void
+typestate_save_instack(verifier_state *state)
+{
+       stackptr sp;
+       stackptr dest;
+       s4 i;
+       
+       LOG("saving input stack types");
+       if (!state->savedstackbuf) {
+               LOG("allocating savedstack buffer");
+               state->savedstackbuf = DMNEW(stackelement, state->cd->maxstack);
+               state->savedstackbuf->prev = NULL;
+               for (i = 1; i < state->cd->maxstack; ++i)
+                       state->savedstackbuf[i].prev = state->savedstackbuf+(i-1);
+       }
+       sp = state->savedstack = state->bptr->instack;
+       dest = state->bptr->instack = state->savedstackbuf + (state->bptr->indepth-1);
+       
+       for(; sp; sp=sp->prev, dest=dest->prev) {
+               dest->type = sp->type;
+               TYPEINFO_COPY(sp->typeinfo,dest->typeinfo);
+       }
+}
 
-#ifdef TYPECHECK_VERBOSE
-#define WORDCHECKFAULT \
-       do { \
-               dolog("localset->td index: %ld\ninstruction belongs to:%s.%s, outermethod:%s.%s\n", \
-               state->iptr->op1,state->iptr->method->class->name->text, \
-                       state->iptr->method->name->text,state->m->class->name->text,state->m->name->text); \
-               show_icmd(state->iptr++, false); \
-               show_icmd(state->iptr, false); \
-       } while (0)
-#else
-#define WORDCHECKFAULT
-#endif
+/* typestate_restore_instack ***************************************************
+   Restore the input stack of the current basic block that has been previously
+   saved by `typestate_save_instack`.
 
+   IN:
+       state............current state of the verifier
 
-#define CHECK_ONEWORD(num,tp)                                                                                  \
-       do {TYPECHECK_COUNT(stat_ins_primload);                                                         \
-               if (state->jsrencountered) {                                                                                    \
-                       if (!typevectorset_checktype(state->localset,num,tp)) {                         \
-                               WORDCHECKFAULT; \
-                               TYPECHECK_VERIFYERROR_bool("Variable type mismatch");                                           \
-                       }       \
-               }                                                                                                                               \
-               else {                                                                                                                  \
-                       if (state->localset->td[num].type != tp) {                                                      \
-                               TYPECHECK_VERIFYERROR_bool("Variable type mismatch");                                           \
-                               WORDCHECKFAULT; \
-                       } \
-               }                                                                                                                               \
-               } while(0)
-
-#define CHECK_TWOWORD(num,type)                                                                                        \
-       do {TYPECHECK_COUNT(stat_ins_primload);                                                         \
-               if (!typevectorset_checktype(state->localset,num,type)) {                \
-                       WORDCHECKFAULT; \
-                       TYPECHECK_VERIFYERROR_bool("Variable type mismatch");                           \
-               } \
-       } while(0)
+*******************************************************************************/
+
+static void
+typestate_restore_instack(verifier_state *state)
+{
+       stackptr sp;
+       stackptr dest;
+       
+       TYPECHECK_COUNT(stat_savedstack);
+       LOG("restoring saved instack");
+
+       sp = state->bptr->instack;
+       dest = state->savedstack;
+       for(; sp; sp=sp->prev, dest=dest->prev) {
+               dest->type = sp->type;
+               TYPEINFO_COPY(sp->typeinfo,dest->typeinfo);
+       }
 
+       state->bptr->instack = state->savedstack;
+       state->savedstack = NULL;
+}
 
 /****************************************************************************/
 /* MISC MACROS                                                              */
@@ -928,21 +1144,6 @@ typestate_ret(verifier_state *state,int retindex)
 
 #define ISBUILTIN(v)   (bte->fp == (functionptr) (v))
 
-/* TYPECHECK_LEAVE: executed when the method is exited non-abruptly
- * Input:
- *     class........class of the current method
- *     state........verifier state
- */
-#define TYPECHECK_LEAVE                                                 \
-    do {                                                                \
-        if (state->initmethod && state->m->class != class_java_lang_Object) {         \
-            /* check the marker variable */                             \
-            LOG("Checking <init> marker");                              \
-            if (!typevectorset_checktype(state->localset,state->numlocals-1,TYPE_INT))\
-                TYPECHECK_VERIFYERROR_bool("<init> method does not initialize 'this'");      \
-        }                                                               \
-    } while (0)
-
 /* verify_invocation ***********************************************************
  
    Verify an ICMD_INVOKE* instruction.
@@ -990,29 +1191,6 @@ verify_invocation(verifier_state *state)
        if (specialmethod && !callinginit)
                TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
 
-       /* record subtype constraints for parameters */
-       
-       if (!constrain_unresolved_method(um,state->m->class,state->m,state->iptr,state->curstack))
-               return false; /* XXX maybe wrap exception */
-
-       /* try to resolve the method lazily */
-       
-       if (!resolve_method(um,resolveLazy,(methodinfo **) &(state->iptr[0].val.a)))
-               return false;
-
-#if 0
-       if (opcode == ICMD_INVOKESPECIAL) {
-               /* XXX for INVOKESPECIAL: check if the invokation is done at all */
-
-               /* (If callinginit the class is checked later.) */
-               if (!callinginit) { 
-                       /* XXX classrefs */
-                       if (!builtin_isanysubclass(myclass,mi->class)) 
-                               XXXTYPECHECK_VERIFYERROR_bool("Illegal instruction: INVOKESPECIAL calling non-superclass method"); 
-               } 
-       }
-#endif
-
        /* allocate parameters if necessary */
        
        if (!md->params)
@@ -1041,12 +1219,19 @@ verify_invocation(verifier_state *state)
                                LOGINFO(&(stack->typeinfo));
                                ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(stack->typeinfo);
                                if (ins)
-                                       initclass = CLASSREF_OR_CLASSINFO(ins[-1].val.a);
+                                       initclass = CLASSREF_OR_CLASSINFO(ins[-1].target);
                                else
                                        initclass.cls = state->m->class;
                                LOGSTR("class: "); LOGNAME(initclass); LOGNL;
                        }
                }
+               else {
+                       /* non-adress argument. if this is the first argument and we are */
+                       /* invoking an instance method, this is an error.                */
+                       if (i==0 && opcode != ICMD_INVOKESTATIC) {
+                               TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
+                       }
+               }
                LOG("ok");
 
                if (i)
@@ -1078,21 +1263,7 @@ verify_invocation(verifier_state *state)
                                 * we are going to replace.
                                 */
                                if (stack <= state->bptr->instack && !state->savedstack)
-                               {
-                                       stackptr sp;
-                                       stackptr copy;
-                                       LOG("saving input stack types");
-                                       if (!state->savedstackbuf) {
-                                               LOG("allocating savedstack buffer");
-                                               state->savedstackbuf = DMNEW(stackelement, state->cd->maxstack);
-                                               state->savedstackbuf->prev = NULL;
-                                               for (i = 1; i < state->cd->maxstack; ++i)
-                                                       state->savedstackbuf[i].prev = state->savedstackbuf+(i-1);
-                                       }
-                                       sp = state->savedstack = state->bptr->instack;
-                                       copy = state->bptr->instack = state->savedstackbuf + (state->bptr->indepth-1);
-                                       TYPESTACK_COPY(sp,copy);
-                               }
+                                       typestate_save_instack(state);
 
                                if (!typeinfo_init_class(&(stack->typeinfo),initclass))
                                        return false;
@@ -1105,34 +1276,112 @@ verify_invocation(verifier_state *state)
 
                /* initializing the 'this' reference? */
                if (!ins) {
+                       classinfo *cls;
                        TYPECHECK_ASSERT(state->initmethod);
-                       /* must be <init> of current class or direct superclass */
-                       /* XXX check with classrefs */
-#if 0
-                       if (mi->class != m->class && mi->class != m->class->super.cls)
+                       /* { we are initializing the 'this' reference }                           */
+                       /* must be <init> of current class or direct superclass                   */
+                       /* the current class is linked, so must be its superclass. thus we can be */
+                       /* sure that resolving will be trivial.                                   */
+                       if (!resolve_classref(state->m,mref->classref,resolveLazy,false,true,&cls))
+                               return false; /* exception */
+
+                       /* if lazy resolving did not succeed, it's not one of the allowed classes */
+                       /* otherwise we check it directly                                         */
+                       if (cls == NULL || (cls != state->m->class && cls != state->m->class->super.cls)) {
                                TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
-#endif
+                       }
 
                        /* set our marker variable to type int */
                        LOG("setting <init> marker");
                        typevectorset_store(state->localset,state->numlocals-1,TYPE_INT,NULL);
                }
                else {
-                       /* initializing an instance created with NEW */
-                       /* XXX is this strictness ok? */
-                       /* XXX check with classrefs */
-#if 0
-                       if (mi->class != initclass.cls)
-                               TYPECHECK_VERIFYERROR_bool("Calling <init> method of the wrong class");
-#endif
+                       /* { we are initializing an instance created with NEW } */
+                       if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mref->classref->name) {
+                               TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
+                       }
+               }
+       }
+
+       /* record subtype constraints for parameters */
+       
+       if (!constrain_unresolved_method(um,state->m->class,state->m,state->iptr,state->curstack))
+               return false; /* XXX maybe wrap exception */
+
+       /* try to resolve the method lazily */
+       
+       if (!resolve_method(um,resolveLazy,(methodinfo **) &(state->iptr[0].val.a)))
+               return false;
+
+       return true;
+}
+
+/* verify_generic_builtin ******************************************************
+   Verify the call of a generic builtin method.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+verify_generic_builtin(verifier_state *state)
+{
+       builtintable_entry *bte;
+       s4 i;
+       u1 rtype;
+       methoddesc *md;
+    stackptr sp;
+
+       TYPECHECK_COUNT(stat_ins_builtin_gen);
+
+       bte = (builtintable_entry *) state->iptr[0].val.a;
+       md = bte->md;
+       i = md->paramcount;
+       
+       /* check the types of the arguments on the stack */
+
+       sp = state->curstack;
+       for (i--; i >= 0; i--) {
+               if (sp->type != md->paramtypes[i].type) {
+                       TYPECHECK_VERIFYERROR_bool("parameter type mismatch for builtin method");
                }
+               
+#ifdef TYPECHECK_DEBUG
+               /* generic builtins may only take primitive types and java.lang.Object references */
+               if (sp->type == TYPE_ADR && md->paramtypes[i].classref->name != utf_java_lang_Object) {
+                       *exceptionptr = new_internalerror("generic builtin method with non-generic reference parameter");
+                       return false;
+               }
+#endif
+               
+               sp = sp->prev;
+       }
+
+       /* check the return type */
+
+       rtype = md->returntype.type;
+       if (rtype != TYPE_VOID) {
+               stackptr dst;
+
+               dst = state->iptr->dst;
+               if (rtype != dst->type)
+                       TYPECHECK_VERIFYERROR_bool("Return type mismatch in generic builtin invocation");
+               if (!typeinfo_init_from_typedesc(&(md->returntype),NULL,&(dst->typeinfo)))
+                       return false;
        }
+
        return true;
 }
 
 /* verify_builtin **************************************************************
  
-   Verify the call of a builtin function.
+   Verify the call of a builtin method.
   
    IN:
        state............the current state of the verifier
@@ -1147,22 +1396,19 @@ static bool
 verify_builtin(verifier_state *state)
 {
        builtintable_entry *bte;
-    classinfo *cls;
+    classref_or_classinfo cls;
     stackptr dst;               /* output stack of current instruction */
 
        bte = (builtintable_entry *) state->iptr[0].val.a;
        dst = state->iptr->dst;
 
-       if (ISBUILTIN(BUILTIN_new) || ISBUILTIN(PATCHER_builtin_new)) {
+       /* XXX this is an ugly if-chain but twisti did not want a function */
+       /* pointer in builtintable_entry for this, so here you go.. ;)     */
+
+       if (ISBUILTIN(BUILTIN_new)) {
                if (state->iptr[-1].opc != ICMD_ACONST)
-                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_new without classinfo");
-               cls = (classinfo *) state->iptr[-1].val.a;
-#ifdef XXX
-               TYPECHECK_ASSERT(!cls || cls->linked);
-               /* The following check also forbids array classes and interfaces: */
-               if ((cls->flags & ACC_ABSTRACT) != 0)
-                       TYPECHECK_VERIFYERROR_bool("Invalid instruction: NEW creating instance of abstract class");
-#endif
+                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_new without class");
+               cls.any = state->iptr[-1].target;
                TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,state->iptr);
        }
        else if (ISBUILTIN(BUILTIN_newarray_boolean)) {
@@ -1199,64 +1445,96 @@ verify_builtin(verifier_state *state)
        }
        else if (ISBUILTIN(BUILTIN_newarray))
        {
-               vftbl_t *vft;
-               TYPECHECK_INT(state->curstack->prev);
-               if (state->iptr[-1].opc != ICMD_ACONST)
-                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_newarray without classinfo");
-               vft = (vftbl_t *)state->iptr[-1].val.a;
-               if (!vft)
-                       TYPECHECK_VERIFYERROR_bool("ANEWARRAY with unlinked class");
-               if (!vft->arraydesc)
-                       TYPECHECK_VERIFYERROR_bool("ANEWARRAY with non-array class");
-               TYPEINFO_INIT_CLASSINFO(dst->typeinfo,vft->class);
-       }
-       else if (ISBUILTIN(PATCHER_builtin_newarray))
-       {
-               TYPECHECK_INT(state->curstack->prev);
-               if (state->iptr[-1].opc != ICMD_ACONST)
-                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_newarray without classinfo");
-               if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(state->iptr[-1].val.a)))
-                       return false;
-       }
-       else if (ISBUILTIN(BUILTIN_newarray))
-       {
-               vftbl_t *vft;
                TYPECHECK_INT(state->curstack->prev);
-               if (state->iptr[-1].opc != ICMD_ACONST)
-                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_newarray without classinfo");
-               vft = (vftbl_t *)state->iptr[-1].val.a;
-               if (!vft)
-                       TYPECHECK_VERIFYERROR_bool("ANEWARRAY with unlinked class");
-               if (!vft->arraydesc)
-                       TYPECHECK_VERIFYERROR_bool("ANEWARRAY with non-array class");
-               TYPEINFO_INIT_CLASSINFO(dst->typeinfo,vft->class);
+               if (state->iptr[-1].opc != ICMD_ACONST || !state->iptr[-1].target)
+                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_newarray without class");
+               /* XXX check that it is an array class(ref) */
+               typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(state->iptr[-1].target));
        }
        else if (ISBUILTIN(BUILTIN_arrayinstanceof))
        {
-               vftbl_t *vft;
                TYPECHECK_ADR(state->curstack->prev);
                if (state->iptr[-1].opc != ICMD_ACONST)
-                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_arrayinstanceof without classinfo");
-               vft = (vftbl_t *)state->iptr[-1].val.a;
-               if (!vft)
-                       TYPECHECK_VERIFYERROR_bool("INSTANCEOF with unlinked class");
-               if (!vft->arraydesc)
-                       TYPECHECK_VERIFYERROR_bool("internal error: builtin_arrayinstanceof with non-array class");
+                       TYPECHECK_VERIFYERROR_bool("illegal instruction: builtin_arrayinstanceof without class");
+               /* XXX check that it is an array class(ref) */
        }
        else {
-#if 0
-               /* XXX put these checks in a function */
-               TYPECHECK_COUNT(stat_ins_builtin_gen);
-               builtindesc = builtin_desc;
-               while (builtindesc->opcode && builtindesc->builtin
-                               != state->iptr->val.fp) builtindesc++;
-               if (!builtindesc->opcode) {
-                       dolog("Builtin not in table: %s",icmd_builtin_name(state->iptr->val.fp));
-                       TYPECHECK_ASSERT(false);
-               }
-               TYPECHECK_ARGS3(builtindesc->type_s3,builtindesc->type_s2,builtindesc->type_s1);
-#endif
+               return verify_generic_builtin(state);
+       }
+       return true;
+}
+
+/* verify_multianewarray *******************************************************
+   Verify a MULTIANEWARRAY instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+verify_multianewarray(verifier_state *state)
+{
+    stackptr sp;
+       classinfo *arrayclass;
+       arraydescriptor *desc;
+       s4 i;
+
+       /* check the array lengths on the stack */
+       i = state->iptr[0].op1;
+       if (i < 1)
+               TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
+
+       sp = state->curstack;
+       while (i--) {
+               if (!sp)
+                       TYPECHECK_VERIFYERROR_bool("Unable to pop operand off an empty stack");
+               TYPECHECK_INT(sp);
+               sp = sp->prev;
        }
+
+       /* check array descriptor */
+       if (state->iptr[0].val.a != NULL) {
+               /* the array class reference has already been resolved */
+               arrayclass = (classinfo *) state->iptr[0].val.a;
+               if (!arrayclass)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
+               if ((desc = arrayclass->vftbl->arraydesc) == NULL)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
+               if (desc->dimension < state->iptr[0].op1)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
+
+               /* set the array type of the result */
+               typeinfo_init_classinfo(&(state->iptr->dst->typeinfo), arrayclass);
+       }
+       else {
+               const char *p;
+               constant_classref *cr;
+               
+               /* the array class reference is still unresolved */
+               /* check that the reference indicates an array class of correct dimension */
+               cr = (constant_classref *) state->iptr[0].target;
+               i = 0;
+               p = cr->name->text;
+               while (p[i] == '[')
+                       i++;
+               /* { the dimension of the array class == i } */
+               if (i < 1)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
+               if (i < state->iptr[0].op1)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
+
+               /* set the array type of the result */
+               if (!typeinfo_init_class(&(state->iptr->dst->typeinfo),CLASSREF_OR_CLASSINFO(state->iptr[0].target)))
+                       return false;
+       }
+
+       /* everything ok */
        return true;
 }
 
@@ -1276,7 +1554,6 @@ verify_builtin(verifier_state *state)
 static bool
 verify_basic_block(verifier_state *state)
 {
-    stackptr srcstack;         /* source stack for copying and merging */
     int opcode;                                      /* current opcode */
     int len;                        /* for counting instructions, etc. */
     bool superblockend;        /* true if no fallthrough to next block */
@@ -1319,11 +1596,11 @@ verify_basic_block(verifier_state *state)
        state->handlers[len] = NULL;
 
        /* init variable types at the start of this block */
-       COPY_TYPEVECTORSET(MGET_TYPEVECTOR(state->localbuf,b_index,state->numlocals),
+       typevectorset_copy_inplace(MGET_TYPEVECTOR(state->localbuf,b_index,state->numlocals),
                        state->localset,state->numlocals);
 
        /* XXX FIXME FOR INLINING */
-       if(!useinlining) {
+       if (!useinlining) {
                if (state->handlers[0])
                        for (i=0; i<state->numlocals; ++i)
                                if (state->localset->td[i].type == TYPE_ADR
@@ -1336,7 +1613,7 @@ verify_basic_block(verifier_state *state)
                                        /* of eclipse 3.0.2                                                  */
                                        if (TYPEINFO_NEWOBJECT_INSTRUCTION(state->localset->td[i].info) != NULL) {
                                                /*show_icmd_method(state->m, state->cd, state->rd);*/
-                                               printf("Uninitialized variale: %d, block: %d\n", i, state->bptr->debug_nr);
+                                               printf("Uninitialized variable: %d, block: %d\n", i, state->bptr->debug_nr);
                                                TYPECHECK_VERIFYERROR_bool("Uninitialized object in local variable inside try block");
                                        }
                                }
@@ -1375,16 +1652,19 @@ verify_basic_block(verifier_state *state)
                         */
 
                        case ICMD_DUP:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst);
                                break;
 
                        case ICMD_DUP_X1:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst);
                                COPYTYPE(state->curstack,dst-2);
                                COPYTYPE(state->curstack->prev,dst-1);
                                break;
 
                        case ICMD_DUP_X2:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst);
                                COPYTYPE(state->curstack,dst-3);
                                COPYTYPE(state->curstack->prev,dst-1);
@@ -1392,11 +1672,13 @@ verify_basic_block(verifier_state *state)
                                break;
 
                        case ICMD_DUP2:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst);
                                COPYTYPE(state->curstack->prev,dst-1);
                                break;
 
                        case ICMD_DUP2_X1:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst);
                                COPYTYPE(state->curstack->prev,dst-1);
                                COPYTYPE(state->curstack,dst-3);
@@ -1405,6 +1687,7 @@ verify_basic_block(verifier_state *state)
                                break;
 
                        case ICMD_DUP2_X2:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst);
                                COPYTYPE(state->curstack->prev,dst-1);
                                COPYTYPE(state->curstack,dst-4);
@@ -1414,6 +1697,7 @@ verify_basic_block(verifier_state *state)
                                break;
 
                        case ICMD_SWAP:
+                               TYPECHECK_COUNT(stat_ins_stack);
                                COPYTYPE(state->curstack,dst-1);
                                COPYTYPE(state->curstack->prev,dst);
                                break;
@@ -1421,16 +1705,26 @@ verify_basic_block(verifier_state *state)
                                /****************************************/
                                /* PRIMITIVE VARIABLE ACCESS            */
 
-                       case ICMD_ILOAD: CHECK_ONEWORD(state->iptr->op1,TYPE_INT); break;
-                       case ICMD_FLOAD: CHECK_ONEWORD(state->iptr->op1,TYPE_FLOAT); break;
-                       case ICMD_IINC:  CHECK_ONEWORD(state->iptr->op1,TYPE_INT); break;
-                       case ICMD_LLOAD: CHECK_TWOWORD(state->iptr->op1,TYPE_LONG); break;
-                       case ICMD_DLOAD: CHECK_TWOWORD(state->iptr->op1,TYPE_DOUBLE); break;
-
-                       case ICMD_FSTORE: STORE_ONEWORD(state->iptr->op1,TYPE_FLOAT); break;
-                       case ICMD_ISTORE: STORE_ONEWORD(state->iptr->op1,TYPE_INT); break;
-                       case ICMD_LSTORE: STORE_TWOWORD(state->iptr->op1,TYPE_LONG); break;
-                       case ICMD_DSTORE: STORE_TWOWORD(state->iptr->op1,TYPE_DOUBLE); break;
+                       case ICMD_ILOAD: if (!typevectorset_checktype(state->localset,state->iptr->op1,TYPE_INT)) 
+                                                                TYPECHECK_VERIFYERROR_bool("Local variable type mismatch");
+                                                        break;
+                       case ICMD_IINC:  if (!typevectorset_checktype(state->localset,state->iptr->op1,TYPE_INT))
+                                                                TYPECHECK_VERIFYERROR_bool("Local variable type mismatch");
+                                                        break;
+                       case ICMD_FLOAD: if (!typevectorset_checktype(state->localset,state->iptr->op1,TYPE_FLOAT))
+                                                                TYPECHECK_VERIFYERROR_bool("Local variable type mismatch");
+                                                        break;
+                       case ICMD_LLOAD: if (!typevectorset_checktype(state->localset,state->iptr->op1,TYPE_LONG))
+                                                                TYPECHECK_VERIFYERROR_bool("Local variable type mismatch");
+                                                        break;
+                       case ICMD_DLOAD: if (!typevectorset_checktype(state->localset,state->iptr->op1,TYPE_DOUBLE))
+                                                                TYPECHECK_VERIFYERROR_bool("Local variable type mismatch");
+                                                        break;
+
+                       case ICMD_ISTORE: typevectorset_store(state->localset,state->iptr->op1,TYPE_INT,NULL); break;
+                       case ICMD_FSTORE: typevectorset_store(state->localset,state->iptr->op1,TYPE_FLOAT,NULL); break;
+                       case ICMD_LSTORE: typevectorset_store_twoword(state->localset,state->iptr->op1,TYPE_LONG); break;
+                       case ICMD_DSTORE: typevectorset_store_twoword(state->localset,state->iptr->op1,TYPE_DOUBLE); break;
 
                                /****************************************/
                                /* LOADING ADDRESS FROM VARIABLE        */
@@ -1526,11 +1820,8 @@ fieldaccess_tail:
                                if (!resolve_field(uf,resolveLazy,fieldinfop))
                                        return false;
 
-                               /* we need a patcher, so this is not a leafmethod */
-#if defined(__MIPS__) || defined(__POWERPC__)
-                               if (!*fieldinfop || !(*fieldinfop)->class->initialized)
-                                       state->cd->method->isleafmethod = false;
-#endif
+                               TYPECHECK_COUNTIF(!*fieldinfop,stat_ins_field_unresolved);
+                               TYPECHECK_COUNTIF(*fieldinfop && !(*fieldinfop)->class->initialized,stat_ins_field_uninitialized);
                                        
                                maythrow = true;
                                break;
@@ -1667,11 +1958,18 @@ fieldaccess_tail:
                                /* ADDRESS CONSTANTS                    */
 
                        case ICMD_ACONST:
-                               if (state->iptr->val.a == NULL)
-                                       TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
-                               else
-                                       /* string constant (or constant for builtin function) */
-                                       TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
+                               if (state->iptr->target) {
+                                       /* a java.lang.Class reference */
+                                       TYPEINFO_INIT_JAVA_LANG_CLASS(dst->typeinfo,(constant_classref *)state->iptr->target);
+                               }
+                               else {
+                                       if (state->iptr->val.a == NULL)
+                                               TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
+                                       else {
+                                               /* string constant (or constant for builtin function) */
+                                               typeinfo_init_classinfo(&(dst->typeinfo),class_java_lang_String);
+                                       }
+                               }
                                break;
 
                                /****************************************/
@@ -1685,32 +1983,13 @@ fieldaccess_tail:
 
                                cls = (classinfo *) state->iptr[0].val.a;
                                if (cls)
-                                       TYPEINFO_INIT_CLASSINFO(dst->typeinfo,cls);
+                                       typeinfo_init_classinfo(&(dst->typeinfo),cls);
                                else
                                        if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(state->iptr[0].target)))
                                                return false;
                                maythrow = true;
                                break;
 
-                       case ICMD_ARRAYCHECKCAST:
-                               TYPECHECK_ADR(state->curstack);
-                               /* returnAddress is not allowed */
-                               if (!TYPEINFO_IS_REFERENCE(state->curstack->typeinfo))
-                                       TYPECHECK_VERIFYERROR_bool("Illegal instruction: ARRAYCHECKCAST on non-reference");
-
-                               if (state->iptr[0].op1) {
-                                       /* a resolved array class */
-                                       cls = ((vftbl_t *)state->iptr[0].target)->class;
-                                       TYPEINFO_INIT_CLASSINFO(dst->typeinfo,cls);
-                               }
-                               else {
-                                       /* an unresolved array class reference */
-                                       if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(state->iptr[0].target)))
-                                               return false;
-                               }
-                               maythrow = true;
-                               break;
-
                        case ICMD_INSTANCEOF:
                                TYPECHECK_ADR(state->curstack);
                                /* returnAddress is not allowed */
@@ -1797,18 +2076,29 @@ switch_instruction_tail:
                                /* ADDRESS RETURNS AND THROW            */
 
                        case ICMD_ATHROW:
+                               TYPECHECK_COUNT(stat_ins_athrow);
                                r = typeinfo_is_assignable_to_class(&state->curstack->typeinfo,
                                                CLASSREF_OR_CLASSINFO(class_java_lang_Throwable));
                                if (r == typecheck_FALSE)
                                        TYPECHECK_VERIFYERROR_bool("illegal instruction: ATHROW on non-Throwable");
                                if (r == typecheck_FAIL)
                                        return false;
-                               /* XXX handle typecheck_MAYBE */
+                               if (r == typecheck_MAYBE) {
+                                       /* the check has to be postponed. we need a patcher */
+                                       TYPECHECK_COUNT(stat_ins_athrow_unresolved);
+                                       state->iptr->val.a = create_unresolved_class(
+                                                       state->m, 
+                                                       /* XXX make this more efficient, use class_java_lang_Throwable
+                                                        * directly */
+                                                       class_get_classref(state->m->class,utf_java_lang_Throwable),
+                                                       &state->curstack->typeinfo);
+                               }
                                superblockend = true;
                                maythrow = true;
                                break;
 
                        case ICMD_ARETURN:
+                               TYPECHECK_COUNT(stat_ins_areturn);
                                if (!TYPEINFO_IS_REFERENCE(state->curstack->typeinfo))
                                        TYPECHECK_VERIFYERROR_bool("illegal instruction: ARETURN on non-reference");
 
@@ -1818,7 +2108,14 @@ switch_instruction_tail:
                                        TYPECHECK_VERIFYERROR_bool("Return type mismatch");
                                if (r == typecheck_FAIL)
                                        return false;
-                               /* XXX handle typecheck_MAYBE */
+                               if (r == typecheck_MAYBE) {
+                                       /* the check has to be postponed, we need a patcher */
+                                       TYPECHECK_COUNT(stat_ins_areturn_unresolved);
+                                       state->iptr->val.a = create_unresolved_class(
+                                                       state->m, 
+                                                       state->m->parseddesc->returntype.classref,
+                                                       &state->curstack->typeinfo);
+                               }
                                goto return_tail;
 
                                /****************************************/
@@ -1843,7 +2140,15 @@ switch_instruction_tail:
                        case ICMD_RETURN:
                                if (state->returntype.type != TYPE_VOID) TYPECHECK_VERIFYERROR_bool("Return type mismatch");
 return_tail:
-                               TYPECHECK_LEAVE;
+                               TYPECHECK_COUNT(stat_ins_primitive_return);
+
+                               if (state->initmethod && state->m->class != class_java_lang_Object) {
+                                       /* Check if the 'this' instance has been initialized. */
+                                       LOG("Checking <init> marker");
+                                       if (!typevectorset_checktype(state->localset,state->numlocals-1,TYPE_INT))
+                                               TYPECHECK_VERIFYERROR_bool("<init> method does not initialize 'this'");
+                               }
+
                                superblockend = true;
                                maythrow = true;
                                break;
@@ -1892,6 +2197,7 @@ return_tail:
                                TYPECHECK_COUNT(stat_ins_invoke);
                                if (!verify_invocation(state))
                                        return false;
+                               TYPECHECK_COUNTIF(!state->iptr[0].val.a,stat_ins_invoke_unresolved);
                                maythrow = true;
                                break;
 
@@ -1899,42 +2205,8 @@ return_tail:
                                /* MULTIANEWARRAY                       */
 
                        case ICMD_MULTIANEWARRAY:
-                               /* XXX make this a separate function */
-                               {
-                                       vftbl_t *arrayvftbl;
-                                       arraydescriptor *desc;
-
-                                       /* check the array lengths on the stack */
-                                       i = state->iptr[0].op1;
-                                       if (i < 1)
-                                               TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
-                                       srcstack = state->curstack;
-                                       while (i--) {
-                                               if (!srcstack)
-                                                       TYPECHECK_VERIFYERROR_bool("Unable to pop operand off an empty stack");
-                                               TYPECHECK_INT(srcstack);
-                                               srcstack = srcstack->prev;
-                                       }
-
-                                       /* check array descriptor */
-                                       if (state->iptr[0].target == NULL) {
-                                               arrayvftbl = (vftbl_t*) state->iptr[0].val.a;
-                                               if (!arrayvftbl)
-                                                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
-                                               if ((desc = arrayvftbl->arraydesc) == NULL)
-                                                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
-                                               if (desc->dimension < state->iptr[0].op1)
-                                                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
-
-                                               /* set the array type of the result */
-                                               TYPEINFO_INIT_CLASSINFO(dst->typeinfo,arrayvftbl->class);
-                                       }
-                                       else {
-                                               /* XXX do checks in patcher */
-                                               if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(state->iptr[0].val.a)))
-                                                       return false;
-                                       }
-                               }
+                               if (!verify_multianewarray(state))
+                                       return false;           
                                maythrow = true;
                                break;
 
@@ -1987,7 +2259,9 @@ return_tail:
                                 * Instructions below...
                                 *     *) don't operate on local variables,
                                 *     *) don't operate on references,
-                                *     *) don't operate on returnAddresses.
+                                *     *) don't operate on returnAddresses,
+                                *     *) don't affect control flow (except
+                                *        by throwing exceptions).
                                 *
                                 * (These instructions are typechecked in
                                 *  analyse_stack.)
@@ -2042,10 +2316,6 @@ return_tail:
                        case ICMD_LSHL:
                        case ICMD_LSHR:
                        case ICMD_LUSHR:
-#if 0
-                       case ICMD_IREM0X10001:
-                       case ICMD_LREM0X10001:
-#endif
                        case ICMD_IMULPOW2:
                        case ICMD_LMULPOW2:
                        case ICMD_IDIVPOW2:
@@ -2126,6 +2396,8 @@ return_tail:
 
                /* reach exception handlers for this instruction */
                if (maythrow) {
+                       TYPECHECK_COUNT(stat_ins_maythrow);
+                       TYPECHECK_MARK(state->stat_maythrow);
                        LOG("reaching exception handlers");
                        i = 0;
                        while (state->handlers[i]) {
@@ -2171,15 +2443,9 @@ return_tail:
         * have been saved if an <init> call inside the block has
         * modified the instack types. (see INVOKESPECIAL) */
 
-       if (state->savedstack) {
-               stackptr sp = state->bptr->instack;
-               stackptr copy = state->savedstack;
-               TYPECHECK_COUNT(stat_savedstack);
-               LOG("restoring saved instack");
-               TYPESTACK_COPY(sp,copy);
-               state->bptr->instack = state->savedstack;
-               state->savedstack = NULL;
-       }
+       if (state->savedstack)
+               typestate_restore_instack(state);
+
        return true;
 }
 
@@ -2227,7 +2493,7 @@ verify_init_locals(verifier_state *state)
         if (state->initmethod)
             TYPEINFO_INIT_NEWOBJECT(td->info,NULL);
         else
-            TYPEINFO_INIT_CLASSINFO(td->info, state->m->class);
+            typeinfo_init_classinfo(&(td->info), state->m->class);
         td++;
                i--;
     }
@@ -2257,6 +2523,90 @@ verify_init_locals(verifier_state *state)
        return true;
 }
 
+/* typecheck_init_flags ********************************************************
+   Initialize the basic block flags for the following CFG traversal.
+  
+   IN:
+       state............the current state of the verifier
+
+*******************************************************************************/
+
+static void
+typecheck_init_flags(verifier_state *state)
+{
+       s4 i;
+       basicblock *block;
+
+    /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+       
+    i = state->m->basicblockcount;
+    block = state->m->basicblocks;
+
+    while (--i >= 0) {
+               
+#ifdef TYPECHECK_DEBUG
+               /* check for invalid flags */
+        if (block->flags != BBFINISHED && block->flags != BBDELETED && block->flags != BBUNDEF)
+        {
+            /*show_icmd_method(state->cd->method,state->cd,state->rd);*/
+            LOGSTR1("block flags: %d\n",block->flags); LOGFLUSH;
+                       TYPECHECK_ASSERT(false);
+        }
+#endif
+
+        if (block->flags >= BBFINISHED) {
+            block->flags = BBTYPECHECK_UNDEF;
+        }
+        block++;
+    }
+
+    /* the first block is always reached */
+       
+    if (state->m->basicblockcount && state->m->basicblocks[0].flags == BBTYPECHECK_UNDEF)
+        state->m->basicblocks[0].flags = BBTYPECHECK_REACHED;
+}
+
+/* typecheck_reset_flags *******************************************************
+   Reset the flags of basic blocks we have not reached.
+  
+   IN:
+       state............the current state of the verifier
+
+*******************************************************************************/
+
+static void
+typecheck_reset_flags(verifier_state *state)
+{
+       s4 i;
+
+       /* check for invalid flags at exit */
+       
+#ifdef TYPECHECK_DEBUG
+       for (i=0; i<state->m->basicblockcount; ++i) {
+               if (state->m->basicblocks[i].flags != BBDELETED
+                       && state->m->basicblocks[i].flags != BBUNDEF
+                       && state->m->basicblocks[i].flags != BBFINISHED
+                       && state->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",
+                                state->m->basicblocks[i].debug_nr,state->m->basicblocks[i].flags);
+                       TYPECHECK_ASSERT(false);
+               }
+       }
+#endif
+       
+       /* Reset blocks we never reached */
+       
+       for (i=0; i<state->m->basicblockcount; ++i) {
+               if (state->m->basicblocks[i].flags == BBTYPECHECK_UNDEF)
+                       state->m->basicblocks[i].flags = BBFINISHED;
+       }
+}
+               
 /****************************************************************************/
 /* typecheck()                                                              */
 /* This is the main function of the bytecode verifier. It is called         */
@@ -2289,11 +2639,13 @@ methodinfo *typecheck(methodinfo *meth, codegendata *cdata, registerdata *rdata)
        int count_iterations = 0;
        TYPECHECK_COUNT(stat_typechecked);
        TYPECHECK_COUNT_FREQ(stat_locals,cdata->maxlocals,STAT_LOCALS);
-       TYPECHECK_COUNT_FREQ(stat_blocks,meth->basicblockcount/10,STAT_BLOCKS);
+       TYPECHECK_COUNT_FREQ(stat_blocks,cdata->method->basicblockcount/10,STAT_BLOCKS);
+       TYPECHECK_COUNTIF(cdata->method->exceptiontablelength != 0,stat_methods_with_handlers);
+       state.stat_maythrow = false;
 #endif
 
        /* some logging on entry */
-       
+
     LOGSTR("\n==============================================================================\n");
     /*DOLOG( show_icmd_method(cdata->method,cdata,rdata));*/
     LOGSTR("\n==============================================================================\n");
@@ -2319,32 +2671,9 @@ methodinfo *typecheck(methodinfo *meth, codegendata *cdata, registerdata *rdata)
 
     state.initmethod = (state.m->name == utf_init);
 
-    /* reset all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
-       
-    i = state.m->basicblockcount;
-    state.bptr = state.m->basicblocks;
-    while (--i >= 0) {
-#ifdef TYPECHECK_DEBUG
-        if (state.bptr->flags != BBFINISHED && state.bptr->flags != BBDELETED
-            && state.bptr->flags != BBUNDEF)
-        {
-            /*show_icmd_method(state.cd->method,state.cd,state.rd);*/
-            LOGSTR1("block flags: %d\n",state.bptr->flags); LOGFLUSH;
-                       TYPECHECK_ASSERT(false);
-        }
-#endif
-        if (state.bptr->flags >= BBFINISHED) {
-            state.bptr->flags = BBTYPECHECK_UNDEF;
-        }
-        state.bptr++;
-    }
+       /* initialize the basic block flags for the following CFG traversal */
 
-    /* the first block is always reached */
-       
-    if (state.m->basicblockcount && state.m->basicblocks[0].flags == BBTYPECHECK_UNDEF)
-        state.m->basicblocks[0].flags = BBTYPECHECK_REACHED;
-
-    LOG("Blocks reset.\n");
+       typecheck_init_flags(&state);
 
     /* number of local variables */
     
@@ -2376,7 +2705,7 @@ methodinfo *typecheck(methodinfo *meth, codegendata *cdata, registerdata *rdata)
        
        state.excstack.prev = NULL;
        state.excstack.type = TYPE_ADR;
-       TYPEINFO_INIT_CLASSINFO(state.excstack.typeinfo,
+       typeinfo_init_classinfo(&(state.excstack.typeinfo),
                                                        class_java_lang_Throwable); /* changed later */
 
     LOG("Exception handler stacks set.\n");
@@ -2412,44 +2741,19 @@ methodinfo *typecheck(methodinfo *meth, codegendata *cdata, registerdata *rdata)
        LOG1("Typechecker did %4d iterations",count_iterations);
        TYPECHECK_COUNT_FREQ(stat_iterations,count_iterations,STAT_ITERATIONS);
        TYPECHECK_COUNTIF(state.jsrencountered,stat_typechecked_jsr);
+       TYPECHECK_COUNTIF(state.stat_maythrow,stat_methods_maythrow);
 #endif
 
-       /* check for invalid flags at exit */
-       /* XXX make this a separate function */
-       
-#ifdef TYPECHECK_DEBUG
-       for (i=0; i<state.m->basicblockcount; ++i) {
-               if (state.m->basicblocks[i].flags != BBDELETED
-                       && state.m->basicblocks[i].flags != BBUNDEF
-                       && state.m->basicblocks[i].flags != BBFINISHED
-                       && state.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",
-                                state.m->basicblocks[i].debug_nr,state.m->basicblocks[i].flags);
-                       TYPECHECK_ASSERT(false);
-               }
-       }
-#endif
-       
-       /* Reset blocks we never reached */
-       
-       for (i=0; i<state.m->basicblockcount; ++i) {
-               if (state.m->basicblocks[i].flags == BBTYPECHECK_UNDEF)
-                       state.m->basicblocks[i].flags = BBFINISHED;
-       }
-               
-    LOGimp("exiting typecheck");
+       /* reset the flags of blocks we haven't reached */
 
-       /* just return methodinfo* to indicate everything was ok */
+       typecheck_reset_flags(&state);
 
+       /* just return methodinfo* to indicate everything was ok */
+    LOGimp("exiting typecheck");
        return state.m;
 }
 
-#undef COPYTYPE
-
-#endif /* CACAO_TYPECHECK */
+#endif /* ENABLE_VERIFIER */
 
 /*
  * These are local overrides for various environment variables in Emacs.