-/********************************* typeinfo.c *********************************
+/* typeinfo.c - type system used by the type checker
- Copyright (c) 2003 ? XXX
+ 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
- See file COPYRIGHT for information on usage and disclaimer of warranties
+ This file is part of CACAO.
- functions for the compiler's type system
-
- Authors: Edwin Steiner
-
- Last Change:
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ 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.
+
+ Contact: cacao@complang.tuwien.ac.at
-*******************************************************************************/
+ Authors: Edwin Steiner
+ $Id: typeinfo.c 1191 2004-06-19 12:46:00Z twisti $
+
+*/
+
+
+#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/ */
-#define TYPEINFO_REUSE_MERGED
#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
( ((index) < (cls)->vftbl->interfacetablelength) \
&& (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS */
+/**********************************************************************/
+
+typevector *
+typevectorset_copy(typevector *src,int k,int size)
+{
+ typevector *dst = DNEW_TYPEVECTOR(size);
+
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ dst->k = k;
+ if (src->alt)
+ dst->alt = typevectorset_copy(src->alt,k+1,size);
+ return dst;
+}
+
+bool
+typevectorset_checktype(typevector *vec,int index,int type)
+{
+ do {
+ if (vec->td[index].type != type)
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+bool
+typevectorset_checkreference(typevector *vec,int index)
+{
+ do {
+ if (!TYPEDESC_IS_REFERENCE(vec->td[index]))
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+bool
+typevectorset_checkretaddr(typevector *vec,int index)
+{
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(vec->td[index]))
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+int
+typevectorset_copymergedtype(typevector *vec,int index,typeinfo *dst)
+{
+ int type;
+ typedescriptor *td;
+
+ td = vec->td + index;
+ type = td->type;
+ TYPEINFO_COPY(td->info,*dst);
+
+ if (vec->alt) {
+ int primitive;
+
+ primitive = TYPEINFO_IS_PRIMITIVE(*dst) ? 1 : 0;
+
+ while ((vec = vec->alt) != NULL) {
+ td = vec->td + index;
+ if (type != td->type)
+ return TYPE_VOID;
+
+ if (type == TYPE_ADDRESS) {
+ if ((TYPEINFO_IS_PRIMITIVE(td->info) ? 1 : 0) != primitive)
+ return TYPE_VOID;
+ typeinfo_merge(dst,&(td->info));
+ }
+ }
+ }
+ return type;
+}
+
+int
+typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result)
+{
+ if (vec->alt) {
+ *result = temp;
+ return typevectorset_copymergedtype(vec,index,temp);
+ }
+
+ *result = &(vec->td[index].info);
+ return vec->td[index].type;
+}
+
+typeinfo *
+typevectorset_mergedtypeinfo(typevector *vec,int index,typeinfo *temp)
+{
+ typeinfo *result;
+ int type = typevectorset_mergedtype(vec,index,temp,&result);
+ return (type == TYPE_ADDRESS) ? result : NULL;
+}
+
+void
+typevectorset_store(typevector *vec,int index,int type,typeinfo *info)
+{
+ do {
+ vec->td[index].type = type;
+ if (info)
+ TYPEINFO_COPY(*info,vec->td[index].info);
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_retaddr(typevector *vec,int index,typeinfo *info)
+{
+ typeinfo_retaddr_set *adr;
+
+ adr = (typeinfo_retaddr_set*) TYPEINFO_RETURNADDRESS(*info);
+ do {
+ vec->td[index].type = TYPE_ADDRESS;
+ TYPEINFO_INIT_RETURNADDRESS(vec->td[index].info,adr->addr);
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ adr = adr->alt;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_twoword(typevector *vec,int index,int type)
+{
+ do {
+ vec->td[index].type = type;
+ vec->td[index+1].type = TYPE_VOID;
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,
+ int size)
+{
+ int i;
+
+ for (;set; set=set->alt) {
+ for (i=0; i<size; ++i) {
+ if (set->td[i].type == TYPE_ADR
+ && TYPEINFO_IS_NEWOBJECT(set->td[i].info)
+ && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins)
+ {
+ TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass);
+ }
+ }
+ }
+}
+
+bool
+typevector_merge(typevector *dst,typevector *y,int size)
+{
+ bool changed = false;
+
+ typedescriptor *a = dst->td;
+ typedescriptor *b = y->td;
+ while (size--) {
+ if (a->type != TYPE_VOID && a->type != b->type) {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ else if (a->type == TYPE_ADDRESS) {
+ if (TYPEINFO_IS_PRIMITIVE(a->info)) {
+ /* 'a' is a returnAddress */
+ if (!TYPEINFO_IS_PRIMITIVE(b->info)
+ || (TYPEINFO_RETURNADDRESS(a->info)
+ != TYPEINFO_RETURNADDRESS(b->info)))
+ {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ }
+ else {
+ /* 'a' is a reference */
+ if (TYPEINFO_IS_PRIMITIVE(b->info)) {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ else {
+ changed |= typeinfo_merge(&(a->info),&(b->info));
+ }
+ }
+ }
+ a++;
+ b++;
+ }
+ return changed;
+}
+
+bool typevector_separable_from(typevector *a,typevector *b,int size)
+{
+ typedescriptor *tda = a->td;
+ typedescriptor *tdb = b->td;
+ for (;size--; tda++,tdb++) {
+ if (TYPEDESC_IS_RETURNADDRESS(*tda)
+ && TYPEDESC_IS_RETURNADDRESS(*tdb)
+ && TYPEINFO_RETURNADDRESS(tda->info)
+ != TYPEINFO_RETURNADDRESS(tdb->info))
+ return true;
+ }
+ return false;
+}
+
+void
+typevectorset_add(typevector *dst,typevector *v,int size)
+{
+ while (dst->alt)
+ dst = dst->alt;
+ dst->alt = DNEW_TYPEVECTOR(size);
+ memcpy(dst->alt,v,TYPEVECTOR_SIZE(size));
+ dst->alt->alt = NULL;
+ dst->alt->k = dst->k + 1;
+}
+
+typevector *
+typevectorset_select(typevector **set,int retindex,void *retaddr)
+{
+ typevector *selected;
+
+ if (!*set) return NULL;
+
+ if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) {
+ selected = *set;
+ *set = selected->alt;
+ selected->alt = typevectorset_select(set,retindex,retaddr);
+ }
+ else {
+ selected = typevectorset_select(&((*set)->alt),retindex,retaddr);
+ }
+ return selected;
+}
+
+bool
+typevectorset_separable_with(typevector *set,typevector *add,int size)
+{
+ int i;
+ typevector *v;
+ void *addr;
+ bool separable;
+
+ for (i=0; i<size; ++i) {
+ if (!TYPEDESC_IS_RETURNADDRESS(add->td[i]))
+ continue;
+ addr = TYPEINFO_RETURNADDRESS(add->td[i].info);
+
+ v = set;
+ separable = false;
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+ goto next_index;
+ if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr)
+ separable = true;
+ v = v->alt;
+ if (!v && separable) return true;
+ } while (v);
+ next_index:
+ ;
+ }
+ return false;
+}
+
+bool
+typevectorset_collapse(typevector *dst,int size)
+{
+ bool changed = false;
+
+ while (dst->alt) {
+ typevector_merge(dst,dst->alt,size);
+ dst->alt = dst->alt->alt;
+ changed = true;
+ }
+ return changed;
+}
+
/**********************************************************************/
/* READ-ONLY FUNCTIONS */
/* The following functions don't change typeinfo data. */
return false;
}
-/* XXX If really a performance issue, this could become a macro. */
static
bool
classinfo_implements_interface(classinfo *cls,classinfo *interf)
{
+ if (!cls->loaded)
+ if (!class_load(cls))
+ return false;
+
+ if (!cls->linked)
+ if (!class_link(cls))
+ return false;
+
if (cls->flags & ACC_INTERFACE) {
/* cls is an interface */
if (cls == interf)
bool
typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
{
- classinfo *cls;
-
- cls = value->typeclass;
-
/* DEBUG CHECK: dest must not have a merged list. */
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (dest->merged)
panic("Internal error: typeinfo_is_assignable on merged destination.");
#endif
-
+
+ return typeinfo_is_assignable_to_classinfo(value,dest->typeclass);
+}
+
+bool
+typeinfo_is_assignable_to_classinfo(typeinfo *value,classinfo *dest)
+{
+ classinfo *cls;
+
+ cls = value->typeclass;
+
/* assignments of primitive values are not checked here. */
- if (!cls && !dest->typeclass)
+ if (!cls && !dest)
return true;
+ /* primitive and reference types are not assignment compatible. */
+ if (!cls || !dest)
+ return false;
+
+ /* maybe we need to load and link the class */
+ if (!cls->loaded)
+ class_load(cls);
+
+ if (!cls->linked)
+ class_link(cls);
+
+#ifdef TYPEINFO_DEBUG
+ if (!dest->linked)
+ panic("Internal error: typeinfo_is_assignable_to_classinfo: unlinked class.");
+#endif
+
/* the null type can be assigned to any type */
if (TYPEINFO_IS_NULLTYPE(*value))
return true;
- /* primitive and reference types are not assignment compatible. */
- if (!cls || !dest->typeclass)
+ /* uninitialized objects are not assignable */
+ if (TYPEINFO_IS_NEWOBJECT(*value))
return false;
- if (dest->typeclass->flags & ACC_INTERFACE) {
+ if (dest->flags & ACC_INTERFACE) {
/* We are assigning to an interface type. */
- return merged_implements_interface(cls,value->merged,
- dest->typeclass);
+ return merged_implements_interface(cls,value->merged,dest);
}
- if (TYPEINFO_IS_ARRAY(*dest)) {
+ if (CLASS_IS_ARRAY(dest)) {
+ arraydescriptor *arraydesc = dest->vftbl->arraydesc;
+ int dimension = arraydesc->dimension;
+ classinfo *elementclass = (arraydesc->elementvftbl)
+ ? arraydesc->elementvftbl->class : NULL;
+
/* We are assigning to an array type. */
if (!TYPEINFO_IS_ARRAY(*value))
return false;
/* {Both value and dest are array types.} */
/* value must have at least the dimension of dest. */
- if (value->dimension < dest->dimension)
+ if (value->dimension < dimension)
return false;
- if (value->dimension > dest->dimension) {
+ if (value->dimension > dimension) {
/* value has higher dimension so we need to check
* if its component array can be assigned to the
* element type of dest */
+
+ if (!elementclass) return false;
- if (dest->elementclass->flags & ACC_INTERFACE) {
+ if (elementclass->flags & ACC_INTERFACE) {
/* We are assigning to an interface type. */
return classinfo_implements_interface(pseudo_class_Arraystub,
- dest->elementclass);
+ elementclass);
}
/* We are assigning to a class type. */
- return class_issubclass(pseudo_class_Arraystub,dest->elementclass);
+ return class_issubclass(pseudo_class_Arraystub,elementclass);
}
/* {value and dest have the same dimension} */
- if (value->elementtype != dest->elementtype)
+ if (value->elementtype != arraydesc->elementtype)
return false;
if (value->elementclass) {
* check if the elements are assignable.
*/
- if (dest->elementclass->flags & ACC_INTERFACE) {
+ if (elementclass->flags & ACC_INTERFACE) {
/* We are assigning to an interface type. */
return merged_implements_interface(value->elementclass,
value->merged,
- dest->elementclass);
+ elementclass);
}
/* We are assigning to a class type. */
- return class_issubclass(value->elementclass,dest->elementclass);
+ return class_issubclass(value->elementclass,elementclass);
}
return true;
if (cls->flags & ACC_INTERFACE)
cls = class_java_lang_Object;
- return class_issubclass(cls,dest->typeclass);
+ return class_issubclass(cls,dest);
}
/**********************************************************************/
/* The following functions fill in uninitialized typeinfo structures. */
/**********************************************************************/
-/* XXX delete */
-#if 0
-void
-typeinfo_init_from_arraydescriptor(typeinfo *info,
- constant_arraydescriptor *desc)
-{
- int dim = 1;
-
- /* Arrays are instances of the pseudo class Array. */
- info->typeclass = pseudo_class_Array; /* XXX */
- info->merged = NULL;
-
- /* Handle multidimensional arrays */
- while (desc->arraytype == ARRAYTYPE_ARRAY) {
- dim++;
- desc = desc->elementdescriptor;
- }
-
- info->dimension = dim;
-
- if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
- info->elementclass = desc->objectclass;
- }
- else {
- info->elementclass = NULL;
- }
-}
-#endif
-
void
typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
{
classinfo *cls;
char *end;
- cls = class_from_descriptor(utf_ptr,end_ptr,&end,CLASSLOAD_NEW);
- if (!cls)
- panic("Invalid descriptor.");
-
- switch (*utf_ptr) {
- case 'L':
- case '[':
- /* a class, interface or array descriptor */
- TYPEINFO_INIT_CLASSINFO(*info,cls);
- break;
- default:
- /* a primitive type */
- TYPEINFO_INIT_PRIMITIVE(*info);
- }
-
- /* exceeding characters */
- if (end!=end_ptr) panic ("descriptor has exceeding chars");
+ cls = class_from_descriptor(utf_ptr,end_ptr,&end,
+ CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NEW
+ | CLASSLOAD_NOVOID
+ | CLASSLOAD_CHECKEND);
+
+ if (cls) {
+ if (!cls->loaded)
+ class_load(cls);
+
+ if (!cls->linked)
+ class_link(cls);
+
+ /* a class, interface or array descriptor */
+ TYPEINFO_INIT_CLASSINFO(*info,cls);
+ } else {
+ /* a primitive type */
+ TYPEINFO_INIT_PRIMITIVE(*info);
+ }
}
int
int args = 0;
char *utf_ptr = d->text;
char *end_pos = utf_end(d);
- char c,ch;
+ char c;
/* method descriptor must start with parenthesis */
if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
/* check arguments */
- while ((c = *utf_ptr++) != ')') {
- switch (c) {
- case 'B':
- case 'C':
- case 'I':
- case 'S':
- case 'Z':
- case 'F':
- /* primitive one-word type */
- args++;
- break;
-
- case 'J':
- case 'D':
- /* primitive two-word type */
- args++;
- if (twoword) args++;
- break;
-
- case 'L':
- /* skip classname */
- while ( *utf_ptr++ != ';' )
- if (utf_ptr>=end_pos)
- panic ("Missing ';' in objecttype-descriptor");
-
- args++;
- break;
-
- case '[' :
- /* array type */
- while ((ch = *utf_ptr++)=='[')
- /* skip */ ;
-
- /* component type of array */
- switch (ch) {
- case 'B':
- case 'C':
- case 'I':
- case 'S':
- case 'Z':
- case 'J':
- case 'F':
- case 'D':
- /* primitive type */
- break;
-
- case 'L':
- /* skip classname */
- while ( *utf_ptr++ != ';' )
- if (utf_ptr>=end_pos)
- panic ("Missing ';' in objecttype-descriptor");
- break;
-
- default:
- panic ("Ill formed methodtype-descriptor");
- }
-
- args++;
- break;
-
- default:
- panic ("Ill formed methodtype-descriptor");
- }
+ while ((c = *utf_ptr) != ')') {
+ class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_SKIP | CLASSLOAD_NOVOID
+ | CLASSLOAD_NULLPRIMITIVE);
+ args++;
+ if (twoword && (c == 'J' || c == 'D'))
+ /* primitive two-word type */
+ args++;
}
return args;
{
char *utf_ptr = desc->text; /* current position in utf text */
char *end_pos = utf_end(desc); /* points behind utf string */
- char c;
int args = 0;
classinfo *cls;
/* method descriptor must start with parenthesis */
- if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+ if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
/* check arguments */
- while ((c = *utf_ptr) != ')') {
- cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
- if (!cls)
- panic("Invalid method descriptor.");
-
- switch (c) {
- case 'B':
- case 'C':
- case 'I':
- case 'S':
- case 'Z':
- case 'F':
- /* primitive one-word type */
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
- if (typebuf)
- *typebuf++ = (c == 'F') ? TYPE_FLOAT : TYPE_INT; /* XXX TYPE_FLT? */
- TYPEINFO_INIT_PRIMITIVE(*infobuf);
- infobuf++;
- break;
-
- case 'J':
- case 'D':
- /* primitive two-word type */
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
- if (typebuf)
- *typebuf++ = (c == 'J') ? TYPE_LONG : TYPE_DOUBLE; /* XXX TYPE_DBL? */
- TYPEINFO_INIT_PRIMITIVE(*infobuf);
- infobuf++;
- if (twoword) {
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
- TYPEINFO_INIT_PRIMITIVE(*infobuf);
- infobuf++;
- }
- break;
-
- case 'L':
- case '[' :
- /* reference type */
-
- if (++args > buflen)
- panic("Buffer too small for method arguments.");
- if (typebuf)
- *typebuf++ = TYPE_ADDRESS;
-
- TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
- /* XXX remove */ /* utf_display(cls->name); */
- infobuf++;
- break;
-
- default:
- panic ("Ill formed methodtype-descriptor (type)");
- }
+ while (utf_ptr != end_pos && *utf_ptr != ')') {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+
+ *typebuf++ = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NEW
+ | CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NOVOID);
+
+ if (cls) {
+ if (!cls->loaded)
+ class_load(cls);
+
+ if (!cls->linked)
+ class_link(cls);
+
+ TYPEINFO_INIT_CLASSINFO(*infobuf, cls);
+
+ } else {
+ TYPEINFO_INIT_PRIMITIVE(*infobuf);
+ }
+ infobuf++;
+
+ if (twoword && (typebuf[-1] == TYPE_LONG || typebuf[-1] == TYPE_DOUBLE)) {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+ *typebuf++ = TYPE_VOID;
+ TYPEINFO_INIT_PRIMITIVE(*infobuf);
+ infobuf++;
+ }
}
utf_ptr++; /* skip ')' */
/* check returntype */
if (returntype) {
- switch (*utf_ptr) {
- case 'B':
- case 'C':
- case 'I':
- case 'S':
- case 'Z':
- *returntype = TYPE_INT;
- goto primitive_tail;
-
- case 'J':
- *returntype = TYPE_LONG;
- goto primitive_tail;
-
- case 'F':
- *returntype = TYPE_FLOAT;
- goto primitive_tail;
-
- case 'D':
- *returntype = TYPE_DOUBLE;
- goto primitive_tail;
-
- case 'V':
- *returntype = TYPE_VOID;
- primitive_tail:
- if ((utf_ptr+1) != end_pos)
- panic ("Method-descriptor has exceeding chars");
- if (returntypeinfo) {
- TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
- }
- break;
+ *returntype = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NEW
+ | CLASSLOAD_CHECKEND);
+
+ if (returntypeinfo) {
+ if (cls) {
+ if (!cls->loaded)
+ class_load(cls);
+
+ if (!cls->linked)
+ class_link(cls);
+
+ TYPEINFO_INIT_CLASSINFO(*returntypeinfo, cls);
+
+ } else {
+ TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
+ }
+ }
+ }
+}
- case 'L':
- case '[':
- *returntype = TYPE_ADDRESS;
- cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
- if (!cls)
- panic("Invalid return type");
- if (utf_ptr != end_pos)
- panic ("Method-descriptor has exceeding chars");
- if (returntypeinfo) {
- TYPEINFO_INIT_CLASSINFO(*returntypeinfo,cls);
- }
- break;
+int
+typedescriptors_init_from_method_args(typedescriptor *td,
+ utf *desc,
+ int buflen,bool twoword,
+ typedescriptor *returntype)
+{
+ char *utf_ptr = desc->text; /* current position in utf text */
+ char *end_pos = utf_end(desc); /* points behind utf string */
+ int args = 0;
+ classinfo *cls;
- default:
- panic ("Ill formed methodtype-descriptor (returntype)");
- }
+ /* method descriptor must start with parenthesis */
+ if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
+ /* check arguments */
+ while (utf_ptr != end_pos && *utf_ptr != ')') {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+
+ td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NEW
+ | CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NOVOID);
+
+ if (cls) {
+ if (!cls->loaded)
+ class_load(cls);
+
+ if (!cls->linked)
+ class_link(cls);
+
+ TYPEINFO_INIT_CLASSINFO(td->info, cls);
+
+ } else {
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ }
+ td++;
+
+ if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+ td->type = TYPE_VOID;
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ td++;
+ }
}
+ utf_ptr++; /* skip ')' */
+
+ /* check returntype */
+ if (returntype) {
+ returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NEW
+ | CLASSLOAD_CHECKEND);
+ if (cls) {
+ if (!cls->loaded)
+ class_load(cls);
+
+ if (!cls->linked)
+ class_link(cls);
+
+ TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+
+ } else {
+ TYPEINFO_INIT_PRIMITIVE(returntype->info);
+ }
+ }
+ return args;
}
-/* XXX could be made a macro if really performance critical */
void
typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
{
vftbl *comp = NULL;
+
+ if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+ TYPEINFO_INIT_NULLTYPE(*dst);
+ return;
+ }
- /* XXX find component class */
if (!TYPEINFO_IS_ARRAY(*srcarray))
panic("Trying to access component of non-array");
else {
TYPEINFO_INIT_PRIMITIVE(*dst);
}
-
- /* XXX assign directly ? */
-#if 0
- if ((dst->dimension = srcarray->dimension - 1) == 0) {
- dst->typeclass = srcarray->elementclass;
- dst->elementtype = 0;
- dst->elementclass = NULL;
- }
- else {
- dst->typeclass = srcarray->typeclass;
- dst->elementtype = srcarray->elementtype;
- dst->elementclass = srcarray->elementclass;
- }
-#endif
dst->merged = srcarray->merged;
}
-/* Condition: src != dest. */
void
typeinfo_clone(typeinfo *src,typeinfo *dest)
{
int count;
classinfo **srclist,**destlist;
-#ifdef DEBUG_TYPES
if (src == dest)
- panic("Internal error: typeinfo_clone with src==dest");
-#endif
+ return;
*dest = *src;
TYPEINFO_ALLOCMERGED(dest->merged,count);
dest->merged->count = count;
- /* XXX use memcpy? */
srclist = src->merged->list;
destlist = dest->merged->list;
while (count--)
void
typeinfo_free(typeinfo *info)
{
- TYPEINFO_FREE(*info);
+ TYPEINFO_FREEMERGED_IF_ANY(info->merged);
+ info->merged = NULL;
}
/**********************************************************************/
static
void
typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
fprintf(stderr,"Typeinfo x:\n");
typeinfo_print(stderr,x,1);
TYPEINFO_ALLOCMERGED(dest->merged,2);
dest->merged->count = 2;
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (clsx == clsy)
panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
#endif
/* {The new mergedlist will have count entries.} */
- if (y->count == count) {
+ if ((x->count != count) && (y->count == count)) {
temp = x; x = y; y = temp;
}
/* {If one of x,y is already the result it is x.} */
typeinfo_mergedlist *tmerged;
bool changed;
- /* XXX remove */
+ /* DEBUG */
/*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
typeinfo dbgx,dbgy;
printf("typeinfo_merge_nonarrays:\n");
TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
#endif
*/
+ /* check clsx */
+ if (!clsx->loaded)
+ if (!class_load(clsx))
+ return false;
+
+ if (!clsx->linked)
+ if (!class_link(clsx))
+ return false;
+
+ /* check clsy */
+ if (!clsy->loaded)
+ if (!class_load(clsy))
+ return false;
+
+ if (!clsy->linked)
+ if (!class_link(clsy))
+ return false;
+
/* Common case: clsx == clsy */
/* (This case is very simple unless *both* x and y really represent
* merges of subclasses of clsx==clsy.)
*/
- /* XXX count this case for statistics */
if ((clsx == clsy) && (!mergedx || !mergedy)) {
return_simple_x:
- /* XXX remove */ /* log_text("return simple x"); */
+ /* DEBUG */ /* log_text("return simple x"); */
changed = (dest->merged != NULL);
TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
dest->merged = NULL;
*result = clsx;
- /* XXX remove */ /* log_text("returning"); */
+ /* DEBUG */ /* log_text("returning"); */
return changed;
}
if (clsy->flags & ACC_INTERFACE) {
/* We are merging two interfaces. */
/* {mergedy == NULL} */
- /* XXX: should we optimize direct superinterfaces? */
/* {We know that clsx!=clsy (see common case at beginning.)} */
*result = class_java_lang_Object;
* by y, too, so we have to add clsx to the mergedlist.
*/
- /* XXX if x has no superinterfaces we could return a simple java.lang.Object */
+ /* if x has no superinterfaces we could return a simple java.lang.Object */
common = class_java_lang_Object;
goto merge_with_simple_x;
/* {common == nearest common anchestor of clsx and clsy.} */
- /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
-
/* If clsx==common and x is a whole class (not a merge of subclasses)
* then the result of the merge is clsx.
*/
int elementtype;
bool changed;
- /* XXX remove */
+ /* DEBUG */
/*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
typeinfo_print(stdout,dest,4);
typeinfo_print(stdout,y,4);
#endif
- */
+ */
+
+ /* Merging something with itself is a nop */
+ if (dest == y)
+ return false;
- /* This function cannot be used to merge primitive types. */
+ /* 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;
+ }
+
+ /* 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 DEBUG_TYPES
- if (dest == y)
- panic("Internal error: typeinfo_merge with 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
- /* XXX remove */ /* log_text("Testing common case"); */
+ /* handle uninitialized object types */
+ /* XXX is there a way we could put this after the common case? */
+ if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
+ if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y))
+ typeinfo_merge_error("Trying to merge uninitialized object type.",dest,y);
+ if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest)
+ != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+ typeinfo_merge_error("Trying to merge different uninitialized objects.",dest,y);
+ return false;
+ }
+
+ /* DEBUG */ /* log_text("Testing common case"); */
/* Common case: class dest == class y */
/* (This case is very simple unless *both* dest and y really represent
* merges of subclasses of class dest==class y.)
*/
- /* XXX count this case for statistics */
if ((dest->typeclass == y->typeclass) && (!dest->merged || !y->merged)) {
changed = (dest->merged != NULL);
- TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if */
+ TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* unify if? */
dest->merged = NULL;
- /* XXX remove */ /* log_text("common case handled"); */
+ /* DEBUG */ /* log_text("common case handled"); */
return changed;
}
- /* XXX remove */ /* log_text("Handling null types"); */
+ /* DEBUG */ /* log_text("Handling null types"); */
/* Handle null types: */
if (TYPEINFO_IS_NULLTYPE(*y)) {
/* Handle merging of arrays: */
if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
- /* XXX remove */ /* log_text("Handling arrays"); */
+ /* DEBUG */ /* log_text("Handling arrays"); */
/* Make x the one with lesser dimension */
if (x->dimension > y->dimension) {
elementclass,
x->merged,y->merged);
- /* XXX otimize this? */
- /* XXX remove */ /* log_text("finding resulting array class: "); */
+ /* DEBUG */ /* log_text("finding resulting array class: "); */
common = class_multiarray_of(dimension,elementclass);
- /* XXX remove */ /* utf_display(common->name); printf("\n"); */
+ /* DEBUG */ /* utf_display(common->name); printf("\n"); */
}
}
}
changed = true;
}
- /* XXX remove */ /* log_text("returning from merge"); */
+ /* DEBUG */ /* log_text("returning from merge"); */
return changed;
}
/* DEBUGGING HELPERS */
/**********************************************************************/
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
#include "tables.h"
#include "loader.h"
+#include "jit/jit.h"
+
+extern instruction *instr;
static int
typeinfo_test_compare(classinfo **a,classinfo **b)
if (x->elementclass != y->elementclass) return false;
if (x->elementtype != y->elementtype) return false;
}
+
+ if (TYPEINFO_IS_NEWOBJECT(*x))
+ if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
+ != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+ return false;
+
if (x->merged || y->merged) {
if (!(x->merged && y->merged)) return false;
if (x->merged->count != y->merged->count) return false;
typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
{
typeinfo dest;
+ bool changed,changed_should_be;
TYPEINFO_CLONE(*a,dest);
typeinfo_print_short(stdout,b);
printf("\n");
- typeinfo_merge(&dest,b);
+ changed = (typeinfo_merge(&dest,b)) ? 1 : 0;
+ changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
+
+ printf(" %s\n",(changed) ? "changed" : "=");
if (typeinfo_equal(&dest,result)) {
printf("OK ");
typeinfo_print_short(stdout,&dest);
printf("\n");
+ if (changed != changed_should_be) {
+ printf("WRONG RETURN VALUE!\n");
+ (*failed)++;
+ }
}
else {
printf("RESULT ");
char bufa[TYPEINFO_TEST_BUFLEN];
char bufb[TYPEINFO_TEST_BUFLEN];
char bufc[TYPEINFO_TEST_BUFLEN];
- typeinfo a,b,c,a2,b2;
+ typeinfo a,b,c;
int maxdim;
int failed = 0;
FILE *file = fopen(filename,"rt");
+ int res;
if (!file)
panic("could not open typeinfo test file");
if (buf[0] == '#' || !strlen(buf))
continue;
- int res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
+ res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc))
panic("Invalid line in typeinfo test file (none of empty, comment or test)");
void
typeinfo_test()
{
-/* typeinfo i1,i2,i3,i4,i5,i6,i7,i8; */
-
-/* typeinfo_init_from_fielddescriptor(&i1,"[Ljava/lang/Integer;"); */
-/* typeinfo_init_from_fielddescriptor(&i2,"[[Ljava/lang/String;"); */
-/* typeinfo_init_from_fielddescriptor(&i3,"[Ljava/lang/Cloneable;"); */
-/* typeinfo_init_from_fielddescriptor(&i3,"[[Ljava/lang/String;"); */
-/* TYPEINFO_INIT_NULLTYPE(i1); */
-/* typeinfo_print_short(stdout,&i1); printf("\n"); */
-/* typeinfo_print_short(stdout,&i2); printf("\n"); */
-/* typeinfo_merge(&i1,&i2); */
-/* typeinfo_print_short(stdout,&i1); printf("\n"); */
-/* typeinfo_print_short(stdout,&i3); printf("\n"); */
-/* typeinfo_merge(&i1,&i3); */
-/* typeinfo_print_short(stdout,&i1); printf("\n"); */
-
log_text("Running typeinfo test file...");
typeinfo_testrun("typeinfo.tst");
log_text("Finished typeinfo test file.");
{
int i;
char ind[TYPEINFO_MAXINDENT + 1];
+ instruction *ins;
+ basicblock *bptr;
if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
ind[i] = (char) 0;
if (TYPEINFO_IS_PRIMITIVE(*info)) {
- fprintf(file,"%sprimitive\n",ind);
+ bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+ if (bptr)
+ fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->debug_nr);
+ else
+ fprintf(file,"%sprimitive\n",ind);
return;
}
fprintf(file,"%snull\n",ind);
return;
}
-
+
+ if (TYPEINFO_IS_NEWOBJECT(*info)) {
+ ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+ if (ins) {
+ fprintf(file,"%sNEW(%d):",ind,ins-instr);
+ utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+ fprintf(file,"\n");
+ }
+ else {
+ fprintf(file,"%sNEW(this)",ind);
+ }
+ return;
+ }
+
fprintf(file,"%sClass: ",ind);
utf_fprint(file,info->typeclass->name);
fprintf(file,"\n");
typeinfo_print_short(FILE *file,typeinfo *info)
{
int i;
+ instruction *ins;
+ basicblock *bptr;
if (TYPEINFO_IS_PRIMITIVE(*info)) {
- fprintf(file,"primitive");
+ bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+ if (bptr)
+ fprintf(file,"ret(L%03d)",bptr->debug_nr);
+ else
+ fprintf(file,"primitive");
return;
}
return;
}
- utf_fprint(file,info->typeclass->name);
-
- /* XXX remove */
-#if 0
- if (TYPEINFO_IS_ARRAY(*info)) {
- fprintf(file,"[%d]",info->dimension);
- switch (info->elementtype) {
- case ARRAYTYPE_INT : fprintf(file,"int"); break;
- case ARRAYTYPE_LONG : fprintf(file,"long"); break;
- case ARRAYTYPE_FLOAT : fprintf(file,"float"); break;
- case ARRAYTYPE_DOUBLE : fprintf(file,"double"); break;
- case ARRAYTYPE_BYTE : fprintf(file,"byte"); break;
- case ARRAYTYPE_CHAR : fprintf(file,"char"); break;
- case ARRAYTYPE_SHORT : fprintf(file,"short"); break;
- case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
-
- case ARRAYTYPE_OBJECT:
- fprintf(file,"object(");
- utf_fprint(file,info->elementclass->name);
- fprintf(file,")");
- break;
-
- default:
- fprintf(file,"INVALID ARRAYTYPE!");
+ if (TYPEINFO_IS_NEWOBJECT(*info)) {
+ ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+ if (ins) {
+ fprintf(file,"NEW(%d):",ins-instr);
+ utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
}
+ else
+ fprintf(file,"NEW(this)");
+ return;
}
-#endif
-
+
+ utf_fprint(file,info->typeclass->name);
+
if (info->merged) {
fprintf(file,"{");
for (i=0; i<info->merged->count; ++i) {
case TYPE_DOUBLE: fprintf(file,"D"); break;
case TYPE_LONG: fprintf(file,"J"); break;
case TYPE_ADDRESS:
- if (TYPEINFO_IS_PRIMITIVE(*info))
- fprintf(file,"R"); /* returnAddress */
- else {
- fprintf(file,"L");
- typeinfo_print_short(file,info);
- fprintf(file,";");
- }
+ typeinfo_print_short(file,info);
break;
default:
}
}
-#endif // DEBUG_TYPES
+void
+typeinfo_print_stacktype(FILE *file,int type,typeinfo *info)
+{
+ if (type == TYPE_ADDRESS && TYPEINFO_IS_PRIMITIVE(*info)) {
+ typeinfo_retaddr_set *set = (typeinfo_retaddr_set*)
+ TYPEINFO_RETURNADDRESS(*info);
+ fprintf(file,"ret(L%03d",((basicblock*)(set->addr))->debug_nr);
+ set = set->alt;
+ while (set) {
+ fprintf(file,"|L%03d",((basicblock*)(set->addr))->debug_nr);
+ set = set->alt;
+ }
+ fprintf(file,")");
+ }
+ else
+ typeinfo_print_type(file,type,info);
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor *td)
+{
+ typeinfo_print_type(file,td->type,&(td->info));
+}
+
+void
+typevector_print(FILE *file,typevector *vec,int size)
+{
+ int i;
+
+ fprintf(file,"[%d]",vec->k);
+ for (i=0; i<size; ++i) {
+ fprintf(file," %d=",i);
+ typedescriptor_print(file,vec->td + i);
+ }
+}
+
+void
+typevectorset_print(FILE *file,typevector *set,int size)
+{
+ int i;
+ typevector *vec;
+
+ fprintf(file,"[%d",set->k);
+ vec = set->alt;
+ while (vec) {
+ fprintf(file,"|%d",vec->k);
+ vec = vec->alt;
+ }
+ fprintf(file,"]");
+
+ for (i=0; i<size; ++i) {
+ fprintf(file," %d=",i);
+ typedescriptor_print(file,set->td + i);
+ vec = set->alt;
+ while (vec) {
+ fprintf(file,"|");
+ typedescriptor_print(file,vec->td + i);
+ vec = vec->alt;
+ }
+ }
+}
+
+#endif /* TYPEINFO_DEBUG */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */