1 /********************************* typeinfo.c *********************************
3 Copyright (c) 2003 ? XXX
5 See file COPYRIGHT for information on usage and disclaimer of warranties
7 functions for the compiler's type system
13 *******************************************************************************/
19 #define TYPEINFO_REUSE_MERGED
21 #define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
22 ( ((index) < (cls)->vftbl->interfacetablelength) \
23 && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
25 /**********************************************************************/
26 /* READ-ONLY FUNCTIONS */
27 /* The following functions don't change typeinfo data. */
28 /**********************************************************************/
31 typeinfo_is_array(typeinfo *info)
33 return TYPEINFO_IS_ARRAY(*info);
37 typeinfo_is_primitive_array(typeinfo *info,int arraytype)
39 return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
43 typeinfo_is_array_of_refs(typeinfo *info)
45 return TYPEINFO_IS_ARRAY_OF_REFS(*info);
50 interface_extends_interface(classinfo *cls,classinfo *interf)
54 /* first check direct superinterfaces */
55 for (i=0; i<cls->interfacescount; ++i) {
56 if (cls->interfaces[i] == interf)
60 /* check indirect superinterfaces */
61 for (i=0; i<cls->interfacescount; ++i) {
62 if (interface_extends_interface(cls->interfaces[i],interf))
69 /* XXX If really a performance issue, this could become a macro. */
72 classinfo_implements_interface(classinfo *cls,classinfo *interf)
74 if (cls->flags & ACC_INTERFACE) {
75 /* cls is an interface */
79 /* check superinterfaces */
80 return interface_extends_interface(cls,interf);
83 return CLASS_IMPLEMENTS_INTERFACE(cls,interf->index);
86 bool mergedlist_implements_interface(typeinfo_mergedlist *merged,
92 /* Check if there is an non-empty mergedlist. */
96 /* If all classinfos in the (non-empty) merged array implement the
97 * interface return true, otherwise false.
102 if (!classinfo_implements_interface(*mlist++,interf))
109 merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist *merged,
112 /* primitive types don't support interfaces. */
116 /* the null type can be cast to any interface type. */
117 if (typeclass == pseudo_class_Null)
120 /* check if typeclass implements the interface. */
121 if (classinfo_implements_interface(typeclass,interf))
124 /* check the mergedlist */
125 return (merged && mergedlist_implements_interface(merged,interf));
129 typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
133 cls = value->typeclass;
135 /* DEBUG CHECK: dest must not have a merged list. */
138 panic("Internal error: typeinfo_is_assignable on merged destination.");
141 /* assignments of primitive values are not checked here. */
142 if (!cls && !dest->typeclass)
145 /* the null type can be assigned to any type */
146 if (TYPEINFO_IS_NULLTYPE(*value))
149 /* primitive and reference types are not assignment compatible. */
150 if (!cls || !dest->typeclass)
153 if (dest->typeclass->flags & ACC_INTERFACE) {
154 /* We are assigning to an interface type. */
155 return merged_implements_interface(cls,value->merged,
159 if (TYPEINFO_IS_ARRAY(*dest)) {
160 /* We are assigning to an array type. */
161 if (!TYPEINFO_IS_ARRAY(*value))
164 /* {Both value and dest are array types.} */
166 /* value must have at least the dimension of dest. */
167 if (value->dimension < dest->dimension)
170 if (value->dimension > dest->dimension) {
171 /* value has higher dimension so we need to check
172 * if its component array can be assigned to the
173 * element type of dest */
175 if (dest->elementclass->flags & ACC_INTERFACE) {
176 /* We are assigning to an interface type. */
177 return classinfo_implements_interface(pseudo_class_Arraystub,
181 /* We are assigning to a class type. */
182 return class_issubclass(pseudo_class_Arraystub,dest->elementclass);
185 /* {value and dest have the same dimension} */
187 if (value->elementtype != dest->elementtype)
190 if (value->elementclass) {
191 /* We are assigning an array of objects so we have to
192 * check if the elements are assignable.
195 if (dest->elementclass->flags & ACC_INTERFACE) {
196 /* We are assigning to an interface type. */
198 return merged_implements_interface(value->elementclass,
203 /* We are assigning to a class type. */
204 return class_issubclass(value->elementclass,dest->elementclass);
210 /* {dest is not an array} */
212 /* We are assigning to a class type */
213 if (cls->flags & ACC_INTERFACE)
214 cls = class_java_lang_Object;
216 return class_issubclass(cls,dest->typeclass);
219 /**********************************************************************/
220 /* INITIALIZATION FUNCTIONS */
221 /* The following functions fill in uninitialized typeinfo structures. */
222 /**********************************************************************/
227 typeinfo_init_from_arraydescriptor(typeinfo *info,
228 constant_arraydescriptor *desc)
232 /* Arrays are instances of the pseudo class Array. */
233 info->typeclass = pseudo_class_Array; /* XXX */
236 /* Handle multidimensional arrays */
237 while (desc->arraytype == ARRAYTYPE_ARRAY) {
239 desc = desc->elementdescriptor;
242 info->dimension = dim;
244 if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
245 info->elementclass = desc->objectclass;
248 info->elementclass = NULL;
254 typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
258 cls = class_from_descriptor(utf_ptr,end_ptr,&end,CLASSLOAD_NEW);
261 panic("Invalid descriptor.");
266 /* a class, interface or array descriptor */
267 TYPEINFO_INIT_CLASSINFO(*info,cls);
270 /* a primitive type */
271 TYPEINFO_INIT_PRIMITIVE(*info);
274 /* exceeding characters */
275 if (end!=end_ptr) panic ("descriptor has exceeding chars");
279 typeinfo_count_method_args(utf *d,bool twoword)
282 char *utf_ptr = d->text;
283 char *end_pos = utf_end(d);
286 /* method descriptor must start with parenthesis */
287 if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
289 /* check arguments */
290 while ((c = *utf_ptr++) != ')') {
298 /* primitive one-word type */
304 /* primitive two-word type */
311 while ( *utf_ptr++ != ';' )
312 if (utf_ptr>=end_pos)
313 panic ("Missing ';' in objecttype-descriptor");
320 while ((ch = *utf_ptr++)=='[')
323 /* component type of array */
338 while ( *utf_ptr++ != ';' )
339 if (utf_ptr>=end_pos)
340 panic ("Missing ';' in objecttype-descriptor");
344 panic ("Ill formed methodtype-descriptor");
351 panic ("Ill formed methodtype-descriptor");
359 typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
360 int buflen,bool twoword,
361 int *returntype,typeinfo *returntypeinfo)
363 char *utf_ptr = desc->text; /* current position in utf text */
364 char *end_pos = utf_end(desc); /* points behind utf string */
369 /* method descriptor must start with parenthesis */
370 if (*utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
372 /* check arguments */
373 while ((c = *utf_ptr) != ')') {
374 cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
376 panic("Invalid method descriptor.");
385 /* primitive one-word type */
387 panic("Buffer too small for method arguments.");
389 *typebuf++ = (c == 'F') ? TYPE_FLOAT : TYPE_INT; /* XXX TYPE_FLT? */
390 TYPEINFO_INIT_PRIMITIVE(*infobuf);
396 /* primitive two-word type */
398 panic("Buffer too small for method arguments.");
400 *typebuf++ = (c == 'J') ? TYPE_LONG : TYPE_DOUBLE; /* XXX TYPE_DBL? */
401 TYPEINFO_INIT_PRIMITIVE(*infobuf);
405 panic("Buffer too small for method arguments.");
406 TYPEINFO_INIT_PRIMITIVE(*infobuf);
416 panic("Buffer too small for method arguments.");
418 *typebuf++ = TYPE_ADDRESS;
420 TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
421 /* XXX remove */ /* utf_display(cls->name); */
426 panic ("Ill formed methodtype-descriptor (type)");
429 utf_ptr++; /* skip ')' */
431 /* check returntype */
439 *returntype = TYPE_INT;
443 *returntype = TYPE_LONG;
447 *returntype = TYPE_FLOAT;
451 *returntype = TYPE_DOUBLE;
455 *returntype = TYPE_VOID;
457 if ((utf_ptr+1) != end_pos)
458 panic ("Method-descriptor has exceeding chars");
459 if (returntypeinfo) {
460 TYPEINFO_INIT_PRIMITIVE(*returntypeinfo);
466 *returntype = TYPE_ADDRESS;
467 cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
469 panic("Invalid return type");
470 if (utf_ptr != end_pos)
471 panic ("Method-descriptor has exceeding chars");
472 if (returntypeinfo) {
473 TYPEINFO_INIT_CLASSINFO(*returntypeinfo,cls);
478 panic ("Ill formed methodtype-descriptor (returntype)");
483 /* XXX could be made a macro if really performance critical */
485 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
489 /* XXX find component class */
490 if (!TYPEINFO_IS_ARRAY(*srcarray))
491 panic("Trying to access component of non-array");
493 comp = srcarray->typeclass->vftbl->arraydesc->componentvftbl;
495 TYPEINFO_INIT_CLASSINFO(*dst,comp->class);
498 TYPEINFO_INIT_PRIMITIVE(*dst);
501 /* XXX assign directly ? */
503 if ((dst->dimension = srcarray->dimension - 1) == 0) {
504 dst->typeclass = srcarray->elementclass;
505 dst->elementtype = 0;
506 dst->elementclass = NULL;
509 dst->typeclass = srcarray->typeclass;
510 dst->elementtype = srcarray->elementtype;
511 dst->elementclass = srcarray->elementclass;
515 dst->merged = srcarray->merged;
518 /* Condition: src != dest. */
520 typeinfo_clone(typeinfo *src,typeinfo *dest)
523 classinfo **srclist,**destlist;
527 panic("Internal error: typeinfo_clone with src==dest");
533 count = src->merged->count;
534 TYPEINFO_ALLOCMERGED(dest->merged,count);
535 dest->merged->count = count;
537 /* XXX use memcpy? */
538 srclist = src->merged->list;
539 destlist = dest->merged->list;
541 *destlist++ = *srclist++;
545 /**********************************************************************/
546 /* MISCELLANEOUS FUNCTIONS */
547 /**********************************************************************/
550 typeinfo_free(typeinfo *info)
552 TYPEINFO_FREE(*info);
555 /**********************************************************************/
556 /* MERGING FUNCTIONS */
557 /* The following functions are used to merge the types represented by */
558 /* two typeinfo structures into one typeinfo structure. */
559 /**********************************************************************/
563 typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
565 fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
566 fprintf(stderr,"Typeinfo x:\n");
567 typeinfo_print(stderr,x,1);
568 fprintf(stderr,"Typeinfo y:\n");
569 typeinfo_print(stderr,y,1);
574 /* Condition: clsx != clsy. */
575 /* Returns: true if dest was changed (always true). */
578 typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy)
580 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
581 TYPEINFO_ALLOCMERGED(dest->merged,2);
582 dest->merged->count = 2;
586 panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
590 dest->merged->list[0] = clsx;
591 dest->merged->list[1] = clsy;
594 dest->merged->list[0] = clsy;
595 dest->merged->list[1] = clsx;
601 /* Returns: true if dest was changed. */
604 typeinfo_merge_add(typeinfo *dest,typeinfo_mergedlist *m,classinfo *cls)
607 typeinfo_mergedlist *newmerged;
608 classinfo **mlist,**newlist;
613 /* Check if cls is already in the mergedlist m. */
615 if (*mlist++ == cls) {
616 /* cls is in the list, so m is the resulting mergedlist */
617 if (dest->merged == m)
620 /* We have to copy the mergedlist */
621 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
623 TYPEINFO_ALLOCMERGED(dest->merged,count);
624 dest->merged->count = count;
625 newlist = dest->merged->list;
628 *newlist++ = *mlist++;
634 /* Add cls to the mergedlist. */
636 TYPEINFO_ALLOCMERGED(newmerged,count+1);
637 newmerged->count = count+1;
638 newlist = newmerged->list;
643 *newlist++ = *mlist++;
648 *newlist++ = *mlist++;
651 /* Put the new mergedlist into dest. */
652 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
653 dest->merged = newmerged;
658 /* Returns: true if dest was changed. */
661 typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x,
662 typeinfo_mergedlist *y)
666 typeinfo_mergedlist *temp,*result;
667 classinfo **clsx,**clsy,**newlist;
669 /* count the elements that will be in the resulting list */
670 /* (Both lists are sorted, equal elements are counted only once.) */
675 while (countx && county) {
676 if (*clsx == *clsy) {
682 else if (*clsx < *clsy) {
692 count += countx + county;
694 /* {The new mergedlist will have count entries.} */
696 if (y->count == count) {
697 temp = x; x = y; y = temp;
699 /* {If one of x,y is already the result it is x.} */
700 if (x->count == count) {
701 /* x->merged is equal to the result */
702 if (x == dest->merged)
705 if (!dest->merged || dest->merged->count != count) {
706 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
707 TYPEINFO_ALLOCMERGED(dest->merged,count);
708 dest->merged->count = count;
711 newlist = dest->merged->list;
714 *newlist++ = *clsx++;
719 /* {We have to merge two lists.} */
721 /* allocate the result list */
722 TYPEINFO_ALLOCMERGED(result,count);
723 result->count = count;
724 newlist = result->list;
726 /* merge the sorted lists */
731 while (countx && county) {
732 if (*clsx == *clsy) {
733 *newlist++ = *clsx++;
738 else if (*clsx < *clsy) {
739 *newlist++ = *clsx++;
743 *newlist++ = *clsy++;
748 *newlist++ = *clsx++;
750 *newlist++ = *clsy++;
752 /* replace the list in dest with the result list */
753 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
754 dest->merged = result;
761 typeinfo_merge_nonarrays(typeinfo *dest,
763 classinfo *clsx,classinfo *clsy,
764 typeinfo_mergedlist *mergedx,
765 typeinfo_mergedlist *mergedy)
767 classinfo *tcls,*common;
768 typeinfo_mergedlist *tmerged;
775 printf("typeinfo_merge_nonarrays:\n");
776 TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
777 dbgx.merged = mergedx;
778 TYPEINFO_INIT_CLASSINFO(dbgy,clsy);
779 dbgy.merged = mergedy;
780 typeinfo_print(stdout,&dbgx,4);
782 typeinfo_print(stdout,&dbgy,4);
786 /* Common case: clsx == clsy */
787 /* (This case is very simple unless *both* x and y really represent
788 * merges of subclasses of clsx==clsy.)
790 /* XXX count this case for statistics */
791 if ((clsx == clsy) && (!mergedx || !mergedy)) {
793 /* XXX remove */ /* log_text("return simple x"); */
794 changed = (dest->merged != NULL);
795 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
798 /* XXX remove */ /* log_text("returning"); */
802 /* If clsy is an interface, swap x and y. */
803 if (clsy->flags & ACC_INTERFACE) {
804 tcls = clsx; clsx = clsy; clsy = tcls;
805 tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
807 /* {We know: If only one of x,y is an interface it is x.} */
809 /* Handle merging of interfaces: */
810 if (clsx->flags & ACC_INTERFACE) {
811 /* {clsx is an interface and mergedx == NULL.} */
813 if (clsy->flags & ACC_INTERFACE) {
814 /* We are merging two interfaces. */
815 /* {mergedy == NULL} */
816 /* XXX: should we optimize direct superinterfaces? */
818 /* {We know that clsx!=clsy (see common case at beginning.)} */
819 *result = class_java_lang_Object;
820 return typeinfo_merge_two(dest,clsx,clsy);
823 /* {We know: x is an interface, clsy is a class.} */
825 /* Check if we are merging an interface with java.lang.Object */
826 if (clsy == class_java_lang_Object && !mergedy) {
828 goto return_simple_x;
832 /* If the type y implements clsx then the result of the merge
833 * is clsx regardless of mergedy.
836 if (CLASS_IMPLEMENTS_INTERFACE(clsy,clsx->index)
837 || mergedlist_implements_interface(mergedy,clsx))
839 /* y implements x, so the result of the merge is x. */
840 goto return_simple_x;
843 /* {We know: x is an interface, the type y a class or a merge
844 * of subclasses and does not implement x.} */
846 /* There may still be superinterfaces of x which are implemented
847 * by y, too, so we have to add clsx to the mergedlist.
850 /* XXX if x has no superinterfaces we could return a simple java.lang.Object */
852 common = class_java_lang_Object;
853 goto merge_with_simple_x;
856 /* {We know: x and y are classes (not interfaces).} */
858 /* If *x is deeper in the inheritance hierarchy swap x and y. */
859 if (clsx->index > clsy->index) {
860 tcls = clsx; clsx = clsy; clsy = tcls;
861 tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
864 /* {We know: y is at least as deep in the hierarchy as x.} */
866 /* Find nearest common anchestor for the classes. */
869 while (tcls->index > common->index)
871 while (common != tcls) {
872 common = common->super;
876 /* {common == nearest common anchestor of clsx and clsy.} */
878 /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
880 /* If clsx==common and x is a whole class (not a merge of subclasses)
881 * then the result of the merge is clsx.
883 if (clsx == common && !mergedx) {
884 goto return_simple_x;
890 return typeinfo_merge_mergedlists(dest,mergedx,mergedy);
892 return typeinfo_merge_add(dest,mergedx,clsy);
898 return typeinfo_merge_add(dest,mergedy,clsx);
900 return typeinfo_merge_two(dest,clsx,clsy);
903 /* Condition: *dest must be a valid initialized typeinfo. */
904 /* Condition: dest != y. */
905 /* Returns: true if dest was changed. */
907 typeinfo_merge(typeinfo *dest,typeinfo* y)
910 typeinfo *tmp; /* used for swapping */
912 classinfo *elementclass;
920 typeinfo_print(stdout,dest,4);
921 typeinfo_print(stdout,y,4);
925 /* This function cannot be used to merge primitive types. */
926 if (!dest->typeclass || !y->typeclass)
927 typeinfo_merge_error("Trying to merge primitive types.",dest,y);
931 panic("Internal error: typeinfo_merge with dest==y");
933 /* check that no unlinked classes are merged. */
934 if (!dest->typeclass->linked || !y->typeclass->linked)
935 typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
938 /* XXX remove */ /* log_text("Testing common case"); */
940 /* Common case: class dest == class y */
941 /* (This case is very simple unless *both* dest and y really represent
942 * merges of subclasses of class dest==class y.)
944 /* XXX count this case for statistics */
945 if ((dest->typeclass == y->typeclass) && (!dest->merged || !y->merged)) {
946 changed = (dest->merged != NULL);
947 TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if */
949 /* XXX remove */ /* log_text("common case handled"); */
953 /* XXX remove */ /* log_text("Handling null types"); */
955 /* Handle null types: */
956 if (TYPEINFO_IS_NULLTYPE(*y)) {
959 if (TYPEINFO_IS_NULLTYPE(*dest)) {
960 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
961 TYPEINFO_CLONE(*y,*dest);
965 /* This function uses x internally, so x and y can be swapped
966 * without changing dest. */
970 /* Handle merging of arrays: */
971 if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
973 /* XXX remove */ /* log_text("Handling arrays"); */
975 /* Make x the one with lesser dimension */
976 if (x->dimension > y->dimension) {
977 tmp = x; x = y; y = tmp;
980 /* If one array (y) has higher dimension than the other,
981 * interpret it as an array (same dim. as x) of Arraystubs. */
982 if (x->dimension < y->dimension) {
983 dimension = x->dimension;
984 elementtype = ARRAYTYPE_OBJECT;
985 elementclass = pseudo_class_Arraystub;
988 dimension = y->dimension;
989 elementtype = y->elementtype;
990 elementclass = y->elementclass;
993 /* {The arrays are of the same dimension.} */
995 if (x->elementtype != elementtype) {
996 /* Different element types are merged, so the resulting array
997 * type has one accessible dimension less. */
998 if (--dimension == 0) {
999 common = pseudo_class_Arraystub;
1001 elementclass = NULL;
1004 common = class_multiarray_of(dimension,pseudo_class_Arraystub);
1005 elementtype = ARRAYTYPE_OBJECT;
1006 elementclass = pseudo_class_Arraystub;
1010 /* {The arrays have the same dimension and elementtype.} */
1012 if (elementtype == ARRAYTYPE_OBJECT) {
1013 /* The elements are references, so their respective
1014 * types must be merged.
1016 changed |= typeinfo_merge_nonarrays(dest,
1020 x->merged,y->merged);
1022 /* XXX otimize this? */
1023 /* XXX remove */ /* log_text("finding resulting array class: "); */
1024 common = class_multiarray_of(dimension,elementclass);
1025 /* XXX remove */ /* utf_display(common->name); printf("\n"); */
1030 /* {We know that at least one of x or y is no array, so the
1031 * result cannot be an array.} */
1033 changed |= typeinfo_merge_nonarrays(dest,
1035 x->typeclass,y->typeclass,
1036 x->merged,y->merged);
1040 elementclass = NULL;
1043 /* Put the new values into dest if neccessary. */
1045 if (dest->typeclass != common) {
1046 dest->typeclass = common;
1049 if (dest->dimension != dimension) {
1050 dest->dimension = dimension;
1053 if (dest->elementtype != elementtype) {
1054 dest->elementtype = elementtype;
1057 if (dest->elementclass != elementclass) {
1058 dest->elementclass = elementclass;
1062 /* XXX remove */ /* log_text("returning from merge"); */
1068 /**********************************************************************/
1069 /* DEBUGGING HELPERS */
1070 /**********************************************************************/
1078 typeinfo_test_compare(classinfo **a,classinfo **b)
1080 if (*a == *b) return 0;
1081 if (*a < *b) return -1;
1086 typeinfo_test_parse(typeinfo *info,char *str)
1093 utf *desc = utf_new_char(str);
1095 num = typeinfo_count_method_args(desc,false);
1097 typebuf = DMNEW(u1,num);
1098 infobuf = DMNEW(typeinfo,num);
1100 typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
1103 TYPEINFO_ALLOCMERGED(info->merged,num);
1104 info->merged->count = num;
1106 for (i=0; i<num; ++i) {
1107 if (typebuf[i] != TYPE_ADDRESS)
1108 panic("non-reference type in mergedlist");
1109 info->merged->list[i] = infobuf[i].typeclass;
1111 qsort(info->merged->list,num,sizeof(classinfo*),
1112 (int(*)(const void *,const void *))&typeinfo_test_compare);
1115 typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
1120 #define TYPEINFO_TEST_BUFLEN 4000
1123 typeinfo_equal(typeinfo *x,typeinfo *y)
1127 if (x->typeclass != y->typeclass) return false;
1128 if (x->dimension != y->dimension) return false;
1130 if (x->elementclass != y->elementclass) return false;
1131 if (x->elementtype != y->elementtype) return false;
1133 if (x->merged || y->merged) {
1134 if (!(x->merged && y->merged)) return false;
1135 if (x->merged->count != y->merged->count) return false;
1136 for (i=0; i<x->merged->count; ++i)
1137 if (x->merged->list[i] != y->merged->list[i])
1144 typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
1148 TYPEINFO_CLONE(*a,dest);
1151 typeinfo_print_short(stdout,&dest);
1153 typeinfo_print_short(stdout,b);
1156 typeinfo_merge(&dest,b);
1158 if (typeinfo_equal(&dest,result)) {
1160 typeinfo_print_short(stdout,&dest);
1165 typeinfo_print_short(stdout,&dest);
1167 printf("SHOULD BE ");
1168 typeinfo_print_short(stdout,result);
1175 typeinfo_inc_dimension(typeinfo *info)
1177 if (info->dimension++ == 0) {
1178 info->elementtype = ARRAYTYPE_OBJECT;
1179 info->elementclass = info->typeclass;
1181 info->typeclass = class_array_of(info->typeclass);
1184 #define TYPEINFO_TEST_MAXDIM 10
1187 typeinfo_testrun(char *filename)
1189 char buf[TYPEINFO_TEST_BUFLEN];
1190 char bufa[TYPEINFO_TEST_BUFLEN];
1191 char bufb[TYPEINFO_TEST_BUFLEN];
1192 char bufc[TYPEINFO_TEST_BUFLEN];
1193 typeinfo a,b,c,a2,b2;
1196 FILE *file = fopen(filename,"rt");
1199 panic("could not open typeinfo test file");
1201 while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
1202 if (buf[0] == '#' || !strlen(buf))
1205 int res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
1206 if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc))
1207 panic("Invalid line in typeinfo test file (none of empty, comment or test)");
1209 typeinfo_test_parse(&a,bufa);
1210 typeinfo_test_parse(&b,bufb);
1211 typeinfo_test_parse(&c,bufc);
1213 typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
1214 typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
1216 if (TYPEINFO_IS_NULLTYPE(a)) break;
1217 if (TYPEINFO_IS_NULLTYPE(b)) break;
1218 if (TYPEINFO_IS_NULLTYPE(c)) break;
1220 maxdim = a.dimension;
1221 if (b.dimension > maxdim) maxdim = b.dimension;
1222 if (c.dimension > maxdim) maxdim = c.dimension;
1224 if (maxdim < TYPEINFO_TEST_MAXDIM) {
1225 typeinfo_inc_dimension(&a);
1226 typeinfo_inc_dimension(&b);
1227 typeinfo_inc_dimension(&c);
1229 } while (maxdim < TYPEINFO_TEST_MAXDIM);
1235 fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
1236 panic("Failed test");
1243 /* typeinfo i1,i2,i3,i4,i5,i6,i7,i8; */
1245 /* typeinfo_init_from_fielddescriptor(&i1,"[Ljava/lang/Integer;"); */
1246 /* typeinfo_init_from_fielddescriptor(&i2,"[[Ljava/lang/String;"); */
1247 /* typeinfo_init_from_fielddescriptor(&i3,"[Ljava/lang/Cloneable;"); */
1248 /* typeinfo_init_from_fielddescriptor(&i3,"[[Ljava/lang/String;"); */
1249 /* TYPEINFO_INIT_NULLTYPE(i1); */
1250 /* typeinfo_print_short(stdout,&i1); printf("\n"); */
1251 /* typeinfo_print_short(stdout,&i2); printf("\n"); */
1252 /* typeinfo_merge(&i1,&i2); */
1253 /* typeinfo_print_short(stdout,&i1); printf("\n"); */
1254 /* typeinfo_print_short(stdout,&i3); printf("\n"); */
1255 /* typeinfo_merge(&i1,&i3); */
1256 /* typeinfo_print_short(stdout,&i1); printf("\n"); */
1258 log_text("Running typeinfo test file...");
1259 typeinfo_testrun("typeinfo.tst");
1260 log_text("Finished typeinfo test file.");
1264 typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc)
1266 typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
1269 #define TYPEINFO_MAXINDENT 80
1272 typeinfo_print(FILE *file,typeinfo *info,int indent)
1275 char ind[TYPEINFO_MAXINDENT + 1];
1277 if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
1279 for (i=0; i<indent; ++i)
1283 if (TYPEINFO_IS_PRIMITIVE(*info)) {
1284 fprintf(file,"%sprimitive\n",ind);
1288 if (TYPEINFO_IS_NULLTYPE(*info)) {
1289 fprintf(file,"%snull\n",ind);
1293 fprintf(file,"%sClass: ",ind);
1294 utf_fprint(file,info->typeclass->name);
1297 if (TYPEINFO_IS_ARRAY(*info)) {
1298 fprintf(file,"%sDimension: %d",ind,(int)info->dimension);
1299 fprintf(file,"\n%sElements: ",ind);
1300 switch (info->elementtype) {
1301 case ARRAYTYPE_INT : fprintf(file,"int\n"); break;
1302 case ARRAYTYPE_LONG : fprintf(file,"long\n"); break;
1303 case ARRAYTYPE_FLOAT : fprintf(file,"float\n"); break;
1304 case ARRAYTYPE_DOUBLE : fprintf(file,"double\n"); break;
1305 case ARRAYTYPE_BYTE : fprintf(file,"byte\n"); break;
1306 case ARRAYTYPE_CHAR : fprintf(file,"char\n"); break;
1307 case ARRAYTYPE_SHORT : fprintf(file,"short\n"); break;
1308 case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
1310 case ARRAYTYPE_OBJECT:
1311 fprintf(file,"reference: ");
1312 utf_fprint(file,info->elementclass->name);
1317 fprintf(file,"INVALID ARRAYTYPE!\n");
1322 fprintf(file,"%sMerged: ",ind);
1323 for (i=0; i<info->merged->count; ++i) {
1324 if (i) fprintf(file,", ");
1325 utf_fprint(file,info->merged->list[i]->name);
1332 typeinfo_print_short(FILE *file,typeinfo *info)
1336 if (TYPEINFO_IS_PRIMITIVE(*info)) {
1337 fprintf(file,"primitive");
1341 if (TYPEINFO_IS_NULLTYPE(*info)) {
1342 fprintf(file,"null");
1346 utf_fprint(file,info->typeclass->name);
1350 if (TYPEINFO_IS_ARRAY(*info)) {
1351 fprintf(file,"[%d]",info->dimension);
1352 switch (info->elementtype) {
1353 case ARRAYTYPE_INT : fprintf(file,"int"); break;
1354 case ARRAYTYPE_LONG : fprintf(file,"long"); break;
1355 case ARRAYTYPE_FLOAT : fprintf(file,"float"); break;
1356 case ARRAYTYPE_DOUBLE : fprintf(file,"double"); break;
1357 case ARRAYTYPE_BYTE : fprintf(file,"byte"); break;
1358 case ARRAYTYPE_CHAR : fprintf(file,"char"); break;
1359 case ARRAYTYPE_SHORT : fprintf(file,"short"); break;
1360 case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
1362 case ARRAYTYPE_OBJECT:
1363 fprintf(file,"object(");
1364 utf_fprint(file,info->elementclass->name);
1369 fprintf(file,"INVALID ARRAYTYPE!");
1376 for (i=0; i<info->merged->count; ++i) {
1377 if (i) fprintf(file,",");
1378 utf_fprint(file,info->merged->list[i]->name);
1385 typeinfo_print_type(FILE *file,int type,typeinfo *info)
1388 case TYPE_VOID: fprintf(file,"V"); break;
1389 case TYPE_INT: fprintf(file,"I"); break;
1390 case TYPE_FLOAT: fprintf(file,"F"); break;
1391 case TYPE_DOUBLE: fprintf(file,"D"); break;
1392 case TYPE_LONG: fprintf(file,"J"); break;
1394 if (TYPEINFO_IS_PRIMITIVE(*info))
1395 fprintf(file,"R"); /* returnAddress */
1398 typeinfo_print_short(file,info);
1408 #endif // DEBUG_TYPES