1 /* src/vm/linker.c - class linker functions
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 Institut f. Computersprachen - TU Wien
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: Reinhard Grafl
29 Changes: Andreas Krall
35 $Id: linker.c 2458 2005-05-12 23:02:07Z twisti $
42 #include "mm/memory.h"
43 #include "native/native.h"
44 #include "vm/builtin.h"
46 #include "vm/classcache.h"
47 #include "vm/exceptions.h"
48 #include "vm/loader.h"
49 #include "vm/options.h"
50 #include "vm/resolve.h"
51 #include "vm/statistics.h"
52 #include "vm/stringlocal.h"
53 #include "vm/jit/codegen.inc.h"
56 /* global variables ***********************************************************/
58 static s4 interfaceindex; /* sequential numbering of interfaces */
62 /* primitivetype_table *********************************************************
64 Structure for primitive classes: contains the class for wrapping
65 the primitive type, the primitive class, the name of the class for
66 wrapping, the one character type signature and the name of the
69 CAUTION: Don't change the order of the types. This table is indexed
70 by the ARRAYTYPE_ constants (expcept ARRAYTYPE_OBJECT).
72 *******************************************************************************/
74 primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = {
75 { NULL, NULL, "java/lang/Integer", 'I', "int" , "[I", NULL, NULL },
76 { NULL, NULL, "java/lang/Long", 'J', "long" , "[J", NULL, NULL },
77 { NULL, NULL, "java/lang/Float", 'F', "float" , "[F", NULL, NULL },
78 { NULL, NULL, "java/lang/Double", 'D', "double" , "[D", NULL, NULL },
79 { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL },
80 { NULL, NULL, "java/lang/Byte", 'B', "byte" , "[B", NULL, NULL },
81 { NULL, NULL, "java/lang/Character", 'C', "char" , "[C", NULL, NULL },
82 { NULL, NULL, "java/lang/Short", 'S', "short" , "[S", NULL, NULL },
83 { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" , "[Z", NULL, NULL },
84 { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL },
85 { NULL, NULL, "java/lang/Void", 'V', "void" , NULL, NULL, NULL }
89 /* private functions **********************************************************/
91 static bool link_primitivetype_table(void);
92 static classinfo *link_class_intern(classinfo *c);
93 static arraydescriptor *link_array(classinfo *c);
94 static void linker_compute_class_values(classinfo *c);
95 static void linker_compute_subclasses(classinfo *c);
96 static void linker_addinterface(classinfo *c, classinfo *ic);
97 static s4 class_highestinterface(classinfo *c);
100 /* linker_init *****************************************************************
102 Initializes the linker subsystem.
104 *******************************************************************************/
106 bool linker_init(void)
108 /* reset interface index */
112 /* link important system classes */
114 if (!link_class(class_java_lang_Object))
117 if (!link_class(class_java_lang_String))
120 if (!link_class(class_java_lang_Cloneable))
123 if (!link_class(class_java_io_Serializable))
127 /* link classes for wrapping primitive types */
129 if (!link_class(class_java_lang_Void))
132 if (!link_class(class_java_lang_Boolean))
135 if (!link_class(class_java_lang_Byte))
138 if (!link_class(class_java_lang_Character))
141 if (!link_class(class_java_lang_Short))
144 if (!link_class(class_java_lang_Integer))
147 if (!link_class(class_java_lang_Long))
150 if (!link_class(class_java_lang_Float))
153 if (!link_class(class_java_lang_Double))
157 /* load some other important classes */
159 if (!link_class(class_java_lang_Class))
162 if (!link_class(class_java_lang_ClassLoader))
165 if (!link_class(class_java_lang_SecurityManager))
168 if (!link_class(class_java_lang_System))
171 if (!link_class(class_java_lang_ThreadGroup))
175 if (!link_class(class_java_util_Vector))
179 /* create pseudo classes used by the typechecker */
181 /* pseudo class for Arraystubs (extends java.lang.Object) */
183 pseudo_class_Arraystub =
184 class_create_classinfo(utf_new_char("$ARRAYSTUB$"));
185 pseudo_class_Arraystub->loaded = true;
186 pseudo_class_Arraystub->super.cls = class_java_lang_Object;
187 pseudo_class_Arraystub->interfacescount = 2;
188 pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2);
189 pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable;
190 pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable;
191 if (!classcache_store(NULL, pseudo_class_Arraystub))
192 panic("could not cache pseudo_class_Arraystub");
194 if (!link_class(pseudo_class_Arraystub))
197 /* pseudo class representing the null type */
199 pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$"));
200 pseudo_class_Null->loaded = true;
201 pseudo_class_Null->super.cls = class_java_lang_Object;
202 if (!classcache_store(NULL, pseudo_class_Null))
203 panic("could not cache pseudo_class_Null");
205 if (!link_class(pseudo_class_Null))
208 /* pseudo class representing new uninitialized objects */
210 pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$"));
211 pseudo_class_New->loaded = true;
212 pseudo_class_New->linked = true; /* XXX is this allright? */
213 pseudo_class_New->super.cls = class_java_lang_Object;
214 if (!classcache_store(NULL,pseudo_class_New))
215 panic("could not cache pseudo_class_New");
217 /* create classes representing primitive types */
219 if (!link_primitivetype_table())
223 /* Correct vftbl-entries (retarded loading and linking of class */
224 /* java/lang/String). */
226 stringtable_update();
232 /* link_primitivetype_table ****************************************************
234 Create classes representing primitive types.
236 *******************************************************************************/
238 static bool link_primitivetype_table(void)
243 for (i = 0; i < PRIMITIVETYPE_COUNT; i++) {
245 if (!primitivetype_table[i].name)
248 /* create primitive class */
249 c = class_create_classinfo(utf_new_char(primitivetype_table[i].name));
250 c->classUsed = NOTUSED; /* not used initially CO-RT */
253 /* prevent loader from loading primitive class */
255 if (!classcache_store(NULL,c)) {
256 log_text("Could not cache primitive class");
262 primitivetype_table[i].class_primitive = c;
264 /* create class for wrapping the primitive type */
265 if (!load_class_bootstrap(utf_new_char(primitivetype_table[i].wrapname),&c))
267 primitivetype_table[i].class_wrap = c;
268 primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */
269 primitivetype_table[i].class_wrap->impldBy = NULL;
271 /* create the primitive array class */
272 if (primitivetype_table[i].arrayname) {
273 c = class_create_classinfo(utf_new_char(primitivetype_table[i].arrayname));
274 if (!load_newly_created_array(c, NULL))
276 primitivetype_table[i].arrayclass = c;
281 primitivetype_table[i].arrayvftbl = c->vftbl;
289 /* link_class ******************************************************************
291 Wrapper function for link_class_intern to ease monitor enter/exit
292 and exception handling.
294 *******************************************************************************/
296 classinfo *link_class(classinfo *c)
301 *exceptionptr = new_nullpointerexception();
305 #if defined(USE_THREADS)
306 /* enter a monitor on the class */
308 builtin_monitorenter((java_objectheader *) c);
311 /* maybe the class is already linked */
313 #if defined(USE_THREADS)
314 builtin_monitorexit((java_objectheader *) c);
320 #if defined(STATISTICS)
323 if (getcompilingtime)
324 compilingtime_stop();
330 /* call the internal function */
331 r = link_class_intern(c);
333 /* if return value is NULL, we had a problem and the class is not linked */
337 #if defined(STATISTICS)
343 if (getcompilingtime)
344 compilingtime_start();
347 #if defined(USE_THREADS)
348 /* leave the monitor */
350 builtin_monitorexit((java_objectheader *) c);
357 /* link_class_intern ***********************************************************
359 Tries to link a class. The function calculates the length in bytes
360 that an instance of this class requires as well as the VTBL for
361 methods and interface methods.
363 *******************************************************************************/
365 static classinfo *link_class_intern(classinfo *c)
367 classinfo *super; /* super class */
368 classinfo *tc; /* temporary class variable */
369 s4 supervftbllength; /* vftbllegnth of super class */
370 s4 vftbllength; /* vftbllength of current class */
371 s4 interfacetablelength; /* interface table length */
372 vftbl_t *v; /* vftbl of current class */
373 s4 i,j; /* interface/method/field counter */
374 arraydescriptor *arraydesc; /* descriptor for array classes */
376 /* maybe the class is already linked */
381 log_message_class("Linking class: ", c);
383 /* the class must be loaded */
385 throw_cacao_exception_exit(string_java_lang_InternalError,
386 "Trying to link unloaded class");
388 /* ok, this class is somewhat linked */
393 /* check interfaces */
395 for (i = 0; i < c->interfacescount; i++) {
396 /* resolve this super interface */
397 if (!resolve_classref_or_classinfo(NULL,c->interfaces[i],resolveEager,false,&tc))
399 c->interfaces[i].cls = tc;
401 /* detect circularity */
405 new_exception_utfmessage(string_java_lang_ClassCircularityError,
412 if (!(tc->flags & ACC_INTERFACE)) {
414 new_exception_message(string_java_lang_IncompatibleClassChangeError,
415 "Implementing class");
424 /* check super class */
427 if (c->super.any == NULL) { /* class java.lang.Object */
429 c->classUsed = USED; /* Object class is always used CO-RT*/
431 c->instancesize = sizeof(java_objectheader);
433 vftbllength = supervftbllength = 0;
438 /* resolve super class */
439 if (!resolve_classref_or_classinfo(NULL,c->super,resolveEager,false,&super))
441 c->super.cls = super;
443 /* detect circularity */
446 new_exception_utfmessage(string_java_lang_ClassCircularityError,
451 assert(super->loaded);
453 if (super->flags & ACC_INTERFACE) {
454 /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */
455 panic("Interface specified as super class");
458 /* Don't allow extending final classes */
459 if (super->flags & ACC_FINAL) {
461 new_exception_message(string_java_lang_VerifyError,
462 "Cannot inherit from final class");
467 if (!link_class(super))
470 /* handle array classes */
471 if (c->name->text[0] == '[')
472 if (!(arraydesc = link_array(c)))
475 if (c->flags & ACC_INTERFACE)
476 c->index = interfaceindex++;
478 c->index = super->index + 1;
480 c->instancesize = super->instancesize;
482 vftbllength = supervftbllength = super->vftbl->vftbllength;
484 c->finalizer = super->finalizer;
488 /* compute vftbl length */
490 for (i = 0; i < c->methodscount; i++) {
491 methodinfo *m = &(c->methods[i]);
493 if (!(m->flags & ACC_STATIC)) { /* is instance method */
499 for (j = 0; j < tc->methodscount; j++) {
500 if (method_canoverwrite(m, &(tc->methods[j]))) {
501 if (tc->methods[j].flags & ACC_PRIVATE)
502 goto notfoundvftblindex;
504 if (tc->methods[j].flags & ACC_FINAL) {
505 /* class a overrides final method . */
507 new_exception(string_java_lang_VerifyError);
511 m->vftblindex = tc->methods[j].vftblindex;
512 goto foundvftblindex;
520 m->vftblindex = (vftbllength++);
527 /* check interfaces of ABSTRACT class for unimplemented methods */
529 if (c->flags & ACC_ABSTRACT) {
532 s4 abstractmethodscount;
536 abstractmethodscount = 0;
538 for (i = 0; i < c->interfacescount; i++) {
539 ic = c->interfaces[i].cls;
541 for (j = 0; j < ic->methodscount; j++) {
542 im = &(ic->methods[j]);
544 /* skip `<clinit>' and `<init>' */
546 if (im->name == utf_clinit || im->name == utf_init)
552 for (k = 0; k < tc->methodscount; k++) {
553 if (method_canoverwrite(im, &(tc->methods[k])))
554 goto noabstractmethod;
560 abstractmethodscount++;
567 if (abstractmethodscount > 0) {
570 /* reallocate methods memory */
572 c->methods = MREALLOC(c->methods, methodinfo, c->methodscount,
573 c->methodscount + abstractmethodscount);
575 for (i = 0; i < c->interfacescount; i++) {
576 ic = c->interfaces[i].cls;
578 for (j = 0; j < ic->methodscount; j++) {
579 im = &(ic->methods[j]);
581 /* skip `<clinit>' and `<init>' */
583 if (im->name == utf_clinit || im->name == utf_init)
589 for (k = 0; k < tc->methodscount; k++) {
590 if (method_canoverwrite(im, &(tc->methods[k])))
591 goto noabstractmethod2;
597 am = &(c->methods[c->methodscount]);
600 MCOPY(am, im, methodinfo, 1);
602 am->vftblindex = (vftbllength++);
613 #if defined(STATISTICS)
616 sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
619 /* compute interfacetable length */
621 interfacetablelength = 0;
624 for (i = 0; i < tc->interfacescount; i++) {
625 s4 h = class_highestinterface(tc->interfaces[i].cls) + 1;
626 if (h > interfacetablelength)
627 interfacetablelength = h;
632 /* allocate virtual function table */
634 v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) +
635 sizeof(methodptr) * (vftbllength - 1) +
636 sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0)));
637 v = (vftbl_t *) (((methodptr *) v) +
638 (interfacetablelength - 1) * (interfacetablelength > 1));
639 c->header.vftbl = c->vftbl = v;
641 v->vftbllength = vftbllength;
642 v->interfacetablelength = interfacetablelength;
643 v->arraydesc = arraydesc;
645 /* store interface index in vftbl */
647 if (c->flags & ACC_INTERFACE)
648 v->baseval = -(c->index);
650 /* copy virtual function table of super class */
652 for (i = 0; i < supervftbllength; i++)
653 v->table[i] = super->vftbl->table[i];
655 /* add method stubs into virtual function table */
657 for (i = 0; i < c->methodscount; i++) {
658 methodinfo *m = &(c->methods[i]);
660 /* Methods in ABSTRACT classes from interfaces maybe already have a */
663 if (!m->stubroutine) {
664 if (!(m->flags & ACC_NATIVE)) {
665 m->stubroutine = createcompilerstub(m);
668 functionptr f = native_findfunction(c->name,
671 (m->flags & ACC_STATIC));
672 #if defined(STATIC_CLASSPATH)
675 m->stubroutine = createnativestub(f, m);
679 if (!(m->flags & ACC_STATIC))
680 v->table[m->vftblindex] = m->stubroutine;
683 /* compute instance size and offset of each field */
685 for (i = 0; i < c->fieldscount; i++) {
687 fieldinfo *f = &(c->fields[i]);
689 if (!(f->flags & ACC_STATIC)) {
690 dsize = desc_typesize(f->descriptor);
691 c->instancesize = ALIGN(c->instancesize, dsize);
692 f->offset = c->instancesize;
693 c->instancesize += dsize;
697 /* initialize interfacetable and interfacevftbllength */
699 v->interfacevftbllength = MNEW(s4, interfacetablelength);
701 #if defined(STATISTICS)
703 count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
706 for (i = 0; i < interfacetablelength; i++) {
707 v->interfacevftbllength[i] = 0;
708 v->interfacetable[-i] = NULL;
713 for (tc = c; tc != NULL; tc = tc->super.cls)
714 for (i = 0; i < tc->interfacescount; i++)
715 linker_addinterface(c, tc->interfaces[i].cls);
717 /* add finalizer method (not for java.lang.Object) */
722 fi = class_findmethod(c, utf_finalize, utf_void__void);
725 if (!(fi->flags & ACC_STATIC))
729 /* resolve exception class references */
731 for (i = 0; i < c->methodscount; i++) {
732 methodinfo *m = c->methods + i;
733 for (j=0; j<m->exceptiontablelength; ++j) {
734 if (!m->exceptiontable[j].catchtype.any)
736 if (!resolve_classref_or_classinfo(NULL,m->exceptiontable[j].catchtype,
737 resolveEager,false,&(m->exceptiontable[j].catchtype.cls)))
740 for (j=0; j<m->thrownexceptionscount; ++j)
741 if (!resolve_classref_or_classinfo(NULL,m->thrownexceptions[j],
742 resolveEager,false,&(m->thrownexceptions[j].cls)))
748 linker_compute_subclasses(c);
751 log_message_class("Linking done class: ", c);
753 /* just return c to show that we didn't had a problem */
759 /* link_array ******************************************************************
761 This function is called by link_class to create the arraydescriptor
764 This function returns NULL if the array cannot be linked because
765 the component type has not been linked yet.
767 *******************************************************************************/
769 static arraydescriptor *link_array(classinfo *c)
771 classinfo *comp = NULL;
772 s4 namelen = c->name->blength;
773 arraydescriptor *desc;
776 /* Check the component type */
777 switch (c->name->text[1]) {
779 /* c is an array of arrays. */
780 if (!load_class_from_classloader(utf_new_intern(c->name->text + 1, namelen - 1),
781 c->classloader,&comp))
786 /* c is an array of objects. */
787 if (!load_class_from_classloader(utf_new_intern(c->name->text + 2, namelen - 3),
788 c->classloader,&comp))
793 /* If the component type has not been linked, link it now */
794 assert(!comp || comp->loaded);
795 if (comp && !comp->linked) {
797 if (!link_class(comp))
801 /* Allocate the arraydescriptor */
802 desc = NEW(arraydescriptor);
805 /* c is an array of references */
806 desc->arraytype = ARRAYTYPE_OBJECT;
807 desc->componentsize = sizeof(void*);
808 desc->dataoffset = OFFSET(java_objectarray, data);
810 compvftbl = comp->vftbl;
812 panic("Component class has no vftbl");
813 desc->componentvftbl = compvftbl;
815 if (compvftbl->arraydesc) {
816 desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
817 if (compvftbl->arraydesc->dimension >= 255)
818 panic("Creating array of dimension >255");
819 desc->dimension = compvftbl->arraydesc->dimension + 1;
820 desc->elementtype = compvftbl->arraydesc->elementtype;
823 desc->elementvftbl = compvftbl;
825 desc->elementtype = ARRAYTYPE_OBJECT;
829 /* c is an array of a primitive type */
830 switch (c->name->text[1]) {
832 desc->arraytype = ARRAYTYPE_BOOLEAN;
833 desc->dataoffset = OFFSET(java_booleanarray,data);
834 desc->componentsize = sizeof(u1);
838 desc->arraytype = ARRAYTYPE_BYTE;
839 desc->dataoffset = OFFSET(java_bytearray,data);
840 desc->componentsize = sizeof(u1);
844 desc->arraytype = ARRAYTYPE_CHAR;
845 desc->dataoffset = OFFSET(java_chararray,data);
846 desc->componentsize = sizeof(u2);
850 desc->arraytype = ARRAYTYPE_DOUBLE;
851 desc->dataoffset = OFFSET(java_doublearray,data);
852 desc->componentsize = sizeof(double);
856 desc->arraytype = ARRAYTYPE_FLOAT;
857 desc->dataoffset = OFFSET(java_floatarray,data);
858 desc->componentsize = sizeof(float);
862 desc->arraytype = ARRAYTYPE_INT;
863 desc->dataoffset = OFFSET(java_intarray,data);
864 desc->componentsize = sizeof(s4);
868 desc->arraytype = ARRAYTYPE_LONG;
869 desc->dataoffset = OFFSET(java_longarray,data);
870 desc->componentsize = sizeof(s8);
874 desc->arraytype = ARRAYTYPE_SHORT;
875 desc->dataoffset = OFFSET(java_shortarray,data);
876 desc->componentsize = sizeof(s2);
880 panic("Invalid array class name");
883 desc->componentvftbl = NULL;
884 desc->elementvftbl = NULL;
886 desc->elementtype = desc->arraytype;
893 /* linker_compute_subclasses ***************************************************
897 *******************************************************************************/
899 static void linker_compute_subclasses(classinfo *c)
901 #if defined(USE_THREADS)
902 #if defined(NATIVE_THREADS)
909 if (!(c->flags & ACC_INTERFACE)) {
914 if (!(c->flags & ACC_INTERFACE) && (c->super.any != NULL)) {
915 c->nextsub = c->super.cls->sub;
916 c->super.cls->sub = c;
921 /* this is the java.lang.Object special case */
923 if (!class_java_lang_Object) {
924 linker_compute_class_values(c);
927 linker_compute_class_values(class_java_lang_Object);
930 #if defined(USE_THREADS)
931 #if defined(NATIVE_THREADS)
940 /* linker_compute_class_values *************************************************
944 *******************************************************************************/
946 static void linker_compute_class_values(classinfo *c)
950 c->vftbl->baseval = ++classvalue;
955 linker_compute_class_values(subs);
957 subs = subs->nextsub;
960 c->vftbl->diffval = classvalue - c->vftbl->baseval;
964 /* linker_addinterface *********************************************************
966 Is needed by link_class for adding a VTBL to a class. All
967 interfaces implemented by ic are added as well.
969 *******************************************************************************/
971 static void linker_addinterface(classinfo *c, classinfo *ic)
975 vftbl_t *v = c->vftbl;
977 if (i >= v->interfacetablelength)
978 panic ("Inernal error: interfacetable overflow");
980 if (v->interfacetable[-i])
983 if (ic->methodscount == 0) { /* fake entry needed for subtype test */
984 v->interfacevftbllength[i] = 1;
985 v->interfacetable[-i] = MNEW(methodptr, 1);
986 v->interfacetable[-i][0] = NULL;
989 v->interfacevftbllength[i] = ic->methodscount;
990 v->interfacetable[-i] = MNEW(methodptr, ic->methodscount);
992 #if defined(STATISTICS)
994 count_vftbl_len += sizeof(methodptr) *
995 (ic->methodscount + (ic->methodscount == 0));
998 for (j = 0; j < ic->methodscount; j++) {
1002 for (m = 0; m < sc->methodscount; m++) {
1003 methodinfo *mi = &(sc->methods[m]);
1005 if (method_canoverwrite(mi, &(ic->methods[j]))) {
1006 v->interfacetable[-i][j] = v->table[mi->vftblindex];
1017 for (j = 0; j < ic->interfacescount; j++)
1018 linker_addinterface(c, ic->interfaces[j].cls);
1022 /* class_highestinterface ******************************************************
1024 Used by the function link_class to determine the amount of memory
1025 needed for the interface table.
1027 *******************************************************************************/
1029 static s4 class_highestinterface(classinfo *c)
1035 /* check for ACC_INTERFACE bit already done in link_class_intern */
1039 for (i = 0; i < c->interfacescount; i++) {
1040 h2 = class_highestinterface(c->interfaces[i].cls);
1050 /***************** Function: print_arraydescriptor ****************************
1052 Debug helper for displaying an arraydescriptor
1054 *******************************************************************************/
1056 void print_arraydescriptor(FILE *file, arraydescriptor *desc)
1059 fprintf(file, "<NULL>");
1064 if (desc->componentvftbl) {
1065 if (desc->componentvftbl->class)
1066 utf_fprint(file, desc->componentvftbl->class->name);
1068 fprintf(file, "<no classinfo>");
1074 if (desc->elementvftbl) {
1075 if (desc->elementvftbl->class)
1076 utf_fprint(file, desc->elementvftbl->class->name);
1078 fprintf(file, "<no classinfo>");
1082 fprintf(file, ",%d,%d,%d,%d}", desc->arraytype, desc->dimension,
1083 desc->dataoffset, desc->componentsize);
1088 * These are local overrides for various environment variables in Emacs.
1089 * Please do not remove this and leave it at the end of the file, where
1090 * Emacs will automagically detect them.
1091 * ---------------------------------------------------------------------
1094 * indent-tabs-mode: t