-/* 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.
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 1067 2004-05-18 10:25:51Z stefan $
+#include "config.h"
-*/
+#include <assert.h>
+#include <string.h>
+#include "mm/memory.h"
-#include <stdlib.h>
-#include <string.h>
-#include "typeinfo.h"
-#include "tables.h"
-#include "loader.h"
#include "toolbox/logging.h"
-#include "toolbox/memory.h"
-#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
+#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"
+
+
+/* check if a linked class is an array class. Only use for linked classes! */
+#define CLASSINFO_IS_ARRAY(clsinfo) ((clsinfo)->vftbl->arraydesc != NULL)
-#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
+/* 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;
-
- 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;
-}
+/* 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
-int
-typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result)
-{
- if (vec->alt) {
- *result = temp;
- return typevectorset_copymergedtype(vec,index,temp);
- }
+ RETURN VALUE:
+ true if the typevector contains a returnAddress at INDEX,
+ false otherwise
- *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)
{
- 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));
- 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)
-{
- 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; i<size; ++i) {
- if (set->td[i].type == TYPE_ADR
- && TYPEINFO_IS_NEWOBJECT(set->td[i].info)
- && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins)
- {
- TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass);
- }
+
+ for (i=0; i<size; ++i) {
+ if (set[i].type == TYPE_ADR
+ && TYPEINFO_IS_NEWOBJECT(set[i].typeinfo)
+ && TYPEINFO_NEWOBJECT_INSTRUCTION(set[i].typeinfo) == ins)
+ {
+ if (!typeinfo_init_class(&(set[i].typeinfo),initclass))
+ return false;
}
}
+ return true;
}
-bool
-typevector_merge(typevector *dst,typevector *y,int size)
+/* typevector_merge ************************************************************
+
+ Merge a typevector with another one.
+ The given typevectors must have the same number of components.
+
+ IN:
+ m................method for exception messages
+ dst..............the first typevector
+ y................the second typevector
+ size.............number of elements per typevector
+
+ OUT:
+ *dst.............the resulting typevector
+
+ RETURN VALUE:
+ typecheck_TRUE...dst has been modified
+ typecheck_FALSE..dst has not been modified
+ typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size)
{
bool changed = false;
+ typecheck_result r;
- typedescriptor *a = dst->td;
- 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;
}
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;
}
}
}
return changed;
}
-bool typevector_separable_from(typevector *a,typevector *b,int size)
-{
- typedescriptor *tda = a->td;
- typedescriptor *tdb = b->td;
- for (;size--; tda++,tdb++) {
- if (TYPEDESC_IS_RETURNADDRESS(*tda)
- && TYPEDESC_IS_RETURNADDRESS(*tdb)
- && TYPEINFO_RETURNADDRESS(tda->info)
- != TYPEINFO_RETURNADDRESS(tdb->info))
- return true;
- }
- return false;
-}
-
-void
-typevectorset_add(typevector *dst,typevector *v,int size)
-{
- while (dst->alt)
- dst = dst->alt;
- dst->alt = DNEW_TYPEVECTOR(size);
- memcpy(dst->alt,v,TYPEVECTOR_SIZE(size));
- dst->alt->alt = NULL;
- dst->alt->k = dst->k + 1;
-}
-
-typevector *
-typevectorset_select(typevector **set,int retindex,void *retaddr)
-{
- typevector *selected;
-
- if (!*set) return NULL;
-
- if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) {
- selected = *set;
- *set = selected->alt;
- selected->alt = typevectorset_select(set,retindex,retaddr);
- }
- else {
- selected = typevectorset_select(&((*set)->alt),retindex,retaddr);
- }
- return selected;
-}
-
-bool
-typevectorset_separable_with(typevector *set,typevector *add,int size)
-{
- int i;
- typevector *v;
- void *addr;
- bool separable;
-
- for (i=0; i<size; ++i) {
- if (!TYPEDESC_IS_RETURNADDRESS(add->td[i]))
- continue;
- addr = TYPEINFO_RETURNADDRESS(add->td[i].info);
-
- v = set;
- separable = false;
- do {
- if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
- goto next_index;
- if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr)
- separable = true;
- v = v->alt;
- if (!v && separable) return true;
- } while (v);
- next_index:
- ;
- }
- return false;
-}
-
-bool
-typevectorset_collapse(typevector *dst,int size)
-{
- bool changed = false;
-
- while (dst->alt) {
- typevector_merge(dst,dst->alt,size);
- dst->alt = dst->alt->alt;
- changed = true;
- }
- return changed;
-}
-
/**********************************************************************/
/* READ-ONLY FUNCTIONS */
/* The following functions don't change typeinfo data. */
/**********************************************************************/
+/* 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; i<cls->interfacescount; ++i) {
- if (cls->interfaces[i] == interf)
+ if (cls->interfaces[i].cls == interf)
return true;
}
/* check indirect superinterfaces */
for (i=0; i<cls->interfacescount; ++i) {
- if (interface_extends_interface(cls->interfaces[i],interf))
+ if (interface_extends_interface(cls->interfaces[i].cls,interf))
return true;
}
return false;
}
-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.
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;
+
+ TYPEINFO_ASSERT(cls);
+
+ /* primitive types aren't subclasses of anything. */
+ if (!typeclass)
+ return typecheck_FALSE;
- return typeinfo_is_assignable_to_classinfo(value,dest->typeclass);
+ /* 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;
}
-bool
-typeinfo_is_assignable_to_classinfo(typeinfo *value,classinfo *dest)
+/* 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;
- cls = value->typeclass;
+ TYPEINFO_ASSERT(value);
+
+ c = value->typeclass;
/* assignments of primitive values are not checked here. */
- if (!cls && !dest)
- return true;
+ if (!c.any && !dest.any)
+ return typecheck_TRUE;
/* primitive and reference types are not assignment compatible. */
- if (!cls || !dest)
- return false;
-
- /* maybe we need to load and link the class */
- if (!cls->loaded)
- class_load(cls);
-
- if (!cls->linked)
- class_link(cls);
+ if (!c.any || !dest.any)
+ return typecheck_FALSE;
-#ifdef TYPEINFO_DEBUG
- if (!dest->linked)
- panic("Internal error: typeinfo_is_assignable_to_classinfo: unlinked class.");
-#endif
-
/* the null type can be assigned to any type */
if (TYPEINFO_IS_NULLTYPE(*value))
- return true;
+ 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 (dest->flags & ACC_INTERFACE) {
+ 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;
+
+ /* 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);
+ return merged_implements_interface(cls,value->merged,dest.cls);
}
- if (CLASS_IS_ARRAY(dest)) {
- arraydescriptor *arraydesc = dest->vftbl->arraydesc;
+ 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. */
+ /* value must have at least the dimension of dest.cls. */
if (value->dimension < dimension)
- return false;
+ return typecheck_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 */
+ * element type of dest.cls */
- if (!elementclass) return false;
+ if (!elementclass) return typecheck_FALSE;
if (elementclass->flags & ACC_INTERFACE) {
/* We are assigning to an interface type. */
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 != arraydesc->elementtype)
- return false;
+ 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 (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,
elementclass);
}
/* We are assigning to a class type. */
- return class_issubclass(value->elementclass,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);
+ return merged_is_subclass(cls,value->merged,dest.cls);
+}
+
+/* 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)
+{
+ TYPEINFO_ASSERT(value);
+ TYPEINFO_ASSERT(dest);
+ TYPEINFO_ASSERT(dest->merged == NULL);
+
+ return typeinfo_is_assignable_to_class(value,dest->typeclass);
}
/**********************************************************************/
/* The following functions fill in uninitialized typeinfo structures. */
/**********************************************************************/
+/* typeinfo_init_classinfo *****************************************************
+
+ Initialize a typeinfo to a resolved class.
+
+ IN:
+ c................the class
+
+ OUT:
+ *info............is initialized
+
+ RETURN VALUE:
+ true.............success
+ false............an exception has been thrown
+
+*******************************************************************************/
+
void
-typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
+typeinfo_init_classinfo(typeinfo *info, classinfo *c)
{
- classinfo *cls;
- char *end;
+ 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
- cls = class_from_descriptor(utf_ptr,end_ptr,&end,
- CLASSLOAD_NULLPRIMITIVE
- | CLASSLOAD_NEW
- | CLASSLOAD_NOVOID
- | CLASSLOAD_CHECKEND);
+ OUT:
+ *info............is initialized
- if (cls) {
- if (!cls->loaded)
- class_load(cls);
+ RETURN VALUE:
+ true.............success
+ false............an exception has been thrown
- if (!cls->linked)
- class_link(cls);
+*******************************************************************************/
- /* a class, interface or array descriptor */
- TYPEINFO_INIT_CLASSINFO(*info,cls);
- } else {
- /* a primitive type */
- TYPEINFO_INIT_PRIMITIVE(*info);
+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;
+ }
+
+ if (cls) {
+ typeinfo_init_classinfo(info,cls);
+ return true;
+ }
+
+ /* {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;
}
-int
-typeinfo_count_method_args(utf *d,bool twoword)
+/* typeinfo_init_from_typedesc *************************************************
+
+ Initialize a typeinfo from a typedesc.
+
+ IN:
+ desc.............the typedesc
+
+ OUT:
+ *type............set to the TYPE_* constant of DESC (if type != NULL)
+ *info............receives the typeinfo (if info != NULL)
+
+ RETURN VALUE:
+ true.............success
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo *info)
{
- int args = 0;
- char *utf_ptr = d->text;
- char *end_pos = utf_end(d);
- char c;
+ TYPEINFO_ASSERT(desc);
- /* method descriptor must start with parenthesis */
- if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+#ifdef TYPEINFO_VERBOSE
+ fprintf(stderr,"typeinfo_init_from_typedesc(");
+ descriptor_debug_print_typedesc(stderr,desc);
+ fprintf(stderr,")\n");
+#endif
-
- /* 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++;
- }
+ if (type)
+ *type = desc->type;
- return args;
+ 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;
}
-void
-typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
- int buflen,bool twoword,
- int *returntype,typeinfo *returntypeinfo)
+/* 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.
+
+*******************************************************************************/
+
+bool
+typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,typeinfo *infobuf,
+ int buflen,bool twoword,
+ u1 *returntype,typeinfo *returntypeinfo)
{
- 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.");
-
- *typebuf++ = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
- CLASSLOAD_NEW
- | CLASSLOAD_NULLPRIMITIVE
- | CLASSLOAD_NOVOID);
-
- if (cls) {
- if (!cls->loaded)
- class_load(cls);
- if (!cls->linked)
- class_link(cls);
+ TYPEINFO_ASSERT(desc);
+ TYPEINFO_ASSERT(typebuf);
+ TYPEINFO_ASSERT(infobuf);
- TYPEINFO_INIT_CLASSINFO(*infobuf, cls);
+#ifdef TYPEINFO_VERBOSE
+ fprintf(stderr,"typeinfos_init_from_methoddesc(");
+ descriptor_debug_print_methoddesc(stderr,desc);
+ fprintf(stderr,")\n");
+#endif
- } else {
- TYPEINFO_INIT_PRIMITIVE(*infobuf);
+ /* check arguments */
+ for (i=0; i<desc->paramcount; ++i) {
+ if (++args > buflen) {
+ exceptions_throw_internalerror("Buffer too small for method arguments.");
+ return false;
}
- infobuf++;
- if (twoword && (typebuf[-1] == TYPE_LONG || typebuf[-1] == TYPE_DOUBLE)) {
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
+ 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++;
}
}
- 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 (!typeinfo_init_from_typedesc(&(desc->returntype),returntype,returntypeinfo))
+ return false;
+ }
+
+ return true;
+}
- if (returntypeinfo) {
- if (cls) {
- if (!cls->loaded)
- class_load(cls);
+/* typedescriptor_init_from_typedesc *******************************************
+
+ Initialize a typedescriptor from a typedesc.
+
+ IN:
+ desc.............the typedesc
- if (!cls->linked)
- class_link(cls);
+ OUT:
+ *td..............receives the typedescriptor
+ td must be != NULL
- TYPEINFO_INIT_CLASSINFO(*returntypeinfo, cls);
+ RETURN VALUE:
+ true.............success
+ false............an exception has been thrown
- } else {
- TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
- }
- }
+*******************************************************************************/
+
+bool
+typedescriptor_init_from_typedesc(typedescriptor *td,
+ typedesc *desc)
+{
+ 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
-typedescriptors_init_from_method_args(typedescriptor *td,
- utf *desc,
- int buflen,bool twoword,
- typedescriptor *returntype)
+/* typeinfo_init_varinfo_from_typedesc *****************************************
+
+ Initialize a varinfo from a typedesc.
+
+ IN:
+ desc.............the typedesc
+
+ OUT:
+ *var.............receives the type
+ var must be != NULL
+
+ RETURN VALUE:
+ true.............success
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+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;
+}
- /* method descriptor must start with parenthesis */
- if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+/* 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.
+
+*******************************************************************************/
+
+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; i<startindex; ++i) {
+ slot++;
+ if (IS_2_WORD_TYPE(desc->paramtypes[i].type))
+ slot++;
+ }
/* check arguments */
- while (utf_ptr != end_pos && *utf_ptr != ')') {
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
-
- td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
- CLASSLOAD_NEW
- | CLASSLOAD_NULLPRIMITIVE
- | CLASSLOAD_NOVOID);
-
- if (cls) {
- if (!cls->loaded)
- class_load(cls);
+ for (i=startindex; i<desc->paramcount; ++i) {
+ type = desc->paramtypes[i].type;
+ varindex = map[5*slot + type];
- if (!cls->linked)
- class_link(cls);
+ slot++;
+ if (IS_2_WORD_TYPE(type))
+ slot++;
- TYPEINFO_INIT_CLASSINFO(td->info, cls);
-
- } else {
- TYPEINFO_INIT_PRIMITIVE(td->info);
- }
- td++;
+ if (varindex == UNUSED)
+ continue;
- if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
- td->type = TYPE_VOID;
- TYPEINFO_INIT_PRIMITIVE(td->info);
- td++;
+ 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 = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
- CLASSLOAD_NULLPRIMITIVE
- | CLASSLOAD_NEW
- | CLASSLOAD_CHECKEND);
- if (cls) {
- if (!cls->loaded)
- class_load(cls);
+ if (!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_methoddesc(typedescriptor *td,
+ methoddesc *desc,
+ int buflen,bool twoword,int startindex,
+ typedescriptor *returntype)
+{
+ int i;
+ int args = 0;
- if (!cls->linked)
- class_link(cls);
+ /* check arguments */
+ for (i=startindex; i<desc->paramcount; ++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++;
- TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+ 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;
+ }
- } else {
- TYPEINFO_INIT_PRIMITIVE(returntype->info);
+ td->type = TYPE_VOID;
+ TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
+ td++;
}
+ }
+
+ /* check returntype */
+ if (returntype) {
+ 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;
}
- 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) */
+
+ 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;
/* 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)
{
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;
}
/* 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;
newlist = newmerged->list;
mlist = m->list;
while (count) {
- if (*mlist > cls)
+ if (mlist->any > cls.any)
break;
*newlist++ = *mlist++;
count--;
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.) */
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--;
}
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--;
}
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;
- /* DEBUG */
- /*
-#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 case: clsx == clsy */
+ /*--------------------------------------------------*/
+ /* common cases */
+ /*--------------------------------------------------*/
+
+ /* 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.)
*/
- if ((clsx == clsy) && (!mergedx || !mergedy)) {
+ if ( (x.any == y.any) && (!mergedx || !mergedy) ) {
return_simple_x:
/* DEBUG */ /* log_text("return simple x"); */
changed = (dest->merged != NULL);
TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
dest->merged = NULL;
- *result = clsx;
+ *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,"<ref>");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n");
+ fprintf(stderr," ");if(IS_CLASSREF(y))fprintf(stderr,"<ref>");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} */
- /* {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.} */
-
- /* There may still be superinterfaces of x which are implemented
- * by y, too, so we have to add clsx to the mergedlist.
- */
+ * of subclasses and is not guaranteed to implement x.} */
- /* 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;
- /* DEBUG */
- /*
-#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;
}
- /* DEBUG */ /* 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.)
*/
- 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); /* unify if? */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
dest->merged = NULL;
- /* DEBUG */ /* log_text("common case handled"); */
return changed;
}
- /* DEBUG */ /* 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;
/* Handle merging of arrays: */
if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
- /* DEBUG */ /* log_text("Handling arrays"); */
-
/* Make x the one with lesser dimension */
if (x->dimension > y->dimension) {
tmp = x; x = y; y = tmp;
if (x->dimension < y->dimension) {
dimension = x->dimension;
elementtype = ARRAYTYPE_OBJECT;
- elementclass = pseudo_class_Arraystub;
+ elementclass.cls = pseudo_class_Arraystub;
}
else {
dimension = y->dimension;
/* 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 {
/* The elements are references, so their respective
* types must be merged.
*/
- changed |= typeinfo_merge_nonarrays(dest,
- &elementclass,
- x->elementclass,
- elementclass,
- x->merged,y->merged);
+ 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: "); */
- common = class_multiarray_of(dimension,elementclass);
- /* DEBUG */ /* utf_display(common->name); printf("\n"); */
+ 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) {
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;
}
- /* DEBUG */ /* log_text("returning from merge"); */
-
return changed;
}
+#endif /* ENABLE_VERIFER */
/**********************************************************************/
#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;
}
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;
+ 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 {
&returntype,info);
}
}
+#endif
#define TYPEINFO_TEST_BUFLEN 4000
{
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;
}
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])
+ if (x->merged->list[i].any != y->merged->list[i].any)
return false;
}
return true;
{
typeinfo dest;
bool changed,changed_should_be;
+ typecheck_result r;
TYPEINFO_CLONE(*a,dest);
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" : "=");
}
}
+#if 0
static void
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
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 */
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);
}
}
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,"<class %p>",c.any);*/
+
+ if (!c.any) {
+ fprintf(file,"<null>");
+ }
+ else {
+ if (IS_CLASSREF(c)) {
+ fprintf(file,"<ref>");
+ 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)
{
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;
}
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 {
}
fprintf(file,"%sClass: ",ind);
- utf_fprint(file,info->typeclass->name);
+ typeinfo_print_class(file,info->typeclass);
fprintf(file,"\n");
if (TYPEINFO_IS_ARRAY(*info)) {
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;
}
if (info->merged) {
- fprintf(file,"%sMerged: ",ind);
+ fprintf(file,"%sMerged: ",ind);
for (i=0; i<info->merged->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");
}
instruction *ins;
basicblock *bptr;
+ /*fprintf(file,"<typeinfo %p>",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;
}
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 %p>",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; i<info->merged->count; ++i) {
if (i) fprintf(file,",");
- utf_fprint(file,info->merged->list[i]->name);
+ typeinfo_print_class(file,info->merged->list[i]);
}
fprintf(file,"}");
}
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;
}
}
-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));
+ typeinfo_print_type(file,td->type,&(td->typeinfo));
}
void
-typevector_print(FILE *file,typevector *vec,int size)
+typevector_print(FILE *file,varinfo *vec,int size)
{
int i;
- fprintf(file,"[%d]",vec->k);
for (i=0; i<size; ++i) {
fprintf(file," %d=",i);
- typedescriptor_print(file,vec->td + i);
- }
-}
-
-void
-typevectorset_print(FILE *file,typevector *set,int size)
-{
- int i;
- typevector *vec;
-
- fprintf(file,"[%d",set->k);
- vec = set->alt;
- while (vec) {
- fprintf(file,"|%d",vec->k);
- vec = vec->alt;
- }
- fprintf(file,"]");
-
- for (i=0; i<size; ++i) {
- fprintf(file," %d=",i);
- typedescriptor_print(file,set->td + i);
- vec = set->alt;
- while (vec) {
- fprintf(file,"|");
- typedescriptor_print(file,vec->td + i);
- vec = vec->alt;
- }
+ typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo));
}
}
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/