sane comments
[cacao.git] / typeinfo.c
index 2260a10c2a06e8e6da3ecf22cd9a5c11966f5933..1c7f3328d4166547419d08e15b1dc285fb053d58 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.c 707 2003-12-07 17:29:08Z twisti $
+   $Id: typeinfo.c 922 2004-02-24 13:26:24Z edwin $
 
 */
 
 #include "loader.h"
 #include "toolbox/loging.h"
 #include "toolbox/memory.h"
+#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
 
 
-#define TYPEINFO_REUSE_MERGED
-
 #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.                */
@@ -90,7 +366,6 @@ 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)
@@ -152,35 +427,54 @@ 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;
 
+#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;
 
-    if (dest->typeclass->flags & ACC_INTERFACE) {
+    /* uninitialized objects are not assignable */
+    if (TYPEINFO_IS_NEWOBJECT(*value))
+        return false;
+
+    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;
@@ -188,27 +482,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) {
@@ -216,16 +512,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;
@@ -237,7 +533,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);
 }
 
 /**********************************************************************/
@@ -250,24 +546,19 @@ typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
 {
     classinfo *cls;
     char *end;
-    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)
+               /* a class, interface or array descriptor */
+               TYPEINFO_INIT_CLASSINFO(*info,cls);
+       else
+               /* a primitive type */
+               TYPEINFO_INIT_PRIMITIVE(*info);
 }
 
 int
@@ -276,75 +567,21 @@ 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;
@@ -357,123 +594,107 @@ 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) != ')') {
-        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)
+                       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)
+                               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)
+                       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
@@ -486,7 +707,6 @@ typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
         return;
     }
     
-    /* XXX find component class */
     if (!TYPEINFO_IS_ARRAY(*srcarray))
         panic("Trying to access component of non-array");
 
@@ -497,20 +717,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;
 }
@@ -531,7 +737,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--)
@@ -546,7 +751,8 @@ typeinfo_clone(typeinfo *src,typeinfo *dest)
 void
 typeinfo_free(typeinfo *info)
 {
-    TYPEINFO_FREE(*info);
+    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
+    info->merged = NULL;
 }
 
 /**********************************************************************/
@@ -765,7 +971,7 @@ typeinfo_merge_nonarrays(typeinfo *dest,
     typeinfo_mergedlist *tmerged;
     bool changed;
 
-    /* XXX remove */
+    /* DEBUG */
     /*
 #ifdef TYPEINFO_DEBUG
     typeinfo dbgx,dbgy;
@@ -784,15 +990,14 @@ typeinfo_merge_nonarrays(typeinfo *dest,
     /* (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;
     }
     
@@ -810,7 +1015,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;
@@ -844,7 +1048,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;
@@ -909,7 +1113,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
     int elementtype;
     bool changed;
 
-    /* XXX remove */
+    /* DEBUG */
     /*
 #ifdef TYPEINFO_DEBUG
     typeinfo_print(stdout,dest,4);
@@ -922,10 +1126,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);
 
@@ -935,22 +1145,32 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
 #endif
 
-    /* XXX remove */ /* log_text("Testing common case"); */
+    /* handle uninitialized object types */
+    /* XXX is there a way we could put this after the common case? */
+    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
+        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y))
+            typeinfo_merge_error("Trying to merge uninitialized object type.",dest,y);
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            typeinfo_merge_error("Trying to merge different uninitialized objects.",dest,y);
+        return false;
+    }
+    
+    /* 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)) {
@@ -970,7 +1190,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) {
@@ -1019,10 +1239,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"); */
             }
         }
     }
@@ -1059,7 +1278,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         changed = true;
     }
 
-    /* XXX remove */ /* log_text("returning from merge"); */
+    /* DEBUG */ /* log_text("returning from merge"); */
     
     return changed;
 }
@@ -1073,6 +1292,9 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 
 #include "tables.h"
 #include "loader.h"
+#include "jit/jit.h"
+
+extern instruction *instr;
 
 static int
 typeinfo_test_compare(classinfo **a,classinfo **b)
@@ -1130,6 +1352,12 @@ typeinfo_equal(typeinfo *x,typeinfo *y)
         if (x->elementclass != y->elementclass) return false;
         if (x->elementtype != y->elementtype) return false;
     }
+
+    if (TYPEINFO_IS_NEWOBJECT(*x))
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            return false;
+
     if (x->merged || y->merged) {
         if (!(x->merged && y->merged)) return false;
         if (x->merged->count != y->merged->count) return false;
@@ -1202,6 +1430,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");
@@ -1210,7 +1439,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)");
 
@@ -1248,21 +1477,6 @@ typeinfo_testrun(char *filename)
 void
 typeinfo_test()
 {
-/*     typeinfo i1,i2,i3,i4,i5,i6,i7,i8; */
-        
-/*     typeinfo_init_from_fielddescriptor(&i1,"[Ljava/lang/Integer;"); */
-/*     typeinfo_init_from_fielddescriptor(&i2,"[[Ljava/lang/String;"); */
-/*     typeinfo_init_from_fielddescriptor(&i3,"[Ljava/lang/Cloneable;"); */
-/*     typeinfo_init_from_fielddescriptor(&i3,"[[Ljava/lang/String;"); */
-/*     TYPEINFO_INIT_NULLTYPE(i1); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-/*     typeinfo_print_short(stdout,&i2); printf("\n"); */
-/*     typeinfo_merge(&i1,&i2); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-/*     typeinfo_print_short(stdout,&i3); printf("\n"); */
-/*     typeinfo_merge(&i1,&i3); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-
     log_text("Running typeinfo test file...");
     typeinfo_testrun("typeinfo.tst");
     log_text("Finished typeinfo test file.");
@@ -1281,6 +1495,8 @@ 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;
     
@@ -1289,7 +1505,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;
     }
     
@@ -1297,7 +1517,20 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
         fprintf(file,"%snull\n",ind);
         return;
     }
-    
+
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"%sNEW(%d):",ind,ins-instr);
+            utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+            fprintf(file,"\n");
+        }
+        else {
+            fprintf(file,"%sNEW(this)",ind);
+        }
+        return;
+    }
+
     fprintf(file,"%sClass:      ",ind);
     utf_fprint(file,info->typeclass->name);
     fprintf(file,"\n");
@@ -1340,9 +1573,15 @@ void
 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;
     }
     
@@ -1351,6 +1590,17 @@ typeinfo_print_short(FILE *file,typeinfo *info)
         return;
     }
     
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"NEW(%d):",ins-instr);
+            utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+        }
+        else
+            fprintf(file,"NEW(this)");
+        return;
+    }
+
     utf_fprint(file,info->typeclass->name);
 
     if (info->merged) {
@@ -1373,11 +1623,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:
@@ -1385,6 +1631,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 */