1 /* src/vm/loader.c - class loader 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: loader.c 2303 2005-04-14 12:04:42Z edwin $
45 #include "mm/memory.h"
46 #include "native/native.h"
47 #include "native/include/java_lang_Throwable.h"
49 #if defined(USE_THREADS)
50 # if defined(NATIVE_THREADS)
51 # include "threads/native/threads.h"
53 # include "threads/green/threads.h"
54 # include "threads/green/locks.h"
58 #include "toolbox/logging.h"
59 #include "toolbox/util.h"
60 #include "vm/exceptions.h"
61 #include "vm/builtin.h"
62 #include "vm/global.h"
63 #include "vm/linker.h"
64 #include "vm/loader.h"
65 #include "vm/options.h"
66 #include "vm/statistics.h"
67 #include "vm/stringlocal.h"
68 #include "vm/tables.h"
69 #include "vm/classcache.h"
72 # include "vm/unzip.h"
75 #include "vm/jit/asmpart.h"
76 #include "vm/jit/codegen.inc.h"
78 /******************************************************************************/
80 /******************************************************************************/
82 /*#define LOADER_VERBOSE*/
89 #define LOADER_ASSERT(cond) assert(cond)
91 #define LOADER_ASSERT(cond)
99 static int loader_recursion = 0;
100 #define LOADER_INDENT(str) do { int i; for(i=0;i<loader_recursion*4;++i) {str[i]=' ';} str[i]=0;} while (0)
101 #define LOADER_INC() loader_recursion++
102 #define LOADER_DEC() loader_recursion--
109 /********************************************************************
110 list of classpath entries (either filesystem directories or
112 ********************************************************************/
114 classpath_info *classpath_entries = NULL;
116 /* loader_init *****************************************************************
118 Initializes all lists and loads all classes required for the system
121 *******************************************************************************/
123 bool loader_init(u1 *stackbottom)
127 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
128 /* Initialize the monitor pointer for zip/jar file locking. */
130 for (cpi = classpath_entries; cpi != NULL; cpi = cpi->next) {
131 if (cpi->type == CLASSPATH_ARCHIVE)
132 initObjectLock(&cpi->header);
136 /* load some important classes */
138 if (!load_class_bootstrap(utf_java_lang_Object, &class_java_lang_Object))
141 if (!load_class_bootstrap(utf_java_lang_String, &class_java_lang_String))
144 if (!load_class_bootstrap(utf_java_lang_Cloneable, &class_java_lang_Cloneable))
147 if (!load_class_bootstrap(utf_java_io_Serializable, &class_java_io_Serializable))
151 /* load classes for wrapping primitive types */
153 if (!load_class_bootstrap(utf_java_lang_Void, &class_java_lang_Void))
156 if (!load_class_bootstrap(utf_java_lang_Boolean, &class_java_lang_Boolean))
159 if (!load_class_bootstrap(utf_java_lang_Byte, &class_java_lang_Byte))
162 if (!load_class_bootstrap(utf_java_lang_Character, &class_java_lang_Character))
165 if (!load_class_bootstrap(utf_java_lang_Short, &class_java_lang_Short))
168 if (!load_class_bootstrap(utf_java_lang_Integer, &class_java_lang_Integer))
171 if (!load_class_bootstrap(utf_java_lang_Long, &class_java_lang_Long))
174 if (!load_class_bootstrap(utf_java_lang_Float, &class_java_lang_Float))
177 if (!load_class_bootstrap(utf_java_lang_Double, &class_java_lang_Double))
181 /* load some other important classes */
183 if (!load_class_bootstrap(utf_java_lang_Class, &class_java_lang_Class))
186 if (!load_class_bootstrap(utf_java_lang_ClassLoader, &class_java_lang_ClassLoader))
189 if (!load_class_bootstrap(utf_java_lang_SecurityManager, &class_java_lang_SecurityManager))
192 if (!load_class_bootstrap(utf_java_lang_System, &class_java_lang_System))
196 if (!load_class_bootstrap(utf_java_util_Vector, &class_java_util_Vector))
199 #if defined(USE_THREADS)
200 if (stackbottom != 0)
208 /************* functions for reading classdata *********************************
210 getting classdata in blocks of variable size
211 (8,16,32,64-bit integer or float)
213 *******************************************************************************/
215 /* check_classbuffer_size ******************************************************
217 assert that at least <len> bytes are left to read
218 <len> is limited to the range of non-negative s4 values
220 *******************************************************************************/
222 inline bool check_classbuffer_size(classbuffer *cb, s4 len)
224 if (len < 0 || ((cb->data + cb->size) - cb->pos - 1) < len) {
226 new_classformaterror((cb)->class, "Truncated class file");
235 /* suck_nbytes *****************************************************************
237 transfer block of classfile data into a buffer
239 *******************************************************************************/
241 inline void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
243 memcpy(buffer, cb->pos + 1, len);
248 /* skip_nbytes ****************************************************************
250 skip block of classfile data
252 *******************************************************************************/
254 inline void skip_nbytes(classbuffer *cb, s4 len)
260 inline u1 suck_u1(classbuffer *cb)
266 inline u2 suck_u2(classbuffer *cb)
270 return ((u2) a << 8) + (u2) b;
274 inline u4 suck_u4(classbuffer *cb)
280 return ((u4) a << 24) + ((u4) b << 16) + ((u4) c << 8) + (u4) d;
284 /* get u8 from classfile data */
285 static u8 suck_u8(classbuffer *cb)
291 return (hi << 32) + lo;
294 v.high = suck_u4(cb);
301 /* get float from classfile data */
302 static float suck_float(classbuffer *cb)
310 for (i = 0; i < 4; i++)
311 buffer[3 - i] = suck_u1(cb);
313 memcpy((u1*) (&f), buffer, 4);
315 suck_nbytes((u1*) (&f), cb, 4);
318 if (sizeof(float) != 4) {
319 *exceptionptr = new_exception_message(string_java_lang_InternalError,
320 "Incompatible float-format");
322 /* XXX should we exit in such a case? */
323 throw_exception_exit();
330 /* get double from classfile data */
331 static double suck_double(classbuffer *cb)
339 for (i = 0; i < 8; i++)
340 buffer[7 - i] = suck_u1(cb);
342 memcpy((u1*) (&d), buffer, 8);
344 suck_nbytes((u1*) (&d), cb, 8);
347 if (sizeof(double) != 8) {
348 *exceptionptr = new_exception_message(string_java_lang_InternalError,
349 "Incompatible double-format");
351 /* XXX should we exit in such a case? */
352 throw_exception_exit();
359 /************************** function suck_init *********************************
361 called once at startup, sets the searchpath for the classfiles
363 *******************************************************************************/
365 void suck_init(char *classpath)
373 classpath_info *lastcpi;
377 /* search for last classpath entry (only if there already some) */
379 if ((lastcpi = classpath_entries)) {
380 while (lastcpi->next)
381 lastcpi = lastcpi->next;
384 for (start = classpath; (*start) != '\0';) {
386 /* search for ':' delimiter to get the end of the current entry */
387 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
391 filenamelen = end - start;
393 if (filenamelen > 3) {
394 if (strncasecmp(end - 3, "zip", 3) == 0 ||
395 strncasecmp(end - 3, "jar", 3) == 0) {
400 /* save classpath entries as absolute pathnames */
405 if (*start != '/') { /* XXX fix me for win32 */
407 cwdlen = strlen(cwd) + strlen("/");
410 /* allocate memory for filename and fill it */
412 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
416 strcpy(filename, cwd);
417 strcat(filename, "/");
418 strncat(filename, start, filenamelen);
420 /* add cwd length to file length */
421 filenamelen += cwdlen;
424 strncpy(filename, start, filenamelen);
425 filename[filenamelen] = '\0';
431 #if defined(USE_ZLIB)
432 unzFile uf = unzOpen(filename);
435 cpi = NEW(classpath_info);
436 cpi->type = CLASSPATH_ARCHIVE;
439 cpi->path = filename;
440 cpi->pathlen = filenamelen;
444 throw_cacao_exception_exit(string_java_lang_InternalError,
445 "zip/jar files not supported");
449 cpi = NEW(classpath_info);
450 cpi->type = CLASSPATH_PATH;
453 if (filename[filenamelen - 1] != '/') {/*PERHAPS THIS SHOULD BE READ FROM A GLOBAL CONFIGURATION */
454 filename[filenamelen] = '/';
455 filename[filenamelen + 1] = '\0';
459 cpi->path = filename;
460 cpi->pathlen = filenamelen;
463 /* attach current classpath entry */
466 if (!classpath_entries)
467 classpath_entries = cpi;
475 /* goto next classpath entry, skip ':' delimiter */
487 void create_all_classes()
492 for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) {
493 #if defined(USE_ZLIB)
494 if (cpi->type == CLASSPATH_ARCHIVE) {
498 s = (unz_s *) cpi->uf;
499 ce = s->cacao_dir_list;
502 load_class_bootstrap(ce->name,&c);
508 #if defined(USE_ZLIB)
515 /* suck_start ******************************************************************
517 Returns true if classbuffer is already loaded or a file for the
518 specified class has succussfully been read in. All directories of
519 the searchpath are used to find the classfile (<classname>.class).
520 Returns false if no classfile is found and writes an error message.
522 *******************************************************************************/
524 classbuffer *suck_start(classinfo *c)
536 /* initialize return value */
541 filenamelen = utf_strlen(c->name) + strlen(".class") + strlen("0");
542 filename = MNEW(char, filenamelen);
544 utf_sprint(filename, c->name);
545 strcat(filename, ".class");
547 /* walk through all classpath entries */
549 for (cpi = classpath_entries; cpi != NULL && cb == NULL; cpi = cpi->next) {
550 #if defined(USE_ZLIB)
551 if (cpi->type == CLASSPATH_ARCHIVE) {
553 #if defined(USE_THREADS)
554 /* enter a monitor on zip/jar archives */
556 builtin_monitorenter((java_objectheader *) cpi);
559 if (cacao_locate(cpi->uf, c->name) == UNZ_OK) {
560 unz_file_info file_info;
562 if (unzGetCurrentFileInfo(cpi->uf, &file_info, filename,
563 sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) {
564 if (unzOpenCurrentFile(cpi->uf) == UNZ_OK) {
565 cb = NEW(classbuffer);
567 cb->size = file_info.uncompressed_size;
568 cb->data = MNEW(u1, cb->size);
569 cb->pos = cb->data - 1;
571 len = unzReadCurrentFile(cpi->uf, cb->data, cb->size);
573 if (len != cb->size) {
575 log_text("Error while unzipping");
582 log_text("Error while opening file in archive");
586 log_text("Error while retrieving fileinfo");
589 unzCloseCurrentFile(cpi->uf);
591 #if defined(USE_THREADS)
592 /* leave the monitor */
594 builtin_monitorexit((java_objectheader *) cpi);
598 #endif /* defined(USE_ZLIB) */
600 path = MNEW(char, cpi->pathlen + filenamelen);
601 strcpy(path, cpi->path);
602 strcat(path, filename);
604 classfile = fopen(path, "r");
606 if (classfile) { /* file exists */
607 if (!stat(path, &buffer)) { /* read classfile data */
608 cb = NEW(classbuffer);
610 cb->size = buffer.st_size;
611 cb->data = MNEW(u1, cb->size);
612 cb->pos = cb->data - 1;
614 /* read class data */
615 len = fread(cb->data, 1, cb->size, classfile);
617 if (len != buffer.st_size) {
619 /* if (ferror(classfile)) { */
628 MFREE(path, char, cpi->pathlen + filenamelen);
629 #if defined(USE_ZLIB)
636 dolog("Warning: Can not open class file '%s'", filename);
638 MFREE(filename, char, filenamelen);
644 /************************** function suck_stop *********************************
646 frees memory for buffer with classfile data.
647 Caution: this function may only be called if buffer has been allocated
648 by suck_start with reading a file
650 *******************************************************************************/
652 void suck_stop(classbuffer *cb)
656 MFREE(cb->data, u1, cb->size);
657 FREE(cb, classbuffer);
661 /******************************************************************************/
662 /******************* Some support functions ***********************************/
663 /******************************************************************************/
665 void fprintflags (FILE *fp, u2 f)
667 if ( f & ACC_PUBLIC ) fprintf (fp," PUBLIC");
668 if ( f & ACC_PRIVATE ) fprintf (fp," PRIVATE");
669 if ( f & ACC_PROTECTED ) fprintf (fp," PROTECTED");
670 if ( f & ACC_STATIC ) fprintf (fp," STATIC");
671 if ( f & ACC_FINAL ) fprintf (fp," FINAL");
672 if ( f & ACC_SYNCHRONIZED ) fprintf (fp," SYNCHRONIZED");
673 if ( f & ACC_VOLATILE ) fprintf (fp," VOLATILE");
674 if ( f & ACC_TRANSIENT ) fprintf (fp," TRANSIENT");
675 if ( f & ACC_NATIVE ) fprintf (fp," NATIVE");
676 if ( f & ACC_INTERFACE ) fprintf (fp," INTERFACE");
677 if ( f & ACC_ABSTRACT ) fprintf (fp," ABSTRACT");
681 /********** internal function: printflags (only for debugging) ***************/
683 void printflags(u2 f)
685 fprintflags(stdout,f);
689 /********************** Function: skipattributebody ****************************
691 skips an attribute after the 16 bit reference to attribute_name has already
694 *******************************************************************************/
696 static bool skipattributebody(classbuffer *cb)
700 if (!check_classbuffer_size(cb, 4))
705 if (!check_classbuffer_size(cb, len))
708 skip_nbytes(cb, len);
714 /************************* Function: skipattributes ****************************
716 skips num attribute structures
718 *******************************************************************************/
720 static bool skipattributes(classbuffer *cb, u4 num)
725 for (i = 0; i < num; i++) {
726 if (!check_classbuffer_size(cb, 2 + 4))
732 if (!check_classbuffer_size(cb, len))
735 skip_nbytes(cb, len);
742 /* load_constantpool ***********************************************************
744 Loads the constantpool of a class, the entries are transformed into
745 a simpler format by resolving references (a detailed overview of
746 the compact structures can be found in global.h).
748 *******************************************************************************/
750 static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool)
753 /* The following structures are used to save information which cannot be
754 processed during the first pass. After the complete constantpool has
755 been traversed the references can be resolved.
756 (only in specific order) */
758 /* CONSTANT_Class entries */
759 typedef struct forward_class {
760 struct forward_class *next;
765 /* CONSTANT_String */
766 typedef struct forward_string {
767 struct forward_string *next;
772 /* CONSTANT_NameAndType */
773 typedef struct forward_nameandtype {
774 struct forward_nameandtype *next;
778 } forward_nameandtype;
780 /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */
781 typedef struct forward_fieldmethint {
782 struct forward_fieldmethint *next;
786 u2 nameandtype_index;
787 } forward_fieldmethint;
793 forward_class *forward_classes = NULL;
794 forward_string *forward_strings = NULL;
795 forward_nameandtype *forward_nameandtypes = NULL;
796 forward_fieldmethint *forward_fieldmethints = NULL;
800 forward_nameandtype *nfn;
801 forward_fieldmethint *nff;
809 /* number of entries in the constant_pool table plus one */
810 if (!check_classbuffer_size(cb, 2))
813 cpcount = c->cpcount = suck_u2(cb);
815 /* allocate memory */
816 cptags = c->cptags = MNEW(u1, cpcount);
817 cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
820 *exceptionptr = new_classformaterror(c, "Illegal constant pool size");
824 #if defined(STATISTICS)
826 count_const_pool_len += (sizeof(voidptr) + 1) * cpcount;
829 /* initialize constantpool */
830 for (idx = 0; idx < cpcount; idx++) {
831 cptags[idx] = CONSTANT_UNUSED;
836 /******* first pass *******/
837 /* entries which cannot be resolved now are written into
838 temporary structures and traversed again later */
841 while (idx < cpcount) {
844 /* get constant type */
845 if (!check_classbuffer_size(cb, 1))
852 nfc = DNEW(forward_class);
854 nfc->next = forward_classes;
855 forward_classes = nfc;
857 nfc->thisindex = idx;
858 /* reference to CONSTANT_NameAndType */
859 if (!check_classbuffer_size(cb, 2))
862 nfc->name_index = suck_u2(cb);
867 case CONSTANT_String:
868 nfs = DNEW(forward_string);
870 nfs->next = forward_strings;
871 forward_strings = nfs;
873 nfs->thisindex = idx;
875 /* reference to CONSTANT_Utf8_info with string characters */
876 if (!check_classbuffer_size(cb, 2))
879 nfs->string_index = suck_u2(cb);
884 case CONSTANT_NameAndType:
885 nfn = DNEW(forward_nameandtype);
887 nfn->next = forward_nameandtypes;
888 forward_nameandtypes = nfn;
890 nfn->thisindex = idx;
892 if (!check_classbuffer_size(cb, 2 + 2))
895 /* reference to CONSTANT_Utf8_info containing simple name */
896 nfn->name_index = suck_u2(cb);
898 /* reference to CONSTANT_Utf8_info containing field or method
900 nfn->sig_index = suck_u2(cb);
905 case CONSTANT_Fieldref:
906 case CONSTANT_Methodref:
907 case CONSTANT_InterfaceMethodref:
908 nff = DNEW(forward_fieldmethint);
910 nff->next = forward_fieldmethints;
911 forward_fieldmethints = nff;
913 nff->thisindex = idx;
917 if (!check_classbuffer_size(cb, 2 + 2))
920 /* class or interface type that contains the declaration of the
922 nff->class_index = suck_u2(cb);
924 /* name and descriptor of the field or method */
925 nff->nameandtype_index = suck_u2(cb);
930 case CONSTANT_Integer: {
931 constant_integer *ci = NEW(constant_integer);
933 #if defined(STATISTICS)
935 count_const_pool_len += sizeof(constant_integer);
938 if (!check_classbuffer_size(cb, 4))
941 ci->value = suck_s4(cb);
942 cptags[idx] = CONSTANT_Integer;
949 case CONSTANT_Float: {
950 constant_float *cf = NEW(constant_float);
952 #if defined(STATISTICS)
954 count_const_pool_len += sizeof(constant_float);
957 if (!check_classbuffer_size(cb, 4))
960 cf->value = suck_float(cb);
961 cptags[idx] = CONSTANT_Float;
968 case CONSTANT_Long: {
969 constant_long *cl = NEW(constant_long);
971 #if defined(STATISTICS)
973 count_const_pool_len += sizeof(constant_long);
976 if (!check_classbuffer_size(cb, 8))
979 cl->value = suck_s8(cb);
980 cptags[idx] = CONSTANT_Long;
985 new_classformaterror(c, "Invalid constant pool entry");
991 case CONSTANT_Double: {
992 constant_double *cd = NEW(constant_double);
994 #if defined(STATISTICS)
996 count_const_pool_len += sizeof(constant_double);
999 if (!check_classbuffer_size(cb, 8))
1002 cd->value = suck_double(cb);
1003 cptags[idx] = CONSTANT_Double;
1006 if (idx > cpcount) {
1008 new_classformaterror(c, "Invalid constant pool entry");
1014 case CONSTANT_Utf8: {
1017 /* number of bytes in the bytes array (not string-length) */
1018 if (!check_classbuffer_size(cb, 2))
1021 length = suck_u2(cb);
1022 cptags[idx] = CONSTANT_Utf8;
1024 /* validate the string */
1025 if (!check_classbuffer_size(cb, length))
1029 !is_valid_utf((char *) (cb->pos + 1),
1030 (char *) (cb->pos + 1 + length))) {
1031 dolog("Invalid UTF-8 string (constant pool index %d)",idx);
1032 panic("Invalid UTF-8 string");
1034 /* insert utf-string into the utf-symboltable */
1035 cpinfos[idx] = utf_new_intern((char *) (cb->pos + 1), length);
1037 /* skip bytes of the string (buffer size check above) */
1038 skip_nbytes(cb, length);
1045 new_classformaterror(c, "Illegal constant pool type");
1050 /* add all class references to the descriptor_pool */
1051 for (nfc=forward_classes; nfc; nfc=nfc->next) {
1052 utf *name = class_getconstant(c,nfc->name_index,CONSTANT_Utf8);
1053 if (!descriptor_pool_add_class(descpool,name))
1056 /* add all descriptors in NameAndTypes to the descriptor_pool */
1057 for (nfn=forward_nameandtypes; nfn; nfn=nfn->next) {
1058 utf *desc = class_getconstant(c,nfn->sig_index,CONSTANT_Utf8);
1059 if (!descriptor_pool_add(descpool,desc,NULL))
1063 /* resolve entries in temporary structures */
1065 while (forward_classes) {
1067 class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8);
1069 if (opt_verify && !is_valid_name_utf(name)) {
1071 new_classformaterror(c, "Class reference with invalid name");
1075 cptags[forward_classes->thisindex] = CONSTANT_Class;
1076 /* the classref is created later */
1077 cpinfos[forward_classes->thisindex] = name;
1079 nfc = forward_classes;
1080 forward_classes = forward_classes->next;
1083 while (forward_strings) {
1085 class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8);
1087 /* resolve utf-string */
1088 cptags[forward_strings->thisindex] = CONSTANT_String;
1089 cpinfos[forward_strings->thisindex] = text;
1091 nfs = forward_strings;
1092 forward_strings = forward_strings->next;
1095 while (forward_nameandtypes) {
1096 constant_nameandtype *cn = NEW(constant_nameandtype);
1098 #if defined(STATISTICS)
1100 count_const_pool_len += sizeof(constant_nameandtype);
1103 /* resolve simple name and descriptor */
1104 cn->name = class_getconstant(c,
1105 forward_nameandtypes->name_index,
1108 cn->descriptor = class_getconstant(c,
1109 forward_nameandtypes->sig_index,
1114 if (!is_valid_name_utf(cn->name)) {
1116 new_classformaterror(c,
1117 "Illegal Field name \"%s\"",
1123 /* disallow referencing <clinit> among others */
1124 if (cn->name->text[0] == '<' && cn->name != utf_init) {
1126 new_exception_utfmessage(string_java_lang_InternalError,
1132 cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType;
1133 cpinfos[forward_nameandtypes->thisindex] = cn;
1135 nfn = forward_nameandtypes;
1136 forward_nameandtypes = forward_nameandtypes->next;
1139 while (forward_fieldmethints) {
1140 constant_nameandtype *nat;
1141 constant_FMIref *fmi = NEW(constant_FMIref);
1143 #if defined(STATISTICS)
1145 count_const_pool_len += sizeof(constant_FMIref);
1147 /* resolve simple name and descriptor */
1148 nat = class_getconstant(c,
1149 forward_fieldmethints->nameandtype_index,
1150 CONSTANT_NameAndType);
1152 /* the classref is created later */
1153 fmi->classref = (constant_classref*) (size_t) forward_fieldmethints->class_index;
1154 fmi->name = nat->name;
1155 fmi->descriptor = nat->descriptor;
1157 cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag;
1158 cpinfos[forward_fieldmethints->thisindex] = fmi;
1160 nff = forward_fieldmethints;
1161 forward_fieldmethints = forward_fieldmethints->next;
1164 /* everything was ok */
1170 /* load_field ******************************************************************
1172 Load everything about a class field from the class file and fill a
1173 'fieldinfo' structure. For static fields, space in the data segment
1176 *******************************************************************************/
1178 #define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */
1180 static bool load_field(classbuffer *cb, fieldinfo *f,descriptor_pool *descpool)
1185 u4 pindex = field_load_NOVALUE; /* constantvalue_index */
1190 if (!check_classbuffer_size(cb, 2 + 2 + 2))
1193 f->flags = suck_u2(cb);
1195 if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1199 if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1202 f->parseddesc = NULL;
1203 if (!descriptor_pool_add(descpool,u,NULL))
1208 if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') {
1209 *exceptionptr = new_classformaterror(c,
1210 "Illegal Field name \"%s\"",
1215 /* check flag consistency */
1216 i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED);
1218 if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) ||
1219 ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) {
1221 new_classformaterror(c,
1222 "Illegal field modifiers: 0x%X",
1227 if (c->flags & ACC_INTERFACE) {
1228 if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
1229 != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) ||
1230 f->flags & ACC_TRANSIENT) {
1232 new_classformaterror(c,
1233 "Illegal field modifiers: 0x%X",
1240 f->type = jtype = desc_to_type(f->descriptor); /* data type */
1241 f->offset = 0; /* offset from start of object */
1246 case TYPE_INT: f->value.i = 0; break;
1247 case TYPE_FLOAT: f->value.f = 0.0; break;
1248 case TYPE_DOUBLE: f->value.d = 0.0; break;
1249 case TYPE_ADDRESS: f->value.a = NULL; break;
1252 f->value.l = 0; break;
1254 f->value.l.low = 0; f->value.l.high = 0; break;
1258 /* read attributes */
1259 if (!check_classbuffer_size(cb, 2))
1262 attrnum = suck_u2(cb);
1263 for (i = 0; i < attrnum; i++) {
1264 if (!check_classbuffer_size(cb, 2))
1267 if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1270 if (u == utf_ConstantValue) {
1271 if (!check_classbuffer_size(cb, 4 + 2))
1274 /* check attribute length */
1275 if (suck_u4(cb) != 2) {
1277 new_classformaterror(c, "Wrong size for VALUE attribute");
1281 /* constant value attribute */
1282 if (pindex != field_load_NOVALUE) {
1284 new_classformaterror(c,
1285 "Multiple ConstantValue attributes");
1289 /* index of value in constantpool */
1290 pindex = suck_u2(cb);
1292 /* initialize field with value from constantpool */
1295 constant_integer *ci;
1297 if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer)))
1300 f->value.i = ci->value;
1307 if (!(cl = class_getconstant(c, pindex, CONSTANT_Long)))
1310 f->value.l = cl->value;
1317 if (!(cf = class_getconstant(c, pindex, CONSTANT_Float)))
1320 f->value.f = cf->value;
1325 constant_double *cd;
1327 if (!(cd = class_getconstant(c, pindex, CONSTANT_Double)))
1330 f->value.d = cd->value;
1335 if (!(u = class_getconstant(c, pindex, CONSTANT_String)))
1338 /* create javastring from compressed utf8-string */
1339 f->value.a = literalstring_new(u);
1343 log_text("Invalid Constant - Type");
1347 /* unknown attribute */
1348 if (!skipattributebody(cb))
1353 /* everything was ok */
1359 /* load_method *****************************************************************
1361 Loads a method from the class file and fills an existing
1362 'methodinfo' structure. For native methods, the function pointer
1363 field is set to the real function pointer, for JavaVM methods a
1364 pointer to the compiler is used preliminarily.
1366 *******************************************************************************/
1368 static bool load_method(classbuffer *cb, methodinfo *m,descriptor_pool *descpool)
1379 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1380 initObjectLock(&m->header);
1385 count_all_methods++;
1388 m->thrownexceptionscount = 0;
1389 m->linenumbercount = 0;
1392 m->nativelyoverloaded = false;
1394 if (!check_classbuffer_size(cb, 2 + 2 + 2))
1397 m->flags = suck_u2(cb);
1399 if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1403 if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1406 m->parseddesc = NULL;
1407 if (!descriptor_pool_add(descpool,u,&argcount))
1411 if (!is_valid_name_utf(m->name))
1412 panic("Method with invalid name");
1414 if (m->name->text[0] == '<'
1415 && m->name != utf_init && m->name != utf_clinit)
1416 panic("Method with invalid special name");
1419 if (!(m->flags & ACC_STATIC))
1420 argcount++; /* count the 'this' argument */
1423 if (argcount > 255) {
1425 new_classformaterror(c, "Too many arguments in signature");
1429 /* check flag consistency */
1430 if (m->name != utf_clinit) {
1431 i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
1433 if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
1435 new_classformaterror(c,
1436 "Illegal method modifiers: 0x%X",
1441 if (m->flags & ACC_ABSTRACT) {
1442 if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
1443 ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
1445 new_classformaterror(c,
1446 "Illegal method modifiers: 0x%X",
1452 if (c->flags & ACC_INTERFACE) {
1453 if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
1455 new_classformaterror(c,
1456 "Illegal method modifiers: 0x%X",
1462 if (m->name == utf_init) {
1463 if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
1464 ACC_NATIVE | ACC_ABSTRACT))
1465 panic("Instance initialization method has invalid flags set");
1471 m->basicblockcount = 0;
1472 m->basicblocks = NULL;
1473 m->basicblockindex = NULL;
1474 m->instructioncount = 0;
1475 m->instructions = NULL;
1478 m->exceptiontable = NULL;
1479 m->stubroutine = NULL;
1481 m->entrypoint = NULL;
1482 m->methodUsed = NOTUSED;
1485 m->subRedefsUsed = 0;
1489 if (!check_classbuffer_size(cb, 2))
1492 attrnum = suck_u2(cb);
1493 for (i = 0; i < attrnum; i++) {
1496 if (!check_classbuffer_size(cb, 2))
1499 if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1502 if (aname == utf_Code) {
1503 if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
1505 new_classformaterror(c,
1506 "Code attribute in native or abstract methods");
1513 new_classformaterror(c, "Multiple Code attributes");
1518 if (!check_classbuffer_size(cb, 4 + 2 + 2))
1522 m->maxstack = suck_u2(cb);
1523 m->maxlocals = suck_u2(cb);
1525 if (m->maxlocals < argcount) {
1527 new_classformaterror(c, "Arguments can't fit into locals");
1532 if (!check_classbuffer_size(cb, 4))
1535 m->jcodelength = suck_u4(cb);
1537 if (m->jcodelength == 0) {
1539 new_classformaterror(c, "Code of a method has length 0");
1544 if (m->jcodelength > 65535) {
1546 new_classformaterror(c,
1547 "Code of a method longer than 65535 bytes");
1552 if (!check_classbuffer_size(cb, m->jcodelength))
1555 m->jcode = MNEW(u1, m->jcodelength);
1556 suck_nbytes(m->jcode, cb, m->jcodelength);
1558 if (!check_classbuffer_size(cb, 2))
1561 m->exceptiontablelength = suck_u2(cb);
1562 if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->exceptiontablelength))
1565 m->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength);
1567 #if defined(STATISTICS)
1569 count_vmcode_len += m->jcodelength + 18;
1570 count_extable_len += 8 * m->exceptiontablelength;
1574 for (j = 0; j < m->exceptiontablelength; j++) {
1576 m->exceptiontable[j].startpc = suck_u2(cb);
1577 m->exceptiontable[j].endpc = suck_u2(cb);
1578 m->exceptiontable[j].handlerpc = suck_u2(cb);
1582 m->exceptiontable[j].catchtype.any = NULL;
1585 /* the classref is created later */
1586 if (!(m->exceptiontable[j].catchtype.any =
1587 (utf*)class_getconstant(c, idx, CONSTANT_Class)))
1592 if (!check_classbuffer_size(cb, 2))
1595 codeattrnum = suck_u2(cb);
1597 for (; codeattrnum > 0; codeattrnum--) {
1600 if (!check_classbuffer_size(cb, 2))
1603 if (!(caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1606 if (caname == utf_LineNumberTable) {
1609 if (!check_classbuffer_size(cb, 4 + 2))
1613 m->linenumbercount = suck_u2(cb);
1615 if (!check_classbuffer_size(cb,
1616 (2 + 2) * m->linenumbercount))
1619 m->linenumbers = MNEW(lineinfo, m->linenumbercount);
1621 for (lncid = 0; lncid < m->linenumbercount; lncid++) {
1622 m->linenumbers[lncid].start_pc = suck_u2(cb);
1623 m->linenumbers[lncid].line_number = suck_u2(cb);
1627 if (!skipattributes(cb, codeattrnum))
1633 if (!skipattributebody(cb))
1638 } else if (aname == utf_Exceptions) {
1641 if (m->thrownexceptions) {
1643 new_classformaterror(c, "Multiple Exceptions attributes");
1647 if (!check_classbuffer_size(cb, 4 + 2))
1650 suck_u4(cb); /* length */
1651 m->thrownexceptionscount = suck_u2(cb);
1653 if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
1656 m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
1658 for (j = 0; j < m->thrownexceptionscount; j++) {
1659 /* the classref is created later */
1660 if (!((m->thrownexceptions)[j].any =
1661 (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
1666 if (!skipattributebody(cb))
1671 if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
1672 *exceptionptr = new_classformaterror(c, "Missing Code attribute");
1677 /* everything was ok */
1683 /* load_attribute **************************************************************
1685 Read attributes from classfile.
1687 *******************************************************************************/
1689 static bool load_attributes(classbuffer *cb, u4 num)
1697 for (i = 0; i < num; i++) {
1698 /* retrieve attribute name */
1699 if (!check_classbuffer_size(cb, 2))
1702 if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1705 if (aname == utf_InnerClasses) {
1706 /* innerclasses attribute */
1707 if (c->innerclass) {
1709 new_classformaterror(c, "Multiple InnerClasses attributes");
1713 if (!check_classbuffer_size(cb, 4 + 2))
1716 /* skip attribute length */
1719 /* number of records */
1720 c->innerclasscount = suck_u2(cb);
1722 if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount))
1725 /* allocate memory for innerclass structure */
1726 c->innerclass = MNEW(innerclassinfo, c->innerclasscount);
1728 for (j = 0; j < c->innerclasscount; j++) {
1729 /* The innerclass structure contains a class with an encoded
1730 name, its defining scope, its simple name and a bitmask of
1731 the access flags. If an inner class is not a member, its
1732 outer_class is NULL, if a class is anonymous, its name is
1735 innerclassinfo *info = c->innerclass + j;
1737 info->inner_class.ref =
1738 innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
1739 info->outer_class.ref =
1740 innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
1742 innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
1743 info->flags = suck_u2(cb);
1746 } else if (aname == utf_SourceFile) {
1747 if (!check_classbuffer_size(cb, 4 + 2))
1750 if (suck_u4(cb) != 2) {
1752 new_classformaterror(c, "Wrong size for VALUE attribute");
1756 if (c->sourcefile) {
1758 new_classformaterror(c, "Multiple SourceFile attributes");
1762 if (!(c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
1766 /* unknown attribute */
1767 if (!skipattributebody(cb))
1775 /* load_class_from_sysloader ***************************************************
1777 Load the class with the given name using the system class loader
1780 name.............the classname
1784 *result..........set to the loaded class
1787 true.............everything ok
1788 false............an exception has been thrown
1790 *******************************************************************************/
1792 bool load_class_from_sysloader(utf *name,classinfo **result)
1795 java_objectheader *cl;
1798 #ifdef LOADER_VERBOSE
1799 char logtext[MAXLOGTEXT];
1800 LOADER_INDENT(logtext);
1801 sprintf(logtext+strlen(logtext),"load_class_from_sysloader(");
1802 utf_sprint(logtext+strlen(logtext),name);strcat(logtext,")");
1806 LOADER_ASSERT(class_java_lang_Object);
1807 LOADER_ASSERT(class_java_lang_ClassLoader);
1808 LOADER_ASSERT(class_java_lang_ClassLoader->linked);
1810 m = class_resolveclassmethod(class_java_lang_ClassLoader,
1811 utf_new_char("getSystemClassLoader"), /* XXX use variable */
1812 utf_new_char("()Ljava/lang/ClassLoader;"), /* XXX use variable */
1813 class_java_lang_Object,
1817 return false; /* exception */
1819 cl = (java_objectheader *) asm_calljavafunction(m, NULL, NULL, NULL, NULL);
1821 return false; /* exception */
1824 success = load_class_from_classloader(name,cl,result);
1829 /* load_class_from_classloader *************************************************
1831 Load the class with the given name using the given user-defined class loader.
1834 name.............the classname
1835 cl...............user-defined class loader
1839 *result..........set to the loaded class
1842 true.............everything ok
1843 false............an exception has been thrown
1845 *******************************************************************************/
1847 bool load_class_from_classloader(utf *name,java_objectheader *cl,classinfo **result)
1852 #ifdef LOADER_VERBOSE
1853 char logtext[MAXLOGTEXT];
1854 LOADER_INDENT(logtext);
1855 strcat(logtext,"load_class_from_classloader(");
1856 utf_sprint(logtext+strlen(logtext),name);sprintf(logtext+strlen(logtext),",%p,",(void*)cl);
1857 if (!cl) strcat(logtext,"<bootstrap>");
1858 else if (cl->vftbl && cl->vftbl->class) utf_sprint(logtext+strlen(logtext),cl->vftbl->class->name);
1859 else strcat(logtext,"<unknown class>");
1860 strcat(logtext,")");
1864 LOADER_ASSERT(name);
1865 LOADER_ASSERT(result);
1867 /* lookup if this class has already been loaded */
1868 *result = classcache_lookup(cl,name);
1869 #ifdef LOADER_VERBOSE
1871 dolog(" cached -> %p",(void*)(*result));
1877 /* if other class loader than bootstrap, call it */
1882 /* handle array classes */
1883 if (name->text[0] == '[') {
1884 char *utf_ptr = name->text + 1;
1885 int len = name->blength - 1;
1893 /* load the component class */
1895 if (!load_class_from_classloader(utf_new(utf_ptr,len),cl,&comp)) {
1900 /* create the array class */
1901 *result = class_array_of(comp,false);
1902 return (*result != 0);
1905 /* primitive array classes are loaded by the bootstrap loader */
1907 success = load_class_bootstrap(name,result);
1913 LOADER_ASSERT(class_java_lang_Object);
1915 lc = class_resolveclassmethod(cl->vftbl->class,
1917 utf_java_lang_String__java_lang_Class,
1918 class_java_lang_Object,
1922 return false; /* exception */
1925 r = (classinfo *) asm_calljavafunction(lc,
1927 javastring_new_slash_to_dot(name),
1931 /* store this class in the loaded class cache */
1932 if (r && !classcache_store(cl,r)) {
1935 r = NULL; /* exception */
1943 success = load_class_bootstrap(name,result);
1949 /* load_class_bootstrap ********************************************************
1951 Load the class with the given name using the bootstrap class loader.
1954 name.............the classname
1957 *result..........set to the loaded class
1960 true.............everything ok
1961 false............an exception has been thrown
1964 load_class_bootstrap is synchronized. It can be treated as an
1967 *******************************************************************************/
1969 bool load_class_bootstrap(utf *name, classinfo **result)
1974 #ifdef LOADER_VERBOSE
1975 char logtext[MAXLOGTEXT];
1979 LOADER_ASSERT(name);
1980 LOADER_ASSERT(result);
1986 /* lookup if this class has already been loaded */
1987 *result = classcache_lookup(NULL, name);
1991 /* check if this class has already been defined */
1992 *result = classcache_lookup_defined(NULL, name);
1996 #ifdef LOADER_VERBOSE
1997 LOADER_INDENT(logtext);
1998 strcat(logtext,"load_class_bootstrap(");
1999 utf_sprint(logtext+strlen(logtext),name);strcat(logtext,")");
2003 /* create the classinfo */
2004 c = class_create_classinfo(name);
2006 /* handle array classes */
2007 if (name->text[0] == '[') {
2008 if (!load_newly_created_array(c, NULL))
2009 goto return_exception;
2010 LOADER_ASSERT(c->loaded);
2015 #if defined(STATISTICS)
2017 if (getcompilingtime)
2018 compilingtime_stop();
2021 loadingtime_start();
2024 /* load classdata, throw exception on error */
2026 if ((cb = suck_start(c)) == NULL) {
2027 /* this means, the classpath was not set properly */
2028 if (name == utf_java_lang_Object)
2029 throw_cacao_exception_exit(string_java_lang_NoClassDefFoundError,
2030 "java/lang/Object");
2033 new_exception_utfmessage(string_java_lang_NoClassDefFoundError,
2035 goto return_exception;
2038 /* load the class from the buffer */
2039 r = load_class_from_classbuffer(cb);
2044 #if defined(STATISTICS)
2049 if (getcompilingtime)
2050 compilingtime_start();
2054 /* the class could not be loaded, free the classinfo struct */
2058 /* store this class in the loaded class cache */
2059 /* this step also checks the loading constraints */
2060 if (r && !classcache_store(NULL, c)) {
2062 r = NULL; /* exception */
2066 goto return_exception;
2083 /* load_class_from_classbuffer *************************************************
2085 Loads everything interesting about a class from the class file. The
2086 'classinfo' structure must have been allocated previously.
2088 The super class and the interfaces implemented by this class need
2089 not be loaded. The link is set later by the function 'class_link'.
2091 The loaded class is removed from the list 'unloadedclasses' and
2092 added to the list 'unlinkedclasses'.
2095 This function is NOT synchronized!
2097 *******************************************************************************/
2099 classinfo *load_class_from_classbuffer(classbuffer *cb)
2107 descriptor_pool *descpool;
2108 char msg[MAXLOGTEXT]; /* maybe we get an exception */ /* XXX BUFFER OVERFLOW! */
2109 #if defined(STATISTICS)
2113 #ifdef LOADER_VERBOSE
2114 char logtext[MAXLOGTEXT];
2117 /* get the classbuffer's class */
2120 /* maybe the class is already loaded */
2124 #ifdef LOADER_VERBOSE
2125 LOADER_INDENT(logtext);
2126 strcat(logtext,"load_class_from_classbuffer(");
2127 utf_sprint(logtext+strlen(logtext),c->name);strcat(logtext,")");
2132 #if defined(STATISTICS)
2134 count_class_loads++;
2137 /* output for debugging purposes */
2139 log_message_class("Loading class: ", c);
2141 /* mark start of dump memory area */
2142 dumpsize = dump_size();
2144 /* class is somewhat loaded */
2147 if (!check_classbuffer_size(cb, 4 + 2 + 2))
2148 goto return_exception;
2150 /* check signature */
2151 if (suck_u4(cb) != MAGIC) {
2152 *exceptionptr = new_classformaterror(c, "Bad magic number");
2154 goto return_exception;
2161 if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
2163 new_unsupportedclassversionerror(c,
2164 "Unsupported major.minor version %d.%d",
2167 goto return_exception;
2170 /* create a new descriptor pool */
2171 descpool = descriptor_pool_new(c);
2173 /* load the constant pool */
2174 if (!load_constantpool(cb,descpool))
2175 goto return_exception;
2178 c->erroneous_state = 0;
2179 c->initializing_thread = 0;
2181 c->classUsed = NOTUSED; /* not used initially CO-RT */
2185 if (!check_classbuffer_size(cb, 2))
2186 goto return_exception;
2188 c->flags = suck_u2(cb);
2190 /* check ACC flags consistency */
2191 if (c->flags & ACC_INTERFACE) {
2192 if (!(c->flags & ACC_ABSTRACT)) {
2193 /* We work around this because interfaces in JDK 1.1 are
2194 * not declared abstract. */
2196 c->flags |= ACC_ABSTRACT;
2199 if (c->flags & ACC_FINAL) {
2201 new_classformaterror(c,
2202 "Illegal class modifiers: 0x%X", c->flags);
2204 goto return_exception;
2207 if (c->flags & ACC_SUPER) {
2208 c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */
2212 if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) {
2214 new_classformaterror(c, "Illegal class modifiers: 0x%X", c->flags);
2216 goto return_exception;
2219 if (!check_classbuffer_size(cb, 2 + 2))
2220 goto return_exception;
2224 if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class)))
2225 goto return_exception;
2227 if (c->name == utf_not_named_yet) {
2228 /* we finally have a name for this class */
2230 class_set_packagename(c);
2232 else if (name != c->name) {
2233 utf_sprint(msg, c->name);
2234 strcat(msg, " (wrong name: ");
2235 utf_strcat(msg, name);
2239 new_exception_message(string_java_lang_NoClassDefFoundError, msg);
2241 goto return_exception;
2244 /* retrieve superclass */
2245 c->super.any = NULL;
2246 if ((i = suck_u2(cb))) {
2247 if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class)))
2248 goto return_exception;
2250 /* java.lang.Object may not have a super class. */
2251 if (c->name == utf_java_lang_Object) {
2253 new_exception_message(string_java_lang_ClassFormatError,
2254 "java.lang.Object with superclass");
2256 goto return_exception;
2259 /* Interfaces must have java.lang.Object as super class. */
2260 if ((c->flags & ACC_INTERFACE) &&
2261 supername != utf_java_lang_Object) {
2263 new_exception_message(string_java_lang_ClassFormatError,
2264 "Interfaces must have java.lang.Object as superclass");
2266 goto return_exception;
2272 /* This is only allowed for java.lang.Object. */
2273 if (c->name != utf_java_lang_Object) {
2274 *exceptionptr = new_classformaterror(c, "Bad superclass index");
2276 goto return_exception;
2280 /* retrieve interfaces */
2281 if (!check_classbuffer_size(cb, 2))
2282 goto return_exception;
2284 c->interfacescount = suck_u2(cb);
2286 if (!check_classbuffer_size(cb, 2 * c->interfacescount))
2287 goto return_exception;
2289 c->interfaces = MNEW(classref_or_classinfo, c->interfacescount);
2290 for (i = 0; i < c->interfacescount; i++) {
2291 /* the classrefs are created later */
2292 if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
2293 goto return_exception;
2297 if (!check_classbuffer_size(cb, 2))
2298 goto return_exception;
2300 c->fieldscount = suck_u2(cb);
2301 c->fields = GCNEW(fieldinfo, c->fieldscount);
2302 /* c->fields = MNEW(fieldinfo, c->fieldscount); */
2303 for (i = 0; i < c->fieldscount; i++) {
2304 if (!load_field(cb, &(c->fields[i]),descpool))
2305 goto return_exception;
2309 if (!check_classbuffer_size(cb, 2))
2310 goto return_exception;
2312 c->methodscount = suck_u2(cb);
2313 /* c->methods = GCNEW(methodinfo, c->methodscount); */
2314 c->methods = MNEW(methodinfo, c->methodscount);
2315 for (i = 0; i < c->methodscount; i++) {
2316 if (!load_method(cb, &(c->methods[i]),descpool))
2317 goto return_exception;
2320 /* create the class reference table */
2321 c->classrefs = descriptor_pool_create_classrefs(descpool,&(c->classrefcount));
2323 /* allocate space for the parsed descriptors */
2324 descriptor_pool_alloc_parsed_descriptors(descpool);
2325 c->parseddescs = descriptor_pool_get_parsed_descriptors(descpool,&(c->parseddescsize));
2327 #if defined(STATISTICS)
2329 descriptor_pool_get_sizes(descpool,&classrefsize,&descsize);
2330 count_classref_len += classrefsize;
2331 count_parsed_desc_len += descsize;
2335 /* put the classrefs in the constant pool */
2336 for (i = 0; i < c->cpcount; i++) {
2337 if (c->cptags[i] == CONSTANT_Class) {
2338 utf *name = (utf *) c->cpinfos[i];
2339 c->cpinfos[i] = descriptor_pool_lookup_classref(descpool, name);
2343 /* set the super class reference */
2345 c->super.ref = descriptor_pool_lookup_classref(descpool, supername);
2347 goto return_exception;
2350 /* set the super interfaces references */
2351 for (i = 0; i < c->interfacescount; i++) {
2352 c->interfaces[i].ref = descriptor_pool_lookup_classref(descpool, (utf *) c->interfaces[i].any);
2353 if (!c->interfaces[i].ref)
2354 goto return_exception;
2357 /* parse the loaded descriptors */
2358 for (i = 0; i < c->cpcount; i++) {
2359 constant_FMIref *fmi;
2362 switch (c->cptags[i]) {
2363 case CONSTANT_Fieldref:
2364 fmi = (constant_FMIref *) c->cpinfos[i];
2365 fmi->parseddesc.fd =
2366 descriptor_pool_parse_field_descriptor(descpool, fmi->descriptor);
2367 if (!fmi->parseddesc.fd)
2368 goto return_exception;
2369 index = (int) (size_t) fmi->classref;
2370 fmi->classref = (constant_classref *) class_getconstant(c, index, CONSTANT_Class);
2372 goto return_exception;
2374 case CONSTANT_Methodref:
2375 case CONSTANT_InterfaceMethodref:
2376 fmi = (constant_FMIref *) c->cpinfos[i];
2377 fmi->parseddesc.md =
2378 descriptor_pool_parse_method_descriptor(descpool, fmi->descriptor);
2379 if (!fmi->parseddesc.md)
2380 goto return_exception;
2381 index = (int) (size_t) fmi->classref;
2382 fmi->classref = (constant_classref *) class_getconstant(c, index, CONSTANT_Class);
2384 goto return_exception;
2389 for (i = 0; i < c->fieldscount; i++) {
2390 c->fields[i].parseddesc = descriptor_pool_parse_field_descriptor(descpool, c->fields[i].descriptor);
2391 if (!c->fields[i].parseddesc)
2392 goto return_exception;
2395 for (i = 0; i < c->methodscount; i++) {
2396 methodinfo *m = c->methods + i;
2397 m->parseddesc = descriptor_pool_parse_method_descriptor(descpool, m->descriptor);
2399 goto return_exception;
2401 for (j = 0; j < m->exceptiontablelength; j++) {
2402 if (!m->exceptiontable[j].catchtype.any)
2404 if ((m->exceptiontable[j].catchtype.ref =
2405 descriptor_pool_lookup_classref(descpool,
2406 (utf *) m->exceptiontable[j].catchtype.any)) == NULL)
2407 goto return_exception;
2410 for (j = 0; j < m->thrownexceptionscount; j++) {
2411 if (!m->thrownexceptions[j].any)
2413 if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool,
2414 (utf *) m->thrownexceptions[j].any)) == NULL)
2415 goto return_exception;
2419 /* Check if all fields and methods can be uniquely
2420 * identified by (name,descriptor). */
2422 /* We use a hash table here to avoid making the
2423 * average case quadratic in # of methods, fields.
2425 static int shift = 0;
2427 u2 *next; /* for chaining colliding hash entries */
2433 /* Allocate hashtable */
2434 len = c->methodscount;
2435 if (len < c->fieldscount) len = c->fieldscount;
2437 hashtab = MNEW(u2,(hashlen + len));
2438 next = hashtab + hashlen;
2440 /* Determine bitshift (to get good hash values) */
2450 memset(hashtab, 0, sizeof(u2) * (hashlen + len));
2452 for (i = 0; i < c->fieldscount; ++i) {
2453 fieldinfo *fi = c->fields + i;
2455 /* It's ok if we lose bits here */
2456 index = ((((size_t) fi->name) +
2457 ((size_t) fi->descriptor)) >> shift) % hashlen;
2459 if ((old = hashtab[index])) {
2463 if (c->fields[old].name == fi->name &&
2464 c->fields[old].descriptor == fi->descriptor) {
2466 new_classformaterror(c,
2467 "Repetitive field name/signature");
2469 goto return_exception;
2471 } while ((old = next[old]));
2473 hashtab[index] = i + 1;
2477 memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5));
2479 for (i = 0; i < c->methodscount; ++i) {
2480 methodinfo *mi = c->methods + i;
2482 /* It's ok if we lose bits here */
2483 index = ((((size_t) mi->name) +
2484 ((size_t) mi->descriptor)) >> shift) % hashlen;
2488 for (dbg=0;dbg<hashlen+hashlen/5;++dbg){
2489 printf("Hash[%d]:%d\n",dbg,hashtab[dbg]);
2493 if ((old = hashtab[index])) {
2497 if (c->methods[old].name == mi->name &&
2498 c->methods[old].descriptor == mi->descriptor) {
2500 new_classformaterror(c,
2501 "Repetitive method name/signature");
2503 goto return_exception;
2505 } while ((old = next[old]));
2507 hashtab[index] = i + 1;
2510 MFREE(hashtab, u2, (hashlen + len));
2513 #if defined(STATISTICS)
2515 count_class_infos += sizeof(classinfo*) * c->interfacescount;
2516 count_class_infos += sizeof(fieldinfo) * c->fieldscount;
2517 count_class_infos += sizeof(methodinfo) * c->methodscount;
2521 /* load attribute structures */
2522 if (!check_classbuffer_size(cb, 2))
2523 goto return_exception;
2525 if (!load_attributes(cb, suck_u2(cb)))
2526 goto return_exception;
2529 /* Pre java 1.5 version don't check this. This implementation is like
2530 java 1.5 do it: for class file version 45.3 we don't check it, older
2531 versions are checked.
2533 if ((ma == 45 && mi > 3) || ma > 45) {
2534 /* check if all data has been read */
2535 s4 classdata_left = ((cb->data + cb->size) - cb->pos - 1);
2537 if (classdata_left > 0) {
2539 new_classformaterror(c, "Extra bytes at the end of class file");
2540 goto return_exception;
2545 /* release dump area */
2546 dump_release(dumpsize);
2549 log_message_class("Loading done class: ", c);
2555 /* release dump area */
2556 dump_release(dumpsize);
2558 /* an exception has been thrown */
2565 /* load_newly_created_array ****************************************************
2567 Load a newly created array class.
2570 This is an internal function. Do not use it unless you know exactly
2573 Use one of the load_class_... functions for general array class loading.
2575 *******************************************************************************/
2577 bool load_newly_created_array(classinfo *c,java_objectheader *loader)
2579 classinfo *comp = NULL;
2581 methoddesc *clonedesc;
2582 constant_classref *classrefs;
2584 java_objectheader *definingloader = NULL;
2586 #ifdef LOADER_VERBOSE
2587 char logtext[MAXLOGTEXT];
2588 LOADER_INDENT(logtext);
2589 strcat(logtext,"load_newly_created_array(");utf_sprint_classname(logtext+strlen(logtext),c->name);
2590 sprintf(logtext+strlen(logtext),") loader=%p",loader);
2594 /* Check array class name */
2595 namelen = c->name->blength;
2596 if (namelen < 2 || c->name->text[0] != '[') {
2597 *exceptionptr = new_internalerror("Invalid array class name");
2601 /* Check the component type */
2602 switch (c->name->text[1]) {
2604 /* c is an array of arrays. We have to create the component class. */
2606 if (!load_class_from_classloader(utf_new_intern(c->name->text + 1,
2615 LOADER_ASSERT(comp->loaded);
2619 definingloader = comp->classloader;
2623 /* c is an array of objects. */
2624 if (namelen < 4 || c->name->text[namelen - 1] != ';') {
2625 *exceptionptr = new_internalerror("Invalid array class name");
2630 if (!load_class_from_classloader(utf_new_intern(c->name->text + 2,
2639 LOADER_ASSERT(comp->loaded);
2643 definingloader = comp->classloader;
2647 LOADER_ASSERT(class_java_lang_Object);
2648 LOADER_ASSERT(class_java_lang_Cloneable);
2649 LOADER_ASSERT(class_java_io_Serializable);
2651 /* Setup the array class */
2652 c->super.cls = class_java_lang_Object;
2653 c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
2655 c->interfacescount = 2;
2656 c->interfaces = MNEW(classref_or_classinfo, 2);
2661 tc = class_java_lang_Cloneable;
2662 LOADER_ASSERT(tc->loaded);
2663 list_addfirst(&unlinkedclasses, tc);
2664 c->interfaces[0].cls = tc;
2666 tc = class_java_io_Serializable;
2667 LOADER_ASSERT(tc->loaded);
2668 list_addfirst(&unlinkedclasses, tc);
2669 c->interfaces[1].cls = tc;
2672 c->interfaces[0].cls = class_java_lang_Cloneable;
2673 c->interfaces[1].cls = class_java_io_Serializable;
2676 c->methodscount = 1;
2677 c->methods = MNEW(methodinfo, c->methodscount);
2679 classrefs = MNEW(constant_classref,1);
2680 CLASSREF_INIT(classrefs[0],c,utf_java_lang_Object);
2682 clonedesc = NEW(methoddesc);
2683 clonedesc->returntype.type = TYPE_ADDRESS;
2684 clonedesc->returntype.classref = classrefs;
2685 clonedesc->returntype.arraydim = 0;
2686 clonedesc->paramcount = 0;
2687 clonedesc->paramslots = 0;
2690 MSET(clone, 0, methodinfo, 1);
2691 clone->flags = ACC_PUBLIC;
2692 clone->name = utf_new_char("clone");
2693 clone->descriptor = utf_void__java_lang_Object;
2694 clone->parseddesc = clonedesc;
2696 clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone);
2697 clone->monoPoly = MONO;
2699 /* XXX: field: length? */
2701 /* array classes are not loaded from class files */
2703 c->parseddescs = (u1*) clonedesc;
2704 c->parseddescsize = sizeof(methodinfo);
2705 c->classrefs = classrefs;
2706 c->classrefcount = 1;
2707 c->classloader = definingloader;
2709 /* insert class into the loaded class cache */
2710 if (!classcache_store(loader,c))
2717 /************************* Function: class_findfield ***************************
2719 Searches a 'classinfo' structure for a field having the given name and
2722 *******************************************************************************/
2724 fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
2728 for (i = 0; i < c->fieldscount; i++) {
2729 if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc))
2730 return &(c->fields[i]);
2733 panic("Can not find field given in CONSTANT_Fieldref");
2735 /* keep compiler happy */
2740 /****************** Function: class_resolvefield_int ***************************
2742 This is an internally used helper function. Do not use this directly.
2744 Tries to resolve a field having the given name and type.
2745 If the field cannot be resolved, NULL is returned.
2747 *******************************************************************************/
2749 static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc)
2754 /* search for field in class c */
2756 for (i = 0; i < c->fieldscount; i++) {
2757 if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) {
2758 return &(c->fields[i]);
2762 /* try superinterfaces recursively */
2764 for (i = 0; i < c->interfacescount; i++) {
2765 fi = class_resolvefield_int(c->interfaces[i].cls, name, desc);
2770 /* try superclass */
2773 return class_resolvefield_int(c->super.cls, name, desc);
2781 /********************* Function: class_resolvefield ***************************
2783 Resolves a reference from REFERER to a field with NAME and DESC in class C.
2785 If the field cannot be resolved the return value is NULL. If EXCEPT is
2786 true *exceptionptr is set, too.
2788 *******************************************************************************/
2790 fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc,
2791 classinfo *referer, bool except)
2795 /* XXX resolve class c */
2796 /* XXX check access from REFERER to C */
2798 fi = class_resolvefield_int(c, name, desc);
2803 new_exception_utfmessage(string_java_lang_NoSuchFieldError,
2809 /* XXX check access rights */
2815 /* class_findmethod ************************************************************
2817 Searches a 'classinfo' structure for a method having the given name
2818 and descriptor. If descriptor is NULL, it is ignored.
2820 *******************************************************************************/
2822 methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
2827 for (i = 0; i < c->methodscount; i++) {
2828 m = &(c->methods[i]);
2830 if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc)))
2838 /*********************** Function: class_fetchmethod **************************
2840 like class_findmethod, but aborts with an error if the method is not found
2842 *******************************************************************************/
2844 methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc)
2848 mi = class_findmethod(c, name, desc);
2851 log_plain("Class: "); if (c) log_plain_utf(c->name); log_nl();
2852 log_plain("Method: "); if (name) log_plain_utf(name); log_nl();
2853 log_plain("Descriptor: "); if (desc) log_plain_utf(desc); log_nl();
2854 panic("Method not found");
2861 /************************* Function: class_findmethod_approx ******************
2863 like class_findmethod but ignores the return value when comparing the
2866 *******************************************************************************/
2868 methodinfo *class_findmethod_approx(classinfo *c, utf *name, utf *desc)
2872 for (i = 0; i < c->methodscount; i++) {
2873 if (c->methods[i].name == name) {
2874 utf *meth_descr = c->methods[i].descriptor;
2878 return &(c->methods[i]);
2880 if (desc->blength <= meth_descr->blength) {
2881 /* current position in utf text */
2882 char *desc_utf_ptr = desc->text;
2883 char *meth_utf_ptr = meth_descr->text;
2884 /* points behind utf strings */
2885 char *desc_end = utf_end(desc);
2886 char *meth_end = utf_end(meth_descr);
2889 /* compare argument types */
2890 while (desc_utf_ptr < desc_end && meth_utf_ptr < meth_end) {
2892 if ((ch = *desc_utf_ptr++) != (*meth_utf_ptr++))
2893 break; /* no match */
2896 return &(c->methods[i]); /* all parameter types equal */
2906 /***************** Function: class_resolvemethod_approx ***********************
2908 Searches a class and every super class for a method (without paying
2909 attention to the return value)
2911 *******************************************************************************/
2913 methodinfo *class_resolvemethod_approx(classinfo *c, utf *name, utf *desc)
2916 /* search for method (ignore returntype) */
2917 methodinfo *m = class_findmethod_approx(c, name, desc);
2920 /* search superclass */
2928 /* class_resolvemethod *********************************************************
2930 Searches a class and it's super classes for a method.
2932 *******************************************************************************/
2934 methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
2939 m = class_findmethod(c, name, desc);
2951 /* class_resolveinterfacemethod_intern *****************************************
2953 Internally used helper function. Do not use this directly.
2955 *******************************************************************************/
2957 static methodinfo *class_resolveinterfacemethod_intern(classinfo *c,
2958 utf *name, utf *desc)
2963 m = class_findmethod(c, name, desc);
2968 /* try the superinterfaces */
2970 for (i = 0; i < c->interfacescount; i++) {
2971 m = class_resolveinterfacemethod_intern(c->interfaces[i].cls, name, desc);
2980 /* class_resolveinterfacemethod ************************************************
2982 Resolves a reference from REFERER to a method with NAME and DESC in
2985 If the method cannot be resolved the return value is NULL. If
2986 EXCEPT is true *exceptionptr is set, too.
2988 *******************************************************************************/
2990 methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc,
2991 classinfo *referer, bool except)
2995 /* XXX resolve class c */
2996 /* XXX check access from REFERER to C */
2998 if (!(c->flags & ACC_INTERFACE)) {
3001 new_exception(string_java_lang_IncompatibleClassChangeError);
3006 mi = class_resolveinterfacemethod_intern(c, name, desc);
3011 /* try class java.lang.Object */
3012 LOADER_ASSERT(class_java_lang_Object);
3013 mi = class_findmethod(class_java_lang_Object, name, desc);
3020 new_exception_utfmessage(string_java_lang_NoSuchMethodError, name);
3026 /* class_resolveclassmethod ****************************************************
3028 Resolves a reference from REFERER to a method with NAME and DESC in
3031 If the method cannot be resolved the return value is NULL. If EXCEPT is
3032 true *exceptionptr is set, too.
3034 *******************************************************************************/
3036 methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc,
3037 classinfo *referer, bool except)
3045 /* XXX resolve class c */
3046 /* XXX check access from REFERER to C */
3048 /* if (c->flags & ACC_INTERFACE) { */
3050 /* *exceptionptr = */
3051 /* new_exception(string_java_lang_IncompatibleClassChangeError); */
3055 /* try class c and its superclasses */
3060 mi = class_findmethod(cls, name, desc);
3065 cls = cls->super.cls;
3068 /* try the superinterfaces */
3070 for (i = 0; i < c->interfacescount; i++) {
3071 mi = class_resolveinterfacemethod_intern(c->interfaces[i].cls, name, desc);
3078 msglen = utf_strlen(c->name) + strlen(".") + utf_strlen(name) +
3079 utf_strlen(desc) + strlen("0");
3081 msg = MNEW(char, msglen);
3083 utf_sprint(msg, c->name);
3085 utf_sprint(msg + strlen(msg), name);
3086 utf_sprint(msg + strlen(msg), desc);
3089 new_exception_message(string_java_lang_NoSuchMethodError, msg);
3091 MFREE(msg, char, msglen);
3097 if ((mi->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) {
3099 *exceptionptr = new_exception(string_java_lang_AbstractMethodError);
3104 /* XXX check access rights */
3110 /************************* Function: class_issubclass **************************
3112 Checks if sub is a descendant of super.
3114 *******************************************************************************/
3116 bool class_issubclass(classinfo *sub, classinfo *super)
3119 if (!sub) return false;
3120 if (sub == super) return true;
3121 sub = sub->super.cls;
3126 void class_showconstanti(classinfo *c, int ii)
3132 printf ("#%d: ", (int) i);
3134 switch (c->cptags [i]) {
3135 case CONSTANT_Class:
3136 printf("Classreference -> ");
3137 utf_display(((constant_classref*)e)->name);
3140 case CONSTANT_Fieldref:
3141 printf("Fieldref -> "); goto displayFMIi;
3142 case CONSTANT_Methodref:
3143 printf("Methodref -> "); goto displayFMIi;
3144 case CONSTANT_InterfaceMethodref:
3145 printf("InterfaceMethod -> "); goto displayFMIi;
3148 constant_FMIref *fmi = e;
3149 utf_display(fmi->classref->name);
3151 utf_display(fmi->name);
3153 utf_display(fmi->descriptor);
3157 case CONSTANT_String:
3158 printf("String -> ");
3161 case CONSTANT_Integer:
3162 printf("Integer -> %d", (int) (((constant_integer*)e)->value));
3164 case CONSTANT_Float:
3165 printf("Float -> %f", ((constant_float*)e)->value);
3167 case CONSTANT_Double:
3168 printf("Double -> %f", ((constant_double*)e)->value);
3172 u8 v = ((constant_long*)e)->value;
3174 printf("Long -> %ld", (long int) v);
3176 printf("Long -> HI: %ld, LO: %ld\n",
3177 (long int) v.high, (long int) v.low);
3181 case CONSTANT_NameAndType:
3183 constant_nameandtype *cnt = e;
3184 printf("NameAndType: ");
3185 utf_display(cnt->name);
3187 utf_display(cnt->descriptor);
3195 panic("Invalid type of ConstantPool-Entry");
3202 void class_showconstantpool (classinfo *c)
3207 printf ("---- dump of constant pool ----\n");
3209 for (i=0; i<c->cpcount; i++) {
3210 printf ("#%d: ", (int) i);
3212 e = c -> cpinfos [i];
3215 switch (c -> cptags [i]) {
3216 case CONSTANT_Class:
3217 printf ("Classreference -> ");
3218 utf_display ( ((constant_classref*)e) -> name );
3221 case CONSTANT_Fieldref:
3222 printf ("Fieldref -> "); goto displayFMI;
3223 case CONSTANT_Methodref:
3224 printf ("Methodref -> "); goto displayFMI;
3225 case CONSTANT_InterfaceMethodref:
3226 printf ("InterfaceMethod -> "); goto displayFMI;
3229 constant_FMIref *fmi = e;
3230 utf_display ( fmi->classref->name );
3232 utf_display ( fmi->name);
3234 utf_display ( fmi->descriptor );
3238 case CONSTANT_String:
3239 printf ("String -> ");
3242 case CONSTANT_Integer:
3243 printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) );
3245 case CONSTANT_Float:
3246 printf ("Float -> %f", ((constant_float*)e) -> value);
3248 case CONSTANT_Double:
3249 printf ("Double -> %f", ((constant_double*)e) -> value);
3253 u8 v = ((constant_long*)e) -> value;
3255 printf ("Long -> %ld", (long int) v);
3257 printf ("Long -> HI: %ld, LO: %ld\n",
3258 (long int) v.high, (long int) v.low);
3262 case CONSTANT_NameAndType:
3264 constant_nameandtype *cnt = e;
3265 printf ("NameAndType: ");
3266 utf_display (cnt->name);
3268 utf_display (cnt->descriptor);
3272 printf ("Utf8 -> ");
3276 panic ("Invalid type of ConstantPool-Entry");
3286 /********** Function: class_showmethods (debugging only) *************/
3288 void class_showmethods (classinfo *c)
3292 printf ("--------- Fields and Methods ----------------\n");
3293 printf ("Flags: "); printflags (c->flags); printf ("\n");
3295 printf ("This: "); utf_display (c->name); printf ("\n");
3297 printf ("Super: "); utf_display (c->super.cls->name); printf ("\n");
3299 printf ("Index: %d\n", c->index);
3301 printf ("interfaces:\n");
3302 for (i=0; i < c-> interfacescount; i++) {
3304 utf_display (c -> interfaces[i].cls -> name);
3305 printf (" (%d)\n", c->interfaces[i].cls -> index);
3308 printf ("fields:\n");
3309 for (i=0; i < c -> fieldscount; i++) {
3310 field_display (&(c -> fields[i]));
3313 printf ("methods:\n");
3314 for (i=0; i < c -> methodscount; i++) {
3315 methodinfo *m = &(c->methods[i]);
3316 if ( !(m->flags & ACC_STATIC))
3317 printf ("vftblindex: %d ", m->vftblindex);
3319 method_display ( m );
3323 printf ("Virtual function table:\n");
3324 for (i=0; i<c->vftbl->vftbllength; i++) {
3325 printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i]) );
3331 /* loader_close ****************************************************************
3333 Frees all resources.
3335 *******************************************************************************/
3337 void loader_close(void)
3344 * These are local overrides for various environment variables in Emacs.
3345 * Please do not remove this and leave it at the end of the file, where
3346 * Emacs will automagically detect them.
3347 * ---------------------------------------------------------------------
3350 * indent-tabs-mode: t