implemented subroutine verification (Coglio's method) + several verifier fixes
authoredwin <none@none>
Sat, 10 Jan 2004 20:12:10 +0000 (20:12 +0000)
committeredwin <none@none>
Sat, 10 Jan 2004 20:12:10 +0000 (20:12 +0000)
20 files changed:
builtin.c
builtin.h
jit/jit.h
jit/parse.c
jit/stack.c
jit/typecheck.c
loader.c
src/vm/builtin.c
src/vm/builtin.h
src/vm/jit/jit.h
src/vm/jit/parse.c
src/vm/jit/stack.c
src/vm/jit/verify/typecheck.c
src/vm/jit/verify/typeinfo.c
src/vm/jit/verify/typeinfo.h
src/vm/loader.c
src/vm/tables.c
tables.c
typeinfo.c
typeinfo.h

index 68bcb9b720769636f6f457e1fe2d1bc3e6655f9d..6d3ee98bbf2cb2dfc99a8205b485e13fd2ca1000 100644 (file)
--- a/builtin.c
+++ b/builtin.c
@@ -34,7 +34,7 @@
    calls instead of machine instructions, using the C calling
    convention.
 
-   $Id: builtin.c 862 2004-01-06 23:42:01Z stefan $
+   $Id: builtin.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -1833,6 +1833,12 @@ java_arrayheader *builtin_clone_array(void *env, java_arrayheader *o)
        return (java_arrayheader *) Java_java_lang_VMObject_clone(0, 0, (java_lang_Cloneable *) o);
 }
 
+s4 builtin_dummy()
+{
+       panic("Internal error: builtin_dummy called (native function is missing)");
+       return 0; /* for the compiler */
+}
+
 
 /*
  * These are local overrides for various environment variables in Emacs.
index 63c407205a6e2525dd6b4b781f3c226f2820de93..b2df84fcc7aafb1a46672c43ffeb8189f5fa81e0 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: builtin.h 862 2004-01-06 23:42:01Z stefan $
+   $Id: builtin.h 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -374,6 +374,10 @@ float    builtin_d2f(double a);    /* XXX? */
 java_arrayheader *builtin_clone_array(void *env, java_arrayheader *o);
 /* NOT AN OP */
 
+/* builtin_dummy just panics if it is executed. */
+s4 builtin_dummy();
+/* NOT AN OP */
+
 /* conversion helper functions */
 
 inline float intBitsToFloat(s4 i);
index fbd023fe13a30c0f72f27cdcf32f3da2fc455150..628bcc2fa73749d4ac0af8d3037cfb0466fc3006 100644 (file)
--- a/jit/jit.h
+++ b/jit/jit.h
@@ -29,7 +29,7 @@
 
    Changes: Christian Thalinger
 
-   $Id: jit.h 845 2004-01-05 10:38:06Z twisti $
+   $Id: jit.h 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -186,6 +186,11 @@ struct dataref {
 };
 
 
+/********** op1 values for ACONST instructions ********************************/
+
+#define ACONST_LOAD     0  /* ACONST_NULL or LDC instruction                  */
+#define ACONST_BUILTIN  1  /* constant argument for a builtin function call   */
+
 /********** JavaVM operation codes (sorted) and instruction lengths ***********/
 
 extern char *icmd_names[256];
index e594e66b7c7d46609d09630e075d09f8666ce9de..825b0dc80481fdea550ef9deff89f9c3e51765cf 100644 (file)
@@ -29,7 +29,7 @@
    Changes: Carolyn Oates
             Edwin Steiner
 
-   $Id: parse.c 863 2004-01-07 18:50:41Z edwin $
+   $Id: parse.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -334,6 +334,13 @@ void descriptor2types(methodinfo *m)
 #define LOADCONST_F(v) iptr->opc=ICMD_FCONST;iptr->op1=0;iptr->val.f=(v);PINC
 #define LOADCONST_D(v) iptr->opc=ICMD_DCONST;iptr->op1=0;iptr->val.d=(v);PINC
 #define LOADCONST_A(v) iptr->opc=ICMD_ACONST;iptr->op1=0;iptr->val.a=(v);PINC
+
+/* ACONST instructions generated as arguments for builtin functions
+ * have op1 set to non-zero. This is used for stack overflow checking
+ * in stack.c. */
+#define LOADCONST_A_BUILTIN(v) \
+                       iptr->opc=ICMD_ACONST;iptr->op1=1;iptr->val.a=(v);PINC
+
 #define OP(o)          iptr->opc=(o);iptr->op1=0;iptr->val.l=0;PINC
 #define OP1(o,o1)      iptr->opc=(o);iptr->op1=(o1);iptr->val.l=(0);PINC
 #define OP2I(o,o1,v)   iptr->opc=(o);iptr->op1=(o1);iptr->val.i=(v);PINC
@@ -903,7 +910,7 @@ void parse()
                        i = code_get_u2(p + 1);
                        {
                                        classinfo *component = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
-                                       LOADCONST_A(class_array_of(component)->vftbl);
+                                       LOADCONST_A_BUILTIN(class_array_of(component)->vftbl);
 
                                s_count++;
 
@@ -1246,7 +1253,7 @@ void parse()
                case JAVA_NEW:
                        i = code_get_u2 (p+1);
 
-                       LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+                       LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
                        s_count++;
                        BUILTIN1(BUILTIN_new, TYPE_ADR);
                        break;
@@ -1260,13 +1267,13 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl);
+                                               LOADCONST_A_BUILTIN(cls->vftbl);
                                                s_count++;
                                                BUILTIN2(BUILTIN_checkarraycast, TYPE_ADR);
                                        }
                                        else { /* object type cast-check */
                                                /*
-+                                                LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
++                                                LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
 +                                                s_count++;
 +                                                BUILTIN2(BUILTIN_checkcast, TYPE_ADR);
 +                                              */
@@ -1286,13 +1293,13 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl);
+                                               LOADCONST_A_BUILTIN(cls->vftbl);
                                                s_count++;
                                                BUILTIN2(BUILTIN_arrayinstanceof, TYPE_INT);
                                        }
                                        else { /* object type cast-check */
                                                /*
-                                                 LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+                                                 LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
                                                  s_count++;
                                                  BUILTIN2(BUILTIN_instanceof, TYPE_INT);
 +                                              */
index 470ea8bf792f000dafc696b781a4dd86d8209bd8..3c3db3367fd73895a16341e311f8b13fe9c1aba0 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: stack.c 846 2004-01-05 10:40:42Z twisti $
+   $Id: stack.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -85,14 +85,15 @@ extern int dseglen;
 #define REQUIRE_4     REQUIRE(4)
 
 /* overflow check */
-/* XXX we allow ACONST to exceed the maximum stack depth because it is
- * generated for builtin calls. Maybe we should check against maximum
- * stack depth only at block boundaries?
+/* XXX we allow ACONST instructions inserted as arguments to builtin
+ * functions to exceed the maximum stack depth.  Maybe we should check
+ * against maximum stack depth only at block boundaries?
  */
 #define CHECKOVERFLOW                                                  \
        do {                                                                            \
                if (stackdepth > maxstack) {                    \
-                       if (iptr[0].opc != ICMD_ACONST)         \
+                       if (iptr[0].opc != ICMD_ACONST          \
+                || iptr[0].op1 == 0)            \
                        {OVERFLOW;}                                                     \
                }                                                                               \
        } while(0)
@@ -290,7 +291,7 @@ extern int dseglen;
  *   - check for matching stack depth at merging points
  *   - check for matching basic types[2] at merging points
  *   - check basic types for instruction input (except for BUILTIN*
- *         opcodes and MULTIANEWARRAY)
+ *         opcodes, INVOKE* opcodes and MULTIANEWARRAY)
  *
  * [1]) XXX Checking this after the instruction should be ok. parse.c
  * counts the number of required stack slots in such a way that it is
@@ -1782,6 +1783,9 @@ void analyse_stack()
                                                iptr->val.a = (void *) iptr->dst;
 
                                                tbptr->type = BBTYPE_SBR;
+
+                                               /* We need to check for overflow right here because
+                                                * the pushed value is poped after MARKREACHED. */
                                                CHECKOVERFLOW;
                                                MARKREACHED(tbptr, copy);
                                                OP1_0ANY;
index 15e62927d72c53ed1d7dd83310c6b2d284c99ff5..35e472826fdcbd4b72ec40488be40df0731d7a6a 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 822 2003-12-31 16:00:58Z edwin $
+   $Id: typecheck.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -147,6 +147,27 @@ typeinfo_print_block(FILE *file,stackptr instack,
     typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
 }
 
+static
+void
+typestack_print(FILE *file,stackptr stack)
+{
+    while (stack) {
+        typeinfo_print_stacktype(file,stack->type,&stack->typeinfo);
+        stack = stack->prev;
+        if (stack) fprintf(file," ");
+    }
+}
+
+static
+void
+typestate_print(FILE *file,stackptr instack,typevector *localset,int size)
+{
+    fprintf(file,"Stack: ");
+    typestack_print(file,instack);
+    fprintf(file," Locals:");
+    typevectorset_print(file,localset,size);
+}
+
 
 #if 0
 static
@@ -173,6 +194,393 @@ typeinfo_print_blocks(FILE *file,int vnum,u1 *vtype,typeinfo *vinfo)
 
 #endif
 
+/****************************************************************************/
+/* TYPESTACK FUNCTIONS                                                      */
+/****************************************************************************/
+
+#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)
+
+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");
+               if (dst->type != y->type)
+                       panic("Stack type mismatch");
+               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");
+}
+
+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 bool
+typestack_canmerge(stackptr a,stackptr b)
+{
+       for (; a; a = a->prev, b = b->prev) {
+               if (!b) return false;
+               if (a->type != b->type) return false;
+               if (a->type == TYPE_ADDRESS) {
+                       if (((TYPEINFO_IS_PRIMITIVE(a->typeinfo)) ? 1 : 0)
+                               ^
+                               ((TYPEINFO_IS_PRIMITIVE(b->typeinfo)) ? 1 : 0))
+                               return false;
+               }
+       }
+       if (b) return false;
+       return true;
+}
+
+static void
+typestack_collapse(stackptr dst)
+{
+       for (; dst; dst = dst->prev) {
+               if (TYPESTACK_IS_RETURNADDRESS(dst))
+                       TYPESTACK_RETURNADDRESSSET(dst)->alt = NULL;
+       }
+}
+
+/* 'dst' and 'y' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_merge(stackptr dst,stackptr y)
+{
+       bool changed = false;
+       for (; dst; dst = dst->prev, y=y->prev) {
+               if (TYPESTACK_IS_REFERENCE(dst))
+                       changed |= typeinfo_merge(&(dst->typeinfo),&(y->typeinfo));
+       }
+       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;
+       int i;
+
+       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;
+}
+
+/****************************************************************************/
+/* TYPESTATE FUNCTIONS                                                      */
+/****************************************************************************/
+
+static bool
+typestate_merge(stackptr deststack,typevector *destloc,
+                               stackptr ystack,typevector *yloc,
+                               /*                              int retindex,void *retaddr, */
+                               int locsize)
+{
+       typevector *dvec,*yvec;
+       int kd,ky;
+       bool changed = false;
+       
+#ifdef TYPECHECK_DEBUG
+       /* Do some sanity checks */
+       /*
+         if (retindex < -1 || retindex >= locsize || (retindex >= 0 && !retaddr))
+         panic("Internal error: typestate_merge: invalid arguments");
+       */
+#endif
+
+       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;
+
+       /* Check if the stack types of deststack and ystack match */
+
+       /* XXX move this check into typestack_merge? */
+       if (!typestack_canmerge(deststack,ystack))
+               panic("Stack depth or stack type mismatch");
+
+       /* The stack is always merged. If there are returnAddresses on
+        * the stack they are ignored in this step. */
+
+       changed |= typestack_merge(deststack,ystack);
+
+       for (yvec=yloc; yvec; yvec=yvec->alt) {
+               ky = yvec->k;
+
+               /* If retindex >= 0 we select only those states (ystack,yvec)
+                * with returnAddress retaddr in variable no. retindex. */
+
+               /*
+                 if (retindex >= 0) {
+                 if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+                 panic("Illegal instruction: RET on non-returnAddress");
+                 if (TYPEINFO_RETURNADDRESS(yvec->td[retindex].info)
+                 != retaddr)
+                 continue;
+                 }
+               */
+
+               /* 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;
+       
+       return changed;
+}
+
+/* Globals used:
+ *     block
+ */
+static bool
+typestate_reach(void *localbuf,
+                               basicblock *current,
+                               basicblock *destblock,
+                               stackptr ystack,typevector *yloc,
+                               int locsize)
+{
+       typevector *yvec;
+       typevector *destloc;
+       int destidx;
+       bool repeat = false;
+       bool changed = false;
+       
+       destidx = destblock - block;
+       destloc = MGET_TYPEVECTOR(localbuf,destidx,locsize);
+
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               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 */
+               
+               LOG1("block (index %04d) reached before",destidx);
+               
+               changed = typestate_merge(destblock->instack,destloc,
+                                                                 ystack,yloc,locsize);
+       }
+
+       if (changed) {
+               LOG("changed!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               if (destblock <= current) {repeat = true; LOG("REPEAT!");}
+       }
+       return repeat;
+}
+
+/* Globals used:
+ *     see typestate_reach
+ */
+static bool
+typestate_ret(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(localbuf,current,destblock,
+                                                                 ystack,selected,locsize);
+       }
+       return repeat;
+}
+
+static bool
+typestate_jsr(void *localbuf,
+                         basicblock *current,basicblock *destblock,
+                         stackptr ystack,typevector *yloc,
+                         int locsize)
+{
+       typestack_put_retaddr(ystack,current+1,yloc);
+       return typestate_reach(localbuf,current,destblock,ystack,yloc,locsize);
+}
+
 /****************************************************************************/
 /* HELPER FUNCTIONS                                                         */
 /****************************************************************************/
@@ -282,12 +690,13 @@ typedef struct jsr_record jsr_record;
  * 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 */
+    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 */
+       instruction *sbr_ret;     /* RET instruction of the subroutine */
+    u1           touched[1];  /* touched flags for local variables */
 };
 
 /****************************************************************************/
@@ -316,24 +725,23 @@ struct jsr_record {
 
 #define STORE_ONEWORD(num,type)                                                                        \
        do {INDEX_ONEWORD(num);                                                                         \
-               SET_VARIABLE(num,type);} while(0)
+               typevectorset_store(localset,num,type,NULL);} while(0)
 
 #define STORE_TWOWORD(num,type)                                                                        \
        do {INDEX_TWOWORD(num);                                                                         \
-               SET_VARIABLE(num,type);                                                                 \
-               vtype[(num)+1] = TYPE_VOID;                                                             \
-               TOUCH_VARIABLE((num)+1);} while(0)
+               typevectorset_store_twoword(localset,num,type);} while(0)
 
 #define CHECK_ONEWORD(num,type)                                                                                        \
        do {INDEX_ONEWORD(num);                                                                                         \
-               if (vtype[(num)] != (type)) panic("Variable type mismatch");    \
-               TOUCH_VARIABLE(num);} while(0)
+               if (!typevectorset_checktype(localset,num,type))                \
+            panic("Variable type mismatch");                           \
+               } while(0)
 
 #define CHECK_TWOWORD(num,type)                                                                                        \
        do {INDEX_TWOWORD(num);                                                                                         \
-               if (vtype[(num)] != (type)) panic("Variable type mismatch");    \
-               TOUCH_VARIABLE(num);                                                                                    \
-               TOUCH_VARIABLE((num)+1);} while(0)
+               if (!typevectorset_checktype(localset,num,type))                \
+            panic("Variable type mismatch");                           \
+               } while(0)
 
 /* XXX maybe it's faster to copy always */
 #define COPYTYPE(source,dest)   \
@@ -607,8 +1015,8 @@ struct jsr_record {
             srcstack = srcstack->prev;                                  \
         }                                                               \
         for (macro_i=0; macro_i<numlocals; ++macro_i)                   \
-            if (vtype[macro_i] == TYPE_ADR &&                           \
-                TYPEINFO_IS_NEWOBJECT(vinfo[macro_i]))                  \
+            if (localset->td[macro_i].type == TYPE_ADR &&               \
+                TYPEINFO_IS_NEWOBJECT(localset->td[macro_i].info))      \
                 panic("Branching backwards with uninitialized object in local variable"); \
     } while(0)
 
@@ -636,39 +1044,10 @@ struct jsr_record {
 #define TYPECHECK_REACH(way)                                            \
     do {                                                                \
     LOG2("reaching block %04d (%d)",tbptr-block,way);                   \
-    if (tbptr <= bptr && way != REACH_THROW)                            \
+    if (tbptr <= bptr)                                                  \
         TYPECHECK_BRANCH_BACKWARDS;                                     \
-    srcstack = dst;                                                     \
-    dststack = tbptr->instack;                                          \
-    ttype = vartype + numlocals*(tbptr-block);                          \
-    tinfo = vartypeinfo + numlocals*(tbptr-block);                      \
-    if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
-        /* This block is reached for the first time */                  \
-        if (way == REACH_JSR) {                                         \
-            TYPECHECK_ADD_JSR;                                          \
-            TYPECHECK_COPYVARS;                                         \
-        }                                                               \
-        else {                                                          \
-            if (way != REACH_THROW) 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 if (way != REACH_THROW)                                                                   \
-            TYPECHECK_MERGEJSR;                                         \
-        TYPECHECK_MERGEVARS;                                            \
-        if (way != REACH_THROW) TYPECHECK_MERGESTACK;                   \
-    }                                                                   \
-    if (changed) {                                                      \
-        LOG("REACHED!");                                                \
-        tbptr->flags = BBTYPECHECK_REACHED;                             \
-        if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");}             \
-    }                                                                   \
+    repeat |= typestate_reach(localbuf,bptr,tbptr,dst,                  \
+                                                         localset,numlocals);                      \
     LOG("done.");                                                       \
     } while (0)
 
@@ -685,7 +1064,7 @@ struct jsr_record {
         if (initmethod && class != class_java_lang_Object) {            \
             /* check the marker variable */                             \
             LOG("Checking <init> marker");                              \
-            if (vtype[numlocals-1] == TYPE_VOID)                        \
+            if (!typevectorset_checktype(localset,numlocals-1,TYPE_INT))\
                 panic("<init> method does not initialize 'this'");      \
         }                                                               \
     } while (0)
@@ -715,21 +1094,22 @@ typecheck()
     basicblock *tbptr;                   /* temporary for target block */
     int numlocals;                        /* number of local variables */
        int validlocals;         /* number of valid local variable indices */
-    u1 *vartype;            /* type of each local for each basic block */
-    typeinfo *vartypeinfo;  /* type of each local for each basic block */
-    u1 *vtype;           /* type of each local for current instruction */
-    typeinfo *vinfo;     /* type of each local for current instruction */
-    u1 *ttype;                                    /* temporary pointer */
-    typeinfo *tinfo;                              /* temporary pointer */
+
+       void *localbuf;       /* local variable types for each block start */
+       typevector *localset;        /* typevector set for local variables */
+       typevector *lset;                             /* temporary pointer */
+       typedescriptor *td;                           /* temporary pointer */
+
     typeinfo tempinfo;                                    /* temporary */
-    int returntype;                   /* return type of current method */
-    typeinfo returntypeinfo;               /* typeinfo for return type */
+
+       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 */
+    basicblock **tptr;    /* pointer into target list of switch instr. */
     jsr_record **jsrbuffer;   /* JSR target chain for each basic block */
     jsr_record *jsrchain;               /* JSR chain for current block */
     jsr_record *jsrtemp,*jsrtemp2;              /* temporary variables */
@@ -799,15 +1179,11 @@ typecheck()
     if (initmethod) numlocals++;
 
     /* allocate the buffers for local variables */
-    vartype = DMNEW(u1,numlocals * (block_count+1));
-    vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
-    touched = DMNEW(u1,numlocals);
-    vtype = vartype + numlocals * block_count;
-    vinfo = vartypeinfo + numlocals * block_count;
-    memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(u1));
-    memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
+       localbuf = DMNEW_TYPEVECTOR(block_count+1, numlocals);
+       localset = MGET_TYPEVECTOR(localbuf,block_count,numlocals);
+       memset(localbuf,0,(block_count+1) * TYPEVECTOR_SIZE(numlocals));
 
-    LOG("Variable buffer initialized.\n");
+    LOG("Variable buffer allocated.\n");
 
     /* allocate the buffer for storing JSR target chains */
     jsrbuffer = DMNEW(jsr_record*,block_count);
@@ -821,26 +1197,34 @@ typecheck()
 
     /* initialize the variable types of the first block */
     /* to the types of the arguments */
-    ttype = vartype;
-    tinfo = vartypeinfo;
+       lset = MGET_TYPEVECTOR(localbuf,0,numlocals);
+       td = lset->td;
+       i = numlocals;
 
     /* if this is an instance method initialize the "this" ref type */
     if (!(method->flags & ACC_STATIC)) {
-        *ttype++ = TYPE_ADDRESS;
+        td->type = TYPE_ADDRESS;
         if (initmethod)
-            TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+            TYPEINFO_INIT_NEWOBJECT(td->info,NULL);
         else
-            TYPEINFO_INIT_CLASSINFO(*tinfo,class);
-        tinfo++;
+            TYPEINFO_INIT_CLASSINFO(td->info,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,
-                                   numlocals - (tinfo-vartypeinfo),
-                                   true, /* two word types use two slots */
-                                   &returntype,&returntypeinfo);
+    i = typedescriptors_init_from_method_args(td,method->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");
 
@@ -892,14 +1276,13 @@ typecheck()
                 handlers[len] = NULL;
                                        
                 /* init variable types at the start of this block */
-                for (i=0; i<numlocals; ++i) {
-                    vtype[i] = vartype[numlocals*b_index + i];
-                    TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
-
-                    if (handlers[0] &&
-                        vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
-                        panic("Uninitialized object in local variable inside try block");
-                }
+                               COPY_TYPEVECTORSET(MGET_TYPEVECTOR(localbuf,b_index,numlocals),
+                                                                  localset,numlocals);
+                               if (handlers[0])
+                                       for (i=0; i<numlocals; ++i)
+                                               if (localset->td[i].type == TYPE_ADR
+                                                       && TYPEINFO_IS_NEWOBJECT(localset->td[i].info))
+                                                       panic("Uninitialized object in local variable inside try block");
 
                 /* init JSR target chain */
                 if ((jsrchain = jsrbuffer[b_index]) != NULL) {
@@ -924,7 +1307,7 @@ typecheck()
 #ifdef TYPECHECK_VERBOSE
                 if (typecheckverbose) {
                     if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
-                    typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    typestate_print(get_logfile(),curstack,localset,numlocals);
                     LOGNL; LOGFLUSH;
                 }
 #endif
@@ -999,17 +1382,31 @@ typecheck()
                           COPYTYPE(curstack->prev,dst);
                           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:
-                          CHECK_ONEWORD(iptr->op1,TYPE_ADR);
+                                                 INDEX_ONEWORD(iptr->op1);
                           
                           /* loading a returnAddress is not allowed */
-                          if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
-                              panic("illegal instruction: ALOAD loading returnAddress");
+                          if (!typevectorset_checkreference(localset,iptr->op1))
+                              panic("illegal instruction: ALOAD loading non-reference");
 
-                          TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+                                                 typevectorset_copymergedtype(localset,iptr->op1,&(dst->typeinfo));
                           break;
                                                        
                           /****************************************/
@@ -1019,9 +1416,13 @@ typecheck()
                           if (handlers[0] &&
                               TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
                               panic("Storing uninitialized object in local variable inside try block");
-                          
-                          STORE_ONEWORD(iptr->op1,TYPE_ADDRESS);
-                          TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+
+                                                 INDEX_ONEWORD(iptr->op1);
+                                                 if (TYPESTACK_IS_RETURNADDRESS(curstack))
+                                                         typevectorset_store_retaddr(localset,iptr->op1,&(curstack->typeinfo));
+                                                 else
+                                                         typevectorset_store(localset,iptr->op1,TYPE_ADDRESS,
+                                                                                                 &(curstack->typeinfo));
                           break;
                           
                           /****************************************/
@@ -1151,7 +1552,8 @@ typecheck()
                               panic("illegal instruction: ARRAYLENGTH on non-array");
                           maythrow = true;
                           break;
-                                                         
+
+                                                 /* XXX unify cases? */
                       case ICMD_BALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
                               && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
@@ -1227,7 +1629,19 @@ typecheck()
                           break;
 
                           /****************************************/
-                          /* OPERATIONS WITH UNCHECKED INPUT      */
+                          /* ADDRESS CONSTANTS                    */
+
+                      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;
+
+                          /****************************************/
+                          /* CHECKCAST AND INSTANCEOF             */
 
                       case ICMD_CHECKCAST:
                                                  TYPECHECK_ADR(curstack);
@@ -1250,15 +1664,6 @@ typecheck()
                           /* XXX optimize statically? */
                           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                  */
 
@@ -1306,8 +1711,8 @@ typecheck()
                       case ICMD_TABLESWITCH:
                           {
                               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;
@@ -1315,8 +1720,8 @@ typecheck()
                       case ICMD_LOOKUPSWITCH:
                           {
                               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;
@@ -1345,29 +1750,29 @@ 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");
                                                  goto return_tail;
                                                  
                       case ICMD_IRETURN:
-                          if (returntype != TYPE_INT) panic("Return type mismatch");
+                          if (returntype.type != TYPE_INT) panic("Return type mismatch");
                                                  goto return_tail;
                                                  
                       case ICMD_LRETURN:
-                          if (returntype != TYPE_LONG) panic("Return type mismatch");
+                          if (returntype.type != TYPE_LONG) panic("Return type mismatch");
                                                  goto return_tail;
                                                  
                       case ICMD_FRETURN:
-                          if (returntype != TYPE_FLOAT) panic("Return type mismatch");
+                          if (returntype.type != TYPE_FLOAT) panic("Return type mismatch");
                                                  goto return_tail;
                                                  
                       case ICMD_DRETURN:
-                          if (returntype != TYPE_DOUBLE) panic("Return type mismatch");
+                          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;
@@ -1385,14 +1790,15 @@ typecheck()
                            */
                           dst = (stackptr) iptr->val.a;
                           
-                          /* push return address */
-                          TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+                          tbptr = (basicblock *) iptr->target;
+                                                 repeat |= typestate_jsr(localbuf,bptr,tbptr,dst,localset,numlocals);
+#if 0
+                          TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,tbptr);
 
                           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 */
@@ -1429,30 +1835,51 @@ typecheck()
                               repeat = true;
                               superblockend = true;
                           }
-                          /* XXX may throw? I don't think. */
+#endif
+                          /* XXX may throw? I don't think so. */
+                                                 superblockend = true;
                           break;
                           
                       case ICMD_RET:
                           /* check returnAddress variable */
-                          CHECK_ONEWORD(iptr->op1,TYPE_ADR);
-                          
-                          if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                          INDEX_ONEWORD(iptr->op1);
+                                                 if (!typevectorset_checkretaddr(localset,iptr->op1))
                               panic("illegal instruction: RET using non-returnAddress variable");
 
+                                                 repeat |= typestate_ret(localbuf,bptr,curstack,
+                                                                                                 localset,iptr->op1,numlocals);
+
+#if 0
                           /* check if we are inside a subroutine */
                           if (!subroutine)
                               panic("RET outside of subroutine");
 
+                                                 /* check if the right returnAddress is used (XXX is this too strict?) */
+                                                 if ((basicblock*)TYPEINFO_RETURNADDRESS(vinfo[iptr->op1])
+                                                         != subroutine->target)
+                                                         panic("RET uses returnAddress of another subroutine");
+
                           /* determine which variables are touched by this subroutine */
                           /* and their types */
                           if (subroutine->sbr_touched) {
+                                                         /* We have reached a RET in this subroutine before. */
+                                                         
+                                                         /* Check if there is more than one RET instruction
+                                                          * returning from this subroutine. */
+                                                         if (subroutine->sbr_ret != iptr)
+                                                                 panic("JSR subroutine has more than one RET instruction");
+
+                                                         /* Merge the array of touched locals and their types */
                               for (i=0; i<numlocals; ++i)
                                   subroutine->sbr_touched[i] |= touched[i];
                               ttype = subroutine->sbr_vtype;
                               tinfo = subroutine->sbr_vinfo;
                               TYPECHECK_MERGEVARS;
+                                                         /* XXX check if subroutine changed types? */
                           }
                           else {
+                                                         /* This is the first time we reach a RET in this subroutine */
+                                                         subroutine->sbr_ret = iptr;
                               subroutine->sbr_touched = DMNEW(u1,numlocals);
                               memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
                               subroutine->sbr_vtype = DMNEW(u1,numlocals);
@@ -1462,14 +1889,13 @@ typecheck()
                                   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,numlocals));
                           LOGNL; LOGFLUSH;
 
-                          /* reach blocks after JSR statements */
+                          /* XXX reach blocks after JSR statements */
                           for (i=0; i<block_count; ++i) {
                               tbptr = block + i;
                               LOG1("block L%03d",tbptr->debug_nr);
@@ -1480,10 +1906,11 @@ typecheck()
                                   continue;
                               tbptr++;
 
-                              LOG1("RET reaches block %04d",tbptr-block);
+                              LOG1("RET reaches block L%03d",tbptr->debug_nr);
 
                               /*TYPECHECK_REACH(REACH_RET);*/
                           }
+#endif
                           
                           superblockend = true;
                           break;
@@ -1596,15 +2023,7 @@ typecheck()
                                       srcstack = srcstack->prev;
                                   }
                                   /* replace uninitialized object type in locals */
-                                  for (i=0; i<numlocals; ++i) {
-                                      if (vtype[i] == TYPE_ADR
-                                          && TYPEINFO_IS_NEWOBJECT(vinfo[i])
-                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
-                                      {
-                                          LOG1("replacing uninitialized type in local %d",i);
-                                          TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
-                                      }
-                                  }
+                                                                 typevectorset_init_object(localset,ins,initclass,numlocals);
 
                                   /* initializing the 'this' reference? */
                                   if (!ins) {
@@ -1618,7 +2037,7 @@ typecheck()
                                                                          
                                       /* set our marker variable to type int */
                                       LOG("setting <init> marker");
-                                                                         vtype[numlocals-1] = TYPE_INT;
+                                                                         typevectorset_store(localset,numlocals-1,TYPE_INT,NULL);
                                   }
                                                                  else {
                                                                          /* initializing an instance created with NEW */
@@ -1756,7 +2175,7 @@ typecheck()
                                                                  panic("Invalid instruction: NEW creating instance of abstract class");
                               TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
                           }
-                                                 /* XXX unify the following cases */
+                                                 /* XXX unify the following cases? */
                           else if (ISBUILTIN(BUILTIN_newarray_boolean)) {
                                                          TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
@@ -1803,22 +2222,35 @@ typecheck()
                           break;
                                                      
                           /****************************************/
-                          /* PRIMITIVE VARIABLE ACCESS            */
+                          /* 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_POP:
+                      case ICMD_POP2:
+                          break;
+
+                          /****************************************/
+                          /* 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: 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;
-                          
                           /****************************************/
                           /* INSTRUCTIONS WHICH SHOULD HAVE BEEN  */
-                          /* REPLACED BY BUILTIN CALLS            */
+                          /* REPLACED BY OTHER OPCODES            */
 
                       case ICMD_NEW:
                       case ICMD_NEWARRAY:
@@ -1832,30 +2264,28 @@ typecheck()
                           panic("Internal error: unexpected instruction encountered");
                           break;
                                                      
-                          /****************************************/
-                          /* 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_POP:
-                      case ICMD_POP2:
-                      case ICMD_READONLY_ARG: /* XXX ? */
-                      case ICMD_CLEAR_ARGREN: /* XXX ? */
-                          break;
-
-                      case ICMD_CHECKASIZE:
-                      case ICMD_NULLCHECKPOP:
-                          maythrow = true;
+                      case ICMD_READONLY_ARG:
+                      case ICMD_CLEAR_ARGREN:
+                          /* XXX only check this in debug mode? */
+                          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;
-
+                                                 
                           /****************************************/
                           /* ARITHMETIC AND CONVERSION            */
-                          /* (These instructions are typechecked in analyse_stack.) */
 
-                          /* The following instructions may throw a runtime exception: */
+                                                 /*********************************************
+                                                  * 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:
@@ -1865,7 +2295,7 @@ typecheck()
                           maythrow = true;
                           break;
                           
-                          /* The following instructions never throw a runtime exception: */
+                          /* Instructions which never throw a runtime exception: */
                           /* XXX only add cases for them in debug mode? */
                           
                       case ICMD_ICONST:
@@ -1980,7 +2410,8 @@ typecheck()
                         i = 0;
                         while (handlers[i]) {
                             tbptr = handlers[i]->handler;
-                            TYPECHECK_REACH(REACH_THROW); /* XXX jsr chain? */
+                                                       repeat |= typestate_reach(localbuf,bptr,tbptr,
+                                                                                                         tbptr->instack,localset,numlocals);
                             i++;
                         }
                     }
@@ -1995,7 +2426,7 @@ typecheck()
 
                 LOG("instructions done");
                 LOGSTR("RESULT=> ");
-                DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+                DOLOG(typestate_print(get_logfile(),curstack,localset,numlocals));
                 LOGNL; LOGFLUSH;
                 
                 /* propagate stack and variables to the following block */
index a427ad559810b4524a63d85cfd229fd1289d408d..8e3b18a6ed4945fa1caec59065c94aa6ee89e641 100644 (file)
--- a/loader.c
+++ b/loader.c
@@ -30,7 +30,7 @@
             Mark Probst
                        Edwin Steiner
 
-   $Id: loader.c 867 2004-01-07 22:05:04Z edwin $
+   $Id: loader.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -744,10 +744,13 @@ static void checkfielddescriptor (char *utf_ptr, char *end_pos)
 
     checks whether a method-descriptor is valid and aborts otherwise.
     All referenced classes are inserted into the list of unloaded classes.
+
+    The number of arguments is returned. A long or double argument is counted
+    as two arguments.
        
 *******************************************************************************/
 
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor (utf *d)
 {
        char *utf_ptr = d->text;     /* current position in utf text   */
        char *end_pos = utf_end(d);  /* points behind utf string       */
@@ -761,9 +764,9 @@ static void checkmethoddescriptor (utf *d)
                /* XXX we cannot count the this argument here because
                 * we don't know if the method is static. */
                if (*utf_ptr == 'J' || *utf_ptr == 'D')
+                       argcount+=2;
+               else
                        argcount++;
-               if (++argcount > 255)
-                       panic("Invalid method descriptor: too many arguments");
                class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
                                                          CLASSLOAD_NEW
                                                          | CLASSLOAD_NULLPRIMITIVE
@@ -778,6 +781,11 @@ static void checkmethoddescriptor (utf *d)
                                                  | CLASSLOAD_NULLPRIMITIVE
                                                  | CLASSLOAD_CHECKEND);
 
+       if (argcount > 255)
+               panic("Invalid method descriptor: too many arguments");
+
+       return argcount;
+
        /* XXX use the following if -noverify */
 #if 0
        /* XXX check length */
@@ -897,6 +905,8 @@ static void field_load(fieldinfo *f, classinfo *c)
                        if ((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
                                != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
                                panic("Interface field is not declared static final public");
+                       if ((f->flags & ACC_TRANSIENT) != 0)
+                               panic("Interface field declared transient");
                }
        }
                
@@ -1021,6 +1031,7 @@ void field_display(fieldinfo *f)
 static void method_load(methodinfo *m, classinfo *c)
 {
        u4 attrnum, i, e;
+       int argcount;
        
 #ifdef STATISTICS
        count_all_methods++;
@@ -1031,10 +1042,15 @@ static void method_load(methodinfo *m, classinfo *c)
        m->flags = suck_u2();
        m->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
        m->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
-       checkmethoddescriptor(m->descriptor);   
+       argcount = checkmethoddescriptor(m->descriptor);
+       if ((m->flags & ACC_STATIC) == 0)
+               argcount++; /* count the 'this' argument */
 
-       /* check flag consistency */
        if (opt_verify) {
+               if (argcount > 255)
+                       panic("Method has more than 255 arguments");
+
+               /* check flag consistency */
                /* XXX could check if <clinit> is STATIC */
                if (m->name != utf_clinit) {
                        i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
@@ -1102,6 +1118,9 @@ static void method_load(methodinfo *m, classinfo *c)
                        suck_u4();
                        m->maxstack = suck_u2();
                        m->maxlocals = suck_u2();
+                       if (m->maxlocals < argcount)
+                               panic("max_locals is smaller than the number of arguments");
+                       
                        codelen = suck_u4();
                        if (codelen == 0)
                                panic("bytecode has zero length");
@@ -1471,7 +1490,10 @@ static void class_loadcpool(classinfo *c)
                                ASSERT_LEFT(length);
                                if (opt_verify &&
                                        !is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
-                                       panic("Invalid UTF-8 string"); 
+                               {
+                                       dolog("Invalid UTF-8 string (constant pool index %d)",idx);
+                                       panic("Invalid UTF-8 string");
+                               }
                                /* insert utf-string into the utf-symboltable */
                                cpinfos [idx] = utf_new(classbuf_pos+1, length);
                                /* skip bytes of the string */
@@ -1653,11 +1675,18 @@ static int class_load(classinfo *c)
 
        /* check ACC flags consistency */
        if ((c->flags & ACC_INTERFACE) != 0) {
-               if ((c->flags & ACC_ABSTRACT) == 0)
-                       panic("Interface class not declared abstract");
+               if ((c->flags & ACC_ABSTRACT) == 0) {
+                       /* XXX We work around this because interfaces in JDK 1.1 are
+                        * not declared abstract. */
+
+                       c->flags |= ACC_ABSTRACT;
+                       /* panic("Interface class not declared abstract"); */
+               }
                if ((c->flags & (ACC_FINAL | ACC_SUPER)) != 0)
                        panic("Interface class has invalid flags");
        }
+       if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
+               panic("Class is declared both abstract and final");
 
        /* this class */
        i = suck_u2();
@@ -2052,8 +2081,13 @@ void class_link(classinfo *c)
                        list_addlast(&unlinkedclasses, c);
                        return; 
                }
-               if ((ic->flags & ACC_INTERFACE) == 0)
+               if ((ic->flags & ACC_INTERFACE) == 0) {
+                       dolog("Specified interface is not declared as interface:");
+                       log_utf(ic->name);
+                       dolog("in");
+                       log_utf(c->name);
                        panic("Specified interface is not declared as interface");
+               }
        }
        
        /*  check super class */
index 68bcb9b720769636f6f457e1fe2d1bc3e6655f9d..6d3ee98bbf2cb2dfc99a8205b485e13fd2ca1000 100644 (file)
@@ -34,7 +34,7 @@
    calls instead of machine instructions, using the C calling
    convention.
 
-   $Id: builtin.c 862 2004-01-06 23:42:01Z stefan $
+   $Id: builtin.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -1833,6 +1833,12 @@ java_arrayheader *builtin_clone_array(void *env, java_arrayheader *o)
        return (java_arrayheader *) Java_java_lang_VMObject_clone(0, 0, (java_lang_Cloneable *) o);
 }
 
+s4 builtin_dummy()
+{
+       panic("Internal error: builtin_dummy called (native function is missing)");
+       return 0; /* for the compiler */
+}
+
 
 /*
  * These are local overrides for various environment variables in Emacs.
index 63c407205a6e2525dd6b4b781f3c226f2820de93..b2df84fcc7aafb1a46672c43ffeb8189f5fa81e0 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: builtin.h 862 2004-01-06 23:42:01Z stefan $
+   $Id: builtin.h 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -374,6 +374,10 @@ float    builtin_d2f(double a);    /* XXX? */
 java_arrayheader *builtin_clone_array(void *env, java_arrayheader *o);
 /* NOT AN OP */
 
+/* builtin_dummy just panics if it is executed. */
+s4 builtin_dummy();
+/* NOT AN OP */
+
 /* conversion helper functions */
 
 inline float intBitsToFloat(s4 i);
index fbd023fe13a30c0f72f27cdcf32f3da2fc455150..628bcc2fa73749d4ac0af8d3037cfb0466fc3006 100644 (file)
@@ -29,7 +29,7 @@
 
    Changes: Christian Thalinger
 
-   $Id: jit.h 845 2004-01-05 10:38:06Z twisti $
+   $Id: jit.h 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -186,6 +186,11 @@ struct dataref {
 };
 
 
+/********** op1 values for ACONST instructions ********************************/
+
+#define ACONST_LOAD     0  /* ACONST_NULL or LDC instruction                  */
+#define ACONST_BUILTIN  1  /* constant argument for a builtin function call   */
+
 /********** JavaVM operation codes (sorted) and instruction lengths ***********/
 
 extern char *icmd_names[256];
index e594e66b7c7d46609d09630e075d09f8666ce9de..825b0dc80481fdea550ef9deff89f9c3e51765cf 100644 (file)
@@ -29,7 +29,7 @@
    Changes: Carolyn Oates
             Edwin Steiner
 
-   $Id: parse.c 863 2004-01-07 18:50:41Z edwin $
+   $Id: parse.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -334,6 +334,13 @@ void descriptor2types(methodinfo *m)
 #define LOADCONST_F(v) iptr->opc=ICMD_FCONST;iptr->op1=0;iptr->val.f=(v);PINC
 #define LOADCONST_D(v) iptr->opc=ICMD_DCONST;iptr->op1=0;iptr->val.d=(v);PINC
 #define LOADCONST_A(v) iptr->opc=ICMD_ACONST;iptr->op1=0;iptr->val.a=(v);PINC
+
+/* ACONST instructions generated as arguments for builtin functions
+ * have op1 set to non-zero. This is used for stack overflow checking
+ * in stack.c. */
+#define LOADCONST_A_BUILTIN(v) \
+                       iptr->opc=ICMD_ACONST;iptr->op1=1;iptr->val.a=(v);PINC
+
 #define OP(o)          iptr->opc=(o);iptr->op1=0;iptr->val.l=0;PINC
 #define OP1(o,o1)      iptr->opc=(o);iptr->op1=(o1);iptr->val.l=(0);PINC
 #define OP2I(o,o1,v)   iptr->opc=(o);iptr->op1=(o1);iptr->val.i=(v);PINC
@@ -903,7 +910,7 @@ void parse()
                        i = code_get_u2(p + 1);
                        {
                                        classinfo *component = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
-                                       LOADCONST_A(class_array_of(component)->vftbl);
+                                       LOADCONST_A_BUILTIN(class_array_of(component)->vftbl);
 
                                s_count++;
 
@@ -1246,7 +1253,7 @@ void parse()
                case JAVA_NEW:
                        i = code_get_u2 (p+1);
 
-                       LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+                       LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
                        s_count++;
                        BUILTIN1(BUILTIN_new, TYPE_ADR);
                        break;
@@ -1260,13 +1267,13 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl);
+                                               LOADCONST_A_BUILTIN(cls->vftbl);
                                                s_count++;
                                                BUILTIN2(BUILTIN_checkarraycast, TYPE_ADR);
                                        }
                                        else { /* object type cast-check */
                                                /*
-+                                                LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
++                                                LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
 +                                                s_count++;
 +                                                BUILTIN2(BUILTIN_checkcast, TYPE_ADR);
 +                                              */
@@ -1286,13 +1293,13 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl);
+                                               LOADCONST_A_BUILTIN(cls->vftbl);
                                                s_count++;
                                                BUILTIN2(BUILTIN_arrayinstanceof, TYPE_INT);
                                        }
                                        else { /* object type cast-check */
                                                /*
-                                                 LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+                                                 LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
                                                  s_count++;
                                                  BUILTIN2(BUILTIN_instanceof, TYPE_INT);
 +                                              */
index 470ea8bf792f000dafc696b781a4dd86d8209bd8..3c3db3367fd73895a16341e311f8b13fe9c1aba0 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: stack.c 846 2004-01-05 10:40:42Z twisti $
+   $Id: stack.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -85,14 +85,15 @@ extern int dseglen;
 #define REQUIRE_4     REQUIRE(4)
 
 /* overflow check */
-/* XXX we allow ACONST to exceed the maximum stack depth because it is
- * generated for builtin calls. Maybe we should check against maximum
- * stack depth only at block boundaries?
+/* XXX we allow ACONST instructions inserted as arguments to builtin
+ * functions to exceed the maximum stack depth.  Maybe we should check
+ * against maximum stack depth only at block boundaries?
  */
 #define CHECKOVERFLOW                                                  \
        do {                                                                            \
                if (stackdepth > maxstack) {                    \
-                       if (iptr[0].opc != ICMD_ACONST)         \
+                       if (iptr[0].opc != ICMD_ACONST          \
+                || iptr[0].op1 == 0)            \
                        {OVERFLOW;}                                                     \
                }                                                                               \
        } while(0)
@@ -290,7 +291,7 @@ extern int dseglen;
  *   - check for matching stack depth at merging points
  *   - check for matching basic types[2] at merging points
  *   - check basic types for instruction input (except for BUILTIN*
- *         opcodes and MULTIANEWARRAY)
+ *         opcodes, INVOKE* opcodes and MULTIANEWARRAY)
  *
  * [1]) XXX Checking this after the instruction should be ok. parse.c
  * counts the number of required stack slots in such a way that it is
@@ -1782,6 +1783,9 @@ void analyse_stack()
                                                iptr->val.a = (void *) iptr->dst;
 
                                                tbptr->type = BBTYPE_SBR;
+
+                                               /* We need to check for overflow right here because
+                                                * the pushed value is poped after MARKREACHED. */
                                                CHECKOVERFLOW;
                                                MARKREACHED(tbptr, copy);
                                                OP1_0ANY;
index 15e62927d72c53ed1d7dd83310c6b2d284c99ff5..35e472826fdcbd4b72ec40488be40df0731d7a6a 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 822 2003-12-31 16:00:58Z edwin $
+   $Id: typecheck.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -147,6 +147,27 @@ typeinfo_print_block(FILE *file,stackptr instack,
     typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
 }
 
+static
+void
+typestack_print(FILE *file,stackptr stack)
+{
+    while (stack) {
+        typeinfo_print_stacktype(file,stack->type,&stack->typeinfo);
+        stack = stack->prev;
+        if (stack) fprintf(file," ");
+    }
+}
+
+static
+void
+typestate_print(FILE *file,stackptr instack,typevector *localset,int size)
+{
+    fprintf(file,"Stack: ");
+    typestack_print(file,instack);
+    fprintf(file," Locals:");
+    typevectorset_print(file,localset,size);
+}
+
 
 #if 0
 static
@@ -173,6 +194,393 @@ typeinfo_print_blocks(FILE *file,int vnum,u1 *vtype,typeinfo *vinfo)
 
 #endif
 
+/****************************************************************************/
+/* TYPESTACK FUNCTIONS                                                      */
+/****************************************************************************/
+
+#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)
+
+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");
+               if (dst->type != y->type)
+                       panic("Stack type mismatch");
+               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");
+}
+
+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 bool
+typestack_canmerge(stackptr a,stackptr b)
+{
+       for (; a; a = a->prev, b = b->prev) {
+               if (!b) return false;
+               if (a->type != b->type) return false;
+               if (a->type == TYPE_ADDRESS) {
+                       if (((TYPEINFO_IS_PRIMITIVE(a->typeinfo)) ? 1 : 0)
+                               ^
+                               ((TYPEINFO_IS_PRIMITIVE(b->typeinfo)) ? 1 : 0))
+                               return false;
+               }
+       }
+       if (b) return false;
+       return true;
+}
+
+static void
+typestack_collapse(stackptr dst)
+{
+       for (; dst; dst = dst->prev) {
+               if (TYPESTACK_IS_RETURNADDRESS(dst))
+                       TYPESTACK_RETURNADDRESSSET(dst)->alt = NULL;
+       }
+}
+
+/* 'dst' and 'y' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_merge(stackptr dst,stackptr y)
+{
+       bool changed = false;
+       for (; dst; dst = dst->prev, y=y->prev) {
+               if (TYPESTACK_IS_REFERENCE(dst))
+                       changed |= typeinfo_merge(&(dst->typeinfo),&(y->typeinfo));
+       }
+       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;
+       int i;
+
+       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;
+}
+
+/****************************************************************************/
+/* TYPESTATE FUNCTIONS                                                      */
+/****************************************************************************/
+
+static bool
+typestate_merge(stackptr deststack,typevector *destloc,
+                               stackptr ystack,typevector *yloc,
+                               /*                              int retindex,void *retaddr, */
+                               int locsize)
+{
+       typevector *dvec,*yvec;
+       int kd,ky;
+       bool changed = false;
+       
+#ifdef TYPECHECK_DEBUG
+       /* Do some sanity checks */
+       /*
+         if (retindex < -1 || retindex >= locsize || (retindex >= 0 && !retaddr))
+         panic("Internal error: typestate_merge: invalid arguments");
+       */
+#endif
+
+       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;
+
+       /* Check if the stack types of deststack and ystack match */
+
+       /* XXX move this check into typestack_merge? */
+       if (!typestack_canmerge(deststack,ystack))
+               panic("Stack depth or stack type mismatch");
+
+       /* The stack is always merged. If there are returnAddresses on
+        * the stack they are ignored in this step. */
+
+       changed |= typestack_merge(deststack,ystack);
+
+       for (yvec=yloc; yvec; yvec=yvec->alt) {
+               ky = yvec->k;
+
+               /* If retindex >= 0 we select only those states (ystack,yvec)
+                * with returnAddress retaddr in variable no. retindex. */
+
+               /*
+                 if (retindex >= 0) {
+                 if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+                 panic("Illegal instruction: RET on non-returnAddress");
+                 if (TYPEINFO_RETURNADDRESS(yvec->td[retindex].info)
+                 != retaddr)
+                 continue;
+                 }
+               */
+
+               /* 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;
+       
+       return changed;
+}
+
+/* Globals used:
+ *     block
+ */
+static bool
+typestate_reach(void *localbuf,
+                               basicblock *current,
+                               basicblock *destblock,
+                               stackptr ystack,typevector *yloc,
+                               int locsize)
+{
+       typevector *yvec;
+       typevector *destloc;
+       int destidx;
+       bool repeat = false;
+       bool changed = false;
+       
+       destidx = destblock - block;
+       destloc = MGET_TYPEVECTOR(localbuf,destidx,locsize);
+
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               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 */
+               
+               LOG1("block (index %04d) reached before",destidx);
+               
+               changed = typestate_merge(destblock->instack,destloc,
+                                                                 ystack,yloc,locsize);
+       }
+
+       if (changed) {
+               LOG("changed!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               if (destblock <= current) {repeat = true; LOG("REPEAT!");}
+       }
+       return repeat;
+}
+
+/* Globals used:
+ *     see typestate_reach
+ */
+static bool
+typestate_ret(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(localbuf,current,destblock,
+                                                                 ystack,selected,locsize);
+       }
+       return repeat;
+}
+
+static bool
+typestate_jsr(void *localbuf,
+                         basicblock *current,basicblock *destblock,
+                         stackptr ystack,typevector *yloc,
+                         int locsize)
+{
+       typestack_put_retaddr(ystack,current+1,yloc);
+       return typestate_reach(localbuf,current,destblock,ystack,yloc,locsize);
+}
+
 /****************************************************************************/
 /* HELPER FUNCTIONS                                                         */
 /****************************************************************************/
@@ -282,12 +690,13 @@ typedef struct jsr_record jsr_record;
  * 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 */
+    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 */
+       instruction *sbr_ret;     /* RET instruction of the subroutine */
+    u1           touched[1];  /* touched flags for local variables */
 };
 
 /****************************************************************************/
@@ -316,24 +725,23 @@ struct jsr_record {
 
 #define STORE_ONEWORD(num,type)                                                                        \
        do {INDEX_ONEWORD(num);                                                                         \
-               SET_VARIABLE(num,type);} while(0)
+               typevectorset_store(localset,num,type,NULL);} while(0)
 
 #define STORE_TWOWORD(num,type)                                                                        \
        do {INDEX_TWOWORD(num);                                                                         \
-               SET_VARIABLE(num,type);                                                                 \
-               vtype[(num)+1] = TYPE_VOID;                                                             \
-               TOUCH_VARIABLE((num)+1);} while(0)
+               typevectorset_store_twoword(localset,num,type);} while(0)
 
 #define CHECK_ONEWORD(num,type)                                                                                        \
        do {INDEX_ONEWORD(num);                                                                                         \
-               if (vtype[(num)] != (type)) panic("Variable type mismatch");    \
-               TOUCH_VARIABLE(num);} while(0)
+               if (!typevectorset_checktype(localset,num,type))                \
+            panic("Variable type mismatch");                           \
+               } while(0)
 
 #define CHECK_TWOWORD(num,type)                                                                                        \
        do {INDEX_TWOWORD(num);                                                                                         \
-               if (vtype[(num)] != (type)) panic("Variable type mismatch");    \
-               TOUCH_VARIABLE(num);                                                                                    \
-               TOUCH_VARIABLE((num)+1);} while(0)
+               if (!typevectorset_checktype(localset,num,type))                \
+            panic("Variable type mismatch");                           \
+               } while(0)
 
 /* XXX maybe it's faster to copy always */
 #define COPYTYPE(source,dest)   \
@@ -607,8 +1015,8 @@ struct jsr_record {
             srcstack = srcstack->prev;                                  \
         }                                                               \
         for (macro_i=0; macro_i<numlocals; ++macro_i)                   \
-            if (vtype[macro_i] == TYPE_ADR &&                           \
-                TYPEINFO_IS_NEWOBJECT(vinfo[macro_i]))                  \
+            if (localset->td[macro_i].type == TYPE_ADR &&               \
+                TYPEINFO_IS_NEWOBJECT(localset->td[macro_i].info))      \
                 panic("Branching backwards with uninitialized object in local variable"); \
     } while(0)
 
@@ -636,39 +1044,10 @@ struct jsr_record {
 #define TYPECHECK_REACH(way)                                            \
     do {                                                                \
     LOG2("reaching block %04d (%d)",tbptr-block,way);                   \
-    if (tbptr <= bptr && way != REACH_THROW)                            \
+    if (tbptr <= bptr)                                                  \
         TYPECHECK_BRANCH_BACKWARDS;                                     \
-    srcstack = dst;                                                     \
-    dststack = tbptr->instack;                                          \
-    ttype = vartype + numlocals*(tbptr-block);                          \
-    tinfo = vartypeinfo + numlocals*(tbptr-block);                      \
-    if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
-        /* This block is reached for the first time */                  \
-        if (way == REACH_JSR) {                                         \
-            TYPECHECK_ADD_JSR;                                          \
-            TYPECHECK_COPYVARS;                                         \
-        }                                                               \
-        else {                                                          \
-            if (way != REACH_THROW) 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 if (way != REACH_THROW)                                                                   \
-            TYPECHECK_MERGEJSR;                                         \
-        TYPECHECK_MERGEVARS;                                            \
-        if (way != REACH_THROW) TYPECHECK_MERGESTACK;                   \
-    }                                                                   \
-    if (changed) {                                                      \
-        LOG("REACHED!");                                                \
-        tbptr->flags = BBTYPECHECK_REACHED;                             \
-        if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");}             \
-    }                                                                   \
+    repeat |= typestate_reach(localbuf,bptr,tbptr,dst,                  \
+                                                         localset,numlocals);                      \
     LOG("done.");                                                       \
     } while (0)
 
@@ -685,7 +1064,7 @@ struct jsr_record {
         if (initmethod && class != class_java_lang_Object) {            \
             /* check the marker variable */                             \
             LOG("Checking <init> marker");                              \
-            if (vtype[numlocals-1] == TYPE_VOID)                        \
+            if (!typevectorset_checktype(localset,numlocals-1,TYPE_INT))\
                 panic("<init> method does not initialize 'this'");      \
         }                                                               \
     } while (0)
@@ -715,21 +1094,22 @@ typecheck()
     basicblock *tbptr;                   /* temporary for target block */
     int numlocals;                        /* number of local variables */
        int validlocals;         /* number of valid local variable indices */
-    u1 *vartype;            /* type of each local for each basic block */
-    typeinfo *vartypeinfo;  /* type of each local for each basic block */
-    u1 *vtype;           /* type of each local for current instruction */
-    typeinfo *vinfo;     /* type of each local for current instruction */
-    u1 *ttype;                                    /* temporary pointer */
-    typeinfo *tinfo;                              /* temporary pointer */
+
+       void *localbuf;       /* local variable types for each block start */
+       typevector *localset;        /* typevector set for local variables */
+       typevector *lset;                             /* temporary pointer */
+       typedescriptor *td;                           /* temporary pointer */
+
     typeinfo tempinfo;                                    /* temporary */
-    int returntype;                   /* return type of current method */
-    typeinfo returntypeinfo;               /* typeinfo for return type */
+
+       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 */
+    basicblock **tptr;    /* pointer into target list of switch instr. */
     jsr_record **jsrbuffer;   /* JSR target chain for each basic block */
     jsr_record *jsrchain;               /* JSR chain for current block */
     jsr_record *jsrtemp,*jsrtemp2;              /* temporary variables */
@@ -799,15 +1179,11 @@ typecheck()
     if (initmethod) numlocals++;
 
     /* allocate the buffers for local variables */
-    vartype = DMNEW(u1,numlocals * (block_count+1));
-    vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
-    touched = DMNEW(u1,numlocals);
-    vtype = vartype + numlocals * block_count;
-    vinfo = vartypeinfo + numlocals * block_count;
-    memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(u1));
-    memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
+       localbuf = DMNEW_TYPEVECTOR(block_count+1, numlocals);
+       localset = MGET_TYPEVECTOR(localbuf,block_count,numlocals);
+       memset(localbuf,0,(block_count+1) * TYPEVECTOR_SIZE(numlocals));
 
-    LOG("Variable buffer initialized.\n");
+    LOG("Variable buffer allocated.\n");
 
     /* allocate the buffer for storing JSR target chains */
     jsrbuffer = DMNEW(jsr_record*,block_count);
@@ -821,26 +1197,34 @@ typecheck()
 
     /* initialize the variable types of the first block */
     /* to the types of the arguments */
-    ttype = vartype;
-    tinfo = vartypeinfo;
+       lset = MGET_TYPEVECTOR(localbuf,0,numlocals);
+       td = lset->td;
+       i = numlocals;
 
     /* if this is an instance method initialize the "this" ref type */
     if (!(method->flags & ACC_STATIC)) {
-        *ttype++ = TYPE_ADDRESS;
+        td->type = TYPE_ADDRESS;
         if (initmethod)
-            TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+            TYPEINFO_INIT_NEWOBJECT(td->info,NULL);
         else
-            TYPEINFO_INIT_CLASSINFO(*tinfo,class);
-        tinfo++;
+            TYPEINFO_INIT_CLASSINFO(td->info,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,
-                                   numlocals - (tinfo-vartypeinfo),
-                                   true, /* two word types use two slots */
-                                   &returntype,&returntypeinfo);
+    i = typedescriptors_init_from_method_args(td,method->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");
 
@@ -892,14 +1276,13 @@ typecheck()
                 handlers[len] = NULL;
                                        
                 /* init variable types at the start of this block */
-                for (i=0; i<numlocals; ++i) {
-                    vtype[i] = vartype[numlocals*b_index + i];
-                    TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
-
-                    if (handlers[0] &&
-                        vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
-                        panic("Uninitialized object in local variable inside try block");
-                }
+                               COPY_TYPEVECTORSET(MGET_TYPEVECTOR(localbuf,b_index,numlocals),
+                                                                  localset,numlocals);
+                               if (handlers[0])
+                                       for (i=0; i<numlocals; ++i)
+                                               if (localset->td[i].type == TYPE_ADR
+                                                       && TYPEINFO_IS_NEWOBJECT(localset->td[i].info))
+                                                       panic("Uninitialized object in local variable inside try block");
 
                 /* init JSR target chain */
                 if ((jsrchain = jsrbuffer[b_index]) != NULL) {
@@ -924,7 +1307,7 @@ typecheck()
 #ifdef TYPECHECK_VERBOSE
                 if (typecheckverbose) {
                     if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
-                    typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    typestate_print(get_logfile(),curstack,localset,numlocals);
                     LOGNL; LOGFLUSH;
                 }
 #endif
@@ -999,17 +1382,31 @@ typecheck()
                           COPYTYPE(curstack->prev,dst);
                           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:
-                          CHECK_ONEWORD(iptr->op1,TYPE_ADR);
+                                                 INDEX_ONEWORD(iptr->op1);
                           
                           /* loading a returnAddress is not allowed */
-                          if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
-                              panic("illegal instruction: ALOAD loading returnAddress");
+                          if (!typevectorset_checkreference(localset,iptr->op1))
+                              panic("illegal instruction: ALOAD loading non-reference");
 
-                          TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+                                                 typevectorset_copymergedtype(localset,iptr->op1,&(dst->typeinfo));
                           break;
                                                        
                           /****************************************/
@@ -1019,9 +1416,13 @@ typecheck()
                           if (handlers[0] &&
                               TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
                               panic("Storing uninitialized object in local variable inside try block");
-                          
-                          STORE_ONEWORD(iptr->op1,TYPE_ADDRESS);
-                          TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+
+                                                 INDEX_ONEWORD(iptr->op1);
+                                                 if (TYPESTACK_IS_RETURNADDRESS(curstack))
+                                                         typevectorset_store_retaddr(localset,iptr->op1,&(curstack->typeinfo));
+                                                 else
+                                                         typevectorset_store(localset,iptr->op1,TYPE_ADDRESS,
+                                                                                                 &(curstack->typeinfo));
                           break;
                           
                           /****************************************/
@@ -1151,7 +1552,8 @@ typecheck()
                               panic("illegal instruction: ARRAYLENGTH on non-array");
                           maythrow = true;
                           break;
-                                                         
+
+                                                 /* XXX unify cases? */
                       case ICMD_BALOAD:
                           if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
                               && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
@@ -1227,7 +1629,19 @@ typecheck()
                           break;
 
                           /****************************************/
-                          /* OPERATIONS WITH UNCHECKED INPUT      */
+                          /* ADDRESS CONSTANTS                    */
+
+                      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;
+
+                          /****************************************/
+                          /* CHECKCAST AND INSTANCEOF             */
 
                       case ICMD_CHECKCAST:
                                                  TYPECHECK_ADR(curstack);
@@ -1250,15 +1664,6 @@ typecheck()
                           /* XXX optimize statically? */
                           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                  */
 
@@ -1306,8 +1711,8 @@ typecheck()
                       case ICMD_TABLESWITCH:
                           {
                               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;
@@ -1315,8 +1720,8 @@ typecheck()
                       case ICMD_LOOKUPSWITCH:
                           {
                               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;
@@ -1345,29 +1750,29 @@ 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");
                                                  goto return_tail;
                                                  
                       case ICMD_IRETURN:
-                          if (returntype != TYPE_INT) panic("Return type mismatch");
+                          if (returntype.type != TYPE_INT) panic("Return type mismatch");
                                                  goto return_tail;
                                                  
                       case ICMD_LRETURN:
-                          if (returntype != TYPE_LONG) panic("Return type mismatch");
+                          if (returntype.type != TYPE_LONG) panic("Return type mismatch");
                                                  goto return_tail;
                                                  
                       case ICMD_FRETURN:
-                          if (returntype != TYPE_FLOAT) panic("Return type mismatch");
+                          if (returntype.type != TYPE_FLOAT) panic("Return type mismatch");
                                                  goto return_tail;
                                                  
                       case ICMD_DRETURN:
-                          if (returntype != TYPE_DOUBLE) panic("Return type mismatch");
+                          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;
@@ -1385,14 +1790,15 @@ typecheck()
                            */
                           dst = (stackptr) iptr->val.a;
                           
-                          /* push return address */
-                          TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+                          tbptr = (basicblock *) iptr->target;
+                                                 repeat |= typestate_jsr(localbuf,bptr,tbptr,dst,localset,numlocals);
+#if 0
+                          TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,tbptr);
 
                           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 */
@@ -1429,30 +1835,51 @@ typecheck()
                               repeat = true;
                               superblockend = true;
                           }
-                          /* XXX may throw? I don't think. */
+#endif
+                          /* XXX may throw? I don't think so. */
+                                                 superblockend = true;
                           break;
                           
                       case ICMD_RET:
                           /* check returnAddress variable */
-                          CHECK_ONEWORD(iptr->op1,TYPE_ADR);
-                          
-                          if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                          INDEX_ONEWORD(iptr->op1);
+                                                 if (!typevectorset_checkretaddr(localset,iptr->op1))
                               panic("illegal instruction: RET using non-returnAddress variable");
 
+                                                 repeat |= typestate_ret(localbuf,bptr,curstack,
+                                                                                                 localset,iptr->op1,numlocals);
+
+#if 0
                           /* check if we are inside a subroutine */
                           if (!subroutine)
                               panic("RET outside of subroutine");
 
+                                                 /* check if the right returnAddress is used (XXX is this too strict?) */
+                                                 if ((basicblock*)TYPEINFO_RETURNADDRESS(vinfo[iptr->op1])
+                                                         != subroutine->target)
+                                                         panic("RET uses returnAddress of another subroutine");
+
                           /* determine which variables are touched by this subroutine */
                           /* and their types */
                           if (subroutine->sbr_touched) {
+                                                         /* We have reached a RET in this subroutine before. */
+                                                         
+                                                         /* Check if there is more than one RET instruction
+                                                          * returning from this subroutine. */
+                                                         if (subroutine->sbr_ret != iptr)
+                                                                 panic("JSR subroutine has more than one RET instruction");
+
+                                                         /* Merge the array of touched locals and their types */
                               for (i=0; i<numlocals; ++i)
                                   subroutine->sbr_touched[i] |= touched[i];
                               ttype = subroutine->sbr_vtype;
                               tinfo = subroutine->sbr_vinfo;
                               TYPECHECK_MERGEVARS;
+                                                         /* XXX check if subroutine changed types? */
                           }
                           else {
+                                                         /* This is the first time we reach a RET in this subroutine */
+                                                         subroutine->sbr_ret = iptr;
                               subroutine->sbr_touched = DMNEW(u1,numlocals);
                               memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
                               subroutine->sbr_vtype = DMNEW(u1,numlocals);
@@ -1462,14 +1889,13 @@ typecheck()
                                   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,numlocals));
                           LOGNL; LOGFLUSH;
 
-                          /* reach blocks after JSR statements */
+                          /* XXX reach blocks after JSR statements */
                           for (i=0; i<block_count; ++i) {
                               tbptr = block + i;
                               LOG1("block L%03d",tbptr->debug_nr);
@@ -1480,10 +1906,11 @@ typecheck()
                                   continue;
                               tbptr++;
 
-                              LOG1("RET reaches block %04d",tbptr-block);
+                              LOG1("RET reaches block L%03d",tbptr->debug_nr);
 
                               /*TYPECHECK_REACH(REACH_RET);*/
                           }
+#endif
                           
                           superblockend = true;
                           break;
@@ -1596,15 +2023,7 @@ typecheck()
                                       srcstack = srcstack->prev;
                                   }
                                   /* replace uninitialized object type in locals */
-                                  for (i=0; i<numlocals; ++i) {
-                                      if (vtype[i] == TYPE_ADR
-                                          && TYPEINFO_IS_NEWOBJECT(vinfo[i])
-                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
-                                      {
-                                          LOG1("replacing uninitialized type in local %d",i);
-                                          TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
-                                      }
-                                  }
+                                                                 typevectorset_init_object(localset,ins,initclass,numlocals);
 
                                   /* initializing the 'this' reference? */
                                   if (!ins) {
@@ -1618,7 +2037,7 @@ typecheck()
                                                                          
                                       /* set our marker variable to type int */
                                       LOG("setting <init> marker");
-                                                                         vtype[numlocals-1] = TYPE_INT;
+                                                                         typevectorset_store(localset,numlocals-1,TYPE_INT,NULL);
                                   }
                                                                  else {
                                                                          /* initializing an instance created with NEW */
@@ -1756,7 +2175,7 @@ typecheck()
                                                                  panic("Invalid instruction: NEW creating instance of abstract class");
                               TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
                           }
-                                                 /* XXX unify the following cases */
+                                                 /* XXX unify the following cases? */
                           else if (ISBUILTIN(BUILTIN_newarray_boolean)) {
                                                          TYPECHECK_INT(curstack);
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
@@ -1803,22 +2222,35 @@ typecheck()
                           break;
                                                      
                           /****************************************/
-                          /* PRIMITIVE VARIABLE ACCESS            */
+                          /* 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_POP:
+                      case ICMD_POP2:
+                          break;
+
+                          /****************************************/
+                          /* 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: 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;
-                          
                           /****************************************/
                           /* INSTRUCTIONS WHICH SHOULD HAVE BEEN  */
-                          /* REPLACED BY BUILTIN CALLS            */
+                          /* REPLACED BY OTHER OPCODES            */
 
                       case ICMD_NEW:
                       case ICMD_NEWARRAY:
@@ -1832,30 +2264,28 @@ typecheck()
                           panic("Internal error: unexpected instruction encountered");
                           break;
                                                      
-                          /****************************************/
-                          /* 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_POP:
-                      case ICMD_POP2:
-                      case ICMD_READONLY_ARG: /* XXX ? */
-                      case ICMD_CLEAR_ARGREN: /* XXX ? */
-                          break;
-
-                      case ICMD_CHECKASIZE:
-                      case ICMD_NULLCHECKPOP:
-                          maythrow = true;
+                      case ICMD_READONLY_ARG:
+                      case ICMD_CLEAR_ARGREN:
+                          /* XXX only check this in debug mode? */
+                          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;
-
+                                                 
                           /****************************************/
                           /* ARITHMETIC AND CONVERSION            */
-                          /* (These instructions are typechecked in analyse_stack.) */
 
-                          /* The following instructions may throw a runtime exception: */
+                                                 /*********************************************
+                                                  * 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:
@@ -1865,7 +2295,7 @@ typecheck()
                           maythrow = true;
                           break;
                           
-                          /* The following instructions never throw a runtime exception: */
+                          /* Instructions which never throw a runtime exception: */
                           /* XXX only add cases for them in debug mode? */
                           
                       case ICMD_ICONST:
@@ -1980,7 +2410,8 @@ typecheck()
                         i = 0;
                         while (handlers[i]) {
                             tbptr = handlers[i]->handler;
-                            TYPECHECK_REACH(REACH_THROW); /* XXX jsr chain? */
+                                                       repeat |= typestate_reach(localbuf,bptr,tbptr,
+                                                                                                         tbptr->instack,localset,numlocals);
                             i++;
                         }
                     }
@@ -1995,7 +2426,7 @@ typecheck()
 
                 LOG("instructions done");
                 LOGSTR("RESULT=> ");
-                DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+                DOLOG(typestate_print(get_logfile(),curstack,localset,numlocals));
                 LOGNL; LOGFLUSH;
                 
                 /* propagate stack and variables to the following block */
index 7b2934f4f1c8e049fec99fc1eb6db45243f2c73b..9496b12cc732f275f8d176e0180d20a8a6802a64 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.c 733 2003-12-12 17:29:40Z stefan $
+   $Id: typeinfo.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
 #include "loader.h"
 #include "toolbox/loging.h"
 #include "toolbox/memory.h"
+#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
 
 
 #define CLASS_IMPLEMENTS_INTERFACE(cls,index)                   \
     ( ((index) < (cls)->vftbl->interfacetablelength)            \
       && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
 
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS                                               */
+/**********************************************************************/
+
+typevector *
+typevectorset_copy(typevector *src,int k,int size)
+{
+       typevector *dst = DNEW_TYPEVECTOR(size);
+       
+       memcpy(dst,src,TYPEVECTOR_SIZE(size));
+       dst->k = k;
+       if (src->alt)
+               dst->alt = typevectorset_copy(src->alt,k+1,size);
+       return dst;
+}
+
+#if 0
+typevector *
+typevectorset_copy_select(typevector *src,
+                                                 int retindex,void *retaddr,int size)
+{
+       typevector *dst;
+       
+       for (;src; src=src->alt) {
+               if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+                       continue;
+
+               dst = DNEW_TYPEVECTOR(size);
+               memcpy(dst,src,TYPEVECTOR_SIZE(size));
+               if (src->alt)
+                       dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+               return dst;
+       }
+
+       return NULL;
+}
+
+void
+typevectorset_copy_select_to(typevector *src,typevector *dst,
+                                                        int retindex,void *retaddr,int size)
+{
+       for (;src; src=src->alt) {
+               if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+                       continue;
+
+               memcpy(dst,src,TYPEVECTOR_SIZE(size));
+               if (src->alt)
+                       dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+               return dst;
+       }
+
+       return NULL;
+}
+#endif
+
+bool
+typevectorset_checktype(typevector *vec,int index,int type)
+{
+       do {
+               if (vec->td[index].type != type)
+                       return false;
+       } while ((vec = vec->alt) != NULL);
+       return true;
+}
+
+bool
+typevectorset_checkreference(typevector *vec,int index)
+{
+       do {
+               if (!TYPEDESC_IS_REFERENCE(vec->td[index]))
+                       return false;
+       } while ((vec = vec->alt) != NULL);
+       return true;
+}
+
+bool
+typevectorset_checkretaddr(typevector *vec,int index)
+{
+       do {
+               if (!TYPEDESC_IS_RETURNADDRESS(vec->td[index]))
+                       return false;
+       } while ((vec = vec->alt) != NULL);
+       return true;
+}
+
+int
+typevectorset_copymergedtype(typevector *vec,int index,typeinfo *dst)
+{
+       int type;
+       typedescriptor *td;
+
+       td = vec->td + index;
+       type = td->type;
+       TYPEINFO_COPY(td->info,*dst);
+       
+       if (vec->alt) {
+               int primitive;
+               
+               primitive = TYPEINFO_IS_PRIMITIVE(*dst) ? 1 : 0;
+               
+               while ((vec = vec->alt) != NULL) {
+                       td = vec->td + index;
+                       if (type != td->type)
+                               return TYPE_VOID;
+
+                       if (type == TYPE_ADDRESS) {
+                               if ((TYPEINFO_IS_PRIMITIVE(td->info) ? 1 : 0) != primitive)
+                                       return TYPE_VOID;
+                               typeinfo_merge(dst,&(td->info));
+                       }
+               }
+       }
+       return type;
+}
+
+int
+typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result)
+{
+       if (vec->alt) {
+               *result = temp;
+               return typevectorset_copymergedtype(vec,index,temp);
+       }
+
+       *result = &(vec->td[index].info);
+       return vec->td[index].type;
+}
+
+typeinfo *
+typevectorset_mergedtypeinfo(typevector *vec,int index,typeinfo *temp)
+{
+       typeinfo *result;
+       int type = typevectorset_mergedtype(vec,index,temp,&result);
+       return (type == TYPE_ADDRESS) ? result : NULL;
+}
+
+void
+typevectorset_store(typevector *vec,int index,int type,typeinfo *info)
+{
+       /* XXX check if a separator was overwritten */
+       do {
+               vec->td[index].type = type;
+               if (info)
+                       TYPEINFO_COPY(*info,vec->td[index].info);
+               if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+                       vec->td[index-1].type = TYPE_VOID;
+       } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_retaddr(typevector *vec,int index,typeinfo *info)
+{
+       typeinfo_retaddr_set *adr;
+       
+       /* XXX check if a separator was overwritten */
+       adr = (typeinfo_retaddr_set*) TYPEINFO_RETURNADDRESS(*info);
+       do {
+               vec->td[index].type = TYPE_ADDRESS;
+               TYPEINFO_INIT_RETURNADDRESS(vec->td[index].info,adr->addr);
+               if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+                       vec->td[index-1].type = TYPE_VOID;
+               adr = adr->alt;
+       } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_twoword(typevector *vec,int index,int type)
+{
+       /* XXX check if a separator was overwritten */
+       do {
+               vec->td[index].type = type;
+               vec->td[index+1].type = TYPE_VOID;
+               if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+                       vec->td[index-1].type = TYPE_VOID;
+       } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,
+                                                 int size)
+{
+       int i;
+       
+       for (;set; set=set->alt) {
+               for (i=0; i<size; ++i) {
+                       if (set->td[i].type == TYPE_ADR
+                               && TYPEINFO_IS_NEWOBJECT(set->td[i].info)
+                               && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins)
+                       {
+                               TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass);
+                       }
+               }
+       }
+}
+
+bool
+typevector_merge(typevector *dst,typevector *y,int size)
+{
+       bool changed = false;
+       
+       typedescriptor *a = dst->td;
+       typedescriptor *b = y->td;
+       while (size--) {
+               if (a->type != TYPE_VOID && a->type != b->type) {
+                       a->type = TYPE_VOID;
+                       changed = true;
+               }
+               else if (a->type == TYPE_ADDRESS) {
+                       if (TYPEINFO_IS_PRIMITIVE(a->info)) {
+                               /* 'a' is a returnAddress */
+                               if (!TYPEINFO_IS_PRIMITIVE(b->info)
+                                       || (TYPEINFO_RETURNADDRESS(a->info)
+                                               != TYPEINFO_RETURNADDRESS(b->info)))
+                               {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                       }
+                       else {
+                               /* 'a' is a reference */
+                               if (TYPEINFO_IS_PRIMITIVE(b->info)) {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                               else {
+                                       changed |= typeinfo_merge(&(a->info),&(b->info));
+                               }
+                       }
+               }
+               a++;
+               b++;
+       }
+       return changed;
+}
+
+bool typevector_separable_from(typevector *a,typevector *b,int size)
+{
+       typedescriptor *tda = a->td;
+       typedescriptor *tdb = b->td;
+       for (;size--; tda++,tdb++) {
+               if (TYPEDESC_IS_RETURNADDRESS(*tda)
+                       && TYPEDESC_IS_RETURNADDRESS(*tdb)
+                       && TYPEINFO_RETURNADDRESS(tda->info)
+                          != TYPEINFO_RETURNADDRESS(tdb->info))
+                       return true;
+       }
+       return false;
+}
+
+void
+typevectorset_add(typevector *dst,typevector *v,int size)
+{
+       while (dst->alt)
+               dst = dst->alt;
+       dst->alt = DNEW_TYPEVECTOR(size);
+       memcpy(dst->alt,v,TYPEVECTOR_SIZE(size));
+       dst->alt->alt = NULL;
+       dst->alt->k = dst->k + 1;
+}
+
+#if 0
+void
+typevectorset_union(typevector *dst,typevector *v,int size)
+{
+       while (dst->alt)
+               dst = dst->alt;
+       dst->alt = typevectorset_copy(v,size);
+}
+#endif
+
+typevector *
+typevectorset_select(typevector **set,int retindex,void *retaddr)
+{
+       typevector *selected;
+
+       if (!*set) return NULL;
+       
+       if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) {
+               selected = *set;
+               *set = selected->alt;
+               selected->alt = typevectorset_select(set,retindex,retaddr);
+       }
+       else {
+               selected = typevectorset_select(&((*set)->alt),retindex,retaddr);
+       }
+       return selected;
+}
+
+/* XXX delete */
+#if 0
+bool
+typevectorset_separable(typevector *vec,int size)
+{
+       int i;
+       typevector *v;
+
+       for (i=0; i<size; ++i) {
+               v = vec;
+               do {
+                       if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+                               goto next_index;
+                       
+                       v = v->alt;
+                       if (!v) return true;
+               } while (v);
+       next_index:
+       }
+       return false;
+}
+#endif
+
+bool
+typevectorset_separable_with(typevector *set,typevector *add,int size)
+{
+       int i;
+       typevector *v;
+       void *addr;
+       bool separable;
+
+       for (i=0; i<size; ++i) {
+               if (!TYPEDESC_IS_RETURNADDRESS(add->td[i]))
+                       continue;
+               addr = TYPEINFO_RETURNADDRESS(add->td[i].info);
+               
+               v = set;
+               separable = false;
+               do {
+                       if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+                               goto next_index;
+                       if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr)
+                               separable = true;
+                       v = v->alt;
+                       if (!v && separable) return true;
+               } while (v);
+       next_index:
+       }
+       return false;
+}
+
+bool
+typevectorset_collapse(typevector *dst,int size)
+{
+       bool changed = false;
+       
+       while (dst->alt) {
+               typevector_merge(dst,dst->alt,size);
+               dst->alt = dst->alt->alt;
+               changed = true;
+       }
+       return changed;
+}
+
 /**********************************************************************/
 /* READ-ONLY FUNCTIONS                                                */
 /* The following functions don't change typeinfo data.                */
@@ -349,6 +701,61 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
        }
 }
 
+int
+typedescriptors_init_from_method_args(typedescriptor *td,
+                                                                         utf *desc,
+                                                                         int buflen,bool twoword,
+                                                                         typedescriptor *returntype)
+{
+    char *utf_ptr = desc->text;     /* current position in utf text   */
+    char *end_pos = utf_end(desc);  /* points behind utf string       */
+    int args = 0;
+    classinfo *cls;
+
+    /* method descriptor must start with parenthesis */
+    if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
+    /* check arguments */
+    while (utf_ptr != end_pos && *utf_ptr != ')') {
+               if (++args > buflen)
+                       panic("Buffer too small for method arguments.");
+               
+        td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+                                                                               CLASSLOAD_NEW
+                                                                               | CLASSLOAD_NULLPRIMITIVE
+                                                                               | CLASSLOAD_NOVOID);
+               
+               if (cls)
+                       TYPEINFO_INIT_CLASSINFO(td->info,cls);
+               else {
+                       TYPEINFO_INIT_PRIMITIVE(td->info);
+               }
+               td++;
+
+               if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
+                       if (++args > buflen)
+                               panic("Buffer too small for method arguments.");
+                       td->type = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(td->info);
+                       td++;
+               }
+    }
+    utf_ptr++; /* skip ')' */
+
+    /* check returntype */
+    if (returntype) {
+               returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+                                                                                               CLASSLOAD_NULLPRIMITIVE
+                                                                                               | CLASSLOAD_NEW
+                                                                                               | CLASSLOAD_CHECKEND);
+               if (cls)
+                       TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+               else
+                       TYPEINFO_INIT_PRIMITIVE(returntype->info);
+       }
+       return args;
+}
+
 void
 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
 {
@@ -796,10 +1203,16 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         return false;
 
     /* Merging two returnAddress types is ok. */
-    if (!dest->typeclass && !y->typeclass)
+    if (!dest->typeclass && !y->typeclass) {
+#ifdef TYPEINFO_DEBUG
+               if (TYPEINFO_RETURNADDRESS(*dest) != TYPEINFO_RETURNADDRESS(*y))
+                       panic("Internal error: typeinfo_merge merges different returnAddresses");
+#endif
         return false;
+       }
     
     /* Primitive types cannot be merged with reference types */
+       /* XXX only check this in debug mode? */
     if (!dest->typeclass || !y->typeclass)
         typeinfo_merge_error("Trying to merge primitive types.",dest,y);
 
@@ -1162,6 +1575,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
     int i;
     char ind[TYPEINFO_MAXINDENT + 1];
     instruction *ins;
+       basicblock *bptr;
 
     if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
     
@@ -1170,7 +1584,11 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
     ind[i] = (char) 0;
     
     if (TYPEINFO_IS_PRIMITIVE(*info)) {
-        fprintf(file,"%sprimitive\n",ind);
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->debug_nr);
+               else
+                       fprintf(file,"%sprimitive\n",ind);
         return;
     }
     
@@ -1235,9 +1653,14 @@ typeinfo_print_short(FILE *file,typeinfo *info)
 {
     int i;
     instruction *ins;
+       basicblock *bptr;
 
     if (TYPEINFO_IS_PRIMITIVE(*info)) {
-        fprintf(file,"primitive");
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"ret(L%03d)",bptr->debug_nr);
+               else
+                       fprintf(file,"primitive");
         return;
     }
     
@@ -1279,11 +1702,7 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
       case TYPE_DOUBLE: fprintf(file,"D"); break;
       case TYPE_LONG:   fprintf(file,"J"); break;
       case TYPE_ADDRESS:
-          if (TYPEINFO_IS_PRIMITIVE(*info))
-              fprintf(file,"R"); /* returnAddress */
-          else {
-              typeinfo_print_short(file,info);
-          }
+                 typeinfo_print_short(file,info);
           break;
           
       default:
@@ -1291,6 +1710,68 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
     }
 }
 
+void
+typeinfo_print_stacktype(FILE *file,int type,typeinfo *info)
+{
+       if (type == TYPE_ADDRESS && TYPEINFO_IS_PRIMITIVE(*info)) {     
+               typeinfo_retaddr_set *set = (typeinfo_retaddr_set*)
+                       TYPEINFO_RETURNADDRESS(*info);
+               fprintf(file,"ret(L%03d",((basicblock*)(set->addr))->debug_nr);
+               set = set->alt;
+               while (set) {
+                       fprintf(file,"|L%03d",((basicblock*)(set->addr))->debug_nr);
+                       set = set->alt;
+               }
+               fprintf(file,")");
+       }
+       else
+               typeinfo_print_type(file,type,info);
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor *td)
+{
+       typeinfo_print_type(file,td->type,&(td->info));
+}
+
+void
+typevector_print(FILE *file,typevector *vec,int size)
+{
+    int i;
+
+       fprintf(file,"[%d]",vec->k);
+    for (i=0; i<size; ++i) {
+               fprintf(file," %d=",i);
+        typedescriptor_print(file,vec->td + i);
+    }
+}
+
+void
+typevectorset_print(FILE *file,typevector *set,int size)
+{
+    int i;
+       typevector *vec;
+
+       fprintf(file,"[%d",set->k);
+       vec = set->alt;
+       while (vec) {
+               fprintf(file,"|%d",vec->k);
+               vec = vec->alt;
+       }
+       fprintf(file,"]");
+       
+    for (i=0; i<size; ++i) {
+               fprintf(file," %d=",i);
+        typedescriptor_print(file,set->td + i);
+               vec = set->alt;
+               while (vec) {
+                       fprintf(file,"|");
+                       typedescriptor_print(file,vec->td + i);
+                       vec = vec->alt;
+               }
+    }
+}
+
 #endif /* TYPEINFO_DEBUG */
 
 
index d038f602aec85aea3a221ae77e848177b7dd2e6f..e01ead8920ef32333db4db31cb1daee0de58d903 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.h 795 2003-12-16 22:27:52Z edwin $
+   $Id: typeinfo.h 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -40,6 +40,9 @@
 
 typedef struct typeinfo typeinfo;
 typedef struct typeinfo_mergedlist typeinfo_mergedlist;
+typedef struct typedescriptor typedescriptor;
+typedef struct typevector typevector;
+typedef struct typeinfo_retaddr_set typeinfo_retaddr_set;
 
 /* global variables ***********************************************************/
 
@@ -134,26 +137,66 @@ typedef struct typeinfo_mergedlist typeinfo_mergedlist;
  *          access typeinfo structures!
  */
 struct typeinfo {
-        classinfo           *typeclass;
-        classinfo           *elementclass; /* valid if dimension>0 */
-        typeinfo_mergedlist *merged;
-        u1                   dimension;
-        u1                   elementtype;  /* valid if dimension>0 */
+       classinfo           *typeclass;
+       classinfo           *elementclass; /* valid if dimension>0 */ /* XXX various uses */
+       typeinfo_mergedlist *merged;
+       u1                   dimension;
+       u1                   elementtype;  /* valid if dimension>0 */
 };
 
 struct typeinfo_mergedlist {
-        s4         count;
-        classinfo *list[1]; /* variable length! */
+       s4         count;
+       classinfo *list[1];       /* variable length!                        */
+};
+
+struct typeinfo_retaddr_set {
+       typeinfo_retaddr_set *alt;  /* next alternative in set               */
+       void                 *addr; /* return address                        */
+};
+
+struct typedescriptor {
+       typeinfo        info;     /* valid if type == TYPE_ADR               */
+       u1              type;     /* basic type (TYPE_INT, ...)              */
+};
+
+/* typevectors are used to store the types of local variables */
+
+struct typevector {
+       typevector      *alt;     /* next alternative in typevector set */
+       int              k;       /* for lining up with the stack set   */
+       typedescriptor   td[1];   /* variable length!                   */
 };
 
 /****************************************************************************/
 /* MACROS                                                                   */
 /****************************************************************************/
 
-/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
- *       You have to dereference any pointers.
+/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
+ *       arguments.  You have to dereference any pointers.
  */
 
+/* typevectors **************************************************************/
+
+#define TYPEVECTOR_SIZE(size)                                          \
+    ((sizeof(typevector) - sizeof(typedescriptor))     \
+     + (size)*sizeof(typedescriptor))
+
+#define DNEW_TYPEVECTOR(size)                                          \
+    ((typevector*)dump_alloc(TYPEVECTOR_SIZE(size)))
+
+#define DMNEW_TYPEVECTOR(num,size)                                             \
+    ((void*)dump_alloc((num) * TYPEVECTOR_SIZE(size)))
+
+#define MGET_TYPEVECTOR(array,index,size) \
+    ((typevector*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
+
+#define COPY_TYPEVECTORSET(src,dst,size)                                               \
+    do {memcpy(dst,src,TYPEVECTOR_SIZE(size));                                 \
+        dst->k = 0;                                             \
+        if ((src)->alt) {                                                                              \
+               (dst)->alt = typevectorset_copy((src)->alt,1,size);     \
+        }} while(0)
+
 /* internally used macros ***************************************************/
 
 /* internal, don't use this explicitly! */
@@ -182,6 +225,10 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_IS_NEWOBJECT(info)                             \
             ((info).typeclass == pseudo_class_New)
 
+/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
+#define TYPEINFO_RETURNADDRESS(info)                            \
+            ((void *)(info).elementclass)
+
 /* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
 #define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
             ((void *)(info).elementclass)
@@ -215,6 +262,20 @@ struct typeinfo_mergedlist {
             ( TYPEINFO_IS_ARRAY(info)                           \
               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
 
+#define TYPE_IS_RETURNADDRESS(type,info)                        \
+            ( ((type)==TYPE_ADDRESS)                            \
+              && TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPE_IS_REFERENCE(type,info)                            \
+            ( ((type)==TYPE_ADDRESS)                            \
+              && !TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPEDESC_IS_RETURNADDRESS(td)                           \
+            TYPE_IS_RETURNADDRESS((td).type,(td).info)
+
+#define TYPEDESC_IS_REFERENCE(td)                               \
+            TYPE_IS_REFERENCE((td).type,(td).info)
+
 /* queries allowing the null type ********************************************/
 
 #define TYPEINFO_MAYBE_ARRAY(info)                              \
@@ -235,6 +296,13 @@ struct typeinfo_mergedlist {
              (info).dimension = 0;                              \
              (info).elementtype = 0;} while(0)
 
+#define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
+         do {(info).typeclass = NULL;                           \
+             (info).elementclass = (classinfo*) (adr);          \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
 #define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
          do {(info).typeclass = (cinfo);                \
              (info).elementclass = NULL;                \
@@ -316,6 +384,39 @@ struct typeinfo_mergedlist {
 /* FUNCTIONS                                                                */
 /****************************************************************************/
 
+/* typevector functions *****************************************************/
+
+/* element read-only access */
+bool typevectorset_checktype(typevector *set,int index,int type);
+bool typevectorset_checkreference(typevector *set,int index);
+bool typevectorset_checkretaddr(typevector *set,int index);
+int typevectorset_copymergedtype(typevector *set,int index,typeinfo *dst);
+typeinfo *typevectorset_mergedtypeinfo(typevector *set,int index,typeinfo *temp);
+int typevectorset_mergedtype(typevector *set,int index,typeinfo *temp,typeinfo **result);
+
+/* element write access */
+void typevectorset_store(typevector *set,int index,int type,typeinfo *info);
+void typevectorset_store_retaddr(typevector *set,int index,typeinfo *info);
+void typevectorset_store_twoword(typevector *set,int index,int type);
+void typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,int size);
+
+/* vector functions */
+bool typevector_separable_from(typevector *a,typevector *b,int size);
+bool typevector_merge(typevector *dst,typevector *y,int size);
+
+/* vector set functions */
+typevector *typevectorset_copy(typevector *src,int k,int size);
+/* typevector *typevectorset_copy_select(typevector *src,
+   int retindex,void *retaddr,int size);
+   void typevectorset_copy_select_to(typevector *src,typevector *dst,
+   int retindex,void *retaddr,int size); */
+/* bool typevectorset_separable(typevector *set,int size); */
+bool typevectorset_separable_with(typevector *set,typevector *add,int size);
+bool typevectorset_collapse(typevector *dst,int size);
+void typevectorset_add(typevector *dst,typevector *v,int size);
+/* void typevectorset_union(typevector *dst,typevector *v,int size); */
+typevector *typevectorset_select(typevector **set,int retindex,void *retaddr);
+
 /* inquiry functions (read-only) ********************************************/
 
 bool typeinfo_is_array(typeinfo *info);
@@ -335,6 +436,10 @@ void typeinfo_init_from_method_args(utf *desc,u1 *typebuf,
                                     typeinfo *infobuf,
                                     int buflen,bool twoword,
                                     int *returntype,typeinfo *returntypeinfo);
+int  typedescriptors_init_from_method_args(typedescriptor *td,
+                                                                                  utf *desc,
+                                                                                  int buflen,bool twoword,
+                                                                                  typedescriptor *returntype);
 
 void typeinfo_clone(typeinfo *src,typeinfo *dest);
 
@@ -355,6 +460,10 @@ void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc);
 void typeinfo_print(FILE *file,typeinfo *info,int indent);
 void typeinfo_print_short(FILE *file,typeinfo *info);
 void typeinfo_print_type(FILE *file,int type,typeinfo *info);
+void typeinfo_print_stacktype(FILE *file,int type,typeinfo *info);
+void typedescriptor_print(FILE *file,typedescriptor *td);
+void typevector_print(FILE *file,typevector *vec,int size);
+void typevectorset_print(FILE *file,typevector *set,int size);
 
 #endif /* TYPEINFO_DEBUG */
 
index a427ad559810b4524a63d85cfd229fd1289d408d..8e3b18a6ed4945fa1caec59065c94aa6ee89e641 100644 (file)
@@ -30,7 +30,7 @@
             Mark Probst
                        Edwin Steiner
 
-   $Id: loader.c 867 2004-01-07 22:05:04Z edwin $
+   $Id: loader.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -744,10 +744,13 @@ static void checkfielddescriptor (char *utf_ptr, char *end_pos)
 
     checks whether a method-descriptor is valid and aborts otherwise.
     All referenced classes are inserted into the list of unloaded classes.
+
+    The number of arguments is returned. A long or double argument is counted
+    as two arguments.
        
 *******************************************************************************/
 
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor (utf *d)
 {
        char *utf_ptr = d->text;     /* current position in utf text   */
        char *end_pos = utf_end(d);  /* points behind utf string       */
@@ -761,9 +764,9 @@ static void checkmethoddescriptor (utf *d)
                /* XXX we cannot count the this argument here because
                 * we don't know if the method is static. */
                if (*utf_ptr == 'J' || *utf_ptr == 'D')
+                       argcount+=2;
+               else
                        argcount++;
-               if (++argcount > 255)
-                       panic("Invalid method descriptor: too many arguments");
                class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
                                                          CLASSLOAD_NEW
                                                          | CLASSLOAD_NULLPRIMITIVE
@@ -778,6 +781,11 @@ static void checkmethoddescriptor (utf *d)
                                                  | CLASSLOAD_NULLPRIMITIVE
                                                  | CLASSLOAD_CHECKEND);
 
+       if (argcount > 255)
+               panic("Invalid method descriptor: too many arguments");
+
+       return argcount;
+
        /* XXX use the following if -noverify */
 #if 0
        /* XXX check length */
@@ -897,6 +905,8 @@ static void field_load(fieldinfo *f, classinfo *c)
                        if ((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
                                != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
                                panic("Interface field is not declared static final public");
+                       if ((f->flags & ACC_TRANSIENT) != 0)
+                               panic("Interface field declared transient");
                }
        }
                
@@ -1021,6 +1031,7 @@ void field_display(fieldinfo *f)
 static void method_load(methodinfo *m, classinfo *c)
 {
        u4 attrnum, i, e;
+       int argcount;
        
 #ifdef STATISTICS
        count_all_methods++;
@@ -1031,10 +1042,15 @@ static void method_load(methodinfo *m, classinfo *c)
        m->flags = suck_u2();
        m->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
        m->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
-       checkmethoddescriptor(m->descriptor);   
+       argcount = checkmethoddescriptor(m->descriptor);
+       if ((m->flags & ACC_STATIC) == 0)
+               argcount++; /* count the 'this' argument */
 
-       /* check flag consistency */
        if (opt_verify) {
+               if (argcount > 255)
+                       panic("Method has more than 255 arguments");
+
+               /* check flag consistency */
                /* XXX could check if <clinit> is STATIC */
                if (m->name != utf_clinit) {
                        i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
@@ -1102,6 +1118,9 @@ static void method_load(methodinfo *m, classinfo *c)
                        suck_u4();
                        m->maxstack = suck_u2();
                        m->maxlocals = suck_u2();
+                       if (m->maxlocals < argcount)
+                               panic("max_locals is smaller than the number of arguments");
+                       
                        codelen = suck_u4();
                        if (codelen == 0)
                                panic("bytecode has zero length");
@@ -1471,7 +1490,10 @@ static void class_loadcpool(classinfo *c)
                                ASSERT_LEFT(length);
                                if (opt_verify &&
                                        !is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
-                                       panic("Invalid UTF-8 string"); 
+                               {
+                                       dolog("Invalid UTF-8 string (constant pool index %d)",idx);
+                                       panic("Invalid UTF-8 string");
+                               }
                                /* insert utf-string into the utf-symboltable */
                                cpinfos [idx] = utf_new(classbuf_pos+1, length);
                                /* skip bytes of the string */
@@ -1653,11 +1675,18 @@ static int class_load(classinfo *c)
 
        /* check ACC flags consistency */
        if ((c->flags & ACC_INTERFACE) != 0) {
-               if ((c->flags & ACC_ABSTRACT) == 0)
-                       panic("Interface class not declared abstract");
+               if ((c->flags & ACC_ABSTRACT) == 0) {
+                       /* XXX We work around this because interfaces in JDK 1.1 are
+                        * not declared abstract. */
+
+                       c->flags |= ACC_ABSTRACT;
+                       /* panic("Interface class not declared abstract"); */
+               }
                if ((c->flags & (ACC_FINAL | ACC_SUPER)) != 0)
                        panic("Interface class has invalid flags");
        }
+       if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
+               panic("Class is declared both abstract and final");
 
        /* this class */
        i = suck_u2();
@@ -2052,8 +2081,13 @@ void class_link(classinfo *c)
                        list_addlast(&unlinkedclasses, c);
                        return; 
                }
-               if ((ic->flags & ACC_INTERFACE) == 0)
+               if ((ic->flags & ACC_INTERFACE) == 0) {
+                       dolog("Specified interface is not declared as interface:");
+                       log_utf(ic->name);
+                       dolog("in");
+                       log_utf(c->name);
                        panic("Specified interface is not declared as interface");
+               }
        }
        
        /*  check super class */
index ebe1d3dedb2dbe73657b99d100af56d37fe5d852..21456a718f5083ef69130dbd1d08c44f80b9d96d 100644 (file)
@@ -35,7 +35,7 @@
        - the heap
        - additional support functions
 
-   $Id: tables.c 775 2003-12-14 12:57:05Z edwin $
+   $Id: tables.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -766,7 +766,8 @@ is_valid_utf(char *utf_ptr,char *end_pos)
                        if (len != 1) return false;           /* Java special */
                }
                else {
-                       if (v < min_codepoint[len]) return false; /* overlong UTF-8 */
+                       /* XXX Sun Java seems to allow overlong UTF-8 encodings */
+                       /* if (v < min_codepoint[len]) return false; */ /* overlong UTF-8 */
                }
 
                /* surrogates in UTF-8 seem to be allowed in Java classfiles */
index ebe1d3dedb2dbe73657b99d100af56d37fe5d852..21456a718f5083ef69130dbd1d08c44f80b9d96d 100644 (file)
--- a/tables.c
+++ b/tables.c
@@ -35,7 +35,7 @@
        - the heap
        - additional support functions
 
-   $Id: tables.c 775 2003-12-14 12:57:05Z edwin $
+   $Id: tables.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -766,7 +766,8 @@ is_valid_utf(char *utf_ptr,char *end_pos)
                        if (len != 1) return false;           /* Java special */
                }
                else {
-                       if (v < min_codepoint[len]) return false; /* overlong UTF-8 */
+                       /* XXX Sun Java seems to allow overlong UTF-8 encodings */
+                       /* if (v < min_codepoint[len]) return false; */ /* overlong UTF-8 */
                }
 
                /* surrogates in UTF-8 seem to be allowed in Java classfiles */
index 7b2934f4f1c8e049fec99fc1eb6db45243f2c73b..9496b12cc732f275f8d176e0180d20a8a6802a64 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.c 733 2003-12-12 17:29:40Z stefan $
+   $Id: typeinfo.c 868 2004-01-10 20:12:10Z edwin $
 
 */
 
 #include "loader.h"
 #include "toolbox/loging.h"
 #include "toolbox/memory.h"
+#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
 
 
 #define CLASS_IMPLEMENTS_INTERFACE(cls,index)                   \
     ( ((index) < (cls)->vftbl->interfacetablelength)            \
       && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
 
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS                                               */
+/**********************************************************************/
+
+typevector *
+typevectorset_copy(typevector *src,int k,int size)
+{
+       typevector *dst = DNEW_TYPEVECTOR(size);
+       
+       memcpy(dst,src,TYPEVECTOR_SIZE(size));
+       dst->k = k;
+       if (src->alt)
+               dst->alt = typevectorset_copy(src->alt,k+1,size);
+       return dst;
+}
+
+#if 0
+typevector *
+typevectorset_copy_select(typevector *src,
+                                                 int retindex,void *retaddr,int size)
+{
+       typevector *dst;
+       
+       for (;src; src=src->alt) {
+               if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+                       continue;
+
+               dst = DNEW_TYPEVECTOR(size);
+               memcpy(dst,src,TYPEVECTOR_SIZE(size));
+               if (src->alt)
+                       dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+               return dst;
+       }
+
+       return NULL;
+}
+
+void
+typevectorset_copy_select_to(typevector *src,typevector *dst,
+                                                        int retindex,void *retaddr,int size)
+{
+       for (;src; src=src->alt) {
+               if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+                       continue;
+
+               memcpy(dst,src,TYPEVECTOR_SIZE(size));
+               if (src->alt)
+                       dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+               return dst;
+       }
+
+       return NULL;
+}
+#endif
+
+bool
+typevectorset_checktype(typevector *vec,int index,int type)
+{
+       do {
+               if (vec->td[index].type != type)
+                       return false;
+       } while ((vec = vec->alt) != NULL);
+       return true;
+}
+
+bool
+typevectorset_checkreference(typevector *vec,int index)
+{
+       do {
+               if (!TYPEDESC_IS_REFERENCE(vec->td[index]))
+                       return false;
+       } while ((vec = vec->alt) != NULL);
+       return true;
+}
+
+bool
+typevectorset_checkretaddr(typevector *vec,int index)
+{
+       do {
+               if (!TYPEDESC_IS_RETURNADDRESS(vec->td[index]))
+                       return false;
+       } while ((vec = vec->alt) != NULL);
+       return true;
+}
+
+int
+typevectorset_copymergedtype(typevector *vec,int index,typeinfo *dst)
+{
+       int type;
+       typedescriptor *td;
+
+       td = vec->td + index;
+       type = td->type;
+       TYPEINFO_COPY(td->info,*dst);
+       
+       if (vec->alt) {
+               int primitive;
+               
+               primitive = TYPEINFO_IS_PRIMITIVE(*dst) ? 1 : 0;
+               
+               while ((vec = vec->alt) != NULL) {
+                       td = vec->td + index;
+                       if (type != td->type)
+                               return TYPE_VOID;
+
+                       if (type == TYPE_ADDRESS) {
+                               if ((TYPEINFO_IS_PRIMITIVE(td->info) ? 1 : 0) != primitive)
+                                       return TYPE_VOID;
+                               typeinfo_merge(dst,&(td->info));
+                       }
+               }
+       }
+       return type;
+}
+
+int
+typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result)
+{
+       if (vec->alt) {
+               *result = temp;
+               return typevectorset_copymergedtype(vec,index,temp);
+       }
+
+       *result = &(vec->td[index].info);
+       return vec->td[index].type;
+}
+
+typeinfo *
+typevectorset_mergedtypeinfo(typevector *vec,int index,typeinfo *temp)
+{
+       typeinfo *result;
+       int type = typevectorset_mergedtype(vec,index,temp,&result);
+       return (type == TYPE_ADDRESS) ? result : NULL;
+}
+
+void
+typevectorset_store(typevector *vec,int index,int type,typeinfo *info)
+{
+       /* XXX check if a separator was overwritten */
+       do {
+               vec->td[index].type = type;
+               if (info)
+                       TYPEINFO_COPY(*info,vec->td[index].info);
+               if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+                       vec->td[index-1].type = TYPE_VOID;
+       } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_retaddr(typevector *vec,int index,typeinfo *info)
+{
+       typeinfo_retaddr_set *adr;
+       
+       /* XXX check if a separator was overwritten */
+       adr = (typeinfo_retaddr_set*) TYPEINFO_RETURNADDRESS(*info);
+       do {
+               vec->td[index].type = TYPE_ADDRESS;
+               TYPEINFO_INIT_RETURNADDRESS(vec->td[index].info,adr->addr);
+               if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+                       vec->td[index-1].type = TYPE_VOID;
+               adr = adr->alt;
+       } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_twoword(typevector *vec,int index,int type)
+{
+       /* XXX check if a separator was overwritten */
+       do {
+               vec->td[index].type = type;
+               vec->td[index+1].type = TYPE_VOID;
+               if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+                       vec->td[index-1].type = TYPE_VOID;
+       } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,
+                                                 int size)
+{
+       int i;
+       
+       for (;set; set=set->alt) {
+               for (i=0; i<size; ++i) {
+                       if (set->td[i].type == TYPE_ADR
+                               && TYPEINFO_IS_NEWOBJECT(set->td[i].info)
+                               && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins)
+                       {
+                               TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass);
+                       }
+               }
+       }
+}
+
+bool
+typevector_merge(typevector *dst,typevector *y,int size)
+{
+       bool changed = false;
+       
+       typedescriptor *a = dst->td;
+       typedescriptor *b = y->td;
+       while (size--) {
+               if (a->type != TYPE_VOID && a->type != b->type) {
+                       a->type = TYPE_VOID;
+                       changed = true;
+               }
+               else if (a->type == TYPE_ADDRESS) {
+                       if (TYPEINFO_IS_PRIMITIVE(a->info)) {
+                               /* 'a' is a returnAddress */
+                               if (!TYPEINFO_IS_PRIMITIVE(b->info)
+                                       || (TYPEINFO_RETURNADDRESS(a->info)
+                                               != TYPEINFO_RETURNADDRESS(b->info)))
+                               {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                       }
+                       else {
+                               /* 'a' is a reference */
+                               if (TYPEINFO_IS_PRIMITIVE(b->info)) {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                               else {
+                                       changed |= typeinfo_merge(&(a->info),&(b->info));
+                               }
+                       }
+               }
+               a++;
+               b++;
+       }
+       return changed;
+}
+
+bool typevector_separable_from(typevector *a,typevector *b,int size)
+{
+       typedescriptor *tda = a->td;
+       typedescriptor *tdb = b->td;
+       for (;size--; tda++,tdb++) {
+               if (TYPEDESC_IS_RETURNADDRESS(*tda)
+                       && TYPEDESC_IS_RETURNADDRESS(*tdb)
+                       && TYPEINFO_RETURNADDRESS(tda->info)
+                          != TYPEINFO_RETURNADDRESS(tdb->info))
+                       return true;
+       }
+       return false;
+}
+
+void
+typevectorset_add(typevector *dst,typevector *v,int size)
+{
+       while (dst->alt)
+               dst = dst->alt;
+       dst->alt = DNEW_TYPEVECTOR(size);
+       memcpy(dst->alt,v,TYPEVECTOR_SIZE(size));
+       dst->alt->alt = NULL;
+       dst->alt->k = dst->k + 1;
+}
+
+#if 0
+void
+typevectorset_union(typevector *dst,typevector *v,int size)
+{
+       while (dst->alt)
+               dst = dst->alt;
+       dst->alt = typevectorset_copy(v,size);
+}
+#endif
+
+typevector *
+typevectorset_select(typevector **set,int retindex,void *retaddr)
+{
+       typevector *selected;
+
+       if (!*set) return NULL;
+       
+       if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) {
+               selected = *set;
+               *set = selected->alt;
+               selected->alt = typevectorset_select(set,retindex,retaddr);
+       }
+       else {
+               selected = typevectorset_select(&((*set)->alt),retindex,retaddr);
+       }
+       return selected;
+}
+
+/* XXX delete */
+#if 0
+bool
+typevectorset_separable(typevector *vec,int size)
+{
+       int i;
+       typevector *v;
+
+       for (i=0; i<size; ++i) {
+               v = vec;
+               do {
+                       if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+                               goto next_index;
+                       
+                       v = v->alt;
+                       if (!v) return true;
+               } while (v);
+       next_index:
+       }
+       return false;
+}
+#endif
+
+bool
+typevectorset_separable_with(typevector *set,typevector *add,int size)
+{
+       int i;
+       typevector *v;
+       void *addr;
+       bool separable;
+
+       for (i=0; i<size; ++i) {
+               if (!TYPEDESC_IS_RETURNADDRESS(add->td[i]))
+                       continue;
+               addr = TYPEINFO_RETURNADDRESS(add->td[i].info);
+               
+               v = set;
+               separable = false;
+               do {
+                       if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+                               goto next_index;
+                       if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr)
+                               separable = true;
+                       v = v->alt;
+                       if (!v && separable) return true;
+               } while (v);
+       next_index:
+       }
+       return false;
+}
+
+bool
+typevectorset_collapse(typevector *dst,int size)
+{
+       bool changed = false;
+       
+       while (dst->alt) {
+               typevector_merge(dst,dst->alt,size);
+               dst->alt = dst->alt->alt;
+               changed = true;
+       }
+       return changed;
+}
+
 /**********************************************************************/
 /* READ-ONLY FUNCTIONS                                                */
 /* The following functions don't change typeinfo data.                */
@@ -349,6 +701,61 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
        }
 }
 
+int
+typedescriptors_init_from_method_args(typedescriptor *td,
+                                                                         utf *desc,
+                                                                         int buflen,bool twoword,
+                                                                         typedescriptor *returntype)
+{
+    char *utf_ptr = desc->text;     /* current position in utf text   */
+    char *end_pos = utf_end(desc);  /* points behind utf string       */
+    int args = 0;
+    classinfo *cls;
+
+    /* method descriptor must start with parenthesis */
+    if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
+    /* check arguments */
+    while (utf_ptr != end_pos && *utf_ptr != ')') {
+               if (++args > buflen)
+                       panic("Buffer too small for method arguments.");
+               
+        td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+                                                                               CLASSLOAD_NEW
+                                                                               | CLASSLOAD_NULLPRIMITIVE
+                                                                               | CLASSLOAD_NOVOID);
+               
+               if (cls)
+                       TYPEINFO_INIT_CLASSINFO(td->info,cls);
+               else {
+                       TYPEINFO_INIT_PRIMITIVE(td->info);
+               }
+               td++;
+
+               if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
+                       if (++args > buflen)
+                               panic("Buffer too small for method arguments.");
+                       td->type = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(td->info);
+                       td++;
+               }
+    }
+    utf_ptr++; /* skip ')' */
+
+    /* check returntype */
+    if (returntype) {
+               returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+                                                                                               CLASSLOAD_NULLPRIMITIVE
+                                                                                               | CLASSLOAD_NEW
+                                                                                               | CLASSLOAD_CHECKEND);
+               if (cls)
+                       TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+               else
+                       TYPEINFO_INIT_PRIMITIVE(returntype->info);
+       }
+       return args;
+}
+
 void
 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
 {
@@ -796,10 +1203,16 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         return false;
 
     /* Merging two returnAddress types is ok. */
-    if (!dest->typeclass && !y->typeclass)
+    if (!dest->typeclass && !y->typeclass) {
+#ifdef TYPEINFO_DEBUG
+               if (TYPEINFO_RETURNADDRESS(*dest) != TYPEINFO_RETURNADDRESS(*y))
+                       panic("Internal error: typeinfo_merge merges different returnAddresses");
+#endif
         return false;
+       }
     
     /* Primitive types cannot be merged with reference types */
+       /* XXX only check this in debug mode? */
     if (!dest->typeclass || !y->typeclass)
         typeinfo_merge_error("Trying to merge primitive types.",dest,y);
 
@@ -1162,6 +1575,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
     int i;
     char ind[TYPEINFO_MAXINDENT + 1];
     instruction *ins;
+       basicblock *bptr;
 
     if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
     
@@ -1170,7 +1584,11 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
     ind[i] = (char) 0;
     
     if (TYPEINFO_IS_PRIMITIVE(*info)) {
-        fprintf(file,"%sprimitive\n",ind);
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->debug_nr);
+               else
+                       fprintf(file,"%sprimitive\n",ind);
         return;
     }
     
@@ -1235,9 +1653,14 @@ typeinfo_print_short(FILE *file,typeinfo *info)
 {
     int i;
     instruction *ins;
+       basicblock *bptr;
 
     if (TYPEINFO_IS_PRIMITIVE(*info)) {
-        fprintf(file,"primitive");
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"ret(L%03d)",bptr->debug_nr);
+               else
+                       fprintf(file,"primitive");
         return;
     }
     
@@ -1279,11 +1702,7 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
       case TYPE_DOUBLE: fprintf(file,"D"); break;
       case TYPE_LONG:   fprintf(file,"J"); break;
       case TYPE_ADDRESS:
-          if (TYPEINFO_IS_PRIMITIVE(*info))
-              fprintf(file,"R"); /* returnAddress */
-          else {
-              typeinfo_print_short(file,info);
-          }
+                 typeinfo_print_short(file,info);
           break;
           
       default:
@@ -1291,6 +1710,68 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
     }
 }
 
+void
+typeinfo_print_stacktype(FILE *file,int type,typeinfo *info)
+{
+       if (type == TYPE_ADDRESS && TYPEINFO_IS_PRIMITIVE(*info)) {     
+               typeinfo_retaddr_set *set = (typeinfo_retaddr_set*)
+                       TYPEINFO_RETURNADDRESS(*info);
+               fprintf(file,"ret(L%03d",((basicblock*)(set->addr))->debug_nr);
+               set = set->alt;
+               while (set) {
+                       fprintf(file,"|L%03d",((basicblock*)(set->addr))->debug_nr);
+                       set = set->alt;
+               }
+               fprintf(file,")");
+       }
+       else
+               typeinfo_print_type(file,type,info);
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor *td)
+{
+       typeinfo_print_type(file,td->type,&(td->info));
+}
+
+void
+typevector_print(FILE *file,typevector *vec,int size)
+{
+    int i;
+
+       fprintf(file,"[%d]",vec->k);
+    for (i=0; i<size; ++i) {
+               fprintf(file," %d=",i);
+        typedescriptor_print(file,vec->td + i);
+    }
+}
+
+void
+typevectorset_print(FILE *file,typevector *set,int size)
+{
+    int i;
+       typevector *vec;
+
+       fprintf(file,"[%d",set->k);
+       vec = set->alt;
+       while (vec) {
+               fprintf(file,"|%d",vec->k);
+               vec = vec->alt;
+       }
+       fprintf(file,"]");
+       
+    for (i=0; i<size; ++i) {
+               fprintf(file," %d=",i);
+        typedescriptor_print(file,set->td + i);
+               vec = set->alt;
+               while (vec) {
+                       fprintf(file,"|");
+                       typedescriptor_print(file,vec->td + i);
+                       vec = vec->alt;
+               }
+    }
+}
+
 #endif /* TYPEINFO_DEBUG */
 
 
index d038f602aec85aea3a221ae77e848177b7dd2e6f..e01ead8920ef32333db4db31cb1daee0de58d903 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.h 795 2003-12-16 22:27:52Z edwin $
+   $Id: typeinfo.h 868 2004-01-10 20:12:10Z edwin $
 
 */
 
@@ -40,6 +40,9 @@
 
 typedef struct typeinfo typeinfo;
 typedef struct typeinfo_mergedlist typeinfo_mergedlist;
+typedef struct typedescriptor typedescriptor;
+typedef struct typevector typevector;
+typedef struct typeinfo_retaddr_set typeinfo_retaddr_set;
 
 /* global variables ***********************************************************/
 
@@ -134,26 +137,66 @@ typedef struct typeinfo_mergedlist typeinfo_mergedlist;
  *          access typeinfo structures!
  */
 struct typeinfo {
-        classinfo           *typeclass;
-        classinfo           *elementclass; /* valid if dimension>0 */
-        typeinfo_mergedlist *merged;
-        u1                   dimension;
-        u1                   elementtype;  /* valid if dimension>0 */
+       classinfo           *typeclass;
+       classinfo           *elementclass; /* valid if dimension>0 */ /* XXX various uses */
+       typeinfo_mergedlist *merged;
+       u1                   dimension;
+       u1                   elementtype;  /* valid if dimension>0 */
 };
 
 struct typeinfo_mergedlist {
-        s4         count;
-        classinfo *list[1]; /* variable length! */
+       s4         count;
+       classinfo *list[1];       /* variable length!                        */
+};
+
+struct typeinfo_retaddr_set {
+       typeinfo_retaddr_set *alt;  /* next alternative in set               */
+       void                 *addr; /* return address                        */
+};
+
+struct typedescriptor {
+       typeinfo        info;     /* valid if type == TYPE_ADR               */
+       u1              type;     /* basic type (TYPE_INT, ...)              */
+};
+
+/* typevectors are used to store the types of local variables */
+
+struct typevector {
+       typevector      *alt;     /* next alternative in typevector set */
+       int              k;       /* for lining up with the stack set   */
+       typedescriptor   td[1];   /* variable length!                   */
 };
 
 /****************************************************************************/
 /* MACROS                                                                   */
 /****************************************************************************/
 
-/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
- *       You have to dereference any pointers.
+/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
+ *       arguments.  You have to dereference any pointers.
  */
 
+/* typevectors **************************************************************/
+
+#define TYPEVECTOR_SIZE(size)                                          \
+    ((sizeof(typevector) - sizeof(typedescriptor))     \
+     + (size)*sizeof(typedescriptor))
+
+#define DNEW_TYPEVECTOR(size)                                          \
+    ((typevector*)dump_alloc(TYPEVECTOR_SIZE(size)))
+
+#define DMNEW_TYPEVECTOR(num,size)                                             \
+    ((void*)dump_alloc((num) * TYPEVECTOR_SIZE(size)))
+
+#define MGET_TYPEVECTOR(array,index,size) \
+    ((typevector*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
+
+#define COPY_TYPEVECTORSET(src,dst,size)                                               \
+    do {memcpy(dst,src,TYPEVECTOR_SIZE(size));                                 \
+        dst->k = 0;                                             \
+        if ((src)->alt) {                                                                              \
+               (dst)->alt = typevectorset_copy((src)->alt,1,size);     \
+        }} while(0)
+
 /* internally used macros ***************************************************/
 
 /* internal, don't use this explicitly! */
@@ -182,6 +225,10 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_IS_NEWOBJECT(info)                             \
             ((info).typeclass == pseudo_class_New)
 
+/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
+#define TYPEINFO_RETURNADDRESS(info)                            \
+            ((void *)(info).elementclass)
+
 /* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
 #define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
             ((void *)(info).elementclass)
@@ -215,6 +262,20 @@ struct typeinfo_mergedlist {
             ( TYPEINFO_IS_ARRAY(info)                           \
               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
 
+#define TYPE_IS_RETURNADDRESS(type,info)                        \
+            ( ((type)==TYPE_ADDRESS)                            \
+              && TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPE_IS_REFERENCE(type,info)                            \
+            ( ((type)==TYPE_ADDRESS)                            \
+              && !TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPEDESC_IS_RETURNADDRESS(td)                           \
+            TYPE_IS_RETURNADDRESS((td).type,(td).info)
+
+#define TYPEDESC_IS_REFERENCE(td)                               \
+            TYPE_IS_REFERENCE((td).type,(td).info)
+
 /* queries allowing the null type ********************************************/
 
 #define TYPEINFO_MAYBE_ARRAY(info)                              \
@@ -235,6 +296,13 @@ struct typeinfo_mergedlist {
              (info).dimension = 0;                              \
              (info).elementtype = 0;} while(0)
 
+#define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
+         do {(info).typeclass = NULL;                           \
+             (info).elementclass = (classinfo*) (adr);          \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
 #define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
          do {(info).typeclass = (cinfo);                \
              (info).elementclass = NULL;                \
@@ -316,6 +384,39 @@ struct typeinfo_mergedlist {
 /* FUNCTIONS                                                                */
 /****************************************************************************/
 
+/* typevector functions *****************************************************/
+
+/* element read-only access */
+bool typevectorset_checktype(typevector *set,int index,int type);
+bool typevectorset_checkreference(typevector *set,int index);
+bool typevectorset_checkretaddr(typevector *set,int index);
+int typevectorset_copymergedtype(typevector *set,int index,typeinfo *dst);
+typeinfo *typevectorset_mergedtypeinfo(typevector *set,int index,typeinfo *temp);
+int typevectorset_mergedtype(typevector *set,int index,typeinfo *temp,typeinfo **result);
+
+/* element write access */
+void typevectorset_store(typevector *set,int index,int type,typeinfo *info);
+void typevectorset_store_retaddr(typevector *set,int index,typeinfo *info);
+void typevectorset_store_twoword(typevector *set,int index,int type);
+void typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,int size);
+
+/* vector functions */
+bool typevector_separable_from(typevector *a,typevector *b,int size);
+bool typevector_merge(typevector *dst,typevector *y,int size);
+
+/* vector set functions */
+typevector *typevectorset_copy(typevector *src,int k,int size);
+/* typevector *typevectorset_copy_select(typevector *src,
+   int retindex,void *retaddr,int size);
+   void typevectorset_copy_select_to(typevector *src,typevector *dst,
+   int retindex,void *retaddr,int size); */
+/* bool typevectorset_separable(typevector *set,int size); */
+bool typevectorset_separable_with(typevector *set,typevector *add,int size);
+bool typevectorset_collapse(typevector *dst,int size);
+void typevectorset_add(typevector *dst,typevector *v,int size);
+/* void typevectorset_union(typevector *dst,typevector *v,int size); */
+typevector *typevectorset_select(typevector **set,int retindex,void *retaddr);
+
 /* inquiry functions (read-only) ********************************************/
 
 bool typeinfo_is_array(typeinfo *info);
@@ -335,6 +436,10 @@ void typeinfo_init_from_method_args(utf *desc,u1 *typebuf,
                                     typeinfo *infobuf,
                                     int buflen,bool twoword,
                                     int *returntype,typeinfo *returntypeinfo);
+int  typedescriptors_init_from_method_args(typedescriptor *td,
+                                                                                  utf *desc,
+                                                                                  int buflen,bool twoword,
+                                                                                  typedescriptor *returntype);
 
 void typeinfo_clone(typeinfo *src,typeinfo *dest);
 
@@ -355,6 +460,10 @@ void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc);
 void typeinfo_print(FILE *file,typeinfo *info,int indent);
 void typeinfo_print_short(FILE *file,typeinfo *info);
 void typeinfo_print_type(FILE *file,int type,typeinfo *info);
+void typeinfo_print_stacktype(FILE *file,int type,typeinfo *info);
+void typedescriptor_print(FILE *file,typedescriptor *td);
+void typevector_print(FILE *file,typevector *vec,int size);
+void typevectorset_print(FILE *file,typevector *set,int size);
 
 #endif /* TYPEINFO_DEBUG */