X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fverify%2Ftypeinfo.c;h=3d0a47888fc582644cd9ca2a1e5292a6735a8e8e;hb=9f859ad50d3d5d98c185d40b86b2179bc4dc9aeb;hp=8f3d592888c989c4a829846b70a032220c10cb6d;hpb=654eb3af12470c817c37f1a5c17f06115f05d3b8;p=cacao.git diff --git a/src/vm/jit/verify/typeinfo.c b/src/vm/jit/verify/typeinfo.c index 8f3d59288..3d0a47888 100644 --- a/src/vm/jit/verify/typeinfo.c +++ b/src/vm/jit/verify/typeinfo.c @@ -1,9 +1,9 @@ -/* typeinfo.c - type system used by the type checker +/* src/vm/jit/verify/typeinfo.c - type system used by the type checker - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 - R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, - M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, - P. Tomsich, J. Wenninger + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -19,205 +19,289 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - Contact: cacao@complang.tuwien.ac.at +*/ - Authors: Edwin Steiner - $Id: typeinfo.c 870 2004-01-10 22:49:32Z edwin $ +#include "config.h" -*/ +#include +#include +#include "mm/memory.h" -#include -#include -#include "typeinfo.h" -#include "tables.h" -#include "loader.h" -#include "toolbox/loging.h" -#include "toolbox/memory.h" -#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */ +#include "toolbox/logging.h" + +#include "vm/array.h" +#include "vm/exceptions.h" +#include "vm/primitive.h" +#include "vm/resolve.h" + +#include "vm/jit/jit.h" +#include "vm/jit/verify/typeinfo.h" +#include "vmcore/class.h" +#include "vmcore/descriptor.h" +#include "vmcore/loader.h" -#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \ + +/* check if a linked class is an array class. Only use for linked classes! */ +#define CLASSINFO_IS_ARRAY(clsinfo) ((clsinfo)->vftbl->arraydesc != NULL) + +/* check if a linked class implements the interface with the given index */ +#define CLASSINFO_IMPLEMENTS_INTERFACE(cls,index) \ ( ((index) < (cls)->vftbl->interfacetablelength) \ - && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) ) + && ( (cls)->vftbl->interfacetable[-(index)] != NULL ) ) + +/******************************************************************************/ +/* DEBUG HELPERS */ +/******************************************************************************/ + +#ifdef TYPEINFO_DEBUG +#define TYPEINFO_ASSERT(cond) assert(cond) +#else +#define TYPEINFO_ASSERT(cond) +#endif /**********************************************************************/ /* TYPEVECTOR FUNCTIONS */ /**********************************************************************/ -typevector * -typevectorset_copy(typevector *src,int k,int size) +#if defined(ENABLE_VERIFIER) + +/* typevector_copy ************************************************************* + + Return a copy of the given typevector. + + IN: + src..............typevector set to copy, must be != NULL + size.............number of elements per typevector + + RETURN VALUE: + a pointer to the new typevector set + +*******************************************************************************/ + +varinfo * +typevector_copy(varinfo *src, int size) { - typevector *dst = DNEW_TYPEVECTOR(size); + varinfo *dst; + TYPEINFO_ASSERT(src); + + dst = DNEW_TYPEVECTOR(size); memcpy(dst,src,TYPEVECTOR_SIZE(size)); - dst->k = k; - if (src->alt) - dst->alt = typevectorset_copy(src->alt,k+1,size); + return dst; } -bool -typevectorset_checktype(typevector *vec,int index,int type) +/* typevector_copy_inplace ***************************************************** + + Copy a typevector to a given destination. + + IN: + src..............typevector to copy, must be != NULL + dst..............destination to write the copy to + size.............number of elements per typevector + +*******************************************************************************/ + +void +typevector_copy_inplace(varinfo *src,varinfo *dst,int size) { - do { - if (vec->td[index].type != type) - return false; - } while ((vec = vec->alt) != NULL); - return true; + memcpy(dst,src,TYPEVECTOR_SIZE(size)); } +/* typevector_checktype ******************************************************** + + Check if the typevector contains a given type at a given index. + + IN: + vec..............typevector set, must be != NULL + index............index of component to check + type.............TYPE_* constant to check against + + RETURN VALUE: + true if the typevector contains TYPE at INDEX, + false otherwise + +*******************************************************************************/ + bool -typevectorset_checkreference(typevector *vec,int index) +typevector_checktype(varinfo *vec,int index,int type) { - do { - if (!TYPEDESC_IS_REFERENCE(vec->td[index])) - return false; - } while ((vec = vec->alt) != NULL); - return true; + TYPEINFO_ASSERT(vec); + + return vec[index].type == type; } +/* typevector_checkreference *************************************************** + + Check if the typevector contains a reference at a given index. + + IN: + vec..............typevector, must be != NULL + index............index of component to check + + RETURN VALUE: + true if the typevector contains a reference at INDEX, + false otherwise + +*******************************************************************************/ + bool -typevectorset_checkretaddr(typevector *vec,int index) +typevector_checkreference(varinfo *vec, int index) { - do { - if (!TYPEDESC_IS_RETURNADDRESS(vec->td[index])) - return false; - } while ((vec = vec->alt) != NULL); - return true; + TYPEINFO_ASSERT(vec); + return TYPEDESC_IS_REFERENCE(vec[index]); } -int -typevectorset_copymergedtype(typevector *vec,int index,typeinfo *dst) -{ - int type; - typedescriptor *td; +/* typevectorset_checkretaddr ************************************************** + + Check if the typevectors contains a returnAddress at a given index. + + IN: + vec..............typevector, must be != NULL + index............index of component to check - td = vec->td + index; - type = td->type; - TYPEINFO_COPY(td->info,*dst); - - if (vec->alt) { - int primitive; - - primitive = TYPEINFO_IS_PRIMITIVE(*dst) ? 1 : 0; - - while ((vec = vec->alt) != NULL) { - td = vec->td + index; - if (type != td->type) - return TYPE_VOID; - - if (type == TYPE_ADDRESS) { - if ((TYPEINFO_IS_PRIMITIVE(td->info) ? 1 : 0) != primitive) - return TYPE_VOID; - typeinfo_merge(dst,&(td->info)); - } - } - } - return type; -} + RETURN VALUE: + true if the typevector contains a returnAddress at INDEX, + false otherwise -int -typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result) -{ - if (vec->alt) { - *result = temp; - return typevectorset_copymergedtype(vec,index,temp); - } - - *result = &(vec->td[index].info); - return vec->td[index].type; -} +*******************************************************************************/ -typeinfo * -typevectorset_mergedtypeinfo(typevector *vec,int index,typeinfo *temp) +bool +typevector_checkretaddr(varinfo *vec,int index) { - typeinfo *result; - int type = typevectorset_mergedtype(vec,index,temp,&result); - return (type == TYPE_ADDRESS) ? result : NULL; + TYPEINFO_ASSERT(vec); + return TYPEDESC_IS_RETURNADDRESS(vec[index]); } +/* typevector_store ************************************************************ + + Store a type at a given index in the typevector. + + IN: + vec..............typevector set, must be != NULL + index............index of component to set + type.............TYPE_* constant of type to set + info.............typeinfo of type to set, may be NULL, + if TYPE != TYPE_ADR + +*******************************************************************************/ + void -typevectorset_store(typevector *vec,int index,int type,typeinfo *info) +typevector_store(varinfo *vec,int index,int type,typeinfo *info) { - /* XXX check if a separator was overwritten */ - do { - vec->td[index].type = type; - if (info) - TYPEINFO_COPY(*info,vec->td[index].info); - if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type)) - vec->td[index-1].type = TYPE_VOID; - } while ((vec = vec->alt) != NULL); + TYPEINFO_ASSERT(vec); + + vec[index].type = type; + if (info) + TYPEINFO_COPY(*info,vec[index].typeinfo); } +/* typevector_store_retaddr **************************************************** + + Store a returnAddress type at a given index in the typevector. + + IN: + vec..............typevector set, must be != NULL + index............index of component to set + info.............typeinfo of the returnAddress. + +*******************************************************************************/ + void -typevectorset_store_retaddr(typevector *vec,int index,typeinfo *info) +typevector_store_retaddr(varinfo *vec,int index,typeinfo *info) { - typeinfo_retaddr_set *adr; + TYPEINFO_ASSERT(vec); + TYPEINFO_ASSERT(TYPEINFO_IS_PRIMITIVE(*info)); - /* XXX check if a separator was overwritten */ - adr = (typeinfo_retaddr_set*) TYPEINFO_RETURNADDRESS(*info); - do { - vec->td[index].type = TYPE_ADDRESS; - TYPEINFO_INIT_RETURNADDRESS(vec->td[index].info,adr->addr); - if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type)) - vec->td[index-1].type = TYPE_VOID; - adr = adr->alt; - } while ((vec = vec->alt) != NULL); + vec[index].type = TYPE_ADR; + TYPEINFO_INIT_RETURNADDRESS(vec[index].typeinfo, + TYPEINFO_RETURNADDRESS(*info)); } -void -typevectorset_store_twoword(typevector *vec,int index,int type) -{ - /* XXX check if a separator was overwritten */ - do { - vec->td[index].type = type; - vec->td[index+1].type = TYPE_VOID; - if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type)) - vec->td[index-1].type = TYPE_VOID; - } while ((vec = vec->alt) != NULL); -} +/* typevector_init_object ****************************************************** + + Replace all uninitialized object types in the typevector set which were + created by the given instruction by initialized object types. + + IN: + set..............typevector set + ins..............instruction which created the uninitialized object type + initclass........class of the initialized object type to set + size.............number of elements per typevector -void -typevectorset_init_object(typevector *set,void *ins,classinfo *initclass, - int size) + RETURN VALUE: + true.............success + false............an exception has been thrown + + XXX maybe we should do the lazy resolving before calling this function + +*******************************************************************************/ + +bool +typevector_init_object(varinfo *set,void *ins, + classref_or_classinfo initclass, + int size) { int i; - - for (;set; set=set->alt) { - for (i=0; itd[i].type == TYPE_ADR - && TYPEINFO_IS_NEWOBJECT(set->td[i].info) - && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins) - { - TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass); - } + + for (i=0; itd; - typedescriptor *b = y->td; + varinfo *a = dst; + varinfo *b = y; while (size--) { if (a->type != TYPE_VOID && a->type != b->type) { a->type = TYPE_VOID; changed = true; } - else if (a->type == TYPE_ADDRESS) { - if (TYPEINFO_IS_PRIMITIVE(a->info)) { + else if (a->type == TYPE_ADR) { + if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) { /* 'a' is a returnAddress */ - if (!TYPEINFO_IS_PRIMITIVE(b->info) - || (TYPEINFO_RETURNADDRESS(a->info) - != TYPEINFO_RETURNADDRESS(b->info))) + if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo) + || (TYPEINFO_RETURNADDRESS(a->typeinfo) + != TYPEINFO_RETURNADDRESS(b->typeinfo))) { a->type = TYPE_VOID; changed = true; @@ -225,12 +309,17 @@ typevector_merge(typevector *dst,typevector *y,int size) } else { /* 'a' is a reference */ - if (TYPEINFO_IS_PRIMITIVE(b->info)) { + if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) { a->type = TYPE_VOID; changed = true; } else { - changed |= typeinfo_merge(&(a->info),&(b->info)); + /* two reference types are merged. There cannot be */ + /* a merge error. In the worst case we get j.l.O. */ + r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo)); + if (r == typecheck_FAIL) + return r; + changed |= r; } } } @@ -240,160 +329,180 @@ typevector_merge(typevector *dst,typevector *y,int size) return changed; } -bool typevector_separable_from(typevector *a,typevector *b,int size) -{ - typedescriptor *tda = a->td; - typedescriptor *tdb = b->td; - for (;size--; tda++,tdb++) { - if (TYPEDESC_IS_RETURNADDRESS(*tda) - && TYPEDESC_IS_RETURNADDRESS(*tdb) - && TYPEINFO_RETURNADDRESS(tda->info) - != TYPEINFO_RETURNADDRESS(tdb->info)) - return true; - } - return false; -} - -void -typevectorset_add(typevector *dst,typevector *v,int size) -{ - while (dst->alt) - dst = dst->alt; - dst->alt = DNEW_TYPEVECTOR(size); - memcpy(dst->alt,v,TYPEVECTOR_SIZE(size)); - dst->alt->alt = NULL; - dst->alt->k = dst->k + 1; -} - -typevector * -typevectorset_select(typevector **set,int retindex,void *retaddr) -{ - typevector *selected; - - if (!*set) return NULL; - - if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) { - selected = *set; - *set = selected->alt; - selected->alt = typevectorset_select(set,retindex,retaddr); - } - else { - selected = typevectorset_select(&((*set)->alt),retindex,retaddr); - } - return selected; -} - -bool -typevectorset_separable_with(typevector *set,typevector *add,int size) -{ - int i; - typevector *v; - void *addr; - bool separable; - - for (i=0; itd[i])) - continue; - addr = TYPEINFO_RETURNADDRESS(add->td[i].info); - - v = set; - separable = false; - do { - if (!TYPEDESC_IS_RETURNADDRESS(v->td[i])) - goto next_index; - if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr) - separable = true; - v = v->alt; - if (!v && separable) return true; - } while (v); - next_index: - } - return false; -} - -bool -typevectorset_collapse(typevector *dst,int size) -{ - bool changed = false; - - while (dst->alt) { - typevector_merge(dst,dst->alt,size); - dst->alt = dst->alt->alt; - changed = true; - } - return changed; -} - /**********************************************************************/ /* READ-ONLY FUNCTIONS */ /* The following functions don't change typeinfo data. */ /**********************************************************************/ +/* typeinfo_is_array *********************************************************** + + Check whether a typeinfo describes an array type. + + IN: + info.............the typeinfo, must be != NULL + + RETURN VALUE: + true if INFO describes an array type. + +*******************************************************************************/ + bool typeinfo_is_array(typeinfo *info) { + TYPEINFO_ASSERT(info); return TYPEINFO_IS_ARRAY(*info); } +/* typeinfo_is_primitive_array ************************************************* + + Check whether a typeinfo describes a primitive array type. + + IN: + info.............the typeinfo, must be != NULL + + RETURN VALUE: + true if INFO describes an array of a primitive type. + +*******************************************************************************/ + bool typeinfo_is_primitive_array(typeinfo *info,int arraytype) { + TYPEINFO_ASSERT(info); return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype); } +/* typeinfo_is_array_of_refs *************************************************** + + Check whether a typeinfo describes an array of references type. + + IN: + info.............the typeinfo, must be != NULL + + RETURN VALUE: + true if INFO describes an array of a refrence type. + +*******************************************************************************/ + bool typeinfo_is_array_of_refs(typeinfo *info) { + TYPEINFO_ASSERT(info); return TYPEINFO_IS_ARRAY_OF_REFS(*info); } -static -bool +/* interface_extends_interface ************************************************* + + Check if a resolved interface extends a given resolved interface. + + IN: + cls..............the interface, must be linked + interf...........the interface to check against + + RETURN VALUE: + true.............CLS extends INTERF + false............CLS does not extend INTERF + +*******************************************************************************/ + +static bool interface_extends_interface(classinfo *cls,classinfo *interf) { int i; + TYPEINFO_ASSERT(cls); + TYPEINFO_ASSERT(interf); + TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0); + TYPEINFO_ASSERT((cls->flags & ACC_INTERFACE) != 0); + TYPEINFO_ASSERT(cls->state & CLASS_LINKED); + /* first check direct superinterfaces */ for (i=0; iinterfacescount; ++i) { - if (cls->interfaces[i] == interf) + if (cls->interfaces[i].cls == interf) return true; } /* check indirect superinterfaces */ for (i=0; iinterfacescount; ++i) { - if (interface_extends_interface(cls->interfaces[i],interf)) + if (interface_extends_interface(cls->interfaces[i].cls,interf)) return true; } return false; } -/* XXX If really a performance issue, this could become a macro. */ -static -bool +/* classinfo_implements_interface ********************************************** + + Check if a resolved class implements a given resolved interface. + + IN: + cls..............the class + interf...........the interface + + RETURN VALUE: + typecheck_TRUE...CLS implements INTERF + typecheck_FALSE..CLS does not implement INTERF + typecheck_FAIL...an exception has been thrown + +*******************************************************************************/ + +static typecheck_result classinfo_implements_interface(classinfo *cls,classinfo *interf) { + TYPEINFO_ASSERT(cls); + TYPEINFO_ASSERT(interf); + TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0); + + if (!(cls->state & CLASS_LINKED)) + if (!link_class(cls)) + return typecheck_FAIL; + if (cls->flags & ACC_INTERFACE) { /* cls is an interface */ if (cls == interf) - return true; + return typecheck_TRUE; /* check superinterfaces */ return interface_extends_interface(cls,interf); } - return CLASS_IMPLEMENTS_INTERFACE(cls,interf->index); + TYPEINFO_ASSERT(cls->state & CLASS_LINKED); + return CLASSINFO_IMPLEMENTS_INTERFACE(cls,interf->index); } -bool mergedlist_implements_interface(typeinfo_mergedlist *merged, - classinfo *interf) +/* mergedlist_implements_interface ********************************************* + + Check if all the classes in a given merged list implement a given resolved + interface. + + IN: + merged...........the list of merged class types + interf...........the interface to check against + + RETURN VALUE: + typecheck_TRUE...all classes implement INTERF + typecheck_FALSE..there is at least one class that does not implement + INTERF + typecheck_MAYBE..check cannot be performed now because of unresolved + classes + typecheck_FAIL...an exception has been thrown + +*******************************************************************************/ + +static typecheck_result +mergedlist_implements_interface(typeinfo_mergedlist *merged, + classinfo *interf) { int i; - classinfo **mlist; + classref_or_classinfo *mlist; + typecheck_result r; + TYPEINFO_ASSERT(interf); + TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0); + /* Check if there is an non-empty mergedlist. */ if (!merged) - return false; + return typecheck_FALSE; /* If all classinfos in the (non-empty) merged array implement the * interface return true, otherwise false. @@ -401,438 +510,894 @@ bool mergedlist_implements_interface(typeinfo_mergedlist *merged, mlist = merged->list; i = merged->count; while (i--) { - if (!classinfo_implements_interface(*mlist++,interf)) - return false; + if (IS_CLASSREF(*mlist)) { + return typecheck_MAYBE; + } + r = classinfo_implements_interface((mlist++)->cls,interf); + if (r != typecheck_TRUE) + return r; } - return true; + return typecheck_TRUE; } -bool +/* merged_implements_interface ************************************************* + + Check if a possible merged type implements a given resolved interface + interface. + + IN: + typeclass........(common) class of the (merged) type + merged...........the list of merged class types + interf...........the interface to check against + + RETURN VALUE: + typecheck_TRUE...the type implement INTERF + typecheck_FALSE..the type does not implement INTERF + typecheck_MAYBE..check cannot be performed now because of unresolved + classes + typecheck_FAIL...an exception has been thrown + +*******************************************************************************/ + +static typecheck_result merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist *merged, classinfo *interf) { + typecheck_result r; + /* primitive types don't support interfaces. */ if (!typeclass) - return false; + return typecheck_FALSE; /* the null type can be cast to any interface type. */ if (typeclass == pseudo_class_Null) - return true; + return typecheck_TRUE; /* check if typeclass implements the interface. */ - if (classinfo_implements_interface(typeclass,interf)) - return true; + r = classinfo_implements_interface(typeclass,interf); + if (r != typecheck_FALSE) + return r; /* check the mergedlist */ - return (merged && mergedlist_implements_interface(merged,interf)); + if (!merged) + return typecheck_FALSE; + return mergedlist_implements_interface(merged,interf); } -bool -typeinfo_is_assignable(typeinfo *value,typeinfo *dest) +/* merged_is_subclass ********************************************************** + + Check if a possible merged type is a subclass of a given class. + A merged type is a subclass of a class C if all types in the merged list + are subclasses of C. A sufficient condition for this is that the + common type of the merged type is a subclass of C. + + IN: + typeclass........(common) class of the (merged) type + MUST be a loaded and linked class + merged...........the list of merged class types + cls..............the class to theck against + + RETURN VALUE: + typecheck_TRUE...the type is a subclass of CLS + typecheck_FALSE..the type is not a subclass of CLS + typecheck_MAYBE..check cannot be performed now because of unresolved + classes + typecheck_FAIL...an exception has been thrown + +*******************************************************************************/ + +static typecheck_result +merged_is_subclass(classinfo *typeclass,typeinfo_mergedlist *merged, + classinfo *cls) { - /* DEBUG CHECK: dest must not have a merged list. */ -#ifdef TYPEINFO_DEBUG - if (dest->merged) - panic("Internal error: typeinfo_is_assignable on merged destination."); -#endif + int i; + classref_or_classinfo *mlist; - return typeinfo_is_assignable_to_classinfo(value,dest->typeclass); + TYPEINFO_ASSERT(cls); + + /* primitive types aren't subclasses of anything. */ + if (!typeclass) + return typecheck_FALSE; - /* XXX delete */ -#if 0 + /* the null type can be cast to any reference type. */ + if (typeclass == pseudo_class_Null) + return typecheck_TRUE; + + TYPEINFO_ASSERT(typeclass->state & CLASS_LOADED); + TYPEINFO_ASSERT(typeclass->state & CLASS_LINKED); + + /* check if the common typeclass is a subclass of CLS. */ + if (class_issubclass(typeclass,cls)) + return typecheck_TRUE; + + /* check the mergedlist */ + if (!merged) + return typecheck_FALSE; + /* If all classinfos in the (non-empty) merged list are subclasses + * of CLS, return true, otherwise false. + * If there is at least one unresolved type in the list, + * return typecheck_MAYBE. + */ + mlist = merged->list; + i = merged->count; + while (i--) { + if (IS_CLASSREF(*mlist)) { + return typecheck_MAYBE; + } + if (!(mlist->cls->state & CLASS_LINKED)) + if (!link_class(mlist->cls)) + return typecheck_FAIL; + if (!class_issubclass(mlist->cls,cls)) + return typecheck_FALSE; + mlist++; + } + return typecheck_TRUE; +} + +/* typeinfo_is_assignable_to_class ********************************************* + + Check if a type is assignable to a given class type. + + IN: + value............the type of the value + dest.............the type of the destination + + RETURN VALUE: + typecheck_TRUE...the type is assignable + typecheck_FALSE..the type is not assignable + typecheck_MAYBE..check cannot be performed now because of unresolved + classes + typecheck_FAIL...an exception has been thrown + +*******************************************************************************/ + +typecheck_result +typeinfo_is_assignable_to_class(typeinfo *value,classref_or_classinfo dest) +{ + classref_or_classinfo c; classinfo *cls; + utf *classname; + + TYPEINFO_ASSERT(value); - cls = value->typeclass; + c = value->typeclass; /* assignments of primitive values are not checked here. */ - if (!cls && !dest->typeclass) - return true; + if (!c.any && !dest.any) + return typecheck_TRUE; /* primitive and reference types are not assignment compatible. */ - if (!cls || !dest->typeclass) - return false; + if (!c.any || !dest.any) + return typecheck_FALSE; /* the null type can be assigned to any type */ if (TYPEINFO_IS_NULLTYPE(*value)) - return true; + return typecheck_TRUE; /* uninitialized objects are not assignable */ if (TYPEINFO_IS_NEWOBJECT(*value)) - return false; + return typecheck_FALSE; + + if (IS_CLASSREF(c)) { + /* The value type is an unresolved class reference. */ + classname = c.ref->name; + } + else { + classname = c.cls->name; + } + + if (IS_CLASSREF(dest)) { + /* the destination type is an unresolved class reference */ + /* In this case we cannot tell a lot about assignability. */ + + /* the common case of value and dest type having the same classname */ + if (dest.ref->name == classname && !value->merged) + return typecheck_TRUE; + + /* we cannot tell if value is assignable to dest, so we */ + /* leave it up to the resolving code to check this */ + return typecheck_MAYBE; + } + + /* { we know that dest is a loaded class } */ + + if (IS_CLASSREF(c)) { + /* the value type is an unresolved class reference */ + + /* the common case of value and dest type having the same classname */ + if (dest.cls->name == classname) + return typecheck_TRUE; - if (dest->typeclass->flags & ACC_INTERFACE) { + /* we cannot tell if value is assignable to dest, so we */ + /* leave it up to the resolving code to check this */ + return typecheck_MAYBE; + } + + /* { we know that both c and dest are loaded classes } */ + /* (c may still have a merged list containing unresolved classrefs!) */ + + TYPEINFO_ASSERT(!IS_CLASSREF(c)); + TYPEINFO_ASSERT(!IS_CLASSREF(dest)); + + cls = c.cls; + + TYPEINFO_ASSERT(cls->state & CLASS_LOADED); + TYPEINFO_ASSERT(dest.cls->state & CLASS_LOADED); + + /* maybe we need to link the classes */ + if (!(cls->state & CLASS_LINKED)) + if (!link_class(cls)) + return typecheck_FAIL; + if (!(dest.cls->state & CLASS_LINKED)) + if (!link_class(dest.cls)) + return typecheck_FAIL; + + /* { we know that both c and dest are linked classes } */ + TYPEINFO_ASSERT(cls->state & CLASS_LINKED); + TYPEINFO_ASSERT(dest.cls->state & CLASS_LINKED); + + if (dest.cls->flags & ACC_INTERFACE) { /* We are assigning to an interface type. */ - return merged_implements_interface(cls,value->merged, - dest->typeclass); + return merged_implements_interface(cls,value->merged,dest.cls); } - if (TYPEINFO_IS_ARRAY(*dest)) { + if (CLASSINFO_IS_ARRAY(dest.cls)) { + arraydescriptor *arraydesc = dest.cls->vftbl->arraydesc; + int dimension = arraydesc->dimension; + classinfo *elementclass = (arraydesc->elementvftbl) + ? arraydesc->elementvftbl->class : NULL; + /* We are assigning to an array type. */ if (!TYPEINFO_IS_ARRAY(*value)) - return false; + return typecheck_FALSE; - /* {Both value and dest are array types.} */ + /* {Both value and dest.cls are array types.} */ - /* value must have at least the dimension of dest. */ - if (value->dimension < dest->dimension) - return false; + /* value must have at least the dimension of dest.cls. */ + if (value->dimension < dimension) + return typecheck_FALSE; - if (value->dimension > dest->dimension) { + if (value->dimension > dimension) { /* value has higher dimension so we need to check * if its component array can be assigned to the - * element type of dest */ + * element type of dest.cls */ + + if (!elementclass) return typecheck_FALSE; - if (dest->elementclass->flags & ACC_INTERFACE) { + if (elementclass->flags & ACC_INTERFACE) { /* We are assigning to an interface type. */ return classinfo_implements_interface(pseudo_class_Arraystub, - dest->elementclass); + elementclass); } /* We are assigning to a class type. */ - return class_issubclass(pseudo_class_Arraystub,dest->elementclass); + return class_issubclass(pseudo_class_Arraystub,elementclass); } - /* {value and dest have the same dimension} */ + /* {value and dest.cls have the same dimension} */ - if (value->elementtype != dest->elementtype) - return false; + if (value->elementtype != arraydesc->elementtype) + return typecheck_FALSE; - if (value->elementclass) { + if (value->elementclass.any) { /* We are assigning an array of objects so we have to * check if the elements are assignable. */ - if (dest->elementclass->flags & ACC_INTERFACE) { + if (elementclass->flags & ACC_INTERFACE) { /* We are assigning to an interface type. */ - return merged_implements_interface(value->elementclass, + return merged_implements_interface(value->elementclass.cls, value->merged, - dest->elementclass); + elementclass); } /* We are assigning to a class type. */ - return class_issubclass(value->elementclass,dest->elementclass); + return merged_is_subclass(value->elementclass.cls,value->merged,elementclass); } - return true; + return typecheck_TRUE; } - /* {dest is not an array} */ + /* {dest.cls is not an array} */ + /* {dest.cls is a loaded class} */ + + /* If there are any unresolved references in the merged list, we cannot */ + /* tell if the assignment will be ok. */ + /* This can only happen when cls is java.lang.Object */ + if (cls == class_java_lang_Object && value->merged) { + classref_or_classinfo *mlist = value->merged->list; + int i = value->merged->count; + while (i--) + if (IS_CLASSREF(*mlist++)) + return typecheck_MAYBE; + } /* We are assigning to a class type */ if (cls->flags & ACC_INTERFACE) cls = class_java_lang_Object; - return class_issubclass(cls,dest->typeclass); -#endif + return merged_is_subclass(cls,value->merged,dest.cls); } -bool -typeinfo_is_assignable_to_classinfo(typeinfo *value,classinfo *dest) +/* typeinfo_is_assignable ****************************************************** + + Check if a type is assignable to a given type. + + IN: + value............the type of the value + dest.............the type of the destination, must not be a merged type + + RETURN VALUE: + typecheck_TRUE...the type is assignable + typecheck_FALSE..the type is not assignable + typecheck_MAYBE..check cannot be performed now because of unresolved + classes + typecheck_FAIL...an exception has been thrown + +*******************************************************************************/ + +typecheck_result +typeinfo_is_assignable(typeinfo *value,typeinfo *dest) { - classinfo *cls; + TYPEINFO_ASSERT(value); + TYPEINFO_ASSERT(dest); + TYPEINFO_ASSERT(dest->merged == NULL); - cls = value->typeclass; + return typeinfo_is_assignable_to_class(value,dest->typeclass); +} - /* assignments of primitive values are not checked here. */ - if (!cls && !dest) - return true; +/**********************************************************************/ +/* INITIALIZATION FUNCTIONS */ +/* The following functions fill in uninitialized typeinfo structures. */ +/**********************************************************************/ - /* primitive and reference types are not assignment compatible. */ - if (!cls || !dest) - return false; +/* typeinfo_init_classinfo ***************************************************** + + Initialize a typeinfo to a resolved class. + + IN: + c................the class -#ifdef TYPEINFO_DEBUG - if (!dest->linked) - panic("Internal error: typeinfo_is_assignable_to_classinfo: unlinked class."); -#endif + OUT: + *info............is initialized + + RETURN VALUE: + true.............success + false............an exception has been thrown + +*******************************************************************************/ + +void +typeinfo_init_classinfo(typeinfo *info, classinfo *c) +{ + if ((info->typeclass.cls = c)->vftbl->arraydesc) { + if (c->vftbl->arraydesc->elementvftbl) + info->elementclass.cls = c->vftbl->arraydesc->elementvftbl->class; + else + info->elementclass.any = NULL; + info->dimension = c->vftbl->arraydesc->dimension; + info->elementtype = c->vftbl->arraydesc->elementtype; + } + else { + info->elementclass.any = NULL; + info->dimension = 0; + info->elementtype = 0; + } + info->merged = NULL; +} + +/* typeinfo_init_class ********************************************************* + + Initialize a typeinfo to a possibly unresolved class type. + + IN: + c................the class type + + OUT: + *info............is initialized + + RETURN VALUE: + true.............success + false............an exception has been thrown + +*******************************************************************************/ + +bool +typeinfo_init_class(typeinfo *info,classref_or_classinfo c) +{ + char *utf_ptr; + int len; + classinfo *cls; + + TYPEINFO_ASSERT(c.any); + TYPEINFO_ASSERT(info); + + /* if necessary, try to resolve lazily */ + if (!resolve_classref_or_classinfo(NULL /* XXX should know method */, + c,resolveLazy,false,true,&cls)) + { + return false; + } - /* the null type can be assigned to any type */ - if (TYPEINFO_IS_NULLTYPE(*value)) - return true; + if (cls) { + typeinfo_init_classinfo(info,cls); + return true; + } - /* uninitialized objects are not assignable */ - if (TYPEINFO_IS_NEWOBJECT(*value)) - return false; + /* {the type could no be resolved lazily} */ + + info->typeclass.ref = c.ref; + info->elementclass.any = NULL; + info->dimension = 0; + info->merged = NULL; + + /* handle array type references */ + utf_ptr = c.ref->name->text; + len = c.ref->name->blength; + if (*utf_ptr == '[') { + /* count dimensions */ + while (*utf_ptr == '[') { + utf_ptr++; + info->dimension++; + len--; + } + if (*utf_ptr == 'L') { + utf_ptr++; + len -= 2; + info->elementtype = ARRAYTYPE_OBJECT; + info->elementclass.ref = class_get_classref(c.ref->referer,utf_new(utf_ptr,len)); + } + else { + /* an array with primitive element type */ + /* should have been resolved above */ + TYPEINFO_ASSERT(false); + } + } + return true; +} - if (dest->flags & ACC_INTERFACE) { - /* We are assigning to an interface type. */ - return merged_implements_interface(cls,value->merged,dest); - } +/* typeinfo_init_from_typedesc ************************************************* + + Initialize a typeinfo from a typedesc. + + IN: + desc.............the typedesc - if (CLASS_IS_ARRAY(dest)) { - arraydescriptor *arraydesc = dest->vftbl->arraydesc; - int dimension = arraydesc->dimension; - classinfo *elementclass = (arraydesc->elementvftbl) - ? arraydesc->elementvftbl->class : NULL; - - /* We are assigning to an array type. */ - if (!TYPEINFO_IS_ARRAY(*value)) - return false; + OUT: + *type............set to the TYPE_* constant of DESC (if type != NULL) + *info............receives the typeinfo (if info != NULL) - /* {Both value and dest are array types.} */ + RETURN VALUE: + true.............success + false............an exception has been thrown - /* value must have at least the dimension of dest. */ - if (value->dimension < dimension) - return false; +*******************************************************************************/ - if (value->dimension > dimension) { - /* value has higher dimension so we need to check - * if its component array can be assigned to the - * element type of dest */ +bool +typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo *info) +{ + TYPEINFO_ASSERT(desc); - if (!elementclass) return false; - - if (elementclass->flags & ACC_INTERFACE) { - /* We are assigning to an interface type. */ - return classinfo_implements_interface(pseudo_class_Arraystub, - elementclass); - } +#ifdef TYPEINFO_VERBOSE + fprintf(stderr,"typeinfo_init_from_typedesc("); + descriptor_debug_print_typedesc(stderr,desc); + fprintf(stderr,")\n"); +#endif - /* We are assigning to a class type. */ - return class_issubclass(pseudo_class_Arraystub,elementclass); - } + if (type) + *type = desc->type; - /* {value and dest have the same dimension} */ + if (info) { + if (desc->type == TYPE_ADR) { + TYPEINFO_ASSERT(desc->classref); + if (!typeinfo_init_class(info,CLASSREF_OR_CLASSINFO(desc->classref))) + return false; + } + else { + TYPEINFO_INIT_PRIMITIVE(*info); + } + } + return true; +} - if (value->elementtype != arraydesc->elementtype) - return false; +/* typeinfos_init_from_methoddesc ********************************************** + + Initialize an array of typeinfos and u1 TYPE_* values from a methoddesc. + + IN: + desc.............the methoddesc + buflen...........number of parameters the buffer can hold + twoword..........if true, use two parameter slots for two-word types + + OUT: + *typebuf.........receives a TYPE_* constant for each parameter + typebuf must be != NULL + *infobuf.........receives a typeinfo for each parameter + infobuf must be != NULL + *returntype......receives a TYPE_* constant for the return type + returntype may be NULL + *returntypeinfo..receives a typeinfo for the return type + returntypeinfo may be NULL + + RETURN VALUE: + true.............success + false............an exception has been thrown + + NOTE: + If (according to BUFLEN) the buffers are to small to hold the + parameter types, an internal error is thrown. This must be + avoided by checking the number of parameters and allocating enough + space before calling this function. + +*******************************************************************************/ - if (value->elementclass) { - /* We are assigning an array of objects so we have to - * check if the elements are assignable. - */ +bool +typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,typeinfo *infobuf, + int buflen,bool twoword, + u1 *returntype,typeinfo *returntypeinfo) +{ + int i; + int args = 0; - if (elementclass->flags & ACC_INTERFACE) { - /* We are assigning to an interface type. */ + TYPEINFO_ASSERT(desc); + TYPEINFO_ASSERT(typebuf); + TYPEINFO_ASSERT(infobuf); - return merged_implements_interface(value->elementclass, - value->merged, - elementclass); - } - - /* We are assigning to a class type. */ - return class_issubclass(value->elementclass,elementclass); - } +#ifdef TYPEINFO_VERBOSE + fprintf(stderr,"typeinfos_init_from_methoddesc("); + descriptor_debug_print_methoddesc(stderr,desc); + fprintf(stderr,")\n"); +#endif - return true; + /* check arguments */ + for (i=0; iparamcount; ++i) { + if (++args > buflen) { + exceptions_throw_internalerror("Buffer too small for method arguments."); + return false; + } + + if (!typeinfo_init_from_typedesc(desc->paramtypes + i,typebuf++,infobuf++)) + return false; + + if (twoword && (typebuf[-1] == TYPE_LNG || typebuf[-1] == TYPE_DBL)) { + if (++args > buflen) { + exceptions_throw_internalerror("Buffer too small for method arguments."); + return false; + } + + *typebuf++ = TYPE_VOID; + TYPEINFO_INIT_PRIMITIVE(*infobuf); + infobuf++; + } } - /* {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); + /* check returntype */ + if (returntype) { + if (!typeinfo_init_from_typedesc(&(desc->returntype),returntype,returntypeinfo)) + return false; + } + + return true; } -/**********************************************************************/ -/* INITIALIZATION FUNCTIONS */ -/* The following functions fill in uninitialized typeinfo structures. */ -/**********************************************************************/ +/* typedescriptor_init_from_typedesc ******************************************* + + Initialize a typedescriptor from a typedesc. + + IN: + desc.............the typedesc -void -typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr) + OUT: + *td..............receives the typedescriptor + td must be != NULL + + RETURN VALUE: + true.............success + false............an exception has been thrown + +*******************************************************************************/ + +bool +typedescriptor_init_from_typedesc(typedescriptor *td, + typedesc *desc) { - classinfo *cls; - char *end; - - /* XXX simplify */ - cls = class_from_descriptor(utf_ptr,end_ptr,&end, - CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NEW - | CLASSLOAD_NOVOID - | CLASSLOAD_CHECKEND); - - if (cls) - /* a class, interface or array descriptor */ - TYPEINFO_INIT_CLASSINFO(*info,cls); - else - /* a primitive type */ - TYPEINFO_INIT_PRIMITIVE(*info); + TYPEINFO_ASSERT(td); + TYPEINFO_ASSERT(desc); + + td->type = desc->type; + if (td->type == TYPE_ADR) { + if (!typeinfo_init_class(&(td->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref))) + return false; + } + else { + TYPEINFO_INIT_PRIMITIVE(td->typeinfo); + } + return true; } -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; +/* typeinfo_init_varinfo_from_typedesc ***************************************** + + Initialize a varinfo from a typedesc. + + IN: + desc.............the typedesc - /* method descriptor must start with parenthesis */ - if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor"); + OUT: + *var.............receives the type + var must be != NULL - - /* check arguments */ - while ((c = *utf_ptr) != ')') { - class_from_descriptor(utf_ptr,end_pos,&utf_ptr, - CLASSLOAD_SKIP | CLASSLOAD_NOVOID - | CLASSLOAD_NULLPRIMITIVE); - args++; - if (twoword && (c == 'J' || c == 'D')) - /* primitive two-word type */ - args++; - } + RETURN VALUE: + true.............success + false............an exception has been thrown - return args; -} +*******************************************************************************/ -void -typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf, - int buflen,bool twoword, - int *returntype,typeinfo *returntypeinfo) +bool +typeinfo_init_varinfo_from_typedesc(varinfo *var, + typedesc *desc) { - char *utf_ptr = desc->text; /* current position in utf text */ - char *end_pos = utf_end(desc); /* points behind utf string */ - int args = 0; - classinfo *cls; + TYPEINFO_ASSERT(var); + TYPEINFO_ASSERT(desc); + + var->type = desc->type; + if (var->type == TYPE_ADR) { + if (!typeinfo_init_class(&(var->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref))) + return false; + } + else { + TYPEINFO_INIT_PRIMITIVE(var->typeinfo); + } + return true; +} + +/* typeinfo_init_varinfos_from_methoddesc ************************************** + + Initialize an array of varinfos from a methoddesc. + + IN: + desc.............the methoddesc + buflen...........number of parameters the buffer can hold + startindex.......the zero-based index of the first parameter to + write to the array. In other words the number of + parameters to skip at the beginning of the methoddesc. + map..............map from parameter indices to varinfo indices + (indexed like jitdata.local_map) + + OUT: + *vars............array receiving the varinfos + td[0] receives the type of the + (startindex+1)th parameter of the method + *returntype......receives the typedescriptor of the return type. + returntype may be NULL + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + + NOTE: + If (according to BUFLEN) the buffer is to small to hold the + parameter types, an internal error is thrown. This must be + avoided by checking the number of parameters and allocating enough + space before calling this function. + +*******************************************************************************/ - /* method descriptor must start with parenthesis */ - if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor"); +bool +typeinfo_init_varinfos_from_methoddesc(varinfo *vars, + methoddesc *desc, + int buflen, int startindex, + s4 *map, + typedescriptor *returntype) +{ + s4 i; + s4 varindex; + s4 type; + s4 slot = 0; + + /* skip arguments */ + for (i=0; iparamtypes[i].type)) + slot++; + } /* check arguments */ - while (utf_ptr != end_pos && *utf_ptr != ')') { - if (++args > buflen) - panic("Buffer too small for method arguments."); - - *typebuf++ = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr, - CLASSLOAD_NEW - | CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NOVOID); - - if (cls) - TYPEINFO_INIT_CLASSINFO(*infobuf,cls); - else { - TYPEINFO_INIT_PRIMITIVE(*infobuf); - } - infobuf++; + for (i=startindex; iparamcount; ++i) { + type = desc->paramtypes[i].type; + varindex = map[5*slot + type]; - if (twoword && (typebuf[-1] == TYPE_LONG || typebuf[-1] == TYPE_DOUBLE)) { - if (++args > buflen) - panic("Buffer too small for method arguments."); - *typebuf++ = TYPE_VOID; - TYPEINFO_INIT_PRIMITIVE(*infobuf); - infobuf++; + slot++; + if (IS_2_WORD_TYPE(type)) + slot++; + + if (varindex == UNUSED) + continue; + + if (varindex >= buflen) { + exceptions_throw_internalerror("Buffer too small for method arguments."); + return false; } + + if (!typeinfo_init_varinfo_from_typedesc(vars + varindex, desc->paramtypes + i)) + return false; } - utf_ptr++; /* skip ')' */ /* check returntype */ if (returntype) { - *returntype = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr, - CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NEW - | CLASSLOAD_CHECKEND); - if (returntypeinfo) { - if (cls) - TYPEINFO_INIT_CLASSINFO(*returntypeinfo,cls); - else - TYPEINFO_INIT_PRIMITIVE(*returntypeinfo); - } + if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype))) + return false; } + + return true; } +/* typedescriptors_init_from_methoddesc **************************************** + + Initialize an array of typedescriptors from a methoddesc. + + IN: + desc.............the methoddesc + buflen...........number of parameters the buffer can hold + twoword..........if true, use two parameter slots for two-word types + startindex.......the zero-based index of the first parameter to + write to the array. In other words the number of + parameters to skip at the beginning of the methoddesc. + + OUT: + *td..............array receiving the typedescriptors. + td[0] receives the typedescriptor of the + (startindex+1)th parameter of the method + *returntype......receives the typedescriptor of the return type. + returntype may be NULL + + RETURN VALUE: + >= 0.............number of typedescriptors filled in TD + -1...............an exception has been thrown + + NOTE: + If (according to BUFLEN) the buffer is to small to hold the + parameter types, an internal error is thrown. This must be + avoided by checking the number of parameters and allocating enough + space before calling this function. + +*******************************************************************************/ + int -typedescriptors_init_from_method_args(typedescriptor *td, - utf *desc, - int buflen,bool twoword, - typedescriptor *returntype) +typedescriptors_init_from_methoddesc(typedescriptor *td, + methoddesc *desc, + int buflen,bool twoword,int startindex, + typedescriptor *returntype) { - char *utf_ptr = desc->text; /* current position in utf text */ - char *end_pos = utf_end(desc); /* points behind utf string */ + int i; int args = 0; - classinfo *cls; - - /* method descriptor must start with parenthesis */ - if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor"); /* check arguments */ - while (utf_ptr != end_pos && *utf_ptr != ')') { - if (++args > buflen) - panic("Buffer too small for method arguments."); - - td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr, - CLASSLOAD_NEW - | CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NOVOID); - - if (cls) - TYPEINFO_INIT_CLASSINFO(td->info,cls); - else { - TYPEINFO_INIT_PRIMITIVE(td->info); + for (i=startindex; iparamcount; ++i) { + if (++args > buflen) { + exceptions_throw_internalerror("Buffer too small for method arguments."); + return -1; } + + if (!typedescriptor_init_from_typedesc(td,desc->paramtypes + i)) + return -1; td++; - if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) { - if (++args > buflen) - panic("Buffer too small for method arguments."); + if (twoword && (td[-1].type == TYPE_LNG || td[-1].type == TYPE_DBL)) { + if (++args > buflen) { + exceptions_throw_internalerror("Buffer too small for method arguments."); + return -1; + } + td->type = TYPE_VOID; - TYPEINFO_INIT_PRIMITIVE(td->info); + TYPEINFO_INIT_PRIMITIVE(td->typeinfo); td++; } } - utf_ptr++; /* skip ')' */ /* check returntype */ if (returntype) { - returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr, - CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NEW - | CLASSLOAD_CHECKEND); - if (cls) - TYPEINFO_INIT_CLASSINFO(returntype->info,cls); - else - TYPEINFO_INIT_PRIMITIVE(returntype->info); + if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype))) + return -1; } + return args; } -void +/* typeinfo_init_component ***************************************************** + + Initialize a typeinfo with the component type of a given array type. + + IN: + srcarray.........the typeinfo of the array type + + OUT: + *dst.............receives the typeinfo of the component type + + RETURN VALUE: + true.............success + false............an exception has been thrown + +*******************************************************************************/ + +bool typeinfo_init_component(typeinfo *srcarray,typeinfo *dst) { - vftbl *comp = NULL; + typeinfo_mergedlist *merged; + + TYPEINFO_ASSERT(srcarray); + TYPEINFO_ASSERT(dst); if (TYPEINFO_IS_NULLTYPE(*srcarray)) { TYPEINFO_INIT_NULLTYPE(*dst); - return; + return true; } - /* XXX find component class */ - if (!TYPEINFO_IS_ARRAY(*srcarray)) - panic("Trying to access component of non-array"); + if (!TYPEINFO_IS_ARRAY(*srcarray)) { + /* XXX should we make that a verify error? */ + exceptions_throw_internalerror("Trying to access component of non-array"); + return false; + } - comp = srcarray->typeclass->vftbl->arraydesc->componentvftbl; - if (comp) { - TYPEINFO_INIT_CLASSINFO(*dst,comp->class); - } - else { - TYPEINFO_INIT_PRIMITIVE(*dst); - } + /* save the mergedlist (maybe dst == srcarray) */ - /* 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 + merged = srcarray->merged; + + if (IS_CLASSREF(srcarray->typeclass)) { + constant_classref *comp; + comp = class_get_classref_component_of(srcarray->typeclass.ref); + + if (comp) { + if (!typeinfo_init_class(dst,CLASSREF_OR_CLASSINFO(comp))) + return false; + } + else { + TYPEINFO_INIT_PRIMITIVE(*dst); + } + } + else { + vftbl_t *comp; + + if (!(srcarray->typeclass.cls->state & CLASS_LINKED)) { + if (!link_class(srcarray->typeclass.cls)) { + return false; + } + } + + TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl); + TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl->arraydesc); + + comp = srcarray->typeclass.cls->vftbl->arraydesc->componentvftbl; + if (comp) + typeinfo_init_classinfo(dst,comp->class); + else + TYPEINFO_INIT_PRIMITIVE(*dst); + } - dst->merged = srcarray->merged; + dst->merged = merged; /* XXX should we do a deep copy? */ + return true; } +/* typeinfo_clone ************************************************************** + + Create a deep copy of a typeinfo struct. + + IN: + src..............the typeinfo to copy + + OUT: + *dest............receives the copy + + NOTE: + If src == dest this function is a nop. + +*******************************************************************************/ + void typeinfo_clone(typeinfo *src,typeinfo *dest) { int count; - classinfo **srclist,**destlist; + classref_or_classinfo *srclist,*destlist; if (src == dest) return; @@ -844,7 +1409,6 @@ typeinfo_clone(typeinfo *src,typeinfo *dest) TYPEINFO_ALLOCMERGED(dest->merged,count); dest->merged->count = count; - /* XXX use memcpy? */ srclist = src->merged->list; destlist = dest->merged->list; while (count--) @@ -856,6 +1420,16 @@ typeinfo_clone(typeinfo *src,typeinfo *dest) /* MISCELLANEOUS FUNCTIONS */ /**********************************************************************/ +/* typeinfo_free *************************************************************** + + Free memory referenced by the given typeinfo. The typeinfo itself is not + freed. + + IN: + info.............the typeinfo + +*******************************************************************************/ + void typeinfo_free(typeinfo *info) { @@ -871,33 +1445,33 @@ typeinfo_free(typeinfo *info) static void -typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) { -#ifdef TYPEINFO_DEBUG +typeinfo_merge_error(methodinfo *m,char *str,typeinfo *x,typeinfo *y) { +#ifdef TYPEINFO_VERBOSE 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); + log_text(str); #endif - panic(str); + + exceptions_throw_verifyerror(m, str); } /* Condition: clsx != clsy. */ -/* Returns: true if dest was changed (always true). */ +/* Returns: true if dest was changed (currently always true). */ static bool -typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy) +typeinfo_merge_two(typeinfo *dest,classref_or_classinfo clsx,classref_or_classinfo clsy) { + TYPEINFO_ASSERT(dest); TYPEINFO_FREEMERGED_IF_ANY(dest->merged); TYPEINFO_ALLOCMERGED(dest->merged,2); dest->merged->count = 2; -#ifdef TYPEINFO_DEBUG - if (clsx == clsy) - panic("Internal error: typeinfo_merge_two called with clsx==clsy."); -#endif + TYPEINFO_ASSERT(clsx.any != clsy.any); - if (clsx < clsy) { + if (clsx.any < clsy.any) { dest->merged->list[0] = clsx; dest->merged->list[1] = clsy; } @@ -912,18 +1486,18 @@ typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy) /* Returns: true if dest was changed. */ static bool -typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classinfo *cls) +typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classref_or_classinfo cls) { int count; typeinfo_mergedlist *newmerged; - classinfo **mlist,**newlist; + classref_or_classinfo *mlist,*newlist; count = m->count; mlist = m->list; /* Check if cls is already in the mergedlist m. */ while (count--) { - if (*mlist++ == cls) { + if ((mlist++)->any == cls.any) { /* XXX check equal classrefs? */ /* cls is in the list, so m is the resulting mergedlist */ if (dest->merged == m) return false; @@ -949,7 +1523,7 @@ typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classinfo *cls) newlist = newmerged->list; mlist = m->list; while (count) { - if (*mlist > cls) + if (mlist->any > cls.any) break; *newlist++ = *mlist++; count--; @@ -975,7 +1549,7 @@ typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x, int count = 0; int countx,county; typeinfo_mergedlist *temp,*result; - classinfo **clsx,**clsy,**newlist; + classref_or_classinfo *clsx,*clsy,*newlist; /* count the elements that will be in the resulting list */ /* (Both lists are sorted, equal elements are counted only once.) */ @@ -984,13 +1558,13 @@ typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x, countx = x->count; county = y->count; while (countx && county) { - if (*clsx == *clsy) { + if (clsx->any == clsy->any) { clsx++; clsy++; countx--; county--; } - else if (*clsx < *clsy) { + else if (clsx->any < clsy->any) { clsx++; countx--; } @@ -1040,13 +1614,13 @@ typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x, countx = x->count; county = y->count; while (countx && county) { - if (*clsx == *clsy) { + if (clsx->any == clsy->any) { *newlist++ = *clsx++; clsy++; countx--; county--; } - else if (*clsx < *clsy) { + else if (clsx->any < clsy->any) { *newlist++ = *clsx++; countx--; } @@ -1067,232 +1641,377 @@ typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x, return true; } -static -bool +/* typeinfo_merge_nonarrays **************************************************** + + Merge two non-array types. + + IN: + x................the first type + y................the second type + mergedx..........merged list of the first type, may be NULL + mergedy..........merged list of the descond type, may be NULL + + OUT: + *dest............receives the resulting merged list + *result..........receives the resulting type + + RETURN VALUE: + typecheck_TRUE...*dest has been modified + typecheck_FALSE..*dest has not been modified + typecheck_FAIL...an exception has been thrown + + NOTE: + RESULT is an extra parameter so it can point to dest->typeclass or to + dest->elementclass. + +*******************************************************************************/ + +static typecheck_result typeinfo_merge_nonarrays(typeinfo *dest, - classinfo **result, - classinfo *clsx,classinfo *clsy, + classref_or_classinfo *result, + classref_or_classinfo x,classref_or_classinfo y, typeinfo_mergedlist *mergedx, typeinfo_mergedlist *mergedy) { + classref_or_classinfo t; classinfo *tcls,*common; typeinfo_mergedlist *tmerged; bool changed; + typecheck_result r; + utf *xname; + utf *yname; - /* XXX remove */ - /* -#ifdef TYPEINFO_DEBUG - 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 - */ + TYPEINFO_ASSERT(dest && result && x.any && y.any); + TYPEINFO_ASSERT(x.cls != pseudo_class_Null); + TYPEINFO_ASSERT(y.cls != pseudo_class_Null); + TYPEINFO_ASSERT(x.cls != pseudo_class_New); + TYPEINFO_ASSERT(y.cls != pseudo_class_New); + + /*--------------------------------------------------*/ + /* common cases */ + /*--------------------------------------------------*/ - /* Common case: clsx == clsy */ + /* Common case 1: x and y are the same class or class reference */ /* (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)) { + if ( (x.any == y.any) && (!mergedx || !mergedy) ) { return_simple_x: - /* XXX remove */ /* log_text("return simple x"); */ + /* DEBUG */ /* log_text("return simple x"); */ changed = (dest->merged != NULL); TYPEINFO_FREEMERGED_IF_ANY(dest->merged); dest->merged = NULL; - *result = clsx; - /* XXX remove */ /* log_text("returning"); */ + *result = x; + /* DEBUG */ /* 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; + + xname = (IS_CLASSREF(x)) ? x.ref->name : x.cls->name; + yname = (IS_CLASSREF(y)) ? y.ref->name : y.cls->name; + + /* Common case 2: xname == yname, at least one unresolved */ + if ((IS_CLASSREF(x) || IS_CLASSREF(y)) && (xname == yname)) + { + /* use the loaded one if any */ + if (!IS_CLASSREF(y)) + x = y; + goto return_simple_x; + } + + /*--------------------------------------------------*/ + /* non-trivial cases */ + /*--------------------------------------------------*/ + +#ifdef TYPEINFO_VERBOSE + { + typeinfo dbgx,dbgy; + fprintf(stderr,"merge_nonarrays:\n"); + fprintf(stderr," ");if(IS_CLASSREF(x))fprintf(stderr,"");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n"); + fprintf(stderr," ");if(IS_CLASSREF(y))fprintf(stderr,"");utf_fprint_printable_ascii(stderr,yname);fprintf(stderr,"\n"); + fflush(stderr); + typeinfo_init_class(&dbgx,x); + dbgx.merged = mergedx; + typeinfo_init_class(&dbgy,y); + dbgy.merged = mergedy; + typeinfo_print(stderr,&dbgx,4); + fprintf(stderr," with:\n"); + typeinfo_print(stderr,&dbgy,4); + } +#endif + + TYPEINFO_ASSERT(IS_CLASSREF(x) || (x.cls->state & CLASS_LOADED)); + TYPEINFO_ASSERT(IS_CLASSREF(y) || (y.cls->state & CLASS_LOADED)); + + /* If y is unresolved or an interface, swap x and y. */ + if (IS_CLASSREF(y) || (!IS_CLASSREF(x) && y.cls->flags & ACC_INTERFACE)) + { + t = x; x = y; y = t; tmerged = mergedx; mergedx = mergedy; mergedy = tmerged; } + + /* {We know: If only one of x,y is unresolved it is x,} */ + /* { If both x,y are resolved and only one of x,y is an interface it is x.} */ + + if (IS_CLASSREF(x)) { + /* {We know: x and y have different class names} */ + + /* Check if we are merging an unresolved type with java.lang.Object */ + if (y.cls == class_java_lang_Object && !mergedy) { + x = y; + goto return_simple_x; + } + + common = class_java_lang_Object; + goto merge_with_simple_x; + } + + /* {We know: both x and y are resolved} */ /* {We know: If only one of x,y is an interface it is x.} */ + TYPEINFO_ASSERT(!IS_CLASSREF(x) && !IS_CLASSREF(y)); + TYPEINFO_ASSERT(x.cls->state & CLASS_LOADED); + TYPEINFO_ASSERT(y.cls->state & CLASS_LOADED); + /* Handle merging of interfaces: */ - if (clsx->flags & ACC_INTERFACE) { - /* {clsx is an interface and mergedx == NULL.} */ + if (x.cls->flags & ACC_INTERFACE) { + /* {x.cls is an interface and mergedx == NULL.} */ - if (clsy->flags & ACC_INTERFACE) { + if (y.cls->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 that x.cls!=y.cls (see common case at beginning.)} */ + result->cls = class_java_lang_Object; + return typeinfo_merge_two(dest,x,y); } - /* {We know: x is an interface, clsy is a class.} */ + /* {We know: x is an interface, y is a class.} */ /* Check if we are merging an interface with java.lang.Object */ - if (clsy == class_java_lang_Object && !mergedy) { - clsx = clsy; + if (y.cls == class_java_lang_Object && !mergedy) { + x = y; goto return_simple_x; } - - /* If the type y implements clsx then the result of the merge - * is clsx regardless of mergedy. + /* If the type y implements x then the result of the merge + * is x regardless of mergedy. */ + + /* we may have to link the classes */ + if (!(x.cls->state & CLASS_LINKED)) + if (!link_class(x.cls)) + return typecheck_FAIL; + if (!(y.cls->state & CLASS_LINKED)) + if (!link_class(y.cls)) + return typecheck_FAIL; - if (CLASS_IMPLEMENTS_INTERFACE(clsy,clsx->index) - || mergedlist_implements_interface(mergedy,clsx)) + TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED); + TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED); + + if (CLASSINFO_IMPLEMENTS_INTERFACE(y.cls,x.cls->index)) + { + /* y implements x, so the result of the merge is x. */ + goto return_simple_x; + } + + r = mergedlist_implements_interface(mergedy,x.cls); + if (r == typecheck_FAIL) + return r; + if (r == typecheck_TRUE) { /* 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.} */ + * of subclasses and is not guaranteed to 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).} */ + /* we may have to link the classes */ + if (!(x.cls->state & CLASS_LINKED)) + if (!link_class(x.cls)) + return typecheck_FAIL; + if (!(y.cls->state & CLASS_LINKED)) + if (!link_class(y.cls)) + return typecheck_FAIL; + + TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED); + TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED); + /* If *x is deeper in the inheritance hierarchy swap x and y. */ - if (clsx->index > clsy->index) { - tcls = clsx; clsx = clsy; clsy = tcls; + if (x.cls->index > y.cls->index) { + t = x; x = y; y = t; 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; + common = x.cls; + tcls = y.cls; while (tcls->index > common->index) - tcls = tcls->super; + tcls = tcls->super.cls; while (common != tcls) { - common = common->super; - tcls = tcls->super; + common = common->super.cls; + tcls = tcls->super.cls; } - /* {common == nearest common anchestor of clsx and clsy.} */ + /* {common == nearest common anchestor of x and y.} */ - /* If clsx==common and x is a whole class (not a merge of subclasses) - * then the result of the merge is clsx. + /* If x.cls==common and x is a whole class (not a merge of subclasses) + * then the result of the merge is x. */ - if (clsx == common && !mergedx) { + if (x.cls == common && !mergedx) { goto return_simple_x; } if (mergedx) { - *result = common; + result->cls = common; if (mergedy) return typeinfo_merge_mergedlists(dest,mergedx,mergedy); else - return typeinfo_merge_add(dest,mergedx,clsy); + return typeinfo_merge_add(dest,mergedx,y); } - merge_with_simple_x: - *result = common; +merge_with_simple_x: + result->cls = common; if (mergedy) - return typeinfo_merge_add(dest,mergedy,clsx); + return typeinfo_merge_add(dest,mergedy,x); else - return typeinfo_merge_two(dest,clsx,clsy); + return typeinfo_merge_two(dest,x,y); } -/* 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_merge ************************************************************** + + Merge two types. + + IN: + m................method for exception messages + dest.............the first type + y................the second type + + OUT: + *dest............receives the result of the merge + + RETURN VALUE: + typecheck_TRUE...*dest has been modified + typecheck_FALSE..*dest has not been modified + typecheck_FAIL...an exception has been thrown + + PRE-CONDITIONS: + 1) *dest must be a valid initialized typeinfo + 2) dest != y + +*******************************************************************************/ + +typecheck_result +typeinfo_merge(methodinfo *m,typeinfo *dest,typeinfo* y) { typeinfo *x; - typeinfo *tmp; /* used for swapping */ - classinfo *common; - classinfo *elementclass; + typeinfo *tmp; + classref_or_classinfo common; + classref_or_classinfo elementclass; int dimension; int elementtype; bool changed; + typecheck_result r; - /* XXX remove */ - /* -#ifdef TYPEINFO_DEBUG - typeinfo_print(stdout,dest,4); - typeinfo_print(stdout,y,4); -#endif - */ + /*--------------------------------------------------*/ + /* fast checks */ + /*--------------------------------------------------*/ /* Merging something with itself is a nop */ if (dest == y) - return false; + return typecheck_FALSE; /* Merging two returnAddress types is ok. */ - if (!dest->typeclass && !y->typeclass) { -#ifdef TYPEINFO_DEBUG - if (TYPEINFO_RETURNADDRESS(*dest) != TYPEINFO_RETURNADDRESS(*y)) - panic("Internal error: typeinfo_merge merges different returnAddresses"); -#endif - return false; + /* Merging two different returnAddresses never happens, as the verifier */ + /* keeps them separate in order to check all the possible return paths */ + /* from JSR subroutines. */ + if (!dest->typeclass.any && !y->typeclass.any) { + TYPEINFO_ASSERT(TYPEINFO_RETURNADDRESS(*dest) == TYPEINFO_RETURNADDRESS(*y)); + return typecheck_FALSE; } /* Primitive types cannot be merged with reference types */ - /* XXX only check this in debug mode? */ - if (!dest->typeclass || !y->typeclass) - typeinfo_merge_error("Trying to merge primitive types.",dest,y); - -#ifdef TYPEINFO_DEBUG - /* 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 + /* This must be checked before calls to typeinfo_merge. */ + TYPEINFO_ASSERT(dest->typeclass.any && y->typeclass.any); /* handle uninitialized object types */ - /* XXX is there a way we could put this after the common case? */ if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) { - if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y)) - typeinfo_merge_error("Trying to merge uninitialized object type.",dest,y); - if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest) - != TYPEINFO_NEWOBJECT_INSTRUCTION(*y)) - typeinfo_merge_error("Trying to merge different uninitialized objects.",dest,y); - return false; + if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y)) { + typeinfo_merge_error(m,"Trying to merge uninitialized object type.",dest,y); + return typecheck_FAIL; + } + if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest) != TYPEINFO_NEWOBJECT_INSTRUCTION(*y)) { + typeinfo_merge_error(m,"Trying to merge different uninitialized objects.",dest,y); + return typecheck_FAIL; + } + /* the same uninitialized object -- no change */ + return typecheck_FALSE; } - /* XXX remove */ /* log_text("Testing common case"); */ + /*--------------------------------------------------*/ + /* common cases */ + /*--------------------------------------------------*/ - /* Common case: class dest == class y */ + /* Common case: dest and y are the same class or class reference */ /* (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)) { + if ((dest->typeclass.any == y->typeclass.any) && (!dest->merged || !y->merged)) { +return_simple: changed = (dest->merged != NULL); - TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if? */ + TYPEINFO_FREEMERGED_IF_ANY(dest->merged); 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; + return typecheck_FALSE; } if (TYPEINFO_IS_NULLTYPE(*dest)) { TYPEINFO_FREEMERGED_IF_ANY(dest->merged); TYPEINFO_CLONE(*y,*dest); - return true; + return typecheck_TRUE; } + /* Common case: two types with the same name, at least one unresolved */ + if (IS_CLASSREF(dest->typeclass)) { + if (IS_CLASSREF(y->typeclass)) { + if (dest->typeclass.ref->name == y->typeclass.ref->name) + goto return_simple; + } + else { + /* XXX should we take y instead of dest here? */ + if (dest->typeclass.ref->name == y->typeclass.cls->name) + goto return_simple; + } + } + else { + if (IS_CLASSREF(y->typeclass) + && (dest->typeclass.cls->name == y->typeclass.ref->name)) + { + goto return_simple; + } + } + + /*--------------------------------------------------*/ + /* non-trivial cases */ + /*--------------------------------------------------*/ + +#ifdef TYPEINFO_VERBOSE + fprintf(stderr,"merge:\n"); + typeinfo_print(stderr,dest,4); + typeinfo_print(stderr,y,4); +#endif + /* This function uses x internally, so x and y can be swapped * without changing dest. */ x = dest; @@ -1301,8 +2020,6 @@ typeinfo_merge(typeinfo *dest,typeinfo* y) /* Handle merging of arrays: */ if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) { - /* XXX remove */ /* log_text("Handling arrays"); */ - /* Make x the one with lesser dimension */ if (x->dimension > y->dimension) { tmp = x; x = y; y = tmp; @@ -1313,7 +2030,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y) if (x->dimension < y->dimension) { dimension = x->dimension; elementtype = ARRAYTYPE_OBJECT; - elementclass = pseudo_class_Arraystub; + elementclass.cls = pseudo_class_Arraystub; } else { dimension = y->dimension; @@ -1327,14 +2044,19 @@ typeinfo_merge(typeinfo *dest,typeinfo* y) /* Different element types are merged, so the resulting array * type has one accessible dimension less. */ if (--dimension == 0) { - common = pseudo_class_Arraystub; + common.cls = pseudo_class_Arraystub; elementtype = 0; - elementclass = NULL; + elementclass.any = NULL; } else { - common = class_multiarray_of(dimension,pseudo_class_Arraystub); + common.cls = class_multiarray_of(dimension,pseudo_class_Arraystub,true); + if (!common.cls) { + exceptions_throw_internalerror("XXX Coult not create array class"); + return typecheck_FAIL; + } + elementtype = ARRAYTYPE_OBJECT; - elementclass = pseudo_class_Arraystub; + elementclass.cls = pseudo_class_Arraystub; } } else { @@ -1344,37 +2066,55 @@ typeinfo_merge(typeinfo *dest,typeinfo* y) /* 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"); */ + r = typeinfo_merge_nonarrays(dest, + &elementclass, + x->elementclass, + elementclass, + x->merged,y->merged); + TYPEINFO_ASSERT(r != typecheck_MAYBE); + if (r == typecheck_FAIL) + return r; + changed |= r; + + /* DEBUG */ /* log_text("finding resulting array class: "); */ + if (IS_CLASSREF(elementclass)) + common.ref = class_get_classref_multiarray_of(dimension,elementclass.ref); + else { + common.cls = class_multiarray_of(dimension,elementclass.cls,true); + if (!common.cls) { + exceptions_throw_internalerror("XXX Coult not create array class"); + return typecheck_FAIL; + } + } + /* DEBUG */ /* utf_display_printable_ascii(common->name); printf("\n"); */ } + else { + common.any = y->typeclass.any; + } } } 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); + r = typeinfo_merge_nonarrays(dest, + &common, + x->typeclass,y->typeclass, + x->merged,y->merged); + TYPEINFO_ASSERT(r != typecheck_MAYBE); + if (r == typecheck_FAIL) + return r; + changed |= r; dimension = 0; elementtype = 0; - elementclass = NULL; + elementclass.any = NULL; } /* Put the new values into dest if neccessary. */ - if (dest->typeclass != common) { - dest->typeclass = common; + if (dest->typeclass.any != common.any) { + dest->typeclass.any = common.any; changed = true; } if (dest->dimension != dimension) { @@ -1385,15 +2125,14 @@ typeinfo_merge(typeinfo *dest,typeinfo* y) dest->elementtype = elementtype; changed = true; } - if (dest->elementclass != elementclass) { - dest->elementclass = elementclass; + if (dest->elementclass.any != elementclass.any) { + dest->elementclass.any = elementclass.any; changed = true; } - /* XXX remove */ /* log_text("returning from merge"); */ - return changed; } +#endif /* ENABLE_VERIFER */ /**********************************************************************/ @@ -1402,17 +2141,12 @@ typeinfo_merge(typeinfo *dest,typeinfo* y) #ifdef TYPEINFO_DEBUG -#include "tables.h" -#include "loader.h" -#include "jit/jit.h" - -extern instruction *instr; - +#if 0 static int -typeinfo_test_compare(classinfo **a,classinfo **b) +typeinfo_test_compare(classref_or_classinfo *a,classref_or_classinfo *b) { - if (*a == *b) return 0; - if (*a < *b) return -1; + if (a->any == b->any) return 0; + if (a->any < b->any) return -1; return +1; } @@ -1438,11 +2172,14 @@ typeinfo_test_parse(typeinfo *info,char *str) info->merged->count = num; for (i=0; imerged->list[i] = infobuf[i].typeclass; + if (typebuf[i] != TYPE_ADR) { + log_text("non-reference type in mergedlist"); + assert(0); + } + + info->merged->list[i].any = infobuf[i].typeclass.any; } - qsort(info->merged->list,num,sizeof(classinfo*), + qsort(info->merged->list,num,sizeof(classref_or_classinfo), (int(*)(const void *,const void *))&typeinfo_test_compare); } else { @@ -1450,6 +2187,7 @@ typeinfo_test_parse(typeinfo *info,char *str) &returntype,info); } } +#endif #define TYPEINFO_TEST_BUFLEN 4000 @@ -1458,10 +2196,10 @@ typeinfo_equal(typeinfo *x,typeinfo *y) { int i; - if (x->typeclass != y->typeclass) return false; + if (x->typeclass.any != y->typeclass.any) return false; if (x->dimension != y->dimension) return false; if (x->dimension) { - if (x->elementclass != y->elementclass) return false; + if (x->elementclass.any != y->elementclass.any) return false; if (x->elementtype != y->elementtype) return false; } @@ -1474,7 +2212,7 @@ typeinfo_equal(typeinfo *x,typeinfo *y) if (!(x->merged && y->merged)) return false; if (x->merged->count != y->merged->count) return false; for (i=0; imerged->count; ++i) - if (x->merged->list[i] != y->merged->list[i]) + if (x->merged->list[i].any != y->merged->list[i].any) return false; } return true; @@ -1485,6 +2223,7 @@ typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed) { typeinfo dest; bool changed,changed_should_be; + typecheck_result r; TYPEINFO_CLONE(*a,dest); @@ -1494,7 +2233,12 @@ typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed) typeinfo_print_short(stdout,b); printf("\n"); - changed = (typeinfo_merge(&dest,b)) ? 1 : 0; + r = typeinfo_merge(NULL,&dest,b); + if (r == typecheck_FAIL) { + printf("EXCEPTION\n"); + return; + } + changed = (r) ? 1 : 0; changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0; printf(" %s\n",(changed) ? "changed" : "="); @@ -1519,6 +2263,7 @@ typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed) } } +#if 0 static void typeinfo_inc_dimension(typeinfo *info) { @@ -1526,8 +2271,9 @@ typeinfo_inc_dimension(typeinfo *info) info->elementtype = ARRAYTYPE_OBJECT; info->elementclass = info->typeclass; } - info->typeclass = class_array_of(info->typeclass); + info->typeclass = class_array_of(info->typeclass,true); } +#endif #define TYPEINFO_TEST_MAXDIM 10 @@ -1544,21 +2290,29 @@ typeinfo_testrun(char *filename) FILE *file = fopen(filename,"rt"); int res; - if (!file) - panic("could not open typeinfo test file"); + if (!file) { + log_text("could not open typeinfo test file"); + assert(0); + } while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) { if (buf[0] == '#' || !strlen(buf)) continue; 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)"); + if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc)) { + log_text("Invalid line in typeinfo test file (none of empty, comment or test)"); + assert(0); + } +#if 0 typeinfo_test_parse(&a,bufa); typeinfo_test_parse(&b,bufb); typeinfo_test_parse(&c,bufc); +#endif +#if 0 do { +#endif typeinfo_testmerge(&a,&b,&c,&failed); /* check result */ typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */ @@ -1570,19 +2324,22 @@ typeinfo_testrun(char *filename) if (b.dimension > maxdim) maxdim = b.dimension; if (c.dimension > maxdim) maxdim = c.dimension; +#if 0 if (maxdim < TYPEINFO_TEST_MAXDIM) { typeinfo_inc_dimension(&a); typeinfo_inc_dimension(&b); typeinfo_inc_dimension(&c); } } while (maxdim < TYPEINFO_TEST_MAXDIM); +#endif } fclose(file); if (failed) { fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed); - panic("Failed test"); + log_text("Failed test"); + assert(0); } } @@ -1594,14 +2351,35 @@ typeinfo_test() log_text("Finished typeinfo test file."); } +#if 0 void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc) { typeinfo_init_from_descriptor(info,desc,desc+strlen(desc)); } +#endif #define TYPEINFO_MAXINDENT 80 +void +typeinfo_print_class(FILE *file,classref_or_classinfo c) +{ + /*fprintf(file,"",c.any);*/ + + if (!c.any) { + fprintf(file,""); + } + else { + if (IS_CLASSREF(c)) { + fprintf(file,""); + utf_fprint_printable_ascii(file,c.ref->name); + } + else { + utf_fprint_printable_ascii(file,c.cls->name); + } + } +} + void typeinfo_print(FILE *file,typeinfo *info,int indent) { @@ -1619,7 +2397,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent) if (TYPEINFO_IS_PRIMITIVE(*info)) { bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info); if (bptr) - fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->debug_nr); + fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->nr); else fprintf(file,"%sprimitive\n",ind); return; @@ -1631,10 +2409,10 @@ typeinfo_print(FILE *file,typeinfo *info,int indent) } if (TYPEINFO_IS_NEWOBJECT(*info)) { - ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info); + ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info); if (ins) { - fprintf(file,"%sNEW(%d):",ind,ins-instr); - utf_fprint(file,((classinfo *)ins[-1].val.a)->name); + fprintf(file,"%sNEW(%p):",ind,(void*)ins); + typeinfo_print_class(file,ins[-1].sx.val.c); fprintf(file,"\n"); } else { @@ -1644,7 +2422,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent) } fprintf(file,"%sClass: ",ind); - utf_fprint(file,info->typeclass->name); + typeinfo_print_class(file,info->typeclass); fprintf(file,"\n"); if (TYPEINFO_IS_ARRAY(*info)) { @@ -1661,8 +2439,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent) case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break; case ARRAYTYPE_OBJECT: - fprintf(file,"reference: "); - utf_fprint(file,info->elementclass->name); + typeinfo_print_class(file,info->elementclass); fprintf(file,"\n"); break; @@ -1672,10 +2449,10 @@ typeinfo_print(FILE *file,typeinfo *info,int indent) } if (info->merged) { - fprintf(file,"%sMerged: ",ind); + fprintf(file,"%sMerged: ",ind); for (i=0; imerged->count; ++i) { if (i) fprintf(file,", "); - utf_fprint(file,info->merged->list[i]->name); + typeinfo_print_class(file,info->merged->list[i]); } fprintf(file,"\n"); } @@ -1688,10 +2465,17 @@ typeinfo_print_short(FILE *file,typeinfo *info) instruction *ins; basicblock *bptr; + /*fprintf(file,"",info);*/ + + if (!info) { + fprintf(file,"(typeinfo*)NULL"); + return; + } + if (TYPEINFO_IS_PRIMITIVE(*info)) { bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info); if (bptr) - fprintf(file,"ret(L%03d)",bptr->debug_nr); + fprintf(file,"ret(L%03d)",bptr->nr); else fprintf(file,"primitive"); return; @@ -1703,23 +2487,24 @@ typeinfo_print_short(FILE *file,typeinfo *info) } if (TYPEINFO_IS_NEWOBJECT(*info)) { - ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info); + ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info); if (ins) { - fprintf(file,"NEW(%d):",ins-instr); - utf_fprint(file,((classinfo *)ins[-1].val.a)->name); + /*fprintf(file,"",ins);*/ + fprintf(file,"NEW(%p):",(void*)ins); + typeinfo_print_class(file,ins[-1].sx.val.c); } else fprintf(file,"NEW(this)"); return; } - utf_fprint(file,info->typeclass->name); + typeinfo_print_class(file,info->typeclass); if (info->merged) { fprintf(file,"{"); for (i=0; imerged->count; ++i) { if (i) fprintf(file,","); - utf_fprint(file,info->merged->list[i]->name); + typeinfo_print_class(file,info->merged->list[i]); } fprintf(file,"}"); } @@ -1729,12 +2514,13 @@ 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: + case TYPE_VOID: fprintf(file,"V"); break; + case TYPE_INT: fprintf(file,"I"); break; + case TYPE_FLT: fprintf(file,"F"); break; + case TYPE_DBL: fprintf(file,"D"); break; + case TYPE_LNG: fprintf(file,"J"); break; + case TYPE_RET: fprintf(file,"R:"); /* FALLTHROUGH! */ + case TYPE_ADR: typeinfo_print_short(file,info); break; @@ -1743,65 +2529,20 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info) } } -void -typeinfo_print_stacktype(FILE *file,int type,typeinfo *info) -{ - if (type == TYPE_ADDRESS && TYPEINFO_IS_PRIMITIVE(*info)) { - typeinfo_retaddr_set *set = (typeinfo_retaddr_set*) - TYPEINFO_RETURNADDRESS(*info); - fprintf(file,"ret(L%03d",((basicblock*)(set->addr))->debug_nr); - set = set->alt; - while (set) { - fprintf(file,"|L%03d",((basicblock*)(set->addr))->debug_nr); - set = set->alt; - } - fprintf(file,")"); - } - else - typeinfo_print_type(file,type,info); -} - void typedescriptor_print(FILE *file,typedescriptor *td) { - typeinfo_print_type(file,td->type,&(td->info)); -} - -void -typevector_print(FILE *file,typevector *vec,int size) -{ - int i; - - fprintf(file,"[%d]",vec->k); - for (i=0; ik); - vec = set->alt; - while (vec) { - fprintf(file,"|%d",vec->k); - vec = vec->alt; - } - fprintf(file,"]"); - for (i=0; itd + i); - vec = vec->alt; - } + typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo)); } } @@ -1819,4 +2560,5 @@ typevectorset_print(FILE *file,typevector *set,int size) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */