Use maxlocals, exceptiontable* from codegendata instead of methodinfo
[cacao.git] / typeinfo.c
index eb1559d4c4dfa9d65310e6bc6ad41f108a8592f2..258ca1cd58f02370cb4bb5a4ba9e66f31dd99bbb 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.c 719 2003-12-08 14:26:05Z edwin $
+   $Id: typeinfo.c 1296 2004-07-10 17:02:15Z stefan $
 
 */
 
 #include "typeinfo.h"
 #include "tables.h"
 #include "loader.h"
-#include "toolbox/loging.h"
+#include "toolbox/logging.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;
+}
+
+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)
+{
+       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;
+       
+       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)
+{
+       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;
+}
+
+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;
+}
+
+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.                */
@@ -88,11 +366,18 @@ interface_extends_interface(classinfo *cls,classinfo *interf)
     return false;
 }
 
-/* XXX If really a performance issue, this could become a macro. */
 static
 bool
 classinfo_implements_interface(classinfo *cls,classinfo *interf)
 {
+       if (!cls->loaded)
+               if (!class_load(cls))
+                       return false;
+
+       if (!cls->linked)
+               if (!class_link(cls))
+                       return false;
+
     if (cls->flags & ACC_INTERFACE) {
         /* cls is an interface */
         if (cls == interf)
@@ -150,24 +435,42 @@ merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist *merged,
 bool
 typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
 {
-    classinfo *cls;
-
-    cls = value->typeclass;
-
     /* DEBUG CHECK: dest must not have a merged list. */
 #ifdef TYPEINFO_DEBUG
     if (dest->merged)
         panic("Internal error: typeinfo_is_assignable on merged destination.");
 #endif
-    
+
+       return typeinfo_is_assignable_to_classinfo(value,dest->typeclass);
+}
+
+bool
+typeinfo_is_assignable_to_classinfo(typeinfo *value,classinfo *dest)
+{
+    classinfo *cls;
+
+    cls = value->typeclass;
+
     /* assignments of primitive values are not checked here. */
-    if (!cls && !dest->typeclass)
+    if (!cls && !dest)
         return true;
 
     /* primitive and reference types are not assignment compatible. */
-    if (!cls || !dest->typeclass)
+    if (!cls || !dest)
         return false;
 
+       /* maybe we need to load and link the class */
+       if (!cls->loaded)
+               class_load(cls);
+
+       if (!cls->linked)
+               class_link(cls);
+
+#ifdef TYPEINFO_DEBUG
+    if (!dest->linked)
+        panic("Internal error: typeinfo_is_assignable_to_classinfo: unlinked class.");
+#endif
+       
     /* the null type can be assigned to any type */
     if (TYPEINFO_IS_NULLTYPE(*value))
         return true;
@@ -176,13 +479,17 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
     if (TYPEINFO_IS_NEWOBJECT(*value))
         return false;
 
-    if (dest->typeclass->flags & ACC_INTERFACE) {
+    if (dest->flags & ACC_INTERFACE) {
         /* We are assigning to an interface type. */
-        return merged_implements_interface(cls,value->merged,
-                                           dest->typeclass);
+        return merged_implements_interface(cls,value->merged,dest);
     }
 
-    if (TYPEINFO_IS_ARRAY(*dest)) {
+    if (CLASS_IS_ARRAY(dest)) {
+               arraydescriptor *arraydesc = dest->vftbl->arraydesc;
+               int dimension = arraydesc->dimension;
+               classinfo *elementclass = (arraydesc->elementvftbl)
+                       ? arraydesc->elementvftbl->class : NULL;
+                       
         /* We are assigning to an array type. */
         if (!TYPEINFO_IS_ARRAY(*value))
             return false;
@@ -190,27 +497,29 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
         /* {Both value and dest are array types.} */
 
         /* value must have at least the dimension of dest. */
-        if (value->dimension < dest->dimension)
+        if (value->dimension < dimension)
             return false;
 
-        if (value->dimension > dest->dimension) {
+        if (value->dimension > dimension) {
             /* value has higher dimension so we need to check
              * if its component array can be assigned to the
              * element type of dest */
+
+                       if (!elementclass) return false;
             
-            if (dest->elementclass->flags & ACC_INTERFACE) {
+            if (elementclass->flags & ACC_INTERFACE) {
                 /* We are assigning to an interface type. */
                 return classinfo_implements_interface(pseudo_class_Arraystub,
-                                                      dest->elementclass);
+                                                      elementclass);
             }
 
             /* We are assigning to a class type. */
-            return class_issubclass(pseudo_class_Arraystub,dest->elementclass);
+            return class_issubclass(pseudo_class_Arraystub,elementclass);
         }
 
         /* {value and dest have the same dimension} */
 
-        if (value->elementtype != dest->elementtype)
+        if (value->elementtype != arraydesc->elementtype)
             return false;
 
         if (value->elementclass) {
@@ -218,16 +527,16 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
              * check if the elements are assignable.
              */
 
-            if (dest->elementclass->flags & ACC_INTERFACE) {
+            if (elementclass->flags & ACC_INTERFACE) {
                 /* We are assigning to an interface type. */
 
                 return merged_implements_interface(value->elementclass,
                                                    value->merged,
-                                                   dest->elementclass);
+                                                   elementclass);
             }
             
             /* We are assigning to a class type. */
-            return class_issubclass(value->elementclass,dest->elementclass);
+            return class_issubclass(value->elementclass,elementclass);
         }
 
         return true;
@@ -239,7 +548,7 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
     if (cls->flags & ACC_INTERFACE)
         cls = class_java_lang_Object;
     
-    return class_issubclass(cls,dest->typeclass);
+    return class_issubclass(cls,dest);
 }
 
 /**********************************************************************/
@@ -253,103 +562,48 @@ typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
     classinfo *cls;
     char *end;
 
-    /* XXX simplify */
-    cls = class_from_descriptor(utf_ptr,end_ptr,&end,CLASSLOAD_NEW);
-
-    if (!cls)
-        panic("Invalid descriptor.");
-
-    switch (*utf_ptr) {
-      case 'L':
-      case '[':
-          /* a class, interface or array descriptor */
-          TYPEINFO_INIT_CLASSINFO(*info,cls);
-          break;
-      default:
-          /* a primitive type */
-          TYPEINFO_INIT_PRIMITIVE(*info);
-    }
-
-    /* exceeding characters */         
-    if (end!=end_ptr) panic ("descriptor has exceeding chars");
+    cls = class_from_descriptor(utf_ptr,end_ptr,&end,
+                                                               CLASSLOAD_NULLPRIMITIVE
+                                                               | CLASSLOAD_NEW
+                                                               | CLASSLOAD_NOVOID
+                                                               | CLASSLOAD_CHECKEND);
+
+       if (cls) {
+               if (!cls->loaded)
+                       class_load(cls);
+
+               if (!cls->linked)
+                       class_link(cls);
+
+               /* a class, interface or array descriptor */
+               TYPEINFO_INIT_CLASSINFO(*info,cls);
+       } else {
+               /* a primitive type */
+               TYPEINFO_INIT_PRIMITIVE(*info);
+       }
 }
 
-/* XXX delete or use SKIP_FIELDDESCRIPTOR_SAFE */
 int
 typeinfo_count_method_args(utf *d,bool twoword)
 {
     int args = 0;
     char *utf_ptr = d->text;
     char *end_pos = utf_end(d);
-    char c,ch;
+    char c;
 
     /* method descriptor must start with parenthesis */
     if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
 
+       
     /* check arguments */
-    while ((c = *utf_ptr++) != ')') {
-        switch (c) {
-          case 'B':
-          case 'C':
-          case 'I':
-          case 'S':
-          case 'Z':  
-          case 'F':  
-              /* primitive one-word type */
-              args++;
-              break;
-              
-          case 'J':  
-          case 'D':
-              /* primitive two-word type */
-              args++;
-              if (twoword) args++;
-              break;
-              
-          case 'L':
-              /* skip classname */
-              while ( *utf_ptr++ != ';' )
-                  if (utf_ptr>=end_pos) 
-                      panic ("Missing ';' in objecttype-descriptor");
-              
-              args++;
-              break;
-              
-          case '[' :
-              /* array type */ 
-              while ((ch = *utf_ptr++)=='[') 
-                  /* skip */ ;
-              
-              /* component type of array */
-              switch (ch) {
-                case 'B':
-                case 'C':
-                case 'I':
-                case 'S':
-                case 'Z':  
-                case 'J':  
-                case 'F':  
-                case 'D':
-                    /* primitive type */  
-                    break;
-                    
-                case 'L':
-                    /* skip classname */
-                    while ( *utf_ptr++ != ';' )
-                        if (utf_ptr>=end_pos) 
-                            panic ("Missing ';' in objecttype-descriptor");
-                    break;
-                    
-                default:   
-                    panic ("Ill formed methodtype-descriptor");
-              }
-              
-              args++;
-              break;
-              
-          default:   
-              panic ("Ill formed methodtype-descriptor");
-        }                      
+    while ((c = *utf_ptr) != ')') {
+               class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
+                                                         CLASSLOAD_SKIP | CLASSLOAD_NOVOID
+                                                         | CLASSLOAD_NULLPRIMITIVE);
+               args++;
+               if (twoword && (c == 'J' || c == 'D'))
+                       /* primitive two-word type */
+                       args++;
     }
 
     return args;
@@ -362,137 +616,150 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
 {
     char *utf_ptr = desc->text;     /* current position in utf text   */
     char *end_pos = utf_end(desc);  /* points behind utf string       */
-    char c;
     int args = 0;
     classinfo *cls;
 
     /* method descriptor must start with parenthesis */
-    if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+    if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
 
     /* check arguments */
-    while ((c = *utf_ptr) != ')') {
-        /* XXX simplify */
-        cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
-        if (!cls)
-            panic("Invalid method descriptor.");
-
-        switch (c) {
-          case 'B':
-          case 'C':
-          case 'I':
-          case 'S':
-          case 'Z':  
-          case 'F':  
-              /* primitive one-word type */
-              if (++args > buflen)
-                  panic("Buffer too small for method arguments.");
-              if (typebuf)
-                  *typebuf++ = (c == 'F') ? TYPE_FLOAT : TYPE_INT; /* XXX TYPE_FLT? */
-              TYPEINFO_INIT_PRIMITIVE(*infobuf);
-              infobuf++;
-              break;
-              
-          case 'J':  
-          case 'D':
-              /* primitive two-word type */
-              if (++args > buflen)
-                  panic("Buffer too small for method arguments.");
-              if (typebuf)
-                  *typebuf++ = (c == 'J') ? TYPE_LONG : TYPE_DOUBLE; /* XXX TYPE_DBL? */
-              TYPEINFO_INIT_PRIMITIVE(*infobuf);
-              infobuf++;
-              if (twoword) {
-                  if (++args > buflen)
-                      panic("Buffer too small for method arguments.");
-                  if (typebuf)
-                      *typebuf++ = TYPE_VOID;
-                  TYPEINFO_INIT_PRIMITIVE(*infobuf);
-                  infobuf++;
-              }
-              break;
-              
-          case 'L':
-          case '[' :
-              /* reference type */
-              
-              if (++args > buflen)
-                  panic("Buffer too small for method arguments.");
-              if (typebuf)
-                  *typebuf++ = TYPE_ADDRESS;
-              
-              TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
-              infobuf++;
-              break;
-          
-          default:   
-              panic ("Ill formed methodtype-descriptor (type)");
-        }
+    while (utf_ptr != end_pos && *utf_ptr != ')') {
+               if (++args > buflen)
+                       panic("Buffer too small for method arguments.");
+               
+        *typebuf++ = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+                                                                                 CLASSLOAD_NEW
+                                                                                 | CLASSLOAD_NULLPRIMITIVE
+                                                                                 | CLASSLOAD_NOVOID);
+               
+               if (cls) {
+                       if (!cls->loaded)
+                               class_load(cls);
+
+                       if (!cls->linked)
+                               class_link(cls);
+
+                       TYPEINFO_INIT_CLASSINFO(*infobuf, cls);
+
+               } else {
+                       TYPEINFO_INIT_PRIMITIVE(*infobuf);
+               }
+               infobuf++;
+
+               if (twoword && (typebuf[-1] == TYPE_LONG || typebuf[-1] == TYPE_DOUBLE)) {
+                       if (++args > buflen)
+                               panic("Buffer too small for method arguments.");
+                       *typebuf++ = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(*infobuf);
+                       infobuf++;
+               }
     }
     utf_ptr++; /* skip ')' */
 
     /* check returntype */
     if (returntype) {
-        switch (*utf_ptr) {
-          case 'B':
-          case 'C':
-          case 'I':
-          case 'S':
-          case 'Z':
-              *returntype = TYPE_INT;
-              goto primitive_tail;
-              
-          case 'J':
-              *returntype = TYPE_LONG;
-              goto primitive_tail;
-              
-          case 'F':  
-              *returntype = TYPE_FLOAT;
-              goto primitive_tail;
-              
-          case 'D':
-              *returntype = TYPE_DOUBLE;
-              goto primitive_tail;
-
-          case 'V':
-              *returntype = TYPE_VOID;
-      primitive_tail:
-              if ((utf_ptr+1) != end_pos)
-                  panic ("Method-descriptor has exceeding chars");
-              if (returntypeinfo) {
-                  TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
-              }
-              break;
+               *returntype = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+                                                                                  CLASSLOAD_NULLPRIMITIVE
+                                                                                  | CLASSLOAD_NEW
+                                                                                  | CLASSLOAD_CHECKEND);
+
+               if (returntypeinfo) {
+                       if (cls) {
+                               if (!cls->loaded)
+                                       class_load(cls);
+
+                               if (!cls->linked)
+                                       class_link(cls);
+
+                               TYPEINFO_INIT_CLASSINFO(*returntypeinfo, cls);
+
+                       } else {
+                               TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
+                       }
+               }
+       }
+}
 
-          case 'L':
-          case '[':
-              *returntype = TYPE_ADDRESS;
-              cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
-              if (!cls)
-                  panic("Invalid return type");
-              if (utf_ptr != end_pos)
-                  panic ("Method-descriptor has exceeding chars");
-              if (returntypeinfo) {
-                  TYPEINFO_INIT_CLASSINFO(*returntypeinfo,cls);
-              }
-              break;
+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;
 
-          default:   
-              panic ("Ill formed methodtype-descriptor (returntype)");
-        }
+    /* 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) {
+                       if (!cls->loaded)
+                               class_load(cls);
+
+                       if (!cls->linked)
+                               class_link(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) {
+                       if (!cls->loaded)
+                               class_load(cls);
+
+                       if (!cls->linked)
+                               class_link(cls);
+
+                       TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+
+               } else {
+                       TYPEINFO_INIT_PRIMITIVE(returntype->info);
+               }
+       }
+       return args;
 }
 
 void
 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
 {
-    vftbl *comp = NULL;
+    vftbl_t *comp = NULL;
 
     if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
         TYPEINFO_INIT_NULLTYPE(*dst);
         return;
     }
     
-    /* XXX find component class */
     if (!TYPEINFO_IS_ARRAY(*srcarray))
         panic("Trying to access component of non-array");
 
@@ -503,20 +770,6 @@ typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
     else {
         TYPEINFO_INIT_PRIMITIVE(*dst);
     }
-
-    /* XXX assign directly ? */
-#if 0
-    if ((dst->dimension = srcarray->dimension - 1) == 0) {
-        dst->typeclass = srcarray->elementclass;
-        dst->elementtype = 0;
-        dst->elementclass = NULL;
-    }
-    else {
-        dst->typeclass = srcarray->typeclass;
-        dst->elementtype = srcarray->elementtype;
-        dst->elementclass = srcarray->elementclass;
-    }
-#endif
     
     dst->merged = srcarray->merged;
 }
@@ -537,7 +790,6 @@ typeinfo_clone(typeinfo *src,typeinfo *dest)
         TYPEINFO_ALLOCMERGED(dest->merged,count);
         dest->merged->count = count;
 
-        /* XXX use memcpy? */
         srclist = src->merged->list;
         destlist = dest->merged->list;
         while (count--)
@@ -772,7 +1024,7 @@ typeinfo_merge_nonarrays(typeinfo *dest,
     typeinfo_mergedlist *tmerged;
     bool changed;
 
-    /* XXX remove */
+    /* DEBUG */
     /*
 #ifdef TYPEINFO_DEBUG
     typeinfo dbgx,dbgy;
@@ -787,19 +1039,36 @@ typeinfo_merge_nonarrays(typeinfo *dest,
 #endif
     */ 
 
+       /* check clsx */
+       if (!clsx->loaded)
+               if (!class_load(clsx))
+                       return false;
+
+       if (!clsx->linked)
+               if (!class_link(clsx))
+                       return false;
+
+       /* check clsy */
+       if (!clsy->loaded)
+               if (!class_load(clsy))
+                       return false;
+
+       if (!clsy->linked)
+               if (!class_link(clsy))
+                       return false;
+
     /* Common case: clsx == clsy */
     /* (This case is very simple unless *both* x and y really represent
      *  merges of subclasses of clsx==clsy.)
      */
-    /* XXX count this case for statistics */
     if ((clsx == clsy) && (!mergedx || !mergedy)) {
   return_simple_x:
-        /* XXX remove */ /* log_text("return simple x"); */
+        /* DEBUG */ /* log_text("return simple x"); */
         changed = (dest->merged != NULL);
         TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
         dest->merged = NULL;
         *result = clsx;
-        /* XXX remove */ /* log_text("returning"); */
+        /* DEBUG */ /* log_text("returning"); */
         return changed;
     }
     
@@ -817,7 +1086,6 @@ typeinfo_merge_nonarrays(typeinfo *dest,
         if (clsy->flags & ACC_INTERFACE) {
             /* We are merging two interfaces. */
             /* {mergedy == NULL} */
-            /* XXX: should we optimize direct superinterfaces? */
 
             /* {We know that clsx!=clsy (see common case at beginning.)} */
             *result = class_java_lang_Object;
@@ -851,7 +1119,7 @@ typeinfo_merge_nonarrays(typeinfo *dest,
          * by y, too, so we have to add clsx to the mergedlist.
          */
 
-        /* XXX if x has no superinterfaces we could return a simple java.lang.Object */
+        /* if x has no superinterfaces we could return a simple java.lang.Object */
         
         common = class_java_lang_Object;
         goto merge_with_simple_x;
@@ -916,7 +1184,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
     int elementtype;
     bool changed;
 
-    /* XXX remove */
+    /* DEBUG */
     /*
 #ifdef TYPEINFO_DEBUG
     typeinfo_print(stdout,dest,4);
@@ -929,10 +1197,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);
 
@@ -953,22 +1227,21 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         return false;
     }
     
-    /* XXX remove */ /* log_text("Testing common case"); */
+    /* DEBUG */ /* log_text("Testing common case"); */
 
     /* Common case: class dest == class y */
     /* (This case is very simple unless *both* dest and y really represent
      *  merges of subclasses of class dest==class y.)
      */
-    /* XXX count this case for statistics */
     if ((dest->typeclass == y->typeclass) && (!dest->merged || !y->merged)) {
         changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if? */
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* unify if? */
         dest->merged = NULL;
-        /* XXX remove */ /* log_text("common case handled"); */
+        /* DEBUG */ /* log_text("common case handled"); */
         return changed;
     }
     
-    /* XXX remove */ /* log_text("Handling null types"); */
+    /* DEBUG */ /* log_text("Handling null types"); */
 
     /* Handle null types: */
     if (TYPEINFO_IS_NULLTYPE(*y)) {
@@ -988,7 +1261,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
     /* Handle merging of arrays: */
     if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
         
-        /* XXX remove */ /* log_text("Handling arrays"); */
+        /* DEBUG */ /* log_text("Handling arrays"); */
 
         /* Make x the one with lesser dimension */
         if (x->dimension > y->dimension) {
@@ -1037,10 +1310,9 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
                                                     elementclass,
                                                     x->merged,y->merged);
 
-                /* XXX otimize this? */
-                /* XXX remove */ /* log_text("finding resulting array class: "); */
+                /* DEBUG */ /* log_text("finding resulting array class: "); */
                 common = class_multiarray_of(dimension,elementclass);
-                /* XXX remove */ /* utf_display(common->name); printf("\n"); */
+                /* DEBUG */ /* utf_display(common->name); printf("\n"); */
             }
         }
     }
@@ -1077,7 +1349,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         changed = true;
     }
 
-    /* XXX remove */ /* log_text("returning from merge"); */
+    /* DEBUG */ /* log_text("returning from merge"); */
     
     return changed;
 }
@@ -1229,6 +1501,7 @@ typeinfo_testrun(char *filename)
     int maxdim;
     int failed = 0;
     FILE *file = fopen(filename,"rt");
+       int res;
     
     if (!file)
         panic("could not open typeinfo test file");
@@ -1237,7 +1510,7 @@ typeinfo_testrun(char *filename)
         if (buf[0] == '#' || !strlen(buf))
             continue;
         
-        int res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
+        res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
         if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc))
             panic("Invalid line in typeinfo test file (none of empty, comment or test)");
 
@@ -1294,6 +1567,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;
     
@@ -1302,7 +1576,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;
     }
     
@@ -1367,9 +1645,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;
     }
     
@@ -1411,11 +1694,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:
@@ -1423,6 +1702,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 */