## Process this file with automake to produce Makefile.in
-# $Id: Makefile.am 682 2003-12-01 15:33:30Z jowenn $
+# $Id: Makefile.am 687 2003-12-04 22:29:54Z edwin $
@SET_MAKE@
jni.h \
tables.c \
tables.h \
- unzip.c
+ unzip.c \
+ typeinfo.c
cacao_LDADD = \
jit/libjit.a \
Philipp Tomsich
Edwin Steiner
- $Id: global.h 682 2003-12-01 15:33:30Z jowenn $
+ $Id: global.h 687 2003-12-04 22:29:54Z edwin $
*/
short dimension; /* dimension of the array (always >= 1) */
s4 dataoffset; /* offset of the array data from object pointer */
s4 componentsize; /* size of a component in bytes */
+ short elementtype; /* ARRAYTYPE_* constant (XXX optimize away?) */
};
/* references to some system classes ******************************************/
Roman Obermaiser
Mark Probst
- $Id: loader.c 682 2003-12-01 15:33:30Z jowenn $
+ $Id: loader.c 687 2003-12-04 22:29:54Z edwin $
*/
if (compvftbl->arraydesc) {
desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
desc->dimension = compvftbl->arraydesc->dimension + 1;
+ desc->elementtype = compvftbl->arraydesc->elementtype;
}
else {
desc->elementvftbl = compvftbl;
desc->dimension = 1;
+ desc->elementtype = ARRAYTYPE_OBJECT;
}
}
else {
desc->componentvftbl = NULL;
desc->elementvftbl = NULL;
desc->dimension = 1;
+ desc->elementtype = desc->arraytype;
}
return desc;
{
/* pseudo class for Arraystubs (extends java.lang.Object) */
- pseudo_class_Arraystub = class_new( utf_new_char(";Arraystub;") );
+ pseudo_class_Arraystub = class_new( utf_new_char("$ARRAYSTUB$") );
list_remove(&unloadedclasses,pseudo_class_Arraystub);
pseudo_class_Arraystub->super = class_java_lang_Object;
/* pseudo class representing the null type */
- pseudo_class_Null = class_new( utf_new_char(";Null;") );
+ pseudo_class_Null = class_new( utf_new_char("$NULL$") );
list_remove(&unloadedclasses,pseudo_class_Null);
pseudo_class_Null->super = class_java_lang_Object;
- Calling the class loader
- Running the main method
- $Id: main.c 664 2003-11-21 18:24:01Z jowenn $
+ $Id: main.c 687 2003-12-04 22:29:54Z edwin $
*/
#include "toolbox/loging.h"
#include "toolbox/memory.h"
#include "parseRTstats.h"
-
+#include "typeinfo.h" /* XXX remove debug */
bool compileall = false;
bool verbose = false;
a->data[i - opt_ind] = javastring_new(utf_new_char(argv[i]));
}
-
+#ifdef DEBUG_TYPES
+ typeinfo_test(); /* XXX remove debug */
+#endif
/*class_showmethods(currentThread->group->header.vftbl->class); */
local_exceptionptr = asm_calljavamethod (mainmethod, a, NULL, NULL, NULL );
- Calling the class loader
- Running the main method
- $Id: cacao.c 664 2003-11-21 18:24:01Z jowenn $
+ $Id: cacao.c 687 2003-12-04 22:29:54Z edwin $
*/
#include "toolbox/loging.h"
#include "toolbox/memory.h"
#include "parseRTstats.h"
-
+#include "typeinfo.h" /* XXX remove debug */
bool compileall = false;
bool verbose = false;
a->data[i - opt_ind] = javastring_new(utf_new_char(argv[i]));
}
-
+#ifdef DEBUG_TYPES
+ typeinfo_test(); /* XXX remove debug */
+#endif
/*class_showmethods(currentThread->group->header.vftbl->class); */
local_exceptionptr = asm_calljavamethod (mainmethod, a, NULL, NULL, NULL );
Philipp Tomsich
Edwin Steiner
- $Id: global.h 682 2003-12-01 15:33:30Z jowenn $
+ $Id: global.h 687 2003-12-04 22:29:54Z edwin $
*/
short dimension; /* dimension of the array (always >= 1) */
s4 dataoffset; /* offset of the array data from object pointer */
s4 componentsize; /* size of a component in bytes */
+ short elementtype; /* ARRAYTYPE_* constant (XXX optimize away?) */
};
/* references to some system classes ******************************************/
--- /dev/null
+/********************************* typeinfo.c *********************************
+
+ Copyright (c) 2003 ? XXX
+
+ See file COPYRIGHT for information on usage and disclaimer of warranties
+
+ functions for the compiler's type system
+
+ Authors: Edwin Steiner
+
+ Last Change:
+
+*******************************************************************************/
+
+#include "typeinfo.h"
+#include "tables.h"
+#include "loader.h"
+
+#define TYPEINFO_REUSE_MERGED
+
+#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
+ ( ((index) < (cls)->vftbl->interfacetablelength) \
+ && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
+
+/**********************************************************************/
+/* READ-ONLY FUNCTIONS */
+/* The following functions don't change typeinfo data. */
+/**********************************************************************/
+
+bool
+typeinfo_is_array(typeinfo *info)
+{
+ return TYPEINFO_IS_ARRAY(*info);
+}
+
+bool
+typeinfo_is_primitive_array(typeinfo *info,int arraytype)
+{
+ return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
+}
+
+bool
+typeinfo_is_array_of_refs(typeinfo *info)
+{
+ return TYPEINFO_IS_ARRAY_OF_REFS(*info);
+}
+
+static
+bool
+interface_extends_interface(classinfo *cls,classinfo *interf)
+{
+ int i;
+
+ /* first check direct superinterfaces */
+ for (i=0; i<cls->interfacescount; ++i) {
+ if (cls->interfaces[i] == interf)
+ return true;
+ }
+
+ /* check indirect superinterfaces */
+ for (i=0; i<cls->interfacescount; ++i) {
+ if (interface_extends_interface(cls->interfaces[i],interf))
+ return true;
+ }
+
+ return false;
+}
+
+/* XXX If really a performance issue, this could become a macro. */
+static
+bool
+classinfo_implements_interface(classinfo *cls,classinfo *interf)
+{
+ if (cls->flags & ACC_INTERFACE) {
+ /* cls is an interface */
+ if (cls == interf)
+ return true;
+
+ /* check superinterfaces */
+ return interface_extends_interface(cls,interf);
+ }
+
+ return CLASS_IMPLEMENTS_INTERFACE(cls,interf->index);
+}
+
+bool mergedlist_implements_interface(typeinfo_mergedlist *merged,
+ classinfo *interf)
+{
+ int i;
+ classinfo **mlist;
+
+ /* Check if there is an non-empty mergedlist. */
+ if (!merged)
+ return false;
+
+ /* If all classinfos in the (non-empty) merged array implement the
+ * interface return true, otherwise false.
+ */
+ mlist = merged->list;
+ i = merged->count;
+ while (i--) {
+ if (!classinfo_implements_interface(*mlist++,interf))
+ return false;
+ }
+ return true;
+}
+
+bool
+merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist *merged,
+ classinfo *interf)
+{
+ /* primitive types don't support interfaces. */
+ if (!typeclass)
+ return false;
+
+ /* the null type can be cast to any interface type. */
+ if (typeclass == pseudo_class_Null)
+ return true;
+
+ /* check if typeclass implements the interface. */
+ if (classinfo_implements_interface(typeclass,interf))
+ return true;
+
+ /* check the mergedlist */
+ return (merged && mergedlist_implements_interface(merged,interf));
+}
+
+bool
+typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
+{
+ classinfo *cls;
+
+ cls = value->typeclass;
+
+ /* DEBUG CHECK: dest must not have a merged list. */
+#ifdef DEBUG_TYPES
+ if (dest->merged)
+ panic("Internal error: typeinfo_is_assignable on merged destination.");
+#endif
+
+ /* assignments of primitive values are not checked here. */
+ if (!cls && !dest->typeclass)
+ return true;
+
+ /* the null type can be assigned to any type */
+ if (TYPEINFO_IS_NULLTYPE(*value))
+ return true;
+
+ /* primitive and reference types are not assignment compatible. */
+ if (!cls || !dest->typeclass)
+ return false;
+
+ if (dest->typeclass->flags & ACC_INTERFACE) {
+ /* We are assigning to an interface type. */
+ return merged_implements_interface(cls,value->merged,
+ dest->typeclass);
+ }
+
+ if (TYPEINFO_IS_ARRAY(*dest)) {
+ /* We are assigning to an array type. */
+ if (!TYPEINFO_IS_ARRAY(*value))
+ return false;
+
+ /* {Both value and dest are array types.} */
+
+ /* value must have at least the dimension of dest. */
+ if (value->dimension < dest->dimension)
+ return false;
+
+ if (value->dimension > dest->dimension) {
+ /* value has higher dimension so we need to check
+ * if its component array can be assigned to the
+ * element type of dest */
+
+ if (dest->elementclass->flags & ACC_INTERFACE) {
+ /* We are assigning to an interface type. */
+ return classinfo_implements_interface(pseudo_class_Arraystub,
+ dest->elementclass);
+ }
+
+ /* We are assigning to a class type. */
+ return class_issubclass(pseudo_class_Arraystub,dest->elementclass);
+ }
+
+ /* {value and dest have the same dimension} */
+
+ if (value->elementtype != dest->elementtype)
+ return false;
+
+ if (value->elementclass) {
+ /* We are assigning an array of objects so we have to
+ * check if the elements are assignable.
+ */
+
+ if (dest->elementclass->flags & ACC_INTERFACE) {
+ /* We are assigning to an interface type. */
+
+ return merged_implements_interface(value->elementclass,
+ value->merged,
+ dest->elementclass);
+ }
+
+ /* We are assigning to a class type. */
+ return class_issubclass(value->elementclass,dest->elementclass);
+ }
+
+ return true;
+ }
+
+ /* {dest is not an array} */
+
+ /* We are assigning to a class type */
+ if (cls->flags & ACC_INTERFACE)
+ cls = class_java_lang_Object;
+
+ return class_issubclass(cls,dest->typeclass);
+}
+
+/**********************************************************************/
+/* INITIALIZATION FUNCTIONS */
+/* The following functions fill in uninitialized typeinfo structures. */
+/**********************************************************************/
+
+/* XXX delete */
+#if 0
+void
+typeinfo_init_from_arraydescriptor(typeinfo *info,
+ constant_arraydescriptor *desc)
+{
+ int dim = 1;
+
+ /* Arrays are instances of the pseudo class Array. */
+ info->typeclass = pseudo_class_Array; /* XXX */
+ info->merged = NULL;
+
+ /* Handle multidimensional arrays */
+ while (desc->arraytype == ARRAYTYPE_ARRAY) {
+ dim++;
+ desc = desc->elementdescriptor;
+ }
+
+ info->dimension = dim;
+
+ if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
+ info->elementclass = desc->objectclass;
+ }
+ else {
+ info->elementclass = NULL;
+ }
+}
+#endif
+
+void
+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");
+}
+
+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;
+
+ /* 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");
+ }
+ }
+
+ return args;
+}
+
+void
+typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
+ int buflen,bool twoword,
+ int *returntype,typeinfo *returntypeinfo)
+{
+ 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");
+
+ /* 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.");
+ 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);
+ /* XXX remove */ /* utf_display(cls->name); */
+ infobuf++;
+ break;
+
+ default:
+ panic ("Ill formed methodtype-descriptor (type)");
+ }
+ }
+ 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;
+
+ 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;
+
+ default:
+ panic ("Ill formed methodtype-descriptor (returntype)");
+ }
+ }
+}
+
+/* XXX could be made a macro if really performance critical */
+void
+typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
+{
+ vftbl *comp = NULL;
+
+ /* XXX find component class */
+ if (!TYPEINFO_IS_ARRAY(*srcarray))
+ panic("Trying to access component of non-array");
+
+ comp = srcarray->typeclass->vftbl->arraydesc->componentvftbl;
+ if (comp) {
+ TYPEINFO_INIT_CLASSINFO(*dst,comp->class);
+ }
+ 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;
+}
+
+/* Condition: src != dest. */
+void
+typeinfo_clone(typeinfo *src,typeinfo *dest)
+{
+ int count;
+ classinfo **srclist,**destlist;
+
+#ifdef DEBUG_TYPES
+ if (src == dest)
+ panic("Internal error: typeinfo_clone with src==dest");
+#endif
+
+ *dest = *src;
+
+ if (src->merged) {
+ count = src->merged->count;
+ TYPEINFO_ALLOCMERGED(dest->merged,count);
+ dest->merged->count = count;
+
+ /* XXX use memcpy? */
+ srclist = src->merged->list;
+ destlist = dest->merged->list;
+ while (count--)
+ *destlist++ = *srclist++;
+ }
+}
+
+/**********************************************************************/
+/* MISCELLANEOUS FUNCTIONS */
+/**********************************************************************/
+
+void
+typeinfo_free(typeinfo *info)
+{
+ TYPEINFO_FREE(*info);
+}
+
+/**********************************************************************/
+/* MERGING FUNCTIONS */
+/* The following functions are used to merge the types represented by */
+/* two typeinfo structures into one typeinfo structure. */
+/**********************************************************************/
+
+static
+void
+typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
+#ifdef DEBUG_TYPES
+ fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
+ fprintf(stderr,"Typeinfo x:\n");
+ typeinfo_print(stderr,x,1);
+ fprintf(stderr,"Typeinfo y:\n");
+ typeinfo_print(stderr,y,1);
+#endif
+ panic(str);
+}
+
+/* Condition: clsx != clsy. */
+/* Returns: true if dest was changed (always true). */
+static
+bool
+typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy)
+{
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ TYPEINFO_ALLOCMERGED(dest->merged,2);
+ dest->merged->count = 2;
+
+#ifdef DEBUG_TYPES
+ if (clsx == clsy)
+ panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
+#endif
+
+ if (clsx < clsy) {
+ dest->merged->list[0] = clsx;
+ dest->merged->list[1] = clsy;
+ }
+ else {
+ dest->merged->list[0] = clsy;
+ dest->merged->list[1] = clsx;
+ }
+
+ return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classinfo *cls)
+{
+ int count;
+ typeinfo_mergedlist *newmerged;
+ classinfo **mlist,**newlist;
+
+ count = m->count;
+ mlist = m->list;
+
+ /* Check if cls is already in the mergedlist m. */
+ while (count--) {
+ if (*mlist++ == cls) {
+ /* cls is in the list, so m is the resulting mergedlist */
+ if (dest->merged == m)
+ return false;
+
+ /* We have to copy the mergedlist */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ count = m->count;
+ TYPEINFO_ALLOCMERGED(dest->merged,count);
+ dest->merged->count = count;
+ newlist = dest->merged->list;
+ mlist = m->list;
+ while (count--) {
+ *newlist++ = *mlist++;
+ }
+ return true;
+ }
+ }
+
+ /* Add cls to the mergedlist. */
+ count = m->count;
+ TYPEINFO_ALLOCMERGED(newmerged,count+1);
+ newmerged->count = count+1;
+ newlist = newmerged->list;
+ mlist = m->list;
+ while (count) {
+ if (*mlist > cls)
+ break;
+ *newlist++ = *mlist++;
+ count--;
+ }
+ *newlist++ = cls;
+ while (count--) {
+ *newlist++ = *mlist++;
+ }
+
+ /* Put the new mergedlist into dest. */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ dest->merged = newmerged;
+
+ return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x,
+ typeinfo_mergedlist *y)
+{
+ int count = 0;
+ int countx,county;
+ typeinfo_mergedlist *temp,*result;
+ classinfo **clsx,**clsy,**newlist;
+
+ /* count the elements that will be in the resulting list */
+ /* (Both lists are sorted, equal elements are counted only once.) */
+ clsx = x->list;
+ clsy = y->list;
+ countx = x->count;
+ county = y->count;
+ while (countx && county) {
+ if (*clsx == *clsy) {
+ clsx++;
+ clsy++;
+ countx--;
+ county--;
+ }
+ else if (*clsx < *clsy) {
+ clsx++;
+ countx--;
+ }
+ else {
+ clsy++;
+ county--;
+ }
+ count++;
+ }
+ count += countx + county;
+
+ /* {The new mergedlist will have count entries.} */
+
+ if (y->count == count) {
+ temp = x; x = y; y = temp;
+ }
+ /* {If one of x,y is already the result it is x.} */
+ if (x->count == count) {
+ /* x->merged is equal to the result */
+ if (x == dest->merged)
+ return false;
+
+ if (!dest->merged || dest->merged->count != count) {
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ TYPEINFO_ALLOCMERGED(dest->merged,count);
+ dest->merged->count = count;
+ }
+
+ newlist = dest->merged->list;
+ clsx = x->list;
+ while (count--) {
+ *newlist++ = *clsx++;
+ }
+ return true;
+ }
+
+ /* {We have to merge two lists.} */
+
+ /* allocate the result list */
+ TYPEINFO_ALLOCMERGED(result,count);
+ result->count = count;
+ newlist = result->list;
+
+ /* merge the sorted lists */
+ clsx = x->list;
+ clsy = y->list;
+ countx = x->count;
+ county = y->count;
+ while (countx && county) {
+ if (*clsx == *clsy) {
+ *newlist++ = *clsx++;
+ clsy++;
+ countx--;
+ county--;
+ }
+ else if (*clsx < *clsy) {
+ *newlist++ = *clsx++;
+ countx--;
+ }
+ else {
+ *newlist++ = *clsy++;
+ county--;
+ }
+ }
+ while (countx--)
+ *newlist++ = *clsx++;
+ while (county--)
+ *newlist++ = *clsy++;
+
+ /* replace the list in dest with the result list */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ dest->merged = result;
+
+ return true;
+}
+
+static
+bool
+typeinfo_merge_nonarrays(typeinfo *dest,
+ classinfo **result,
+ classinfo *clsx,classinfo *clsy,
+ typeinfo_mergedlist *mergedx,
+ typeinfo_mergedlist *mergedy)
+{
+ classinfo *tcls,*common;
+ typeinfo_mergedlist *tmerged;
+ bool changed;
+
+ /* XXX remove */
+ /*
+#ifdef DEBUG_TYPES
+ typeinfo dbgx,dbgy;
+ printf("typeinfo_merge_nonarrays:\n");
+ TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
+ dbgx.merged = mergedx;
+ TYPEINFO_INIT_CLASSINFO(dbgy,clsy);
+ dbgy.merged = mergedy;
+ typeinfo_print(stdout,&dbgx,4);
+ printf(" with:\n");
+ typeinfo_print(stdout,&dbgy,4);
+#endif
+ */
+
+ /* 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"); */
+ changed = (dest->merged != NULL);
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ dest->merged = NULL;
+ *result = clsx;
+ /* XXX remove */ /* log_text("returning"); */
+ return changed;
+ }
+
+ /* If clsy is an interface, swap x and y. */
+ if (clsy->flags & ACC_INTERFACE) {
+ tcls = clsx; clsx = clsy; clsy = tcls;
+ tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+ }
+ /* {We know: If only one of x,y is an interface it is x.} */
+
+ /* Handle merging of interfaces: */
+ if (clsx->flags & ACC_INTERFACE) {
+ /* {clsx is an interface and mergedx == NULL.} */
+
+ 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;
+ return typeinfo_merge_two(dest,clsx,clsy);
+ }
+
+ /* {We know: x is an interface, clsy is a class.} */
+
+ /* Check if we are merging an interface with java.lang.Object */
+ if (clsy == class_java_lang_Object && !mergedy) {
+ clsx = clsy;
+ goto return_simple_x;
+ }
+
+
+ /* If the type y implements clsx then the result of the merge
+ * is clsx regardless of mergedy.
+ */
+
+ if (CLASS_IMPLEMENTS_INTERFACE(clsy,clsx->index)
+ || mergedlist_implements_interface(mergedy,clsx))
+ {
+ /* y implements x, so the result of the merge is x. */
+ goto return_simple_x;
+ }
+
+ /* {We know: x is an interface, the type y a class or a merge
+ * of subclasses and does not implement x.} */
+
+ /* There may still be superinterfaces of x which are implemented
+ * 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 */
+
+ common = class_java_lang_Object;
+ goto merge_with_simple_x;
+ }
+
+ /* {We know: x and y are classes (not interfaces).} */
+
+ /* If *x is deeper in the inheritance hierarchy swap x and y. */
+ if (clsx->index > clsy->index) {
+ tcls = clsx; clsx = clsy; clsy = tcls;
+ tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+ }
+
+ /* {We know: y is at least as deep in the hierarchy as x.} */
+
+ /* Find nearest common anchestor for the classes. */
+ common = clsx;
+ tcls = clsy;
+ while (tcls->index > common->index)
+ tcls = tcls->super;
+ while (common != tcls) {
+ common = common->super;
+ tcls = tcls->super;
+ }
+
+ /* {common == nearest common anchestor of clsx and clsy.} */
+
+ /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
+
+ /* If clsx==common and x is a whole class (not a merge of subclasses)
+ * then the result of the merge is clsx.
+ */
+ if (clsx == common && !mergedx) {
+ goto return_simple_x;
+ }
+
+ if (mergedx) {
+ *result = common;
+ if (mergedy)
+ return typeinfo_merge_mergedlists(dest,mergedx,mergedy);
+ else
+ return typeinfo_merge_add(dest,mergedx,clsy);
+ }
+
+ merge_with_simple_x:
+ *result = common;
+ if (mergedy)
+ return typeinfo_merge_add(dest,mergedy,clsx);
+ else
+ return typeinfo_merge_two(dest,clsx,clsy);
+}
+
+/* Condition: *dest must be a valid initialized typeinfo. */
+/* Condition: dest != y. */
+/* Returns: true if dest was changed. */
+bool
+typeinfo_merge(typeinfo *dest,typeinfo* y)
+{
+ typeinfo *x;
+ typeinfo *tmp; /* used for swapping */
+ classinfo *common;
+ classinfo *elementclass;
+ int dimension;
+ int elementtype;
+ bool changed;
+
+ /* XXX remove */
+ /*
+#ifdef DEBUG_TYPES
+ typeinfo_print(stdout,dest,4);
+ typeinfo_print(stdout,y,4);
+#endif
+ */
+
+ /* This function cannot be used to merge primitive types. */
+ if (!dest->typeclass || !y->typeclass)
+ typeinfo_merge_error("Trying to merge primitive types.",dest,y);
+
+#ifdef DEBUG_TYPES
+ if (dest == y)
+ panic("Internal error: typeinfo_merge with dest==y");
+
+ /* check that no unlinked classes are merged. */
+ if (!dest->typeclass->linked || !y->typeclass->linked)
+ typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
+#endif
+
+ /* XXX remove */ /* 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 */
+ dest->merged = NULL;
+ /* XXX remove */ /* log_text("common case handled"); */
+ return changed;
+ }
+
+ /* XXX remove */ /* log_text("Handling null types"); */
+
+ /* Handle null types: */
+ if (TYPEINFO_IS_NULLTYPE(*y)) {
+ return false;
+ }
+ if (TYPEINFO_IS_NULLTYPE(*dest)) {
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ TYPEINFO_CLONE(*y,*dest);
+ return true;
+ }
+
+ /* This function uses x internally, so x and y can be swapped
+ * without changing dest. */
+ x = dest;
+ changed = false;
+
+ /* Handle merging of arrays: */
+ if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
+
+ /* XXX remove */ /* log_text("Handling arrays"); */
+
+ /* Make x the one with lesser dimension */
+ if (x->dimension > y->dimension) {
+ tmp = x; x = y; y = tmp;
+ }
+
+ /* If one array (y) has higher dimension than the other,
+ * interpret it as an array (same dim. as x) of Arraystubs. */
+ if (x->dimension < y->dimension) {
+ dimension = x->dimension;
+ elementtype = ARRAYTYPE_OBJECT;
+ elementclass = pseudo_class_Arraystub;
+ }
+ else {
+ dimension = y->dimension;
+ elementtype = y->elementtype;
+ elementclass = y->elementclass;
+ }
+
+ /* {The arrays are of the same dimension.} */
+
+ if (x->elementtype != elementtype) {
+ /* Different element types are merged, so the resulting array
+ * type has one accessible dimension less. */
+ if (--dimension == 0) {
+ common = pseudo_class_Arraystub;
+ elementtype = 0;
+ elementclass = NULL;
+ }
+ else {
+ common = class_multiarray_of(dimension,pseudo_class_Arraystub);
+ elementtype = ARRAYTYPE_OBJECT;
+ elementclass = pseudo_class_Arraystub;
+ }
+ }
+ else {
+ /* {The arrays have the same dimension and elementtype.} */
+
+ if (elementtype == ARRAYTYPE_OBJECT) {
+ /* The elements are references, so their respective
+ * types must be merged.
+ */
+ changed |= typeinfo_merge_nonarrays(dest,
+ &elementclass,
+ x->elementclass,
+ elementclass,
+ x->merged,y->merged);
+
+ /* XXX otimize this? */
+ /* XXX remove */ /* log_text("finding resulting array class: "); */
+ common = class_multiarray_of(dimension,elementclass);
+ /* XXX remove */ /* utf_display(common->name); printf("\n"); */
+ }
+ }
+ }
+ else {
+ /* {We know that at least one of x or y is no array, so the
+ * result cannot be an array.} */
+
+ changed |= typeinfo_merge_nonarrays(dest,
+ &common,
+ x->typeclass,y->typeclass,
+ x->merged,y->merged);
+
+ dimension = 0;
+ elementtype = 0;
+ elementclass = NULL;
+ }
+
+ /* Put the new values into dest if neccessary. */
+
+ if (dest->typeclass != common) {
+ dest->typeclass = common;
+ changed = true;
+ }
+ if (dest->dimension != dimension) {
+ dest->dimension = dimension;
+ changed = true;
+ }
+ if (dest->elementtype != elementtype) {
+ dest->elementtype = elementtype;
+ changed = true;
+ }
+ if (dest->elementclass != elementclass) {
+ dest->elementclass = elementclass;
+ changed = true;
+ }
+
+ /* XXX remove */ /* log_text("returning from merge"); */
+
+ return changed;
+}
+
+
+/**********************************************************************/
+/* DEBUGGING HELPERS */
+/**********************************************************************/
+
+#ifdef DEBUG_TYPES
+
+#include "tables.h"
+#include "loader.h"
+
+static int
+typeinfo_test_compare(classinfo **a,classinfo **b)
+{
+ if (*a == *b) return 0;
+ if (*a < *b) return -1;
+ return +1;
+}
+
+static void
+typeinfo_test_parse(typeinfo *info,char *str)
+{
+ int num;
+ int i;
+ typeinfo *infobuf;
+ u1 *typebuf;
+ int returntype;
+ utf *desc = utf_new_char(str);
+
+ num = typeinfo_count_method_args(desc,false);
+ if (num) {
+ typebuf = DMNEW(u1,num);
+ infobuf = DMNEW(typeinfo,num);
+
+ typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
+ &returntype,info);
+
+ TYPEINFO_ALLOCMERGED(info->merged,num);
+ info->merged->count = num;
+
+ for (i=0; i<num; ++i) {
+ if (typebuf[i] != TYPE_ADDRESS)
+ panic("non-reference type in mergedlist");
+ info->merged->list[i] = infobuf[i].typeclass;
+ }
+ qsort(info->merged->list,num,sizeof(classinfo*),
+ (int(*)(const void *,const void *))&typeinfo_test_compare);
+ }
+ else {
+ typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
+ &returntype,info);
+ }
+}
+
+#define TYPEINFO_TEST_BUFLEN 4000
+
+static bool
+typeinfo_equal(typeinfo *x,typeinfo *y)
+{
+ int i;
+
+ if (x->typeclass != y->typeclass) return false;
+ if (x->dimension != y->dimension) return false;
+ if (x->dimension) {
+ if (x->elementclass != y->elementclass) return false;
+ if (x->elementtype != y->elementtype) return false;
+ }
+ if (x->merged || y->merged) {
+ if (!(x->merged && y->merged)) return false;
+ if (x->merged->count != y->merged->count) return false;
+ for (i=0; i<x->merged->count; ++i)
+ if (x->merged->list[i] != y->merged->list[i])
+ return false;
+ }
+ return true;
+}
+
+static void
+typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
+{
+ typeinfo dest;
+
+ TYPEINFO_CLONE(*a,dest);
+
+ printf("\n ");
+ typeinfo_print_short(stdout,&dest);
+ printf("\n ");
+ typeinfo_print_short(stdout,b);
+ printf("\n");
+
+ typeinfo_merge(&dest,b);
+
+ if (typeinfo_equal(&dest,result)) {
+ printf("OK ");
+ typeinfo_print_short(stdout,&dest);
+ printf("\n");
+ }
+ else {
+ printf("RESULT ");
+ typeinfo_print_short(stdout,&dest);
+ printf("\n");
+ printf("SHOULD BE ");
+ typeinfo_print_short(stdout,result);
+ printf("\n");
+ (*failed)++;
+ }
+}
+
+static void
+typeinfo_inc_dimension(typeinfo *info)
+{
+ if (info->dimension++ == 0) {
+ info->elementtype = ARRAYTYPE_OBJECT;
+ info->elementclass = info->typeclass;
+ }
+ info->typeclass = class_array_of(info->typeclass);
+}
+
+#define TYPEINFO_TEST_MAXDIM 10
+
+static void
+typeinfo_testrun(char *filename)
+{
+ char buf[TYPEINFO_TEST_BUFLEN];
+ char bufa[TYPEINFO_TEST_BUFLEN];
+ char bufb[TYPEINFO_TEST_BUFLEN];
+ char bufc[TYPEINFO_TEST_BUFLEN];
+ typeinfo a,b,c,a2,b2;
+ int maxdim;
+ int failed = 0;
+ FILE *file = fopen(filename,"rt");
+
+ if (!file)
+ panic("could not open typeinfo test file");
+
+ while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
+ if (buf[0] == '#' || !strlen(buf))
+ continue;
+
+ int 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)");
+
+ typeinfo_test_parse(&a,bufa);
+ typeinfo_test_parse(&b,bufb);
+ typeinfo_test_parse(&c,bufc);
+ do {
+ typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
+ typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
+
+ if (TYPEINFO_IS_NULLTYPE(a)) break;
+ if (TYPEINFO_IS_NULLTYPE(b)) break;
+ if (TYPEINFO_IS_NULLTYPE(c)) break;
+
+ maxdim = a.dimension;
+ if (b.dimension > maxdim) maxdim = b.dimension;
+ if (c.dimension > maxdim) maxdim = c.dimension;
+
+ if (maxdim < TYPEINFO_TEST_MAXDIM) {
+ typeinfo_inc_dimension(&a);
+ typeinfo_inc_dimension(&b);
+ typeinfo_inc_dimension(&c);
+ }
+ } while (maxdim < TYPEINFO_TEST_MAXDIM);
+ }
+
+ fclose(file);
+
+ if (failed) {
+ fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
+ panic("Failed test");
+ }
+}
+
+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.");
+}
+
+void
+typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc)
+{
+ typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
+}
+
+#define TYPEINFO_MAXINDENT 80
+
+void
+typeinfo_print(FILE *file,typeinfo *info,int indent)
+{
+ int i;
+ char ind[TYPEINFO_MAXINDENT + 1];
+
+ if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
+
+ for (i=0; i<indent; ++i)
+ ind[i] = ' ';
+ ind[i] = (char) 0;
+
+ if (TYPEINFO_IS_PRIMITIVE(*info)) {
+ fprintf(file,"%sprimitive\n",ind);
+ return;
+ }
+
+ if (TYPEINFO_IS_NULLTYPE(*info)) {
+ fprintf(file,"%snull\n",ind);
+ return;
+ }
+
+ fprintf(file,"%sClass: ",ind);
+ utf_fprint(file,info->typeclass->name);
+ fprintf(file,"\n");
+
+ if (TYPEINFO_IS_ARRAY(*info)) {
+ fprintf(file,"%sDimension: %d",ind,(int)info->dimension);
+ fprintf(file,"\n%sElements: ",ind);
+ switch (info->elementtype) {
+ case ARRAYTYPE_INT : fprintf(file,"int\n"); break;
+ case ARRAYTYPE_LONG : fprintf(file,"long\n"); break;
+ case ARRAYTYPE_FLOAT : fprintf(file,"float\n"); break;
+ case ARRAYTYPE_DOUBLE : fprintf(file,"double\n"); break;
+ case ARRAYTYPE_BYTE : fprintf(file,"byte\n"); break;
+ case ARRAYTYPE_CHAR : fprintf(file,"char\n"); break;
+ case ARRAYTYPE_SHORT : fprintf(file,"short\n"); break;
+ case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
+
+ case ARRAYTYPE_OBJECT:
+ fprintf(file,"reference: ");
+ utf_fprint(file,info->elementclass->name);
+ fprintf(file,"\n");
+ break;
+
+ default:
+ fprintf(file,"INVALID ARRAYTYPE!\n");
+ }
+ }
+
+ if (info->merged) {
+ fprintf(file,"%sMerged: ",ind);
+ for (i=0; i<info->merged->count; ++i) {
+ if (i) fprintf(file,", ");
+ utf_fprint(file,info->merged->list[i]->name);
+ }
+ fprintf(file,"\n");
+ }
+}
+
+void
+typeinfo_print_short(FILE *file,typeinfo *info)
+{
+ int i;
+
+ if (TYPEINFO_IS_PRIMITIVE(*info)) {
+ fprintf(file,"primitive");
+ return;
+ }
+
+ if (TYPEINFO_IS_NULLTYPE(*info)) {
+ fprintf(file,"null");
+ return;
+ }
+
+ utf_fprint(file,info->typeclass->name);
+
+ /* XXX remove */
+#if 0
+ if (TYPEINFO_IS_ARRAY(*info)) {
+ fprintf(file,"[%d]",info->dimension);
+ switch (info->elementtype) {
+ case ARRAYTYPE_INT : fprintf(file,"int"); break;
+ case ARRAYTYPE_LONG : fprintf(file,"long"); break;
+ case ARRAYTYPE_FLOAT : fprintf(file,"float"); break;
+ case ARRAYTYPE_DOUBLE : fprintf(file,"double"); break;
+ case ARRAYTYPE_BYTE : fprintf(file,"byte"); break;
+ case ARRAYTYPE_CHAR : fprintf(file,"char"); break;
+ case ARRAYTYPE_SHORT : fprintf(file,"short"); break;
+ case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
+
+ case ARRAYTYPE_OBJECT:
+ fprintf(file,"object(");
+ utf_fprint(file,info->elementclass->name);
+ fprintf(file,")");
+ break;
+
+ default:
+ fprintf(file,"INVALID ARRAYTYPE!");
+ }
+ }
+#endif
+
+ if (info->merged) {
+ fprintf(file,"{");
+ for (i=0; i<info->merged->count; ++i) {
+ if (i) fprintf(file,",");
+ utf_fprint(file,info->merged->list[i]->name);
+ }
+ fprintf(file,"}");
+ }
+}
+
+void
+typeinfo_print_type(FILE *file,int type,typeinfo *info)
+{
+ switch (type) {
+ case TYPE_VOID: fprintf(file,"V"); break;
+ case TYPE_INT: fprintf(file,"I"); break;
+ case TYPE_FLOAT: fprintf(file,"F"); break;
+ 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 {
+ fprintf(file,"L");
+ typeinfo_print_short(file,info);
+ fprintf(file,";");
+ }
+ break;
+
+ default:
+ fprintf(file,"!");
+ }
+}
+
+#endif // DEBUG_TYPES
--- /dev/null
+/********************************* typeinfo.h **********************************
+
+ Copyright (c) 2003 ? XXX
+
+ See file COPYRIGHT for information on usage and disclaimer of warranties
+
+ defininitions for the compiler's type system
+
+ Authors: Edwin Steiner
+
+ Last Change:
+
+*******************************************************************************/
+
+#ifndef __typeinfo_h_
+#define __typeinfo_h_
+
+/* #define DEBUG_TYPES */ /* XXX */
+
+#include "global.h"
+
+/* resolve typedef cycles *****************************************************/
+
+typedef struct typeinfo typeinfo;
+typedef struct typeinfo_mergedlist typeinfo_mergedlist;
+
+/* global variables ***********************************************************/
+
+/* XXX move this documentation to global.h */
+/* The following classinfo pointers are used internally by the type system.
+ * Please do not use them directly, use the TYPEINFO_ macros instead.
+ */
+
+/*
+ * pseudo_class_Arraystub
+ * (extends Object implements Cloneable, java.io.Serializable)
+ *
+ * If two arrays of incompatible component types are merged,
+ * the resulting reference has no accessible components.
+ * The result does, however, implement the interfaces Cloneable
+ * and java.io.Serializable. This pseudo class is used internally
+ * to represent such results. (They are *not* considered arrays!)
+ *
+ * pseudo_class_Array XXX delete?
+ * (extends pseudo_class_Arraystub)
+ *
+ * This pseudo class is used internally as the class of all arrays
+ * to distinguish them from arbitrary Objects.
+ *
+ * pseudo_class_Null
+ *
+ * This pseudo class is used internally to represent the
+ * null type.
+ */
+
+/* data structures for the type system ****************************************/
+
+/* The typeinfo structure stores detailed information on reference types.
+ * (stack elements, variables, etc. with type == TYPE_ADR.)
+ * XXX: exclude ReturnAddresses?
+ *
+ * For primitive types either there is no typeinfo allocated or the
+ * typeclass pointer in the typeinfo struct is NULL.
+ *
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ * typeinfo.[ch]. Please use the macros and functions defined here to
+ * access typeinfo structures!
+ */
+
+/* At all times *exactly one* of the following conditions is true for
+ * a particular typeinfo struct:
+ *
+ * A) typeclass == NULL
+ *
+ * In this case the other fields of the structure
+ * are INVALID.
+ *
+ * B) typeclass == pseudo_class_Null
+ *
+ * XXX
+ *
+ * C) typeclass is an array class
+ *
+ * XXX
+ *
+ * D) typeclass == pseudo_class_Arraystub
+ *
+ * XXX
+ *
+ * E) typeclass is an interface
+ *
+ * XXX
+ *
+ * F) typeclass is a (non-pseudo-)class != java.lang.Object
+ *
+ * XXX
+ * All classinfos in u.merged.list (if any) are
+ * subclasses of typeclass.
+ *
+ * G) typeclass is java.lang.Object
+ *
+ * XXX
+ * In this case u.merged.count and u.merged.list
+ * are valid and may be non-zero.
+ * The classinfos in u.merged.list (if any) can be
+ * classes, interfaces or pseudo classes.
+ */
+
+/* The following algorithm is used to determine if the type described
+ * by this typeinfo struct supports the interface X:
+ *
+ * 1) If typeclass is X or a subinterface of X the answer is "yes".
+ * 2) If typeclass is a (pseudo) class implementing X the answer is "yes".
+ * 3) XXX If typeclass is not an array and u.merged.count>0
+ * and all classes/interfaces in u.merged.list implement X
+ * the answer is "yes".
+ * 4) If none of the above is true the answer is "no".
+ */
+
+/*
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ * typeinfo.[ch]. Please use the macros and functions defined here to
+ * access typeinfo structures!
+ */
+struct typeinfo {
+ classinfo *typeclass;
+ classinfo *elementclass; /* valid if dimension>0 */
+ typeinfo_mergedlist *merged;
+ u1 dimension;
+ u1 elementtype; /* valid if dimension>0 */
+};
+
+struct typeinfo_mergedlist {
+ s4 count;
+ classinfo *list[1]; /* variable length! */
+};
+
+/****************************************************************************/
+/* MACROS */
+/****************************************************************************/
+
+/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
+ * You have to dereference any pointers.
+ */
+
+/* internally used macros ***************************************************/
+
+/* internal, don't use this explicitly! */
+/* XXX change to GC? */
+#define TYPEINFO_ALLOCMERGED(mergedlist,count) \
+ {(mergedlist) = (typeinfo_mergedlist*)dump_alloc( \
+ sizeof(typeinfo_mergedlist) \
+ + ((count)-1)*sizeof(classinfo*));}
+
+/* internal, don't use this explicitly! */
+/* XXX change to GC? */
+#if 0
+#define TYPEINFO_FREEMERGED(mergedlist) \
+ {mem_free((mergedlist),sizeof(typeinfo_mergedlist) \
+ + ((mergedlist)->count - 1)*sizeof(classinfo*));}
+#endif
+#define TYPEINFO_FREEMERGED(mergedlist)
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist) \
+ {if (mergedlist) TYPEINFO_FREEMERGED(mergedlist);}
+
+/* macros for type queries **************************************************/
+
+#define TYPEINFO_IS_PRIMITIVE(info) \
+ ((info).typeclass == NULL)
+
+#define TYPEINFO_IS_REFERENCE(info) \
+ ((info).typeclass != NULL)
+
+#define TYPEINFO_IS_NULLTYPE(info) \
+ ((info).typeclass == pseudo_class_Null)
+
+/* macros for array type queries ********************************************/
+
+#define TYPEINFO_IS_ARRAY(info) \
+ ( TYPEINFO_IS_REFERENCE(info) \
+ && ((info).dimension != 0) )
+
+#define TYPEINFO_IS_SIMPLE_ARRAY(info) \
+ ( ((info).dimension == 1) )
+
+#define TYPEINFO_IS_ARRAY_ARRAY(info) \
+ ( ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype) \
+ ( TYPEINFO_IS_SIMPLE_ARRAY(info) \
+ && ((info).elementtype == (arraytype)) )
+
+#define TYPEINFO_IS_OBJECT_ARRAY(info) \
+ ( TYPEINFO_IS_SIMPLE_ARRAY(info) \
+ && ((info).elementclass != NULL) )
+
+/* assumes that info describes an array type */
+#define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) \
+ ( ((info).elementclass != NULL) \
+ || ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_ARRAY_OF_REFS(info) \
+ ( TYPEINFO_IS_ARRAY(info) \
+ && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+
+/* macros for initializing typeinfo structures ******************************/
+
+#define TYPEINFO_INIT_PRIMITIVE(info) \
+ {(info).typeclass = NULL; \
+ (info).elementclass = NULL; \
+ (info).merged = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0;}
+
+#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo) \
+ {(info).typeclass = (cinfo); \
+ (info).elementclass = NULL; \
+ (info).merged = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0;}
+
+#define TYPEINFO_INIT_NULLTYPE(info) \
+ TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
+
+/* XXX delete */
+#if 0
+#define TYPEINFO_INIT_ARRAY(info,dim,elmtype,elmcinfo) \
+ {(info).typeclass = pseudo_class_Array; \
+ (info).elementclass = (elmcinfo); \
+ (info).merged = NULL; \
+ (info).dimension = (dim); \
+ (info).elementtype = (elmtype);}
+#endif
+
+/* XXX delete? */
+#define TYPEINFO_INIT_ARRAY(info,cls) \
+ {(info).typeclass = cls; \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ else \
+ (info).elementclass = NULL; \
+ (info).merged = NULL; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+
+#define TYPEINFO_INIT_CLASSINFO(info,cls) \
+ {if (((info).typeclass = cls)->vftbl->arraydesc) { \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ else \
+ (info).elementclass = NULL; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype;\
+ } \
+ else { \
+ (info).elementclass = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0; \
+ } \
+ (info).merged = NULL;}
+
+/* XXX */
+#define TYPEINFO_INC_DIMENSION(info) \
+ (info).dimension++
+
+#define TYPEINFO_INIT_FROM_FIELDINFO(info,fi) \
+ typeinfo_init_from_descriptor(&(info), \
+ (fi)->descriptor->text,utf_end((fi)->descriptor));
+
+/* macros for freeing typeinfo structures ***********************************/
+
+#define TYPEINFO_FREE(info) \
+ {TYPEINFO_FREEMERGED_IF_ANY((info).merged); \
+ (info).merged = NULL;}
+
+/* macros for writing types (destination must have been initialized) ********/
+/* XXX delete them? */
+
+#define TYPEINFO_PUT_NULLTYPE(info) \
+ {(info).typeclass = pseudo_class_Null;}
+
+#define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo) \
+ {(info).typeclass = (cinfo);}
+
+/* XXX delete */
+#if 0
+#define TYPEINFO_PUT_ARRAY(info,dim,elmtype) \
+ {(info).typeclass = pseudo_class_Array; \
+ (info).dimension = (dim); \
+ (info).elementtype = (elmtype);}
+#endif
+
+/* XXX delete? */
+#define TYPEINFO_PUT_ARRAY(info,cls) \
+ {(info).typeclass = cls; \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+
+#define TYPEINFO_PUT_CLASSINFO(info,cls) \
+ {if (((info).typeclass = cls)->vftbl->arraydesc) { \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype; \
+ }}
+
+/* XXX delete */
+#if 0
+#define TYPEINFO_PUT_OBJECT_ARRAY(info,dim,elmcinfo) \
+ {TYPEINFO_PUT_ARRAY(info,dim,ARRAYTYPE_OBJECT); \
+ (info).elementclass = (elmcinfo);}
+#endif
+
+/* srcarray must be an array (not checked) */
+#define TYPEINFO_PUT_COMPONENT(srcarray,dst) \
+ {typeinfo_put_component(&(srcarray),&(dst));}
+
+/* macros for copying types (destinition is not checked or freed) ***********/
+
+/* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
+#define TYPEINFO_COPY(src,dst) \
+ {(dst) = (src);}
+
+/* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
+ * into a newly allocated array.
+ */
+#define TYPEINFO_CLONE(src,dst) \
+ {(dst) = (src); \
+ if ((dst).merged) typeinfo_clone(&(src),&(dst));}
+
+/****************************************************************************/
+/* FUNCTIONS */
+/****************************************************************************/
+
+/* inquiry functions (read-only) ********************************************/
+
+bool typeinfo_is_array(typeinfo *info);
+bool typeinfo_is_primitive_array(typeinfo *info,int arraytype);
+bool typeinfo_is_array_of_refs(typeinfo *info);
+
+bool typeinfo_implements_interface(typeinfo *info,classinfo *interf);
+bool typeinfo_is_assignable(typeinfo *value,typeinfo *dest);
+
+/* initialization functions *************************************************/
+
+void typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr);
+void typeinfo_init_component(typeinfo *srcarray,typeinfo *dst);
+
+int typeinfo_count_method_args(utf *d,bool twoword); /* this not included */
+void typeinfo_init_from_method_args(utf *desc,u1 *typebuf,
+ typeinfo *infobuf,
+ int buflen,bool twoword,
+ int *returntype,typeinfo *returntypeinfo);
+
+void typeinfo_clone(typeinfo *src,typeinfo *dest);
+
+/* functions for the type system ********************************************/
+
+void typeinfo_free(typeinfo *info);
+
+bool typeinfo_merge(typeinfo *dest,typeinfo* y);
+
+/* debugging helpers ********************************************************/
+
+#ifdef DEBUG_TYPES
+
+void typeinfo_test();
+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);
+
+#endif // DEBUG_TYPES
+
+#endif
--- /dev/null
+# Input for testing the typeinfo_ functions
+#
+# simple merges (result is common ancestor)
+#
+()Ljava/lang/Object; ()Ljava/lang/Object; ()Ljava/lang/Object;
+()Ljava/lang/Object; ()Ljava/lang/String; ()Ljava/lang/Object;
+()Ljava/lang/Number; ()Ljava/lang/Integer; ()Ljava/lang/Number;
+()Ljava/lang/Object; ()Ljava/lang/Integer; ()Ljava/lang/Object;
+()Ljava/lang/Object; ()Ljava/lang/Cloneable; ()Ljava/lang/Object;
+()Ljava/lang/Cloneable; ()Ljava/lang/Cloneable; ()Ljava/lang/Cloneable;
+()Ljava/lang/Cloneable; ()[Ljava/lang/Object; ()Ljava/lang/Cloneable;
+()Ljava/lang/Cloneable; ()[I ()Ljava/lang/Cloneable;
+()Ljava/io/Serializable; ()[Ljava/lang/Object; ()Ljava/io/Serializable;
+()Ljava/io/Serializable; ()[D ()Ljava/io/Serializable;
+()Ljava/lang/Object; ()[Ljava/lang/Object; ()Ljava/lang/Object;
+()Ljava/lang/Object; ()[I ()Ljava/lang/Object;
+()L$ARRAYSTUB$; ()L$ARRAYSTUB$; ()L$ARRAYSTUB$;
+()L$ARRAYSTUB$; ()Ljava/lang/Object; ()Ljava/lang/Object;
+()L$ARRAYSTUB$; ()Ljava/lang/Cloneable; ()Ljava/lang/Cloneable;
+()L$ARRAYSTUB$; ()Ljava/io/Serializable; ()Ljava/io/Serializable;
+()L$NULL$; ()L$NULL$; ()L$NULL$;
+()L$NULL$; ()[Ljava/lang/Object; ()[Ljava/lang/Object;
+#
+#
+# merges where the result is a mergedlist
+#
+()Ljava/lang/String; ()Ljava/lang/Number; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+#
+#
+# merges with one mergedlist where the resulting mergedlist is unchanged
+#
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; ()Ljava/lang/String; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; ()Ljava/lang/Number; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Integer; (Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Long; (Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()L$NULL$; (Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number;
+#
+#
+# merges with one mergedlist where the result has no mergedlist
+#
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; ()Ljava/lang/Object; ()Ljava/lang/Object;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Number; ()Ljava/lang/Number;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Object; ()Ljava/lang/Object;
+#
+#
+# one mergedlist where the resulting mergeslist is longer
+#
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Double; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/Double;)Ljava/lang/Number;
+#
+#
+# merges with two mergedlists with the same typeclass
+#
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/Float;)Ljava/lang/Number; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/Float;)Ljava/lang/Number;
+#
+#
+# merges with two mergedlists with different typeclass
+#
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; (Ljava/lang/Integer;Ljava/lang/String;)Ljava/lang/Object; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/String;)Ljava/lang/Object;
+#
+#
+# merging primitive arrays
+#
+()[I ()[I ()[I
+()[I ()[F ()L$ARRAYSTUB$;
+#
+#
+# merging reference arrays with primitive arrays
+#
+()[I ()[Ljava/lang/String; ()L$ARRAYSTUB$;
Roman Obermaiser
Mark Probst
- $Id: loader.c 682 2003-12-01 15:33:30Z jowenn $
+ $Id: loader.c 687 2003-12-04 22:29:54Z edwin $
*/
if (compvftbl->arraydesc) {
desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
desc->dimension = compvftbl->arraydesc->dimension + 1;
+ desc->elementtype = compvftbl->arraydesc->elementtype;
}
else {
desc->elementvftbl = compvftbl;
desc->dimension = 1;
+ desc->elementtype = ARRAYTYPE_OBJECT;
}
}
else {
desc->componentvftbl = NULL;
desc->elementvftbl = NULL;
desc->dimension = 1;
+ desc->elementtype = desc->arraytype;
}
return desc;
{
/* pseudo class for Arraystubs (extends java.lang.Object) */
- pseudo_class_Arraystub = class_new( utf_new_char(";Arraystub;") );
+ pseudo_class_Arraystub = class_new( utf_new_char("$ARRAYSTUB$") );
list_remove(&unloadedclasses,pseudo_class_Arraystub);
pseudo_class_Arraystub->super = class_java_lang_Object;
/* pseudo class representing the null type */
- pseudo_class_Null = class_new( utf_new_char(";Null;") );
+ pseudo_class_Null = class_new( utf_new_char("$NULL$") );
list_remove(&unloadedclasses,pseudo_class_Null);
pseudo_class_Null->super = class_java_lang_Object;
- the heap
- additional support functions
- $Id: tables.c 682 2003-12-01 15:33:30Z jowenn $
+ $Id: tables.c 687 2003-12-04 22:29:54Z edwin $
*/
return class_new( utf_new(namebuf,namelen) );
}
+/*************** Function: class_multiarray_of ********************************
+
+ Returns an array class with the given dimension and element class.
+ The array class is dynamically created if neccessary.
+
+*******************************************************************************/
+
+classinfo *class_multiarray_of(int dim,classinfo *element)
+{
+ int namelen;
+ char *namebuf;
+
+ if (dim<1)
+ panic("Invalid array dimension requested");
+
+ /* Assemble the array class name */
+ namelen = element->name->blength;
+
+ if (element->name->text[0] == '[') {
+ /* the element is itself an array */
+ namebuf = DMNEW(char,namelen+dim);
+ memcpy(namebuf+dim,element->name->text,namelen);
+ namelen += dim;
+ }
+ else {
+ /* the element is a non-array class */
+ namebuf = DMNEW(char,namelen+2+dim);
+ namebuf[dim] = 'L';
+ memcpy(namebuf+dim+1,element->name->text,namelen);
+ namelen += (2+dim);
+ namebuf[namelen-1] = ';';
+ }
+ memset(namebuf,'[',dim);
+
+ return class_new( utf_new(namebuf,namelen) );
+}
+
/************************** function: utf_strlen ******************************
determine number of unicode characters in the utf string
Authors: Reinhard Grafl
- $Id: tables.h 664 2003-11-21 18:24:01Z jowenn $
+ $Id: tables.h 687 2003-12-04 22:29:54Z edwin $
*/
/* return an array class with the given component class */
classinfo *class_array_of(classinfo *component);
+/* return an array class with the given dimension and element class */
+classinfo *class_multiarray_of(int dim,classinfo *element);
+
/* get javatype according to a typedescriptor */
u2 desc_to_type(utf *descriptor);
- the heap
- additional support functions
- $Id: tables.c 682 2003-12-01 15:33:30Z jowenn $
+ $Id: tables.c 687 2003-12-04 22:29:54Z edwin $
*/
return class_new( utf_new(namebuf,namelen) );
}
+/*************** Function: class_multiarray_of ********************************
+
+ Returns an array class with the given dimension and element class.
+ The array class is dynamically created if neccessary.
+
+*******************************************************************************/
+
+classinfo *class_multiarray_of(int dim,classinfo *element)
+{
+ int namelen;
+ char *namebuf;
+
+ if (dim<1)
+ panic("Invalid array dimension requested");
+
+ /* Assemble the array class name */
+ namelen = element->name->blength;
+
+ if (element->name->text[0] == '[') {
+ /* the element is itself an array */
+ namebuf = DMNEW(char,namelen+dim);
+ memcpy(namebuf+dim,element->name->text,namelen);
+ namelen += dim;
+ }
+ else {
+ /* the element is a non-array class */
+ namebuf = DMNEW(char,namelen+2+dim);
+ namebuf[dim] = 'L';
+ memcpy(namebuf+dim+1,element->name->text,namelen);
+ namelen += (2+dim);
+ namebuf[namelen-1] = ';';
+ }
+ memset(namebuf,'[',dim);
+
+ return class_new( utf_new(namebuf,namelen) );
+}
+
/************************** function: utf_strlen ******************************
determine number of unicode characters in the utf string
Authors: Reinhard Grafl
- $Id: tables.h 664 2003-11-21 18:24:01Z jowenn $
+ $Id: tables.h 687 2003-12-04 22:29:54Z edwin $
*/
/* return an array class with the given component class */
classinfo *class_array_of(classinfo *component);
+/* return an array class with the given dimension and element class */
+classinfo *class_multiarray_of(int dim,classinfo *element);
+
/* get javatype according to a typedescriptor */
u2 desc_to_type(utf *descriptor);
--- /dev/null
+/********************************* typeinfo.c *********************************
+
+ Copyright (c) 2003 ? XXX
+
+ See file COPYRIGHT for information on usage and disclaimer of warranties
+
+ functions for the compiler's type system
+
+ Authors: Edwin Steiner
+
+ Last Change:
+
+*******************************************************************************/
+
+#include "typeinfo.h"
+#include "tables.h"
+#include "loader.h"
+
+#define TYPEINFO_REUSE_MERGED
+
+#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
+ ( ((index) < (cls)->vftbl->interfacetablelength) \
+ && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
+
+/**********************************************************************/
+/* READ-ONLY FUNCTIONS */
+/* The following functions don't change typeinfo data. */
+/**********************************************************************/
+
+bool
+typeinfo_is_array(typeinfo *info)
+{
+ return TYPEINFO_IS_ARRAY(*info);
+}
+
+bool
+typeinfo_is_primitive_array(typeinfo *info,int arraytype)
+{
+ return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
+}
+
+bool
+typeinfo_is_array_of_refs(typeinfo *info)
+{
+ return TYPEINFO_IS_ARRAY_OF_REFS(*info);
+}
+
+static
+bool
+interface_extends_interface(classinfo *cls,classinfo *interf)
+{
+ int i;
+
+ /* first check direct superinterfaces */
+ for (i=0; i<cls->interfacescount; ++i) {
+ if (cls->interfaces[i] == interf)
+ return true;
+ }
+
+ /* check indirect superinterfaces */
+ for (i=0; i<cls->interfacescount; ++i) {
+ if (interface_extends_interface(cls->interfaces[i],interf))
+ return true;
+ }
+
+ return false;
+}
+
+/* XXX If really a performance issue, this could become a macro. */
+static
+bool
+classinfo_implements_interface(classinfo *cls,classinfo *interf)
+{
+ if (cls->flags & ACC_INTERFACE) {
+ /* cls is an interface */
+ if (cls == interf)
+ return true;
+
+ /* check superinterfaces */
+ return interface_extends_interface(cls,interf);
+ }
+
+ return CLASS_IMPLEMENTS_INTERFACE(cls,interf->index);
+}
+
+bool mergedlist_implements_interface(typeinfo_mergedlist *merged,
+ classinfo *interf)
+{
+ int i;
+ classinfo **mlist;
+
+ /* Check if there is an non-empty mergedlist. */
+ if (!merged)
+ return false;
+
+ /* If all classinfos in the (non-empty) merged array implement the
+ * interface return true, otherwise false.
+ */
+ mlist = merged->list;
+ i = merged->count;
+ while (i--) {
+ if (!classinfo_implements_interface(*mlist++,interf))
+ return false;
+ }
+ return true;
+}
+
+bool
+merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist *merged,
+ classinfo *interf)
+{
+ /* primitive types don't support interfaces. */
+ if (!typeclass)
+ return false;
+
+ /* the null type can be cast to any interface type. */
+ if (typeclass == pseudo_class_Null)
+ return true;
+
+ /* check if typeclass implements the interface. */
+ if (classinfo_implements_interface(typeclass,interf))
+ return true;
+
+ /* check the mergedlist */
+ return (merged && mergedlist_implements_interface(merged,interf));
+}
+
+bool
+typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
+{
+ classinfo *cls;
+
+ cls = value->typeclass;
+
+ /* DEBUG CHECK: dest must not have a merged list. */
+#ifdef DEBUG_TYPES
+ if (dest->merged)
+ panic("Internal error: typeinfo_is_assignable on merged destination.");
+#endif
+
+ /* assignments of primitive values are not checked here. */
+ if (!cls && !dest->typeclass)
+ return true;
+
+ /* the null type can be assigned to any type */
+ if (TYPEINFO_IS_NULLTYPE(*value))
+ return true;
+
+ /* primitive and reference types are not assignment compatible. */
+ if (!cls || !dest->typeclass)
+ return false;
+
+ if (dest->typeclass->flags & ACC_INTERFACE) {
+ /* We are assigning to an interface type. */
+ return merged_implements_interface(cls,value->merged,
+ dest->typeclass);
+ }
+
+ if (TYPEINFO_IS_ARRAY(*dest)) {
+ /* We are assigning to an array type. */
+ if (!TYPEINFO_IS_ARRAY(*value))
+ return false;
+
+ /* {Both value and dest are array types.} */
+
+ /* value must have at least the dimension of dest. */
+ if (value->dimension < dest->dimension)
+ return false;
+
+ if (value->dimension > dest->dimension) {
+ /* value has higher dimension so we need to check
+ * if its component array can be assigned to the
+ * element type of dest */
+
+ if (dest->elementclass->flags & ACC_INTERFACE) {
+ /* We are assigning to an interface type. */
+ return classinfo_implements_interface(pseudo_class_Arraystub,
+ dest->elementclass);
+ }
+
+ /* We are assigning to a class type. */
+ return class_issubclass(pseudo_class_Arraystub,dest->elementclass);
+ }
+
+ /* {value and dest have the same dimension} */
+
+ if (value->elementtype != dest->elementtype)
+ return false;
+
+ if (value->elementclass) {
+ /* We are assigning an array of objects so we have to
+ * check if the elements are assignable.
+ */
+
+ if (dest->elementclass->flags & ACC_INTERFACE) {
+ /* We are assigning to an interface type. */
+
+ return merged_implements_interface(value->elementclass,
+ value->merged,
+ dest->elementclass);
+ }
+
+ /* We are assigning to a class type. */
+ return class_issubclass(value->elementclass,dest->elementclass);
+ }
+
+ return true;
+ }
+
+ /* {dest is not an array} */
+
+ /* We are assigning to a class type */
+ if (cls->flags & ACC_INTERFACE)
+ cls = class_java_lang_Object;
+
+ return class_issubclass(cls,dest->typeclass);
+}
+
+/**********************************************************************/
+/* INITIALIZATION FUNCTIONS */
+/* The following functions fill in uninitialized typeinfo structures. */
+/**********************************************************************/
+
+/* XXX delete */
+#if 0
+void
+typeinfo_init_from_arraydescriptor(typeinfo *info,
+ constant_arraydescriptor *desc)
+{
+ int dim = 1;
+
+ /* Arrays are instances of the pseudo class Array. */
+ info->typeclass = pseudo_class_Array; /* XXX */
+ info->merged = NULL;
+
+ /* Handle multidimensional arrays */
+ while (desc->arraytype == ARRAYTYPE_ARRAY) {
+ dim++;
+ desc = desc->elementdescriptor;
+ }
+
+ info->dimension = dim;
+
+ if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
+ info->elementclass = desc->objectclass;
+ }
+ else {
+ info->elementclass = NULL;
+ }
+}
+#endif
+
+void
+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");
+}
+
+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;
+
+ /* 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");
+ }
+ }
+
+ return args;
+}
+
+void
+typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
+ int buflen,bool twoword,
+ int *returntype,typeinfo *returntypeinfo)
+{
+ 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");
+
+ /* 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.");
+ 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);
+ /* XXX remove */ /* utf_display(cls->name); */
+ infobuf++;
+ break;
+
+ default:
+ panic ("Ill formed methodtype-descriptor (type)");
+ }
+ }
+ 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;
+
+ 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;
+
+ default:
+ panic ("Ill formed methodtype-descriptor (returntype)");
+ }
+ }
+}
+
+/* XXX could be made a macro if really performance critical */
+void
+typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
+{
+ vftbl *comp = NULL;
+
+ /* XXX find component class */
+ if (!TYPEINFO_IS_ARRAY(*srcarray))
+ panic("Trying to access component of non-array");
+
+ comp = srcarray->typeclass->vftbl->arraydesc->componentvftbl;
+ if (comp) {
+ TYPEINFO_INIT_CLASSINFO(*dst,comp->class);
+ }
+ 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;
+}
+
+/* Condition: src != dest. */
+void
+typeinfo_clone(typeinfo *src,typeinfo *dest)
+{
+ int count;
+ classinfo **srclist,**destlist;
+
+#ifdef DEBUG_TYPES
+ if (src == dest)
+ panic("Internal error: typeinfo_clone with src==dest");
+#endif
+
+ *dest = *src;
+
+ if (src->merged) {
+ count = src->merged->count;
+ TYPEINFO_ALLOCMERGED(dest->merged,count);
+ dest->merged->count = count;
+
+ /* XXX use memcpy? */
+ srclist = src->merged->list;
+ destlist = dest->merged->list;
+ while (count--)
+ *destlist++ = *srclist++;
+ }
+}
+
+/**********************************************************************/
+/* MISCELLANEOUS FUNCTIONS */
+/**********************************************************************/
+
+void
+typeinfo_free(typeinfo *info)
+{
+ TYPEINFO_FREE(*info);
+}
+
+/**********************************************************************/
+/* MERGING FUNCTIONS */
+/* The following functions are used to merge the types represented by */
+/* two typeinfo structures into one typeinfo structure. */
+/**********************************************************************/
+
+static
+void
+typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
+#ifdef DEBUG_TYPES
+ fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
+ fprintf(stderr,"Typeinfo x:\n");
+ typeinfo_print(stderr,x,1);
+ fprintf(stderr,"Typeinfo y:\n");
+ typeinfo_print(stderr,y,1);
+#endif
+ panic(str);
+}
+
+/* Condition: clsx != clsy. */
+/* Returns: true if dest was changed (always true). */
+static
+bool
+typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy)
+{
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ TYPEINFO_ALLOCMERGED(dest->merged,2);
+ dest->merged->count = 2;
+
+#ifdef DEBUG_TYPES
+ if (clsx == clsy)
+ panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
+#endif
+
+ if (clsx < clsy) {
+ dest->merged->list[0] = clsx;
+ dest->merged->list[1] = clsy;
+ }
+ else {
+ dest->merged->list[0] = clsy;
+ dest->merged->list[1] = clsx;
+ }
+
+ return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classinfo *cls)
+{
+ int count;
+ typeinfo_mergedlist *newmerged;
+ classinfo **mlist,**newlist;
+
+ count = m->count;
+ mlist = m->list;
+
+ /* Check if cls is already in the mergedlist m. */
+ while (count--) {
+ if (*mlist++ == cls) {
+ /* cls is in the list, so m is the resulting mergedlist */
+ if (dest->merged == m)
+ return false;
+
+ /* We have to copy the mergedlist */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ count = m->count;
+ TYPEINFO_ALLOCMERGED(dest->merged,count);
+ dest->merged->count = count;
+ newlist = dest->merged->list;
+ mlist = m->list;
+ while (count--) {
+ *newlist++ = *mlist++;
+ }
+ return true;
+ }
+ }
+
+ /* Add cls to the mergedlist. */
+ count = m->count;
+ TYPEINFO_ALLOCMERGED(newmerged,count+1);
+ newmerged->count = count+1;
+ newlist = newmerged->list;
+ mlist = m->list;
+ while (count) {
+ if (*mlist > cls)
+ break;
+ *newlist++ = *mlist++;
+ count--;
+ }
+ *newlist++ = cls;
+ while (count--) {
+ *newlist++ = *mlist++;
+ }
+
+ /* Put the new mergedlist into dest. */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ dest->merged = newmerged;
+
+ return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x,
+ typeinfo_mergedlist *y)
+{
+ int count = 0;
+ int countx,county;
+ typeinfo_mergedlist *temp,*result;
+ classinfo **clsx,**clsy,**newlist;
+
+ /* count the elements that will be in the resulting list */
+ /* (Both lists are sorted, equal elements are counted only once.) */
+ clsx = x->list;
+ clsy = y->list;
+ countx = x->count;
+ county = y->count;
+ while (countx && county) {
+ if (*clsx == *clsy) {
+ clsx++;
+ clsy++;
+ countx--;
+ county--;
+ }
+ else if (*clsx < *clsy) {
+ clsx++;
+ countx--;
+ }
+ else {
+ clsy++;
+ county--;
+ }
+ count++;
+ }
+ count += countx + county;
+
+ /* {The new mergedlist will have count entries.} */
+
+ if (y->count == count) {
+ temp = x; x = y; y = temp;
+ }
+ /* {If one of x,y is already the result it is x.} */
+ if (x->count == count) {
+ /* x->merged is equal to the result */
+ if (x == dest->merged)
+ return false;
+
+ if (!dest->merged || dest->merged->count != count) {
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ TYPEINFO_ALLOCMERGED(dest->merged,count);
+ dest->merged->count = count;
+ }
+
+ newlist = dest->merged->list;
+ clsx = x->list;
+ while (count--) {
+ *newlist++ = *clsx++;
+ }
+ return true;
+ }
+
+ /* {We have to merge two lists.} */
+
+ /* allocate the result list */
+ TYPEINFO_ALLOCMERGED(result,count);
+ result->count = count;
+ newlist = result->list;
+
+ /* merge the sorted lists */
+ clsx = x->list;
+ clsy = y->list;
+ countx = x->count;
+ county = y->count;
+ while (countx && county) {
+ if (*clsx == *clsy) {
+ *newlist++ = *clsx++;
+ clsy++;
+ countx--;
+ county--;
+ }
+ else if (*clsx < *clsy) {
+ *newlist++ = *clsx++;
+ countx--;
+ }
+ else {
+ *newlist++ = *clsy++;
+ county--;
+ }
+ }
+ while (countx--)
+ *newlist++ = *clsx++;
+ while (county--)
+ *newlist++ = *clsy++;
+
+ /* replace the list in dest with the result list */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ dest->merged = result;
+
+ return true;
+}
+
+static
+bool
+typeinfo_merge_nonarrays(typeinfo *dest,
+ classinfo **result,
+ classinfo *clsx,classinfo *clsy,
+ typeinfo_mergedlist *mergedx,
+ typeinfo_mergedlist *mergedy)
+{
+ classinfo *tcls,*common;
+ typeinfo_mergedlist *tmerged;
+ bool changed;
+
+ /* XXX remove */
+ /*
+#ifdef DEBUG_TYPES
+ typeinfo dbgx,dbgy;
+ printf("typeinfo_merge_nonarrays:\n");
+ TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
+ dbgx.merged = mergedx;
+ TYPEINFO_INIT_CLASSINFO(dbgy,clsy);
+ dbgy.merged = mergedy;
+ typeinfo_print(stdout,&dbgx,4);
+ printf(" with:\n");
+ typeinfo_print(stdout,&dbgy,4);
+#endif
+ */
+
+ /* 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"); */
+ changed = (dest->merged != NULL);
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ dest->merged = NULL;
+ *result = clsx;
+ /* XXX remove */ /* log_text("returning"); */
+ return changed;
+ }
+
+ /* If clsy is an interface, swap x and y. */
+ if (clsy->flags & ACC_INTERFACE) {
+ tcls = clsx; clsx = clsy; clsy = tcls;
+ tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+ }
+ /* {We know: If only one of x,y is an interface it is x.} */
+
+ /* Handle merging of interfaces: */
+ if (clsx->flags & ACC_INTERFACE) {
+ /* {clsx is an interface and mergedx == NULL.} */
+
+ 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;
+ return typeinfo_merge_two(dest,clsx,clsy);
+ }
+
+ /* {We know: x is an interface, clsy is a class.} */
+
+ /* Check if we are merging an interface with java.lang.Object */
+ if (clsy == class_java_lang_Object && !mergedy) {
+ clsx = clsy;
+ goto return_simple_x;
+ }
+
+
+ /* If the type y implements clsx then the result of the merge
+ * is clsx regardless of mergedy.
+ */
+
+ if (CLASS_IMPLEMENTS_INTERFACE(clsy,clsx->index)
+ || mergedlist_implements_interface(mergedy,clsx))
+ {
+ /* y implements x, so the result of the merge is x. */
+ goto return_simple_x;
+ }
+
+ /* {We know: x is an interface, the type y a class or a merge
+ * of subclasses and does not implement x.} */
+
+ /* There may still be superinterfaces of x which are implemented
+ * 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 */
+
+ common = class_java_lang_Object;
+ goto merge_with_simple_x;
+ }
+
+ /* {We know: x and y are classes (not interfaces).} */
+
+ /* If *x is deeper in the inheritance hierarchy swap x and y. */
+ if (clsx->index > clsy->index) {
+ tcls = clsx; clsx = clsy; clsy = tcls;
+ tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+ }
+
+ /* {We know: y is at least as deep in the hierarchy as x.} */
+
+ /* Find nearest common anchestor for the classes. */
+ common = clsx;
+ tcls = clsy;
+ while (tcls->index > common->index)
+ tcls = tcls->super;
+ while (common != tcls) {
+ common = common->super;
+ tcls = tcls->super;
+ }
+
+ /* {common == nearest common anchestor of clsx and clsy.} */
+
+ /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
+
+ /* If clsx==common and x is a whole class (not a merge of subclasses)
+ * then the result of the merge is clsx.
+ */
+ if (clsx == common && !mergedx) {
+ goto return_simple_x;
+ }
+
+ if (mergedx) {
+ *result = common;
+ if (mergedy)
+ return typeinfo_merge_mergedlists(dest,mergedx,mergedy);
+ else
+ return typeinfo_merge_add(dest,mergedx,clsy);
+ }
+
+ merge_with_simple_x:
+ *result = common;
+ if (mergedy)
+ return typeinfo_merge_add(dest,mergedy,clsx);
+ else
+ return typeinfo_merge_two(dest,clsx,clsy);
+}
+
+/* Condition: *dest must be a valid initialized typeinfo. */
+/* Condition: dest != y. */
+/* Returns: true if dest was changed. */
+bool
+typeinfo_merge(typeinfo *dest,typeinfo* y)
+{
+ typeinfo *x;
+ typeinfo *tmp; /* used for swapping */
+ classinfo *common;
+ classinfo *elementclass;
+ int dimension;
+ int elementtype;
+ bool changed;
+
+ /* XXX remove */
+ /*
+#ifdef DEBUG_TYPES
+ typeinfo_print(stdout,dest,4);
+ typeinfo_print(stdout,y,4);
+#endif
+ */
+
+ /* This function cannot be used to merge primitive types. */
+ if (!dest->typeclass || !y->typeclass)
+ typeinfo_merge_error("Trying to merge primitive types.",dest,y);
+
+#ifdef DEBUG_TYPES
+ if (dest == y)
+ panic("Internal error: typeinfo_merge with dest==y");
+
+ /* check that no unlinked classes are merged. */
+ if (!dest->typeclass->linked || !y->typeclass->linked)
+ typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
+#endif
+
+ /* XXX remove */ /* 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 */
+ dest->merged = NULL;
+ /* XXX remove */ /* log_text("common case handled"); */
+ return changed;
+ }
+
+ /* XXX remove */ /* log_text("Handling null types"); */
+
+ /* Handle null types: */
+ if (TYPEINFO_IS_NULLTYPE(*y)) {
+ return false;
+ }
+ if (TYPEINFO_IS_NULLTYPE(*dest)) {
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+ TYPEINFO_CLONE(*y,*dest);
+ return true;
+ }
+
+ /* This function uses x internally, so x and y can be swapped
+ * without changing dest. */
+ x = dest;
+ changed = false;
+
+ /* Handle merging of arrays: */
+ if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
+
+ /* XXX remove */ /* log_text("Handling arrays"); */
+
+ /* Make x the one with lesser dimension */
+ if (x->dimension > y->dimension) {
+ tmp = x; x = y; y = tmp;
+ }
+
+ /* If one array (y) has higher dimension than the other,
+ * interpret it as an array (same dim. as x) of Arraystubs. */
+ if (x->dimension < y->dimension) {
+ dimension = x->dimension;
+ elementtype = ARRAYTYPE_OBJECT;
+ elementclass = pseudo_class_Arraystub;
+ }
+ else {
+ dimension = y->dimension;
+ elementtype = y->elementtype;
+ elementclass = y->elementclass;
+ }
+
+ /* {The arrays are of the same dimension.} */
+
+ if (x->elementtype != elementtype) {
+ /* Different element types are merged, so the resulting array
+ * type has one accessible dimension less. */
+ if (--dimension == 0) {
+ common = pseudo_class_Arraystub;
+ elementtype = 0;
+ elementclass = NULL;
+ }
+ else {
+ common = class_multiarray_of(dimension,pseudo_class_Arraystub);
+ elementtype = ARRAYTYPE_OBJECT;
+ elementclass = pseudo_class_Arraystub;
+ }
+ }
+ else {
+ /* {The arrays have the same dimension and elementtype.} */
+
+ if (elementtype == ARRAYTYPE_OBJECT) {
+ /* The elements are references, so their respective
+ * types must be merged.
+ */
+ changed |= typeinfo_merge_nonarrays(dest,
+ &elementclass,
+ x->elementclass,
+ elementclass,
+ x->merged,y->merged);
+
+ /* XXX otimize this? */
+ /* XXX remove */ /* log_text("finding resulting array class: "); */
+ common = class_multiarray_of(dimension,elementclass);
+ /* XXX remove */ /* utf_display(common->name); printf("\n"); */
+ }
+ }
+ }
+ else {
+ /* {We know that at least one of x or y is no array, so the
+ * result cannot be an array.} */
+
+ changed |= typeinfo_merge_nonarrays(dest,
+ &common,
+ x->typeclass,y->typeclass,
+ x->merged,y->merged);
+
+ dimension = 0;
+ elementtype = 0;
+ elementclass = NULL;
+ }
+
+ /* Put the new values into dest if neccessary. */
+
+ if (dest->typeclass != common) {
+ dest->typeclass = common;
+ changed = true;
+ }
+ if (dest->dimension != dimension) {
+ dest->dimension = dimension;
+ changed = true;
+ }
+ if (dest->elementtype != elementtype) {
+ dest->elementtype = elementtype;
+ changed = true;
+ }
+ if (dest->elementclass != elementclass) {
+ dest->elementclass = elementclass;
+ changed = true;
+ }
+
+ /* XXX remove */ /* log_text("returning from merge"); */
+
+ return changed;
+}
+
+
+/**********************************************************************/
+/* DEBUGGING HELPERS */
+/**********************************************************************/
+
+#ifdef DEBUG_TYPES
+
+#include "tables.h"
+#include "loader.h"
+
+static int
+typeinfo_test_compare(classinfo **a,classinfo **b)
+{
+ if (*a == *b) return 0;
+ if (*a < *b) return -1;
+ return +1;
+}
+
+static void
+typeinfo_test_parse(typeinfo *info,char *str)
+{
+ int num;
+ int i;
+ typeinfo *infobuf;
+ u1 *typebuf;
+ int returntype;
+ utf *desc = utf_new_char(str);
+
+ num = typeinfo_count_method_args(desc,false);
+ if (num) {
+ typebuf = DMNEW(u1,num);
+ infobuf = DMNEW(typeinfo,num);
+
+ typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
+ &returntype,info);
+
+ TYPEINFO_ALLOCMERGED(info->merged,num);
+ info->merged->count = num;
+
+ for (i=0; i<num; ++i) {
+ if (typebuf[i] != TYPE_ADDRESS)
+ panic("non-reference type in mergedlist");
+ info->merged->list[i] = infobuf[i].typeclass;
+ }
+ qsort(info->merged->list,num,sizeof(classinfo*),
+ (int(*)(const void *,const void *))&typeinfo_test_compare);
+ }
+ else {
+ typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
+ &returntype,info);
+ }
+}
+
+#define TYPEINFO_TEST_BUFLEN 4000
+
+static bool
+typeinfo_equal(typeinfo *x,typeinfo *y)
+{
+ int i;
+
+ if (x->typeclass != y->typeclass) return false;
+ if (x->dimension != y->dimension) return false;
+ if (x->dimension) {
+ if (x->elementclass != y->elementclass) return false;
+ if (x->elementtype != y->elementtype) return false;
+ }
+ if (x->merged || y->merged) {
+ if (!(x->merged && y->merged)) return false;
+ if (x->merged->count != y->merged->count) return false;
+ for (i=0; i<x->merged->count; ++i)
+ if (x->merged->list[i] != y->merged->list[i])
+ return false;
+ }
+ return true;
+}
+
+static void
+typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
+{
+ typeinfo dest;
+
+ TYPEINFO_CLONE(*a,dest);
+
+ printf("\n ");
+ typeinfo_print_short(stdout,&dest);
+ printf("\n ");
+ typeinfo_print_short(stdout,b);
+ printf("\n");
+
+ typeinfo_merge(&dest,b);
+
+ if (typeinfo_equal(&dest,result)) {
+ printf("OK ");
+ typeinfo_print_short(stdout,&dest);
+ printf("\n");
+ }
+ else {
+ printf("RESULT ");
+ typeinfo_print_short(stdout,&dest);
+ printf("\n");
+ printf("SHOULD BE ");
+ typeinfo_print_short(stdout,result);
+ printf("\n");
+ (*failed)++;
+ }
+}
+
+static void
+typeinfo_inc_dimension(typeinfo *info)
+{
+ if (info->dimension++ == 0) {
+ info->elementtype = ARRAYTYPE_OBJECT;
+ info->elementclass = info->typeclass;
+ }
+ info->typeclass = class_array_of(info->typeclass);
+}
+
+#define TYPEINFO_TEST_MAXDIM 10
+
+static void
+typeinfo_testrun(char *filename)
+{
+ char buf[TYPEINFO_TEST_BUFLEN];
+ char bufa[TYPEINFO_TEST_BUFLEN];
+ char bufb[TYPEINFO_TEST_BUFLEN];
+ char bufc[TYPEINFO_TEST_BUFLEN];
+ typeinfo a,b,c,a2,b2;
+ int maxdim;
+ int failed = 0;
+ FILE *file = fopen(filename,"rt");
+
+ if (!file)
+ panic("could not open typeinfo test file");
+
+ while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
+ if (buf[0] == '#' || !strlen(buf))
+ continue;
+
+ int 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)");
+
+ typeinfo_test_parse(&a,bufa);
+ typeinfo_test_parse(&b,bufb);
+ typeinfo_test_parse(&c,bufc);
+ do {
+ typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
+ typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
+
+ if (TYPEINFO_IS_NULLTYPE(a)) break;
+ if (TYPEINFO_IS_NULLTYPE(b)) break;
+ if (TYPEINFO_IS_NULLTYPE(c)) break;
+
+ maxdim = a.dimension;
+ if (b.dimension > maxdim) maxdim = b.dimension;
+ if (c.dimension > maxdim) maxdim = c.dimension;
+
+ if (maxdim < TYPEINFO_TEST_MAXDIM) {
+ typeinfo_inc_dimension(&a);
+ typeinfo_inc_dimension(&b);
+ typeinfo_inc_dimension(&c);
+ }
+ } while (maxdim < TYPEINFO_TEST_MAXDIM);
+ }
+
+ fclose(file);
+
+ if (failed) {
+ fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
+ panic("Failed test");
+ }
+}
+
+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.");
+}
+
+void
+typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc)
+{
+ typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
+}
+
+#define TYPEINFO_MAXINDENT 80
+
+void
+typeinfo_print(FILE *file,typeinfo *info,int indent)
+{
+ int i;
+ char ind[TYPEINFO_MAXINDENT + 1];
+
+ if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
+
+ for (i=0; i<indent; ++i)
+ ind[i] = ' ';
+ ind[i] = (char) 0;
+
+ if (TYPEINFO_IS_PRIMITIVE(*info)) {
+ fprintf(file,"%sprimitive\n",ind);
+ return;
+ }
+
+ if (TYPEINFO_IS_NULLTYPE(*info)) {
+ fprintf(file,"%snull\n",ind);
+ return;
+ }
+
+ fprintf(file,"%sClass: ",ind);
+ utf_fprint(file,info->typeclass->name);
+ fprintf(file,"\n");
+
+ if (TYPEINFO_IS_ARRAY(*info)) {
+ fprintf(file,"%sDimension: %d",ind,(int)info->dimension);
+ fprintf(file,"\n%sElements: ",ind);
+ switch (info->elementtype) {
+ case ARRAYTYPE_INT : fprintf(file,"int\n"); break;
+ case ARRAYTYPE_LONG : fprintf(file,"long\n"); break;
+ case ARRAYTYPE_FLOAT : fprintf(file,"float\n"); break;
+ case ARRAYTYPE_DOUBLE : fprintf(file,"double\n"); break;
+ case ARRAYTYPE_BYTE : fprintf(file,"byte\n"); break;
+ case ARRAYTYPE_CHAR : fprintf(file,"char\n"); break;
+ case ARRAYTYPE_SHORT : fprintf(file,"short\n"); break;
+ case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
+
+ case ARRAYTYPE_OBJECT:
+ fprintf(file,"reference: ");
+ utf_fprint(file,info->elementclass->name);
+ fprintf(file,"\n");
+ break;
+
+ default:
+ fprintf(file,"INVALID ARRAYTYPE!\n");
+ }
+ }
+
+ if (info->merged) {
+ fprintf(file,"%sMerged: ",ind);
+ for (i=0; i<info->merged->count; ++i) {
+ if (i) fprintf(file,", ");
+ utf_fprint(file,info->merged->list[i]->name);
+ }
+ fprintf(file,"\n");
+ }
+}
+
+void
+typeinfo_print_short(FILE *file,typeinfo *info)
+{
+ int i;
+
+ if (TYPEINFO_IS_PRIMITIVE(*info)) {
+ fprintf(file,"primitive");
+ return;
+ }
+
+ if (TYPEINFO_IS_NULLTYPE(*info)) {
+ fprintf(file,"null");
+ return;
+ }
+
+ utf_fprint(file,info->typeclass->name);
+
+ /* XXX remove */
+#if 0
+ if (TYPEINFO_IS_ARRAY(*info)) {
+ fprintf(file,"[%d]",info->dimension);
+ switch (info->elementtype) {
+ case ARRAYTYPE_INT : fprintf(file,"int"); break;
+ case ARRAYTYPE_LONG : fprintf(file,"long"); break;
+ case ARRAYTYPE_FLOAT : fprintf(file,"float"); break;
+ case ARRAYTYPE_DOUBLE : fprintf(file,"double"); break;
+ case ARRAYTYPE_BYTE : fprintf(file,"byte"); break;
+ case ARRAYTYPE_CHAR : fprintf(file,"char"); break;
+ case ARRAYTYPE_SHORT : fprintf(file,"short"); break;
+ case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
+
+ case ARRAYTYPE_OBJECT:
+ fprintf(file,"object(");
+ utf_fprint(file,info->elementclass->name);
+ fprintf(file,")");
+ break;
+
+ default:
+ fprintf(file,"INVALID ARRAYTYPE!");
+ }
+ }
+#endif
+
+ if (info->merged) {
+ fprintf(file,"{");
+ for (i=0; i<info->merged->count; ++i) {
+ if (i) fprintf(file,",");
+ utf_fprint(file,info->merged->list[i]->name);
+ }
+ fprintf(file,"}");
+ }
+}
+
+void
+typeinfo_print_type(FILE *file,int type,typeinfo *info)
+{
+ switch (type) {
+ case TYPE_VOID: fprintf(file,"V"); break;
+ case TYPE_INT: fprintf(file,"I"); break;
+ case TYPE_FLOAT: fprintf(file,"F"); break;
+ 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 {
+ fprintf(file,"L");
+ typeinfo_print_short(file,info);
+ fprintf(file,";");
+ }
+ break;
+
+ default:
+ fprintf(file,"!");
+ }
+}
+
+#endif // DEBUG_TYPES
--- /dev/null
+/********************************* typeinfo.h **********************************
+
+ Copyright (c) 2003 ? XXX
+
+ See file COPYRIGHT for information on usage and disclaimer of warranties
+
+ defininitions for the compiler's type system
+
+ Authors: Edwin Steiner
+
+ Last Change:
+
+*******************************************************************************/
+
+#ifndef __typeinfo_h_
+#define __typeinfo_h_
+
+/* #define DEBUG_TYPES */ /* XXX */
+
+#include "global.h"
+
+/* resolve typedef cycles *****************************************************/
+
+typedef struct typeinfo typeinfo;
+typedef struct typeinfo_mergedlist typeinfo_mergedlist;
+
+/* global variables ***********************************************************/
+
+/* XXX move this documentation to global.h */
+/* The following classinfo pointers are used internally by the type system.
+ * Please do not use them directly, use the TYPEINFO_ macros instead.
+ */
+
+/*
+ * pseudo_class_Arraystub
+ * (extends Object implements Cloneable, java.io.Serializable)
+ *
+ * If two arrays of incompatible component types are merged,
+ * the resulting reference has no accessible components.
+ * The result does, however, implement the interfaces Cloneable
+ * and java.io.Serializable. This pseudo class is used internally
+ * to represent such results. (They are *not* considered arrays!)
+ *
+ * pseudo_class_Array XXX delete?
+ * (extends pseudo_class_Arraystub)
+ *
+ * This pseudo class is used internally as the class of all arrays
+ * to distinguish them from arbitrary Objects.
+ *
+ * pseudo_class_Null
+ *
+ * This pseudo class is used internally to represent the
+ * null type.
+ */
+
+/* data structures for the type system ****************************************/
+
+/* The typeinfo structure stores detailed information on reference types.
+ * (stack elements, variables, etc. with type == TYPE_ADR.)
+ * XXX: exclude ReturnAddresses?
+ *
+ * For primitive types either there is no typeinfo allocated or the
+ * typeclass pointer in the typeinfo struct is NULL.
+ *
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ * typeinfo.[ch]. Please use the macros and functions defined here to
+ * access typeinfo structures!
+ */
+
+/* At all times *exactly one* of the following conditions is true for
+ * a particular typeinfo struct:
+ *
+ * A) typeclass == NULL
+ *
+ * In this case the other fields of the structure
+ * are INVALID.
+ *
+ * B) typeclass == pseudo_class_Null
+ *
+ * XXX
+ *
+ * C) typeclass is an array class
+ *
+ * XXX
+ *
+ * D) typeclass == pseudo_class_Arraystub
+ *
+ * XXX
+ *
+ * E) typeclass is an interface
+ *
+ * XXX
+ *
+ * F) typeclass is a (non-pseudo-)class != java.lang.Object
+ *
+ * XXX
+ * All classinfos in u.merged.list (if any) are
+ * subclasses of typeclass.
+ *
+ * G) typeclass is java.lang.Object
+ *
+ * XXX
+ * In this case u.merged.count and u.merged.list
+ * are valid and may be non-zero.
+ * The classinfos in u.merged.list (if any) can be
+ * classes, interfaces or pseudo classes.
+ */
+
+/* The following algorithm is used to determine if the type described
+ * by this typeinfo struct supports the interface X:
+ *
+ * 1) If typeclass is X or a subinterface of X the answer is "yes".
+ * 2) If typeclass is a (pseudo) class implementing X the answer is "yes".
+ * 3) XXX If typeclass is not an array and u.merged.count>0
+ * and all classes/interfaces in u.merged.list implement X
+ * the answer is "yes".
+ * 4) If none of the above is true the answer is "no".
+ */
+
+/*
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ * typeinfo.[ch]. Please use the macros and functions defined here to
+ * access typeinfo structures!
+ */
+struct typeinfo {
+ classinfo *typeclass;
+ classinfo *elementclass; /* valid if dimension>0 */
+ typeinfo_mergedlist *merged;
+ u1 dimension;
+ u1 elementtype; /* valid if dimension>0 */
+};
+
+struct typeinfo_mergedlist {
+ s4 count;
+ classinfo *list[1]; /* variable length! */
+};
+
+/****************************************************************************/
+/* MACROS */
+/****************************************************************************/
+
+/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
+ * You have to dereference any pointers.
+ */
+
+/* internally used macros ***************************************************/
+
+/* internal, don't use this explicitly! */
+/* XXX change to GC? */
+#define TYPEINFO_ALLOCMERGED(mergedlist,count) \
+ {(mergedlist) = (typeinfo_mergedlist*)dump_alloc( \
+ sizeof(typeinfo_mergedlist) \
+ + ((count)-1)*sizeof(classinfo*));}
+
+/* internal, don't use this explicitly! */
+/* XXX change to GC? */
+#if 0
+#define TYPEINFO_FREEMERGED(mergedlist) \
+ {mem_free((mergedlist),sizeof(typeinfo_mergedlist) \
+ + ((mergedlist)->count - 1)*sizeof(classinfo*));}
+#endif
+#define TYPEINFO_FREEMERGED(mergedlist)
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist) \
+ {if (mergedlist) TYPEINFO_FREEMERGED(mergedlist);}
+
+/* macros for type queries **************************************************/
+
+#define TYPEINFO_IS_PRIMITIVE(info) \
+ ((info).typeclass == NULL)
+
+#define TYPEINFO_IS_REFERENCE(info) \
+ ((info).typeclass != NULL)
+
+#define TYPEINFO_IS_NULLTYPE(info) \
+ ((info).typeclass == pseudo_class_Null)
+
+/* macros for array type queries ********************************************/
+
+#define TYPEINFO_IS_ARRAY(info) \
+ ( TYPEINFO_IS_REFERENCE(info) \
+ && ((info).dimension != 0) )
+
+#define TYPEINFO_IS_SIMPLE_ARRAY(info) \
+ ( ((info).dimension == 1) )
+
+#define TYPEINFO_IS_ARRAY_ARRAY(info) \
+ ( ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype) \
+ ( TYPEINFO_IS_SIMPLE_ARRAY(info) \
+ && ((info).elementtype == (arraytype)) )
+
+#define TYPEINFO_IS_OBJECT_ARRAY(info) \
+ ( TYPEINFO_IS_SIMPLE_ARRAY(info) \
+ && ((info).elementclass != NULL) )
+
+/* assumes that info describes an array type */
+#define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) \
+ ( ((info).elementclass != NULL) \
+ || ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_ARRAY_OF_REFS(info) \
+ ( TYPEINFO_IS_ARRAY(info) \
+ && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+
+/* macros for initializing typeinfo structures ******************************/
+
+#define TYPEINFO_INIT_PRIMITIVE(info) \
+ {(info).typeclass = NULL; \
+ (info).elementclass = NULL; \
+ (info).merged = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0;}
+
+#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo) \
+ {(info).typeclass = (cinfo); \
+ (info).elementclass = NULL; \
+ (info).merged = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0;}
+
+#define TYPEINFO_INIT_NULLTYPE(info) \
+ TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
+
+/* XXX delete */
+#if 0
+#define TYPEINFO_INIT_ARRAY(info,dim,elmtype,elmcinfo) \
+ {(info).typeclass = pseudo_class_Array; \
+ (info).elementclass = (elmcinfo); \
+ (info).merged = NULL; \
+ (info).dimension = (dim); \
+ (info).elementtype = (elmtype);}
+#endif
+
+/* XXX delete? */
+#define TYPEINFO_INIT_ARRAY(info,cls) \
+ {(info).typeclass = cls; \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ else \
+ (info).elementclass = NULL; \
+ (info).merged = NULL; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+
+#define TYPEINFO_INIT_CLASSINFO(info,cls) \
+ {if (((info).typeclass = cls)->vftbl->arraydesc) { \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ else \
+ (info).elementclass = NULL; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype;\
+ } \
+ else { \
+ (info).elementclass = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0; \
+ } \
+ (info).merged = NULL;}
+
+/* XXX */
+#define TYPEINFO_INC_DIMENSION(info) \
+ (info).dimension++
+
+#define TYPEINFO_INIT_FROM_FIELDINFO(info,fi) \
+ typeinfo_init_from_descriptor(&(info), \
+ (fi)->descriptor->text,utf_end((fi)->descriptor));
+
+/* macros for freeing typeinfo structures ***********************************/
+
+#define TYPEINFO_FREE(info) \
+ {TYPEINFO_FREEMERGED_IF_ANY((info).merged); \
+ (info).merged = NULL;}
+
+/* macros for writing types (destination must have been initialized) ********/
+/* XXX delete them? */
+
+#define TYPEINFO_PUT_NULLTYPE(info) \
+ {(info).typeclass = pseudo_class_Null;}
+
+#define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo) \
+ {(info).typeclass = (cinfo);}
+
+/* XXX delete */
+#if 0
+#define TYPEINFO_PUT_ARRAY(info,dim,elmtype) \
+ {(info).typeclass = pseudo_class_Array; \
+ (info).dimension = (dim); \
+ (info).elementtype = (elmtype);}
+#endif
+
+/* XXX delete? */
+#define TYPEINFO_PUT_ARRAY(info,cls) \
+ {(info).typeclass = cls; \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+
+#define TYPEINFO_PUT_CLASSINFO(info,cls) \
+ {if (((info).typeclass = cls)->vftbl->arraydesc) { \
+ if (cls->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ (info).dimension = cls->vftbl->arraydesc->dimension; \
+ (info).elementtype = cls->vftbl->arraydesc->elementtype; \
+ }}
+
+/* XXX delete */
+#if 0
+#define TYPEINFO_PUT_OBJECT_ARRAY(info,dim,elmcinfo) \
+ {TYPEINFO_PUT_ARRAY(info,dim,ARRAYTYPE_OBJECT); \
+ (info).elementclass = (elmcinfo);}
+#endif
+
+/* srcarray must be an array (not checked) */
+#define TYPEINFO_PUT_COMPONENT(srcarray,dst) \
+ {typeinfo_put_component(&(srcarray),&(dst));}
+
+/* macros for copying types (destinition is not checked or freed) ***********/
+
+/* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
+#define TYPEINFO_COPY(src,dst) \
+ {(dst) = (src);}
+
+/* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
+ * into a newly allocated array.
+ */
+#define TYPEINFO_CLONE(src,dst) \
+ {(dst) = (src); \
+ if ((dst).merged) typeinfo_clone(&(src),&(dst));}
+
+/****************************************************************************/
+/* FUNCTIONS */
+/****************************************************************************/
+
+/* inquiry functions (read-only) ********************************************/
+
+bool typeinfo_is_array(typeinfo *info);
+bool typeinfo_is_primitive_array(typeinfo *info,int arraytype);
+bool typeinfo_is_array_of_refs(typeinfo *info);
+
+bool typeinfo_implements_interface(typeinfo *info,classinfo *interf);
+bool typeinfo_is_assignable(typeinfo *value,typeinfo *dest);
+
+/* initialization functions *************************************************/
+
+void typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr);
+void typeinfo_init_component(typeinfo *srcarray,typeinfo *dst);
+
+int typeinfo_count_method_args(utf *d,bool twoword); /* this not included */
+void typeinfo_init_from_method_args(utf *desc,u1 *typebuf,
+ typeinfo *infobuf,
+ int buflen,bool twoword,
+ int *returntype,typeinfo *returntypeinfo);
+
+void typeinfo_clone(typeinfo *src,typeinfo *dest);
+
+/* functions for the type system ********************************************/
+
+void typeinfo_free(typeinfo *info);
+
+bool typeinfo_merge(typeinfo *dest,typeinfo* y);
+
+/* debugging helpers ********************************************************/
+
+#ifdef DEBUG_TYPES
+
+void typeinfo_test();
+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);
+
+#endif // DEBUG_TYPES
+
+#endif
--- /dev/null
+# Input for testing the typeinfo_ functions
+#
+# simple merges (result is common ancestor)
+#
+()Ljava/lang/Object; ()Ljava/lang/Object; ()Ljava/lang/Object;
+()Ljava/lang/Object; ()Ljava/lang/String; ()Ljava/lang/Object;
+()Ljava/lang/Number; ()Ljava/lang/Integer; ()Ljava/lang/Number;
+()Ljava/lang/Object; ()Ljava/lang/Integer; ()Ljava/lang/Object;
+()Ljava/lang/Object; ()Ljava/lang/Cloneable; ()Ljava/lang/Object;
+()Ljava/lang/Cloneable; ()Ljava/lang/Cloneable; ()Ljava/lang/Cloneable;
+()Ljava/lang/Cloneable; ()[Ljava/lang/Object; ()Ljava/lang/Cloneable;
+()Ljava/lang/Cloneable; ()[I ()Ljava/lang/Cloneable;
+()Ljava/io/Serializable; ()[Ljava/lang/Object; ()Ljava/io/Serializable;
+()Ljava/io/Serializable; ()[D ()Ljava/io/Serializable;
+()Ljava/lang/Object; ()[Ljava/lang/Object; ()Ljava/lang/Object;
+()Ljava/lang/Object; ()[I ()Ljava/lang/Object;
+()L$ARRAYSTUB$; ()L$ARRAYSTUB$; ()L$ARRAYSTUB$;
+()L$ARRAYSTUB$; ()Ljava/lang/Object; ()Ljava/lang/Object;
+()L$ARRAYSTUB$; ()Ljava/lang/Cloneable; ()Ljava/lang/Cloneable;
+()L$ARRAYSTUB$; ()Ljava/io/Serializable; ()Ljava/io/Serializable;
+()L$NULL$; ()L$NULL$; ()L$NULL$;
+()L$NULL$; ()[Ljava/lang/Object; ()[Ljava/lang/Object;
+#
+#
+# merges where the result is a mergedlist
+#
+()Ljava/lang/String; ()Ljava/lang/Number; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+#
+#
+# merges with one mergedlist where the resulting mergedlist is unchanged
+#
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; ()Ljava/lang/String; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; ()Ljava/lang/Number; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Integer; (Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Long; (Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()L$NULL$; (Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number;
+#
+#
+# merges with one mergedlist where the result has no mergedlist
+#
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; ()Ljava/lang/Object; ()Ljava/lang/Object;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Number; ()Ljava/lang/Number;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Object; ()Ljava/lang/Object;
+#
+#
+# one mergedlist where the resulting mergeslist is longer
+#
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; ()Ljava/lang/Double; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/Double;)Ljava/lang/Number;
+#
+#
+# merges with two mergedlists with the same typeclass
+#
+(Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object; (Ljava/lang/String;Ljava/lang/Number;)Ljava/lang/Object;
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/Float;)Ljava/lang/Number; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/Float;)Ljava/lang/Number;
+#
+#
+# merges with two mergedlists with different typeclass
+#
+(Ljava/lang/Integer;Ljava/lang/Long;)Ljava/lang/Number; (Ljava/lang/Integer;Ljava/lang/String;)Ljava/lang/Object; (Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/String;)Ljava/lang/Object;
+#
+#
+# merging primitive arrays
+#
+()[I ()[I ()[I
+()[I ()[F ()L$ARRAYSTUB$;
+#
+#
+# merging reference arrays with primitive arrays
+#
+()[I ()[Ljava/lang/String; ()L$ARRAYSTUB$;