1 /* typeinfo.c - type system used by the type checker
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5 M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6 P. Tomsich, J. Wenninger
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Edwin Steiner
29 $Id: typeinfo.c 696 2003-12-06 20:10:05Z edwin $
37 #define TYPEINFO_REUSE_MERGED
39 #define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
40 ( ((index) < (cls)->vftbl->interfacetablelength) \
41 && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
43 /**********************************************************************/
44 /* READ-ONLY FUNCTIONS */
45 /* The following functions don't change typeinfo data. */
46 /**********************************************************************/
49 typeinfo_is_array(typeinfo *info)
51 return TYPEINFO_IS_ARRAY(*info);
55 typeinfo_is_primitive_array(typeinfo *info,int arraytype)
57 return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
61 typeinfo_is_array_of_refs(typeinfo *info)
63 return TYPEINFO_IS_ARRAY_OF_REFS(*info);
68 interface_extends_interface(classinfo *cls,classinfo *interf)
72 /* first check direct superinterfaces */
73 for (i=0; i<cls->interfacescount; ++i) {
74 if (cls->interfaces[i] == interf)
78 /* check indirect superinterfaces */
79 for (i=0; i<cls->interfacescount; ++i) {
80 if (interface_extends_interface(cls->interfaces[i],interf))
87 /* XXX If really a performance issue, this could become a macro. */
90 classinfo_implements_interface(classinfo *cls,classinfo *interf)
92 if (cls->flags & ACC_INTERFACE) {
93 /* cls is an interface */
97 /* check superinterfaces */
98 return interface_extends_interface(cls,interf);
101 return CLASS_IMPLEMENTS_INTERFACE(cls,interf->index);
104 bool mergedlist_implements_interface(typeinfo_mergedlist *merged,
110 /* Check if there is an non-empty mergedlist. */
114 /* If all classinfos in the (non-empty) merged array implement the
115 * interface return true, otherwise false.
117 mlist = merged->list;
120 if (!classinfo_implements_interface(*mlist++,interf))
127 merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist *merged,
130 /* primitive types don't support interfaces. */
134 /* the null type can be cast to any interface type. */
135 if (typeclass == pseudo_class_Null)
138 /* check if typeclass implements the interface. */
139 if (classinfo_implements_interface(typeclass,interf))
142 /* check the mergedlist */
143 return (merged && mergedlist_implements_interface(merged,interf));
147 typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
151 cls = value->typeclass;
153 /* DEBUG CHECK: dest must not have a merged list. */
154 #ifdef TYPEINFO_DEBUG
156 panic("Internal error: typeinfo_is_assignable on merged destination.");
159 /* assignments of primitive values are not checked here. */
160 if (!cls && !dest->typeclass)
163 /* the null type can be assigned to any type */
164 if (TYPEINFO_IS_NULLTYPE(*value))
167 /* primitive and reference types are not assignment compatible. */
168 if (!cls || !dest->typeclass)
171 if (dest->typeclass->flags & ACC_INTERFACE) {
172 /* We are assigning to an interface type. */
173 return merged_implements_interface(cls,value->merged,
177 if (TYPEINFO_IS_ARRAY(*dest)) {
178 /* We are assigning to an array type. */
179 if (!TYPEINFO_IS_ARRAY(*value))
182 /* {Both value and dest are array types.} */
184 /* value must have at least the dimension of dest. */
185 if (value->dimension < dest->dimension)
188 if (value->dimension > dest->dimension) {
189 /* value has higher dimension so we need to check
190 * if its component array can be assigned to the
191 * element type of dest */
193 if (dest->elementclass->flags & ACC_INTERFACE) {
194 /* We are assigning to an interface type. */
195 return classinfo_implements_interface(pseudo_class_Arraystub,
199 /* We are assigning to a class type. */
200 return class_issubclass(pseudo_class_Arraystub,dest->elementclass);
203 /* {value and dest have the same dimension} */
205 if (value->elementtype != dest->elementtype)
208 if (value->elementclass) {
209 /* We are assigning an array of objects so we have to
210 * check if the elements are assignable.
213 if (dest->elementclass->flags & ACC_INTERFACE) {
214 /* We are assigning to an interface type. */
216 return merged_implements_interface(value->elementclass,
221 /* We are assigning to a class type. */
222 return class_issubclass(value->elementclass,dest->elementclass);
228 /* {dest is not an array} */
230 /* We are assigning to a class type */
231 if (cls->flags & ACC_INTERFACE)
232 cls = class_java_lang_Object;
234 return class_issubclass(cls,dest->typeclass);
237 /**********************************************************************/
238 /* INITIALIZATION FUNCTIONS */
239 /* The following functions fill in uninitialized typeinfo structures. */
240 /**********************************************************************/
243 typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
247 cls = class_from_descriptor(utf_ptr,end_ptr,&end,CLASSLOAD_NEW);
250 panic("Invalid descriptor.");
255 /* a class, interface or array descriptor */
256 TYPEINFO_INIT_CLASSINFO(*info,cls);
259 /* a primitive type */
260 TYPEINFO_INIT_PRIMITIVE(*info);
263 /* exceeding characters */
264 if (end!=end_ptr) panic ("descriptor has exceeding chars");
268 typeinfo_count_method_args(utf *d,bool twoword)
271 char *utf_ptr = d->text;
272 char *end_pos = utf_end(d);
275 /* method descriptor must start with parenthesis */
276 if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
278 /* check arguments */
279 while ((c = *utf_ptr++) != ')') {
287 /* primitive one-word type */
293 /* primitive two-word type */
300 while ( *utf_ptr++ != ';' )
301 if (utf_ptr>=end_pos)
302 panic ("Missing ';' in objecttype-descriptor");
309 while ((ch = *utf_ptr++)=='[')
312 /* component type of array */
327 while ( *utf_ptr++ != ';' )
328 if (utf_ptr>=end_pos)
329 panic ("Missing ';' in objecttype-descriptor");
333 panic ("Ill formed methodtype-descriptor");
340 panic ("Ill formed methodtype-descriptor");
348 typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
349 int buflen,bool twoword,
350 int *returntype,typeinfo *returntypeinfo)
352 char *utf_ptr = desc->text; /* current position in utf text */
353 char *end_pos = utf_end(desc); /* points behind utf string */
358 /* method descriptor must start with parenthesis */
359 if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
361 /* check arguments */
362 while ((c = *utf_ptr) != ')') {
363 cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
365 panic("Invalid method descriptor.");
374 /* primitive one-word type */
376 panic("Buffer too small for method arguments.");
378 *typebuf++ = (c == 'F') ? TYPE_FLOAT : TYPE_INT; /* XXX TYPE_FLT? */
379 TYPEINFO_INIT_PRIMITIVE(*infobuf);
385 /* primitive two-word type */
387 panic("Buffer too small for method arguments.");
389 *typebuf++ = (c == 'J') ? TYPE_LONG : TYPE_DOUBLE; /* XXX TYPE_DBL? */
390 TYPEINFO_INIT_PRIMITIVE(*infobuf);
394 panic("Buffer too small for method arguments.");
396 *typebuf++ = TYPE_VOID;
397 TYPEINFO_INIT_PRIMITIVE(*infobuf);
407 panic("Buffer too small for method arguments.");
409 *typebuf++ = TYPE_ADDRESS;
411 TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
416 panic ("Ill formed methodtype-descriptor (type)");
419 utf_ptr++; /* skip ')' */
421 /* check returntype */
429 *returntype = TYPE_INT;
433 *returntype = TYPE_LONG;
437 *returntype = TYPE_FLOAT;
441 *returntype = TYPE_DOUBLE;
445 *returntype = TYPE_VOID;
447 if ((utf_ptr+1) != end_pos)
448 panic ("Method-descriptor has exceeding chars");
449 if (returntypeinfo) {
450 TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
456 *returntype = TYPE_ADDRESS;
457 cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
459 panic("Invalid return type");
460 if (utf_ptr != end_pos)
461 panic ("Method-descriptor has exceeding chars");
462 if (returntypeinfo) {
463 TYPEINFO_INIT_CLASSINFO(*returntypeinfo,cls);
468 panic ("Ill formed methodtype-descriptor (returntype)");
473 /* XXX could be made a macro if really performance critical */
475 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
479 if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
480 TYPEINFO_INIT_NULLTYPE(*dst);
484 /* XXX find component class */
485 if (!TYPEINFO_IS_ARRAY(*srcarray))
486 panic("Trying to access component of non-array");
488 comp = srcarray->typeclass->vftbl->arraydesc->componentvftbl;
490 TYPEINFO_INIT_CLASSINFO(*dst,comp->class);
493 TYPEINFO_INIT_PRIMITIVE(*dst);
496 /* XXX assign directly ? */
498 if ((dst->dimension = srcarray->dimension - 1) == 0) {
499 dst->typeclass = srcarray->elementclass;
500 dst->elementtype = 0;
501 dst->elementclass = NULL;
504 dst->typeclass = srcarray->typeclass;
505 dst->elementtype = srcarray->elementtype;
506 dst->elementclass = srcarray->elementclass;
510 dst->merged = srcarray->merged;
513 /* Condition: src != dest. */
515 typeinfo_clone(typeinfo *src,typeinfo *dest)
518 classinfo **srclist,**destlist;
520 #ifdef TYPEINFO_DEBUG
522 panic("Internal error: typeinfo_clone with src==dest");
528 count = src->merged->count;
529 TYPEINFO_ALLOCMERGED(dest->merged,count);
530 dest->merged->count = count;
532 /* XXX use memcpy? */
533 srclist = src->merged->list;
534 destlist = dest->merged->list;
536 *destlist++ = *srclist++;
540 /**********************************************************************/
541 /* MISCELLANEOUS FUNCTIONS */
542 /**********************************************************************/
545 typeinfo_free(typeinfo *info)
547 TYPEINFO_FREE(*info);
550 /**********************************************************************/
551 /* MERGING FUNCTIONS */
552 /* The following functions are used to merge the types represented by */
553 /* two typeinfo structures into one typeinfo structure. */
554 /**********************************************************************/
558 typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
559 #ifdef TYPEINFO_DEBUG
560 fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
561 fprintf(stderr,"Typeinfo x:\n");
562 typeinfo_print(stderr,x,1);
563 fprintf(stderr,"Typeinfo y:\n");
564 typeinfo_print(stderr,y,1);
569 /* Condition: clsx != clsy. */
570 /* Returns: true if dest was changed (always true). */
573 typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy)
575 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
576 TYPEINFO_ALLOCMERGED(dest->merged,2);
577 dest->merged->count = 2;
579 #ifdef TYPEINFO_DEBUG
581 panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
585 dest->merged->list[0] = clsx;
586 dest->merged->list[1] = clsy;
589 dest->merged->list[0] = clsy;
590 dest->merged->list[1] = clsx;
596 /* Returns: true if dest was changed. */
599 typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classinfo *cls)
602 typeinfo_mergedlist *newmerged;
603 classinfo **mlist,**newlist;
608 /* Check if cls is already in the mergedlist m. */
610 if (*mlist++ == cls) {
611 /* cls is in the list, so m is the resulting mergedlist */
612 if (dest->merged == m)
615 /* We have to copy the mergedlist */
616 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
618 TYPEINFO_ALLOCMERGED(dest->merged,count);
619 dest->merged->count = count;
620 newlist = dest->merged->list;
623 *newlist++ = *mlist++;
629 /* Add cls to the mergedlist. */
631 TYPEINFO_ALLOCMERGED(newmerged,count+1);
632 newmerged->count = count+1;
633 newlist = newmerged->list;
638 *newlist++ = *mlist++;
643 *newlist++ = *mlist++;
646 /* Put the new mergedlist into dest. */
647 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
648 dest->merged = newmerged;
653 /* Returns: true if dest was changed. */
656 typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x,
657 typeinfo_mergedlist *y)
661 typeinfo_mergedlist *temp,*result;
662 classinfo **clsx,**clsy,**newlist;
664 /* count the elements that will be in the resulting list */
665 /* (Both lists are sorted, equal elements are counted only once.) */
670 while (countx && county) {
671 if (*clsx == *clsy) {
677 else if (*clsx < *clsy) {
687 count += countx + county;
689 /* {The new mergedlist will have count entries.} */
691 if ((x->count != count) && (y->count == count)) {
692 temp = x; x = y; y = temp;
694 /* {If one of x,y is already the result it is x.} */
695 if (x->count == count) {
696 /* x->merged is equal to the result */
697 if (x == dest->merged)
700 if (!dest->merged || dest->merged->count != count) {
701 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
702 TYPEINFO_ALLOCMERGED(dest->merged,count);
703 dest->merged->count = count;
706 newlist = dest->merged->list;
709 *newlist++ = *clsx++;
714 /* {We have to merge two lists.} */
716 /* allocate the result list */
717 TYPEINFO_ALLOCMERGED(result,count);
718 result->count = count;
719 newlist = result->list;
721 /* merge the sorted lists */
726 while (countx && county) {
727 if (*clsx == *clsy) {
728 *newlist++ = *clsx++;
733 else if (*clsx < *clsy) {
734 *newlist++ = *clsx++;
738 *newlist++ = *clsy++;
743 *newlist++ = *clsx++;
745 *newlist++ = *clsy++;
747 /* replace the list in dest with the result list */
748 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
749 dest->merged = result;
756 typeinfo_merge_nonarrays(typeinfo *dest,
758 classinfo *clsx,classinfo *clsy,
759 typeinfo_mergedlist *mergedx,
760 typeinfo_mergedlist *mergedy)
762 classinfo *tcls,*common;
763 typeinfo_mergedlist *tmerged;
768 #ifdef TYPEINFO_DEBUG
770 printf("typeinfo_merge_nonarrays:\n");
771 TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
772 dbgx.merged = mergedx;
773 TYPEINFO_INIT_CLASSINFO(dbgy,clsy);
774 dbgy.merged = mergedy;
775 typeinfo_print(stdout,&dbgx,4);
777 typeinfo_print(stdout,&dbgy,4);
781 /* Common case: clsx == clsy */
782 /* (This case is very simple unless *both* x and y really represent
783 * merges of subclasses of clsx==clsy.)
785 /* XXX count this case for statistics */
786 if ((clsx == clsy) && (!mergedx || !mergedy)) {
788 /* XXX remove */ /* log_text("return simple x"); */
789 changed = (dest->merged != NULL);
790 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
793 /* XXX remove */ /* log_text("returning"); */
797 /* If clsy is an interface, swap x and y. */
798 if (clsy->flags & ACC_INTERFACE) {
799 tcls = clsx; clsx = clsy; clsy = tcls;
800 tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
802 /* {We know: If only one of x,y is an interface it is x.} */
804 /* Handle merging of interfaces: */
805 if (clsx->flags & ACC_INTERFACE) {
806 /* {clsx is an interface and mergedx == NULL.} */
808 if (clsy->flags & ACC_INTERFACE) {
809 /* We are merging two interfaces. */
810 /* {mergedy == NULL} */
811 /* XXX: should we optimize direct superinterfaces? */
813 /* {We know that clsx!=clsy (see common case at beginning.)} */
814 *result = class_java_lang_Object;
815 return typeinfo_merge_two(dest,clsx,clsy);
818 /* {We know: x is an interface, clsy is a class.} */
820 /* Check if we are merging an interface with java.lang.Object */
821 if (clsy == class_java_lang_Object && !mergedy) {
823 goto return_simple_x;
827 /* If the type y implements clsx then the result of the merge
828 * is clsx regardless of mergedy.
831 if (CLASS_IMPLEMENTS_INTERFACE(clsy,clsx->index)
832 || mergedlist_implements_interface(mergedy,clsx))
834 /* y implements x, so the result of the merge is x. */
835 goto return_simple_x;
838 /* {We know: x is an interface, the type y a class or a merge
839 * of subclasses and does not implement x.} */
841 /* There may still be superinterfaces of x which are implemented
842 * by y, too, so we have to add clsx to the mergedlist.
845 /* XXX if x has no superinterfaces we could return a simple java.lang.Object */
847 common = class_java_lang_Object;
848 goto merge_with_simple_x;
851 /* {We know: x and y are classes (not interfaces).} */
853 /* If *x is deeper in the inheritance hierarchy swap x and y. */
854 if (clsx->index > clsy->index) {
855 tcls = clsx; clsx = clsy; clsy = tcls;
856 tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
859 /* {We know: y is at least as deep in the hierarchy as x.} */
861 /* Find nearest common anchestor for the classes. */
864 while (tcls->index > common->index)
866 while (common != tcls) {
867 common = common->super;
871 /* {common == nearest common anchestor of clsx and clsy.} */
873 /* If clsx==common and x is a whole class (not a merge of subclasses)
874 * then the result of the merge is clsx.
876 if (clsx == common && !mergedx) {
877 goto return_simple_x;
883 return typeinfo_merge_mergedlists(dest,mergedx,mergedy);
885 return typeinfo_merge_add(dest,mergedx,clsy);
891 return typeinfo_merge_add(dest,mergedy,clsx);
893 return typeinfo_merge_two(dest,clsx,clsy);
896 /* Condition: *dest must be a valid initialized typeinfo. */
897 /* Condition: dest != y. */
898 /* Returns: true if dest was changed. */
900 typeinfo_merge(typeinfo *dest,typeinfo* y)
903 typeinfo *tmp; /* used for swapping */
905 classinfo *elementclass;
912 #ifdef TYPEINFO_DEBUG
913 typeinfo_print(stdout,dest,4);
914 typeinfo_print(stdout,y,4);
918 /* Merging two returnAddress types is ok. */
919 if (!dest->typeclass && !y->typeclass)
922 /* Primitive types cannot be merged with reference types */
923 if (!dest->typeclass || !y->typeclass)
924 typeinfo_merge_error("Trying to merge primitive types.",dest,y);
926 #ifdef TYPEINFO_DEBUG
928 panic("Internal error: typeinfo_merge with dest==y");
930 /* check that no unlinked classes are merged. */
931 if (!dest->typeclass->linked || !y->typeclass->linked)
932 typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
935 /* XXX remove */ /* log_text("Testing common case"); */
937 /* Common case: class dest == class y */
938 /* (This case is very simple unless *both* dest and y really represent
939 * merges of subclasses of class dest==class y.)
941 /* XXX count this case for statistics */
942 if ((dest->typeclass == y->typeclass) && (!dest->merged || !y->merged)) {
943 changed = (dest->merged != NULL);
944 TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if */
946 /* XXX remove */ /* log_text("common case handled"); */
950 /* XXX remove */ /* log_text("Handling null types"); */
952 /* Handle null types: */
953 if (TYPEINFO_IS_NULLTYPE(*y)) {
956 if (TYPEINFO_IS_NULLTYPE(*dest)) {
957 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
958 TYPEINFO_CLONE(*y,*dest);
962 /* This function uses x internally, so x and y can be swapped
963 * without changing dest. */
967 /* Handle merging of arrays: */
968 if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
970 /* XXX remove */ /* log_text("Handling arrays"); */
972 /* Make x the one with lesser dimension */
973 if (x->dimension > y->dimension) {
974 tmp = x; x = y; y = tmp;
977 /* If one array (y) has higher dimension than the other,
978 * interpret it as an array (same dim. as x) of Arraystubs. */
979 if (x->dimension < y->dimension) {
980 dimension = x->dimension;
981 elementtype = ARRAYTYPE_OBJECT;
982 elementclass = pseudo_class_Arraystub;
985 dimension = y->dimension;
986 elementtype = y->elementtype;
987 elementclass = y->elementclass;
990 /* {The arrays are of the same dimension.} */
992 if (x->elementtype != elementtype) {
993 /* Different element types are merged, so the resulting array
994 * type has one accessible dimension less. */
995 if (--dimension == 0) {
996 common = pseudo_class_Arraystub;
1001 common = class_multiarray_of(dimension,pseudo_class_Arraystub);
1002 elementtype = ARRAYTYPE_OBJECT;
1003 elementclass = pseudo_class_Arraystub;
1007 /* {The arrays have the same dimension and elementtype.} */
1009 if (elementtype == ARRAYTYPE_OBJECT) {
1010 /* The elements are references, so their respective
1011 * types must be merged.
1013 changed |= typeinfo_merge_nonarrays(dest,
1017 x->merged,y->merged);
1019 /* XXX otimize this? */
1020 /* XXX remove */ /* log_text("finding resulting array class: "); */
1021 common = class_multiarray_of(dimension,elementclass);
1022 /* XXX remove */ /* utf_display(common->name); printf("\n"); */
1027 /* {We know that at least one of x or y is no array, so the
1028 * result cannot be an array.} */
1030 changed |= typeinfo_merge_nonarrays(dest,
1032 x->typeclass,y->typeclass,
1033 x->merged,y->merged);
1037 elementclass = NULL;
1040 /* Put the new values into dest if neccessary. */
1042 if (dest->typeclass != common) {
1043 dest->typeclass = common;
1046 if (dest->dimension != dimension) {
1047 dest->dimension = dimension;
1050 if (dest->elementtype != elementtype) {
1051 dest->elementtype = elementtype;
1054 if (dest->elementclass != elementclass) {
1055 dest->elementclass = elementclass;
1059 /* XXX remove */ /* log_text("returning from merge"); */
1065 /**********************************************************************/
1066 /* DEBUGGING HELPERS */
1067 /**********************************************************************/
1069 #ifdef TYPEINFO_DEBUG
1075 typeinfo_test_compare(classinfo **a,classinfo **b)
1077 if (*a == *b) return 0;
1078 if (*a < *b) return -1;
1083 typeinfo_test_parse(typeinfo *info,char *str)
1090 utf *desc = utf_new_char(str);
1092 num = typeinfo_count_method_args(desc,false);
1094 typebuf = DMNEW(u1,num);
1095 infobuf = DMNEW(typeinfo,num);
1097 typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
1100 TYPEINFO_ALLOCMERGED(info->merged,num);
1101 info->merged->count = num;
1103 for (i=0; i<num; ++i) {
1104 if (typebuf[i] != TYPE_ADDRESS)
1105 panic("non-reference type in mergedlist");
1106 info->merged->list[i] = infobuf[i].typeclass;
1108 qsort(info->merged->list,num,sizeof(classinfo*),
1109 (int(*)(const void *,const void *))&typeinfo_test_compare);
1112 typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
1117 #define TYPEINFO_TEST_BUFLEN 4000
1120 typeinfo_equal(typeinfo *x,typeinfo *y)
1124 if (x->typeclass != y->typeclass) return false;
1125 if (x->dimension != y->dimension) return false;
1127 if (x->elementclass != y->elementclass) return false;
1128 if (x->elementtype != y->elementtype) return false;
1130 if (x->merged || y->merged) {
1131 if (!(x->merged && y->merged)) return false;
1132 if (x->merged->count != y->merged->count) return false;
1133 for (i=0; i<x->merged->count; ++i)
1134 if (x->merged->list[i] != y->merged->list[i])
1141 typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
1144 bool changed,changed_should_be;
1146 TYPEINFO_CLONE(*a,dest);
1149 typeinfo_print_short(stdout,&dest);
1151 typeinfo_print_short(stdout,b);
1154 changed = (typeinfo_merge(&dest,b)) ? 1 : 0;
1155 changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
1157 printf(" %s\n",(changed) ? "changed" : "=");
1159 if (typeinfo_equal(&dest,result)) {
1161 typeinfo_print_short(stdout,&dest);
1163 if (changed != changed_should_be) {
1164 printf("WRONG RETURN VALUE!\n");
1170 typeinfo_print_short(stdout,&dest);
1172 printf("SHOULD BE ");
1173 typeinfo_print_short(stdout,result);
1180 typeinfo_inc_dimension(typeinfo *info)
1182 if (info->dimension++ == 0) {
1183 info->elementtype = ARRAYTYPE_OBJECT;
1184 info->elementclass = info->typeclass;
1186 info->typeclass = class_array_of(info->typeclass);
1189 #define TYPEINFO_TEST_MAXDIM 10
1192 typeinfo_testrun(char *filename)
1194 char buf[TYPEINFO_TEST_BUFLEN];
1195 char bufa[TYPEINFO_TEST_BUFLEN];
1196 char bufb[TYPEINFO_TEST_BUFLEN];
1197 char bufc[TYPEINFO_TEST_BUFLEN];
1201 FILE *file = fopen(filename,"rt");
1204 panic("could not open typeinfo test file");
1206 while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
1207 if (buf[0] == '#' || !strlen(buf))
1210 int res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
1211 if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc))
1212 panic("Invalid line in typeinfo test file (none of empty, comment or test)");
1214 typeinfo_test_parse(&a,bufa);
1215 typeinfo_test_parse(&b,bufb);
1216 typeinfo_test_parse(&c,bufc);
1218 typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
1219 typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
1221 if (TYPEINFO_IS_NULLTYPE(a)) break;
1222 if (TYPEINFO_IS_NULLTYPE(b)) break;
1223 if (TYPEINFO_IS_NULLTYPE(c)) break;
1225 maxdim = a.dimension;
1226 if (b.dimension > maxdim) maxdim = b.dimension;
1227 if (c.dimension > maxdim) maxdim = c.dimension;
1229 if (maxdim < TYPEINFO_TEST_MAXDIM) {
1230 typeinfo_inc_dimension(&a);
1231 typeinfo_inc_dimension(&b);
1232 typeinfo_inc_dimension(&c);
1234 } while (maxdim < TYPEINFO_TEST_MAXDIM);
1240 fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
1241 panic("Failed test");
1248 /* typeinfo i1,i2,i3,i4,i5,i6,i7,i8; */
1250 /* typeinfo_init_from_fielddescriptor(&i1,"[Ljava/lang/Integer;"); */
1251 /* typeinfo_init_from_fielddescriptor(&i2,"[[Ljava/lang/String;"); */
1252 /* typeinfo_init_from_fielddescriptor(&i3,"[Ljava/lang/Cloneable;"); */
1253 /* typeinfo_init_from_fielddescriptor(&i3,"[[Ljava/lang/String;"); */
1254 /* TYPEINFO_INIT_NULLTYPE(i1); */
1255 /* typeinfo_print_short(stdout,&i1); printf("\n"); */
1256 /* typeinfo_print_short(stdout,&i2); printf("\n"); */
1257 /* typeinfo_merge(&i1,&i2); */
1258 /* typeinfo_print_short(stdout,&i1); printf("\n"); */
1259 /* typeinfo_print_short(stdout,&i3); printf("\n"); */
1260 /* typeinfo_merge(&i1,&i3); */
1261 /* typeinfo_print_short(stdout,&i1); printf("\n"); */
1263 log_text("Running typeinfo test file...");
1264 typeinfo_testrun("typeinfo.tst");
1265 log_text("Finished typeinfo test file.");
1269 typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc)
1271 typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
1274 #define TYPEINFO_MAXINDENT 80
1277 typeinfo_print(FILE *file,typeinfo *info,int indent)
1280 char ind[TYPEINFO_MAXINDENT + 1];
1282 if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
1284 for (i=0; i<indent; ++i)
1288 if (TYPEINFO_IS_PRIMITIVE(*info)) {
1289 fprintf(file,"%sprimitive\n",ind);
1293 if (TYPEINFO_IS_NULLTYPE(*info)) {
1294 fprintf(file,"%snull\n",ind);
1298 fprintf(file,"%sClass: ",ind);
1299 utf_fprint(file,info->typeclass->name);
1302 if (TYPEINFO_IS_ARRAY(*info)) {
1303 fprintf(file,"%sDimension: %d",ind,(int)info->dimension);
1304 fprintf(file,"\n%sElements: ",ind);
1305 switch (info->elementtype) {
1306 case ARRAYTYPE_INT : fprintf(file,"int\n"); break;
1307 case ARRAYTYPE_LONG : fprintf(file,"long\n"); break;
1308 case ARRAYTYPE_FLOAT : fprintf(file,"float\n"); break;
1309 case ARRAYTYPE_DOUBLE : fprintf(file,"double\n"); break;
1310 case ARRAYTYPE_BYTE : fprintf(file,"byte\n"); break;
1311 case ARRAYTYPE_CHAR : fprintf(file,"char\n"); break;
1312 case ARRAYTYPE_SHORT : fprintf(file,"short\n"); break;
1313 case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
1315 case ARRAYTYPE_OBJECT:
1316 fprintf(file,"reference: ");
1317 utf_fprint(file,info->elementclass->name);
1322 fprintf(file,"INVALID ARRAYTYPE!\n");
1327 fprintf(file,"%sMerged: ",ind);
1328 for (i=0; i<info->merged->count; ++i) {
1329 if (i) fprintf(file,", ");
1330 utf_fprint(file,info->merged->list[i]->name);
1337 typeinfo_print_short(FILE *file,typeinfo *info)
1341 if (TYPEINFO_IS_PRIMITIVE(*info)) {
1342 fprintf(file,"primitive");
1346 if (TYPEINFO_IS_NULLTYPE(*info)) {
1347 fprintf(file,"null");
1351 utf_fprint(file,info->typeclass->name);
1355 for (i=0; i<info->merged->count; ++i) {
1356 if (i) fprintf(file,",");
1357 utf_fprint(file,info->merged->list[i]->name);
1364 typeinfo_print_type(FILE *file,int type,typeinfo *info)
1367 case TYPE_VOID: fprintf(file,"V"); break;
1368 case TYPE_INT: fprintf(file,"I"); break;
1369 case TYPE_FLOAT: fprintf(file,"F"); break;
1370 case TYPE_DOUBLE: fprintf(file,"D"); break;
1371 case TYPE_LONG: fprintf(file,"J"); break;
1373 if (TYPEINFO_IS_PRIMITIVE(*info))
1374 fprintf(file,"R"); /* returnAddress */
1376 typeinfo_print_short(file,info);
1385 #endif // TYPEINFO_DEBUG