Authors: Edwin Steiner
- $Id: typeinfo.c 723 2003-12-08 19:51:32Z edwin $
+ $Id: typeinfo.c 922 2004-02-24 13:26:24Z edwin $
*/
#include "loader.h"
#include "toolbox/loging.h"
#include "toolbox/memory.h"
+#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
#define 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)
bool
typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
{
- classinfo *cls;
-
- cls = value->typeclass;
-
/* DEBUG CHECK: dest must not have a merged list. */
#ifdef TYPEINFO_DEBUG
if (dest->merged)
panic("Internal error: typeinfo_is_assignable on merged destination.");
#endif
-
+
+ return typeinfo_is_assignable_to_classinfo(value,dest->typeclass);
+}
+
+bool
+typeinfo_is_assignable_to_classinfo(typeinfo *value,classinfo *dest)
+{
+ classinfo *cls;
+
+ cls = value->typeclass;
+
/* assignments of primitive values are not checked here. */
- if (!cls && !dest->typeclass)
+ if (!cls && !dest)
return true;
/* primitive and reference types are not assignment compatible. */
- if (!cls || !dest->typeclass)
+ if (!cls || !dest)
return false;
+#ifdef TYPEINFO_DEBUG
+ if (!dest->linked)
+ panic("Internal error: typeinfo_is_assignable_to_classinfo: unlinked class.");
+#endif
+
/* the null type can be assigned to any type */
if (TYPEINFO_IS_NULLTYPE(*value))
return true;
if (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);
}
/**********************************************************************/
classinfo *cls;
char *end;
- /* XXX simplify */
cls = class_from_descriptor(utf_ptr,end_ptr,&end,
CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_NEW
}
}
+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;
+
+ /* method descriptor must start with parenthesis */
+ if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
+ /* check arguments */
+ while (utf_ptr != end_pos && *utf_ptr != ')') {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+
+ td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NEW
+ | CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NOVOID);
+
+ if (cls)
+ TYPEINFO_INIT_CLASSINFO(td->info,cls);
+ else {
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ }
+ td++;
+
+ if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+ td->type = TYPE_VOID;
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ td++;
+ }
+ }
+ utf_ptr++; /* skip ')' */
+
+ /* check returntype */
+ if (returntype) {
+ returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NEW
+ | CLASSLOAD_CHECKEND);
+ if (cls)
+ TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+ else
+ TYPEINFO_INIT_PRIMITIVE(returntype->info);
+ }
+ return args;
+}
+
void
typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
{
return;
}
- /* XXX find component class */
if (!TYPEINFO_IS_ARRAY(*srcarray))
panic("Trying to access component of non-array");
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;
}
TYPEINFO_ALLOCMERGED(dest->merged,count);
dest->merged->count = count;
- /* XXX use memcpy? */
srclist = src->merged->list;
destlist = dest->merged->list;
while (count--)
typeinfo_mergedlist *tmerged;
bool changed;
- /* XXX remove */
+ /* DEBUG */
/*
#ifdef TYPEINFO_DEBUG
typeinfo dbgx,dbgy;
/* (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;
int elementtype;
bool changed;
- /* XXX remove */
+ /* DEBUG */
/*
#ifdef TYPEINFO_DEBUG
typeinfo_print(stdout,dest,4);
return false;
/* Merging two returnAddress types is ok. */
- if (!dest->typeclass && !y->typeclass)
+ if (!dest->typeclass && !y->typeclass) {
+#ifdef TYPEINFO_DEBUG
+ if (TYPEINFO_RETURNADDRESS(*dest) != TYPEINFO_RETURNADDRESS(*y))
+ panic("Internal error: typeinfo_merge merges different returnAddresses");
+#endif
return false;
+ }
/* Primitive types cannot be merged with reference types */
+ /* XXX only check this in debug mode? */
if (!dest->typeclass || !y->typeclass)
typeinfo_merge_error("Trying to merge primitive types.",dest,y);
return false;
}
- /* XXX remove */ /* log_text("Testing common case"); */
+ /* 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;
}
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)");
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;
}
{
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;
}
case TYPE_DOUBLE: fprintf(file,"D"); break;
case TYPE_LONG: fprintf(file,"J"); break;
case TYPE_ADDRESS:
- if (TYPEINFO_IS_PRIMITIVE(*info))
- fprintf(file,"R"); /* returnAddress */
- else {
- typeinfo_print_short(file,info);
- }
+ typeinfo_print_short(file,info);
break;
default:
}
}
+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 */