1 /* src/vmcore/loader.c - class loader functions
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
36 #include "mm/memory.h"
38 #include "native/llni.h"
40 #include "threads/lock-common.h"
42 #include "toolbox/logging.h"
44 #include "vm/builtin.h"
45 #include "vm/exceptions.h"
46 #include "vm/global.h"
47 #include "vm/primitive.h"
48 #include "vm/stringlocal.h"
51 #include "vm/jit_interface.h"
53 #if defined(ENABLE_JAVASE)
54 # include "vmcore/annotation.h"
55 # include "vmcore/stackmap.h"
58 #include "vmcore/classcache.h"
59 #include "vmcore/field.h"
60 #include "vmcore/linker.h"
61 #include "vmcore/loader.h"
62 #include "vmcore/method.h"
63 #include "vmcore/options.h"
64 #include "vmcore/rt-timing.h"
66 #if defined(ENABLE_STATISTICS)
67 # include "vmcore/statistics.h"
70 #include "vmcore/suck.h"
72 #if defined(ENABLE_ZLIB)
73 # include "vmcore/zip.h"
76 #if defined(ENABLE_JVMTI)
77 # include "native/jvmti/cacaodbg.h"
81 /* loader_preinit **************************************************************
83 Initializes the classpath list and loads classes required for the
86 *******************************************************************************/
88 void loader_preinit(void)
90 #if defined(ENABLE_THREADS)
91 list_classpath_entry *lce;
93 /* Initialize the monitor pointer for zip/jar file locking. */
95 for (lce = list_first(list_classpath_entries); lce != NULL;
96 lce = list_next(list_classpath_entries, lce)) {
97 if (lce->type == CLASSPATH_ARCHIVE)
98 LOCK_INIT_OBJECT_LOCK(lce);
102 /* Load the most basic class. */
104 if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object)))
105 vm_abort("loader_preinit: loading java/lang/Object failed");
107 #if defined(ENABLE_JAVASE)
108 if (!(class_java_lang_Cloneable =
109 load_class_bootstrap(utf_java_lang_Cloneable)))
110 vm_abort("loader_preinit: loading java/lang/Cloneable failed");
112 if (!(class_java_io_Serializable =
113 load_class_bootstrap(utf_java_io_Serializable)))
114 vm_abort("loader_preinit: loading java/io/Serializable failed");
119 /* loader_init *****************************************************************
121 Loads all classes required in the VM.
123 *******************************************************************************/
125 void loader_init(void)
127 /* Load primitive-type wrapping classes. */
129 #if defined(ENABLE_JAVASE)
130 if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void)))
131 vm_abort("loader_init: loading failed");
134 if (!(class_java_lang_Boolean =
135 load_class_bootstrap(utf_java_lang_Boolean)))
136 vm_abort("loader_init: loading failed");
138 if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte)))
139 vm_abort("loader_init: loading failed");
141 if (!(class_java_lang_Character =
142 load_class_bootstrap(utf_java_lang_Character)))
143 vm_abort("loader_init: loading failed");
145 if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short)))
146 vm_abort("loader_init: loading failed");
148 if (!(class_java_lang_Integer =
149 load_class_bootstrap(utf_java_lang_Integer)))
150 vm_abort("loader_init: loading failed");
152 if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long)))
153 vm_abort("loader_init: loading failed");
155 if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float)))
156 vm_abort("loader_init: loading failed");
158 if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double)))
159 vm_abort("loader_init: loading failed");
161 /* Load important system classes. */
163 if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class)))
164 vm_abort("loader_init: loading failed");
166 if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String)))
167 vm_abort("loader_init: loading failed");
169 #if defined(ENABLE_JAVASE)
170 if (!(class_java_lang_ClassLoader =
171 load_class_bootstrap(utf_java_lang_ClassLoader)))
172 vm_abort("loader_init: loading failed");
174 if (!(class_java_lang_SecurityManager =
175 load_class_bootstrap(utf_java_lang_SecurityManager)))
176 vm_abort("loader_init: loading failed");
179 if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System)))
180 vm_abort("loader_init: loading failed");
182 if (!(class_java_lang_Thread =
183 load_class_bootstrap(utf_new_char("java/lang/Thread"))))
184 vm_abort("loader_init: loading failed");
186 #if defined(ENABLE_JAVASE)
187 if (!(class_java_lang_ThreadGroup =
188 load_class_bootstrap(utf_java_lang_ThreadGroup)))
189 vm_abort("loader_init: loading failed");
192 #if defined(WITH_CLASSPATH_GNU)
193 if (!(class_java_lang_VMSystem =
194 load_class_bootstrap(utf_new_char("java/lang/VMSystem"))))
195 vm_abort("loader_init: loading failed");
197 if (!(class_java_lang_VMThread =
198 load_class_bootstrap(utf_new_char("java/lang/VMThread"))))
199 vm_abort("loader_init: loading failed");
203 /* some classes which may be used more often */
205 #if defined(ENABLE_JAVASE)
206 if (!(class_java_lang_StackTraceElement =
207 load_class_bootstrap(utf_java_lang_StackTraceElement)))
208 vm_abort("loader_init: loading failed");
210 if (!(class_java_lang_reflect_Constructor =
211 load_class_bootstrap(utf_java_lang_reflect_Constructor)))
212 vm_abort("loader_init: loading failed");
214 if (!(class_java_lang_reflect_Field =
215 load_class_bootstrap(utf_java_lang_reflect_Field)))
216 vm_abort("loader_init: loading failed");
218 if (!(class_java_lang_reflect_Method =
219 load_class_bootstrap(utf_java_lang_reflect_Method)))
220 vm_abort("loader_init: loading failed");
222 if (!(class_java_security_PrivilegedAction =
223 load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"))))
224 vm_abort("loader_init: loading failed");
226 if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector)))
227 vm_abort("loader_init: loading failed");
229 # if defined(WITH_CLASSPATH_SUN)
230 if (!(class_sun_reflect_MagicAccessorImpl =
231 load_class_bootstrap(utf_new_char("sun/reflect/MagicAccessorImpl"))))
232 vm_abort("loader_init: loading failed");
235 if (!(arrayclass_java_lang_Object =
236 load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"))))
237 vm_abort("loader_init: loading failed");
239 # if defined(ENABLE_ANNOTATIONS)
240 /* needed by annotation support */
241 if (!(class_sun_reflect_ConstantPool =
242 load_class_bootstrap(utf_new_char("sun/reflect/ConstantPool"))))
243 vm_abort("loader_init: loading failed");
245 # if defined(WITH_CLASSPATH_GNU)
246 /* needed by GNU Classpaths annotation support */
247 if (!(class_sun_reflect_annotation_AnnotationParser =
248 load_class_bootstrap(utf_new_char("sun/reflect/annotation/AnnotationParser"))))
249 vm_abort("loader_init: loading failed");
256 /* loader_load_all_classes *****************************************************
258 Loads all classes specified in the BOOTCLASSPATH.
260 *******************************************************************************/
262 void loader_load_all_classes(void)
264 list_classpath_entry *lce;
265 #if defined(ENABLE_ZLIB)
268 hashtable_zipfile_entry *htzfe;
272 for (lce = list_first(list_classpath_entries); lce != NULL;
273 lce = list_next(list_classpath_entries, lce)) {
274 #if defined(ENABLE_ZLIB)
275 if (lce->type == CLASSPATH_ARCHIVE) {
276 /* get the classes hashtable */
280 for (slot = 0; slot < ht->size; slot++) {
281 htzfe = (hashtable_zipfile_entry *) ht->ptr[slot];
283 for (; htzfe; htzfe = htzfe->hashlink) {
286 /* skip all entries in META-INF and .properties,
289 if (!strncmp(u->text, "META-INF", strlen("META-INF")) ||
290 strstr(u->text, ".properties") ||
291 strstr(u->text, ".png"))
294 /* load class from bootstrap classloader */
296 if (!load_class_bootstrap(u)) {
297 fprintf(stderr, "Error loading: ");
298 utf_fprint_printable_ascii_classname(stderr, u);
299 fprintf(stderr, "\n");
302 /* print out exception and cause */
304 exceptions_print_current_exception();
312 #if defined(ENABLE_ZLIB)
319 /* loader_skip_attribute_body **************************************************
321 Skips an attribute the attribute_name_index has already been read.
324 u2 attribute_name_index;
326 u1 info[attribute_length];
329 *******************************************************************************/
331 bool loader_skip_attribute_body(classbuffer *cb)
335 if (!suck_check_classbuffer_size(cb, 4))
338 attribute_length = suck_u4(cb);
340 if (!suck_check_classbuffer_size(cb, attribute_length))
343 suck_skip_nbytes(cb, attribute_length);
349 /* load_constantpool ***********************************************************
351 Loads the constantpool of a class, the entries are transformed into
352 a simpler format by resolving references (a detailed overview of
353 the compact structures can be found in global.h).
355 *******************************************************************************/
357 static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool)
360 /* The following structures are used to save information which cannot be
361 processed during the first pass. After the complete constantpool has
362 been traversed the references can be resolved.
363 (only in specific order) */
365 /* CONSTANT_Class entries */
366 typedef struct forward_class {
367 struct forward_class *next;
372 /* CONSTANT_String */
373 typedef struct forward_string {
374 struct forward_string *next;
379 /* CONSTANT_NameAndType */
380 typedef struct forward_nameandtype {
381 struct forward_nameandtype *next;
385 } forward_nameandtype;
387 /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */
388 typedef struct forward_fieldmethint {
389 struct forward_fieldmethint *next;
393 u2 nameandtype_index;
394 } forward_fieldmethint;
400 forward_class *forward_classes = NULL;
401 forward_string *forward_strings = NULL;
402 forward_nameandtype *forward_nameandtypes = NULL;
403 forward_fieldmethint *forward_fieldmethints = NULL;
407 forward_nameandtype *nfn;
408 forward_fieldmethint *nff;
416 /* number of entries in the constant_pool table plus one */
417 if (!suck_check_classbuffer_size(cb, 2))
420 cpcount = c->cpcount = suck_u2(cb);
422 /* allocate memory */
423 cptags = c->cptags = MNEW(u1, cpcount);
424 cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
427 exceptions_throw_classformaterror(c, "Illegal constant pool size");
431 #if defined(ENABLE_STATISTICS)
433 count_const_pool_len += (sizeof(u1) + sizeof(voidptr)) * cpcount;
436 /* initialize constantpool */
437 for (idx = 0; idx < cpcount; idx++) {
438 cptags[idx] = CONSTANT_UNUSED;
443 /******* first pass *******/
444 /* entries which cannot be resolved now are written into
445 temporary structures and traversed again later */
448 while (idx < cpcount) {
451 /* get constant type */
452 if (!suck_check_classbuffer_size(cb, 1))
459 nfc = DNEW(forward_class);
461 nfc->next = forward_classes;
462 forward_classes = nfc;
464 nfc->thisindex = idx;
465 /* reference to CONSTANT_NameAndType */
466 if (!suck_check_classbuffer_size(cb, 2))
469 nfc->name_index = suck_u2(cb);
474 case CONSTANT_String:
475 nfs = DNEW(forward_string);
477 nfs->next = forward_strings;
478 forward_strings = nfs;
480 nfs->thisindex = idx;
482 /* reference to CONSTANT_Utf8_info with string characters */
483 if (!suck_check_classbuffer_size(cb, 2))
486 nfs->string_index = suck_u2(cb);
491 case CONSTANT_NameAndType:
492 nfn = DNEW(forward_nameandtype);
494 nfn->next = forward_nameandtypes;
495 forward_nameandtypes = nfn;
497 nfn->thisindex = idx;
499 if (!suck_check_classbuffer_size(cb, 2 + 2))
502 /* reference to CONSTANT_Utf8_info containing simple name */
503 nfn->name_index = suck_u2(cb);
505 /* reference to CONSTANT_Utf8_info containing field or method
507 nfn->sig_index = suck_u2(cb);
512 case CONSTANT_Fieldref:
513 case CONSTANT_Methodref:
514 case CONSTANT_InterfaceMethodref:
515 nff = DNEW(forward_fieldmethint);
517 nff->next = forward_fieldmethints;
518 forward_fieldmethints = nff;
520 nff->thisindex = idx;
524 if (!suck_check_classbuffer_size(cb, 2 + 2))
527 /* class or interface type that contains the declaration of the
529 nff->class_index = suck_u2(cb);
531 /* name and descriptor of the field or method */
532 nff->nameandtype_index = suck_u2(cb);
537 case CONSTANT_Integer: {
538 constant_integer *ci = NEW(constant_integer);
540 #if defined(ENABLE_STATISTICS)
542 count_const_pool_len += sizeof(constant_integer);
545 if (!suck_check_classbuffer_size(cb, 4))
548 ci->value = suck_s4(cb);
549 cptags[idx] = CONSTANT_Integer;
556 case CONSTANT_Float: {
557 constant_float *cf = NEW(constant_float);
559 #if defined(ENABLE_STATISTICS)
561 count_const_pool_len += sizeof(constant_float);
564 if (!suck_check_classbuffer_size(cb, 4))
567 cf->value = suck_float(cb);
568 cptags[idx] = CONSTANT_Float;
575 case CONSTANT_Long: {
576 constant_long *cl = NEW(constant_long);
578 #if defined(ENABLE_STATISTICS)
580 count_const_pool_len += sizeof(constant_long);
583 if (!suck_check_classbuffer_size(cb, 8))
586 cl->value = suck_s8(cb);
587 cptags[idx] = CONSTANT_Long;
591 exceptions_throw_classformaterror(c, "Invalid constant pool entry");
597 case CONSTANT_Double: {
598 constant_double *cd = NEW(constant_double);
600 #if defined(ENABLE_STATISTICS)
602 count_const_pool_len += sizeof(constant_double);
605 if (!suck_check_classbuffer_size(cb, 8))
608 cd->value = suck_double(cb);
609 cptags[idx] = CONSTANT_Double;
613 exceptions_throw_classformaterror(c, "Invalid constant pool entry");
619 case CONSTANT_Utf8: {
622 /* number of bytes in the bytes array (not string-length) */
623 if (!suck_check_classbuffer_size(cb, 2))
626 length = suck_u2(cb);
627 cptags[idx] = CONSTANT_Utf8;
629 /* validate the string */
630 if (!suck_check_classbuffer_size(cb, length))
633 #ifdef ENABLE_VERIFIER
635 !is_valid_utf((char *) cb->pos, (char *) (cb->pos + length)))
637 exceptions_throw_classformaterror(c, "Invalid UTF-8 string");
640 #endif /* ENABLE_VERIFIER */
641 /* insert utf-string into the utf-symboltable */
642 cpinfos[idx] = utf_new((char *) cb->pos, length);
644 /* skip bytes of the string (buffer size check above) */
645 suck_skip_nbytes(cb, length);
651 exceptions_throw_classformaterror(c, "Illegal constant pool type");
657 /* resolve entries in temporary structures */
659 while (forward_classes) {
661 class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8);
665 #ifdef ENABLE_VERIFIER
666 if (opt_verify && !is_valid_name_utf(name)) {
667 exceptions_throw_classformaterror(c, "Class reference with invalid name");
670 #endif /* ENABLE_VERIFIER */
672 /* add all class references to the descriptor_pool */
674 if (!descriptor_pool_add_class(descpool, name))
677 cptags[forward_classes->thisindex] = CONSTANT_Class;
679 /* the classref is created later */
680 cpinfos[forward_classes->thisindex] = name;
682 nfc = forward_classes;
683 forward_classes = forward_classes->next;
686 while (forward_strings) {
688 class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8);
692 /* resolve utf-string */
693 cptags[forward_strings->thisindex] = CONSTANT_String;
694 cpinfos[forward_strings->thisindex] = text;
696 nfs = forward_strings;
697 forward_strings = forward_strings->next;
700 while (forward_nameandtypes) {
701 constant_nameandtype *cn = NEW(constant_nameandtype);
703 #if defined(ENABLE_STATISTICS)
705 count_const_pool_len += sizeof(constant_nameandtype);
708 /* resolve simple name and descriptor */
709 cn->name = class_getconstant(c,
710 forward_nameandtypes->name_index,
715 cn->descriptor = class_getconstant(c,
716 forward_nameandtypes->sig_index,
721 #ifdef ENABLE_VERIFIER
724 if (!is_valid_name_utf(cn->name)) {
725 exceptions_throw_classformaterror(c,
726 "Illegal Field name \"%s\"",
732 /* disallow referencing <clinit> among others */
733 if (cn->name->text[0] == '<' && cn->name != utf_init) {
734 exceptions_throw_classformaterror(c, "Illegal reference to special method");
738 #endif /* ENABLE_VERIFIER */
740 cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType;
741 cpinfos[forward_nameandtypes->thisindex] = cn;
743 nfn = forward_nameandtypes;
744 forward_nameandtypes = forward_nameandtypes->next;
747 while (forward_fieldmethints) {
748 constant_nameandtype *nat;
749 constant_FMIref *fmi = NEW(constant_FMIref);
751 #if defined(ENABLE_STATISTICS)
753 count_const_pool_len += sizeof(constant_FMIref);
755 /* resolve simple name and descriptor */
757 nat = class_getconstant(c,
758 forward_fieldmethints->nameandtype_index,
759 CONSTANT_NameAndType);
763 /* add all descriptors in {Field,Method}ref to the descriptor_pool */
765 if (!descriptor_pool_add(descpool, nat->descriptor, NULL))
768 /* the classref is created later */
770 fmi->p.index = forward_fieldmethints->class_index;
771 fmi->name = nat->name;
772 fmi->descriptor = nat->descriptor;
774 cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag;
775 cpinfos[forward_fieldmethints->thisindex] = fmi;
777 nff = forward_fieldmethints;
778 forward_fieldmethints = forward_fieldmethints->next;
781 /* everything was ok */
787 /* loader_load_attribute_signature *********************************************
789 Signature_attribute {
790 u2 attribute_name_index;
795 *******************************************************************************/
797 #if defined(ENABLE_JAVASE)
798 bool loader_load_attribute_signature(classbuffer *cb, utf **signature)
808 /* check remaining bytecode */
810 if (!suck_check_classbuffer_size(cb, 4 + 2))
813 /* check attribute length */
815 attribute_length = suck_u4(cb);
817 if (attribute_length != 2) {
818 exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
822 if (*signature != NULL) {
823 exceptions_throw_classformaterror(c, "Multiple Signature attributes");
829 signature_index = suck_u2(cb);
831 if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8)))
836 #endif /* defined(ENABLE_JAVASE) */
839 /* load_class_from_sysloader ***************************************************
841 Load the class with the given name using the system class loader
844 name.............the classname
848 NULL if an exception has been thrown
850 *******************************************************************************/
852 classinfo *load_class_from_sysloader(utf *name)
858 assert(class_java_lang_Object);
859 assert(class_java_lang_ClassLoader);
860 assert(class_java_lang_ClassLoader->state & CLASS_LINKED);
862 m = class_resolveclassmethod(class_java_lang_ClassLoader,
863 utf_getSystemClassLoader,
864 utf_void__java_lang_ClassLoader,
865 class_java_lang_Object,
871 cl = vm_call_method(m, NULL);
876 c = load_class_from_classloader(name, cl);
882 /* load_class_from_classloader *************************************************
884 Load the class with the given name using the given user-defined class loader.
887 name.............the classname
888 cl...............user-defined class loader
892 NULL if an exception has been thrown
894 *******************************************************************************/
896 classinfo *load_class_from_classloader(utf *name, classloader *cl)
901 java_handle_t *string;
902 #if defined(ENABLE_RT_TIMING)
903 struct timespec time_start, time_lookup, time_prepare, time_java,
907 RT_TIMING_GET_TIME(time_start);
911 /* lookup if this class has already been loaded */
913 c = classcache_lookup(cl, name);
915 RT_TIMING_GET_TIME(time_lookup);
916 RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_CL_LOOKUP);
921 /* if other class loader than bootstrap, call it */
929 namelen = name->blength;
931 /* handle array classes */
932 if (text[0] == '[') {
938 /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */
939 if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') {
940 exceptions_throw_classnotfoundexception(name);
944 u = utf_new(text + 2, namelen - 3);
946 if (!(comp = load_class_from_classloader(u, cl)))
949 /* create the array class */
951 c = class_array_of(comp, false);
953 tmpc = classcache_store(cl, c, true);
956 /* exception, free the loaded class */
957 c->state &= ~CLASS_LOADING;
964 /* load the component class */
966 u = utf_new(text + 1, namelen - 1);
968 if (!(comp = load_class_from_classloader(u, cl)))
971 /* create the array class */
973 c = class_array_of(comp, false);
975 tmpc = classcache_store(cl, c, true);
978 /* exception, free the loaded class */
979 c->state &= ~CLASS_LOADING;
986 /* primitive array classes are loaded by the bootstrap loader */
988 c = load_class_bootstrap(name);
994 #if defined(WITH_CLASSPATH_SUN)
995 /* OpenJDK uses this internal function because it's
998 lc = class_resolveclassmethod(cl->vftbl->class,
999 utf_loadClassInternal,
1000 utf_java_lang_String__java_lang_Class,
1004 lc = class_resolveclassmethod(cl->vftbl->class,
1006 utf_java_lang_String__java_lang_Class,
1012 return false; /* exception */
1014 /* move return value into `o' and cast it afterwards to a classinfo* */
1016 string = javastring_new_slash_to_dot(name);
1018 RT_TIMING_GET_TIME(time_prepare);
1020 o = vm_call_method(lc, cl, string);
1022 RT_TIMING_GET_TIME(time_java);
1024 c = LLNI_classinfo_unwrap(o);
1027 /* Store this class in the loaded class cache. If another
1028 class with the same (initloader,name) pair has been
1029 stored earlier it will be returned by classcache_store
1030 In this case classcache_store may not free the class
1031 because it has already been exposed to Java code which
1032 may have kept references to that class. */
1034 tmpc = classcache_store(cl, c, false);
1037 /* exception, free the loaded class */
1038 c->state &= ~CLASS_LOADING;
1045 RT_TIMING_GET_TIME(time_cache);
1047 RT_TIMING_TIME_DIFF(time_lookup , time_prepare, RT_TIMING_LOAD_CL_PREPARE);
1048 RT_TIMING_TIME_DIFF(time_prepare, time_java , RT_TIMING_LOAD_CL_JAVA);
1049 RT_TIMING_TIME_DIFF(time_java , time_cache , RT_TIMING_LOAD_CL_CACHE);
1051 /* SUN compatible -verbose:class output */
1053 if (opt_verboseclass && (c != NULL) && (c->classloader == cl)) {
1055 utf_display_printable_ascii_classname(name);
1059 #if defined(ENABLE_JVMTI)
1060 /* fire Class Load JVMTI event */
1061 if (jvmti) jvmti_ClassLoadPrepare(false, c);
1068 c = load_class_bootstrap(name);
1074 /* load_class_bootstrap ********************************************************
1076 Load the class with the given name using the bootstrap class loader.
1079 name.............the classname
1082 loaded classinfo, or
1083 NULL if an exception has been thrown
1086 load_class_bootstrap is synchronized. It can be treated as an
1089 *******************************************************************************/
1091 classinfo *load_class_bootstrap(utf *name)
1096 #if defined(ENABLE_RT_TIMING)
1097 struct timespec time_start, time_lookup, time_array, time_suck,
1098 time_load, time_cache;
1101 RT_TIMING_GET_TIME(time_start);
1107 /* lookup if this class has already been loaded */
1109 r = classcache_lookup(NULL, name);
1112 RT_TIMING_GET_TIME(time_lookup);
1113 RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP);
1118 RT_TIMING_GET_TIME(time_lookup);
1119 RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP);
1121 /* create the classinfo */
1123 c = class_create_classinfo(name);
1125 /* handle array classes */
1127 if (name->text[0] == '[') {
1128 c = load_newly_created_array(c, NULL);
1133 assert(c->state & CLASS_LOADED);
1135 RT_TIMING_GET_TIME(time_array);
1136 RT_TIMING_TIME_DIFF(time_start,time_array,RT_TIMING_LOAD_BOOT_ARRAY);
1141 #if defined(ENABLE_STATISTICS)
1144 if (opt_getcompilingtime)
1145 compilingtime_stop();
1147 if (opt_getloadingtime)
1148 loadingtime_start();
1151 /* load classdata, throw exception on error */
1156 /* this normally means, the classpath was not set properly */
1158 if (name == utf_java_lang_Object)
1159 vm_abort("java/lang/NoClassDefFoundError: java/lang/Object");
1161 exceptions_throw_classnotfoundexception(name);
1166 RT_TIMING_GET_TIME(time_suck);
1168 /* load the class from the buffer */
1170 r = load_class_from_classbuffer(cb);
1172 RT_TIMING_GET_TIME(time_load);
1175 /* the class could not be loaded, free the classinfo struct */
1180 /* Store this class in the loaded class cache this step also
1181 checks the loading constraints. If the class has been loaded
1182 before, the earlier loaded class is returned. */
1184 classinfo *res = classcache_store(NULL, c, true);
1194 RT_TIMING_GET_TIME(time_cache);
1196 /* SUN compatible -verbose:class output */
1198 if (opt_verboseclass && r) {
1200 utf_display_printable_ascii_classname(name);
1201 printf(" from %s]\n", cb->path);
1208 #if defined(ENABLE_STATISTICS)
1211 if (opt_getloadingtime)
1214 if (opt_getcompilingtime)
1215 compilingtime_start();
1218 RT_TIMING_TIME_DIFF(time_lookup, time_suck , RT_TIMING_LOAD_BOOT_SUCK);
1219 RT_TIMING_TIME_DIFF(time_suck , time_load , RT_TIMING_LOAD_BOOT_LOAD);
1220 RT_TIMING_TIME_DIFF(time_load , time_cache, RT_TIMING_LOAD_BOOT_CACHE);
1221 RT_TIMING_TIME_DIFF(time_lookup, time_cache, RT_TIMING_LOAD_BOOT_TOTAL);
1227 /* load_class_from_classbuffer_intern ******************************************
1229 Loads a class from a classbuffer into a given classinfo structure.
1230 Super-classes are also loaded at this point and some verfication
1234 This function is NOT synchronized!
1236 *******************************************************************************/
1238 static bool load_class_from_classbuffer_intern(classbuffer *cb)
1245 descriptor_pool *descpool;
1246 #if defined(ENABLE_STATISTICS)
1250 #if defined(ENABLE_RT_TIMING)
1251 struct timespec time_start, time_checks, time_ndpool, time_cpool,
1252 time_setup, time_fields, time_methods, time_classrefs,
1253 time_descs, time_setrefs, time_parsefds, time_parsemds,
1254 time_parsecpool, time_verify, time_attrs;
1257 RT_TIMING_GET_TIME(time_start);
1259 /* Get the classbuffer's class. */
1263 if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
1266 /* check signature */
1268 if (suck_u4(cb) != MAGIC) {
1269 exceptions_throw_classformaterror(c, "Bad magic number");
1278 if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
1279 exceptions_throw_unsupportedclassversionerror(c, ma, mi);
1283 RT_TIMING_GET_TIME(time_checks);
1285 /* create a new descriptor pool */
1287 descpool = descriptor_pool_new(c);
1289 RT_TIMING_GET_TIME(time_ndpool);
1291 /* load the constant pool */
1293 if (!load_constantpool(cb, descpool))
1296 RT_TIMING_GET_TIME(time_cpool);
1300 if (!suck_check_classbuffer_size(cb, 2))
1303 /* We OR the flags here, as we set already some flags in
1304 class_create_classinfo. */
1306 c->flags |= suck_u2(cb);
1308 /* check ACC flags consistency */
1310 if (c->flags & ACC_INTERFACE) {
1311 if (!(c->flags & ACC_ABSTRACT)) {
1312 /* We work around this because interfaces in JDK 1.1 are
1313 * not declared abstract. */
1315 c->flags |= ACC_ABSTRACT;
1318 if (c->flags & ACC_FINAL) {
1319 exceptions_throw_classformaterror(c,
1320 "Illegal class modifiers: 0x%X",
1325 if (c->flags & ACC_SUPER) {
1326 c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */
1330 if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) {
1331 exceptions_throw_classformaterror(c,
1332 "Illegal class modifiers: 0x%X",
1337 if (!suck_check_classbuffer_size(cb, 2 + 2))
1344 if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class)))
1347 if (c->name == utf_not_named_yet) {
1348 /* we finally have a name for this class */
1350 class_set_packagename(c);
1352 else if (name != c->name) {
1353 exceptions_throw_noclassdeffounderror_wrong_name(c, name);
1357 /* retrieve superclass */
1359 c->super.any = NULL;
1361 if ((i = suck_u2(cb))) {
1362 if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class)))
1365 /* java.lang.Object may not have a super class. */
1367 if (c->name == utf_java_lang_Object) {
1368 exceptions_throw_classformaterror(NULL, "java.lang.Object with superclass");
1372 /* Interfaces must have java.lang.Object as super class. */
1374 if ((c->flags & ACC_INTERFACE) && (supername != utf_java_lang_Object)) {
1375 exceptions_throw_classformaterror(c, "Interfaces must have java.lang.Object as superclass");
1382 /* This is only allowed for java.lang.Object. */
1384 if (c->name != utf_java_lang_Object) {
1385 exceptions_throw_classformaterror(c, "Bad superclass index");
1390 /* retrieve interfaces */
1392 if (!suck_check_classbuffer_size(cb, 2))
1395 c->interfacescount = suck_u2(cb);
1397 if (!suck_check_classbuffer_size(cb, 2 * c->interfacescount))
1400 c->interfaces = MNEW(classref_or_classinfo, c->interfacescount);
1402 for (i = 0; i < c->interfacescount; i++) {
1403 /* the classrefs are created later */
1404 if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
1408 RT_TIMING_GET_TIME(time_setup);
1412 if (!suck_check_classbuffer_size(cb, 2))
1415 c->fieldscount = suck_u2(cb);
1416 c->fields = MNEW(fieldinfo, c->fieldscount);
1418 MZERO(c->fields, fieldinfo, c->fieldscount);
1420 for (i = 0; i < c->fieldscount; i++) {
1421 if (!field_load(cb, &(c->fields[i]), descpool))
1425 RT_TIMING_GET_TIME(time_fields);
1429 if (!suck_check_classbuffer_size(cb, 2))
1432 c->methodscount = suck_u2(cb);
1433 c->methods = MNEW(methodinfo, c->methodscount);
1435 MZERO(c->methods, methodinfo, c->methodscount);
1437 for (i = 0; i < c->methodscount; i++) {
1438 if (!method_load(cb, &(c->methods[i]), descpool))
1442 RT_TIMING_GET_TIME(time_methods);
1444 /* create the class reference table */
1447 descriptor_pool_create_classrefs(descpool, &(c->classrefcount));
1449 RT_TIMING_GET_TIME(time_classrefs);
1451 /* allocate space for the parsed descriptors */
1453 descriptor_pool_alloc_parsed_descriptors(descpool);
1455 descriptor_pool_get_parsed_descriptors(descpool, &(c->parseddescsize));
1457 #if defined(ENABLE_STATISTICS)
1459 descriptor_pool_get_sizes(descpool, &classrefsize, &descsize);
1460 count_classref_len += classrefsize;
1461 count_parsed_desc_len += descsize;
1465 RT_TIMING_GET_TIME(time_descs);
1467 /* put the classrefs in the constant pool */
1468 for (i = 0; i < c->cpcount; i++) {
1469 if (c->cptags[i] == CONSTANT_Class) {
1470 utf *name = (utf *) c->cpinfos[i];
1471 c->cpinfos[i] = descriptor_pool_lookup_classref(descpool, name);
1475 /* set the super class reference */
1478 c->super.ref = descriptor_pool_lookup_classref(descpool, supername);
1483 /* set the super interfaces references */
1485 for (i = 0; i < c->interfacescount; i++) {
1486 c->interfaces[i].ref =
1487 descriptor_pool_lookup_classref(descpool,
1488 (utf *) c->interfaces[i].any);
1489 if (!c->interfaces[i].ref)
1493 RT_TIMING_GET_TIME(time_setrefs);
1495 /* parse field descriptors */
1497 for (i = 0; i < c->fieldscount; i++) {
1498 c->fields[i].parseddesc =
1499 descriptor_pool_parse_field_descriptor(descpool,
1500 c->fields[i].descriptor);
1501 if (!c->fields[i].parseddesc)
1505 RT_TIMING_GET_TIME(time_parsefds);
1507 /* parse method descriptors */
1509 for (i = 0; i < c->methodscount; i++) {
1510 methodinfo *m = &c->methods[i];
1512 descriptor_pool_parse_method_descriptor(descpool, m->descriptor,
1513 m->flags, class_get_self_classref(m->class));
1517 for (j = 0; j < m->rawexceptiontablelength; j++) {
1518 if (!m->rawexceptiontable[j].catchtype.any)
1521 if ((m->rawexceptiontable[j].catchtype.ref =
1522 descriptor_pool_lookup_classref(descpool,
1523 (utf *) m->rawexceptiontable[j].catchtype.any)) == NULL)
1527 for (j = 0; j < m->thrownexceptionscount; j++) {
1528 if (!m->thrownexceptions[j].any)
1531 if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool,
1532 (utf *) m->thrownexceptions[j].any)) == NULL)
1537 RT_TIMING_GET_TIME(time_parsemds);
1539 /* parse the loaded descriptors */
1541 for (i = 0; i < c->cpcount; i++) {
1542 constant_FMIref *fmi;
1545 switch (c->cptags[i]) {
1546 case CONSTANT_Fieldref:
1547 fmi = (constant_FMIref *) c->cpinfos[i];
1548 fmi->parseddesc.fd =
1549 descriptor_pool_parse_field_descriptor(descpool,
1551 if (!fmi->parseddesc.fd)
1554 index = fmi->p.index;
1556 (constant_classref *) class_getconstant(c, index,
1558 if (!fmi->p.classref)
1561 case CONSTANT_Methodref:
1562 case CONSTANT_InterfaceMethodref:
1563 fmi = (constant_FMIref *) c->cpinfos[i];
1564 index = fmi->p.index;
1566 (constant_classref *) class_getconstant(c, index,
1568 if (!fmi->p.classref)
1570 fmi->parseddesc.md =
1571 descriptor_pool_parse_method_descriptor(descpool,
1575 if (!fmi->parseddesc.md)
1581 RT_TIMING_GET_TIME(time_parsecpool);
1583 #ifdef ENABLE_VERIFIER
1584 /* Check if all fields and methods can be uniquely
1585 * identified by (name,descriptor). */
1588 /* We use a hash table here to avoid making the
1589 * average case quadratic in # of methods, fields.
1591 static int shift = 0;
1593 u2 *next; /* for chaining colliding hash entries */
1599 /* Allocate hashtable */
1600 len = c->methodscount;
1601 if (len < c->fieldscount) len = c->fieldscount;
1603 hashtab = MNEW(u2,(hashlen + len));
1604 next = hashtab + hashlen;
1606 /* Determine bitshift (to get good hash values) */
1616 memset(hashtab, 0, sizeof(u2) * (hashlen + len));
1618 for (i = 0; i < c->fieldscount; ++i) {
1619 fieldinfo *fi = c->fields + i;
1621 /* It's ok if we lose bits here */
1622 index = ((((size_t) fi->name) +
1623 ((size_t) fi->descriptor)) >> shift) % hashlen;
1625 if ((old = hashtab[index])) {
1629 if (c->fields[old].name == fi->name &&
1630 c->fields[old].descriptor == fi->descriptor) {
1631 exceptions_throw_classformaterror(c, "Repetitive field name/signature");
1634 } while ((old = next[old]));
1636 hashtab[index] = i + 1;
1640 memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5));
1642 for (i = 0; i < c->methodscount; ++i) {
1643 methodinfo *mi = c->methods + i;
1645 /* It's ok if we lose bits here */
1646 index = ((((size_t) mi->name) +
1647 ((size_t) mi->descriptor)) >> shift) % hashlen;
1649 if ((old = hashtab[index])) {
1653 if (c->methods[old].name == mi->name &&
1654 c->methods[old].descriptor == mi->descriptor) {
1655 exceptions_throw_classformaterror(c, "Repetitive method name/signature");
1658 } while ((old = next[old]));
1660 hashtab[index] = i + 1;
1663 MFREE(hashtab, u2, (hashlen + len));
1665 #endif /* ENABLE_VERIFIER */
1667 RT_TIMING_GET_TIME(time_verify);
1669 #if defined(ENABLE_STATISTICS)
1671 size_classinfo += sizeof(classinfo*) * c->interfacescount;
1672 size_fieldinfo += sizeof(fieldinfo) * c->fieldscount;
1673 size_methodinfo += sizeof(methodinfo) * c->methodscount;
1677 /* load attribute structures */
1679 if (!class_load_attributes(cb))
1682 /* Pre Java 1.5 version don't check this. This implementation is
1683 like Java 1.5 do it: for class file version 45.3 we don't check
1684 it, older versions are checked. */
1686 if (((ma == 45) && (mi > 3)) || (ma > 45)) {
1687 /* check if all data has been read */
1688 s4 classdata_left = ((cb->data + cb->size) - cb->pos);
1690 if (classdata_left > 0) {
1691 exceptions_throw_classformaterror(c, "Extra bytes at the end of class file");
1696 RT_TIMING_GET_TIME(time_attrs);
1698 RT_TIMING_TIME_DIFF(time_start , time_checks , RT_TIMING_LOAD_CHECKS);
1699 RT_TIMING_TIME_DIFF(time_checks , time_ndpool , RT_TIMING_LOAD_NDPOOL);
1700 RT_TIMING_TIME_DIFF(time_ndpool , time_cpool , RT_TIMING_LOAD_CPOOL);
1701 RT_TIMING_TIME_DIFF(time_cpool , time_setup , RT_TIMING_LOAD_SETUP);
1702 RT_TIMING_TIME_DIFF(time_setup , time_fields , RT_TIMING_LOAD_FIELDS);
1703 RT_TIMING_TIME_DIFF(time_fields , time_methods , RT_TIMING_LOAD_METHODS);
1704 RT_TIMING_TIME_DIFF(time_methods , time_classrefs , RT_TIMING_LOAD_CLASSREFS);
1705 RT_TIMING_TIME_DIFF(time_classrefs , time_descs , RT_TIMING_LOAD_DESCS);
1706 RT_TIMING_TIME_DIFF(time_descs , time_setrefs , RT_TIMING_LOAD_SETREFS);
1707 RT_TIMING_TIME_DIFF(time_setrefs , time_parsefds , RT_TIMING_LOAD_PARSEFDS);
1708 RT_TIMING_TIME_DIFF(time_parsefds , time_parsemds , RT_TIMING_LOAD_PARSEMDS);
1709 RT_TIMING_TIME_DIFF(time_parsemds , time_parsecpool, RT_TIMING_LOAD_PARSECP);
1710 RT_TIMING_TIME_DIFF(time_parsecpool, time_verify , RT_TIMING_LOAD_VERIFY);
1711 RT_TIMING_TIME_DIFF(time_verify , time_attrs , RT_TIMING_LOAD_ATTRS);
1712 RT_TIMING_TIME_DIFF(time_start , time_attrs , RT_TIMING_LOAD_TOTAL);
1718 /* load_class_from_classbuffer *************************************************
1720 Convenience wrapper for load_class_from_classbuffer.
1723 This function is NOT synchronized!
1725 *******************************************************************************/
1727 classinfo *load_class_from_classbuffer(classbuffer *cb)
1733 /* Get the classbuffer's class. */
1737 /* Check if the class is already loaded. */
1739 if (c->state & CLASS_LOADED)
1742 #if defined(ENABLE_STATISTICS)
1744 count_class_loads++;
1747 #if !defined(NDEBUG)
1749 log_message_class("Loading class: ", c);
1752 /* Mark start of dump memory area. */
1754 dumpsize = dump_size();
1756 /* Class is currently loading. */
1758 c->state |= CLASS_LOADING;
1760 /* Parse the classbuffer. */
1762 result = load_class_from_classbuffer_intern(cb);
1764 /* Release dump area. */
1766 dump_release(dumpsize);
1768 /* An error occurred. */
1770 if (result == false) {
1771 /* Revert loading state. */
1773 c->state = (c->state & ~CLASS_LOADING);
1778 /* Revert loading state and set loaded. */
1780 c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED;
1782 #if defined(ENABLE_JVMTI)
1783 /* fire Class Prepare JVMTI event */
1786 jvmti_ClassLoadPrepare(true, c);
1789 #if !defined(NDEBUG)
1791 log_message_class("Loading done class: ", c);
1798 /* load_newly_created_array ****************************************************
1800 Load a newly created array class.
1803 c....................the array class C has been loaded
1804 other classinfo......the array class was found in the class cache,
1806 NULL.................an exception has been thrown
1809 This is an internal function. Do not use it unless you know exactly
1812 Use one of the load_class_... functions for general array class loading.
1814 *******************************************************************************/
1816 classinfo *load_newly_created_array(classinfo *c, classloader *loader)
1818 classinfo *comp = NULL;
1820 methoddesc *clonedesc;
1821 constant_classref *classrefs;
1826 text = c->name->text;
1827 namelen = c->name->blength;
1829 /* Check array class name */
1831 if ((namelen < 2) || (text[0] != '[')) {
1832 exceptions_throw_classnotfoundexception(c->name);
1836 /* Check the element type */
1840 /* c is an array of arrays. We have to create the component class. */
1842 u = utf_new(text + 1, namelen - 1);
1844 comp = load_class_from_classloader(u, loader);
1849 assert(comp->state & CLASS_LOADED);
1851 /* the array's flags are that of the component class */
1852 c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT;
1853 c->classloader = comp->classloader;
1857 /* c is an array of objects. */
1859 /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */
1860 if ((namelen < 4) || (text[2] == '[') || (text[namelen - 1] != ';')) {
1861 exceptions_throw_classnotfoundexception(c->name);
1865 u = utf_new(text + 2, namelen - 3);
1867 if (!(comp = load_class_from_classloader(u, loader)))
1870 assert(comp->state & CLASS_LOADED);
1872 /* the array's flags are that of the component class */
1873 c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT;
1874 c->classloader = comp->classloader;
1878 /* c is an array of a primitive type */
1880 /* check for cases like `[II' and whether the character is a
1881 valid primitive type */
1883 if ((namelen > 2) || (primitive_class_get_by_char(text[1]) == NULL)) {
1884 exceptions_throw_classnotfoundexception(c->name);
1888 /* the accessibility of the array class is public (VM Spec 5.3.3) */
1889 c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
1890 c->classloader = NULL;
1893 assert(class_java_lang_Object);
1894 #if defined(ENABLE_JAVASE)
1895 assert(class_java_lang_Cloneable);
1896 assert(class_java_io_Serializable);
1899 /* setup the array class */
1901 c->super.cls = class_java_lang_Object;
1903 #if defined(ENABLE_JAVASE)
1905 c->interfacescount = 2;
1906 c->interfaces = MNEW(classref_or_classinfo, 2);
1907 c->interfaces[0].cls = class_java_lang_Cloneable;
1908 c->interfaces[1].cls = class_java_io_Serializable;
1910 #elif defined(ENABLE_JAVAME_CLDC1_1)
1912 c->interfacescount = 0;
1913 c->interfaces = NULL;
1916 # error unknow Java configuration
1919 c->methodscount = 1;
1920 c->methods = MNEW(methodinfo, c->methodscount);
1921 MZERO(c->methods, methodinfo, c->methodscount);
1923 classrefs = MNEW(constant_classref, 2);
1924 CLASSREF_INIT(classrefs[0], c, c->name);
1925 CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object);
1927 /* create descriptor for clone method */
1928 /* we need one paramslot which is reserved for the 'this' parameter */
1929 clonedesc = NEW(methoddesc);
1930 clonedesc->returntype.type = TYPE_ADR;
1931 clonedesc->returntype.classref = classrefs + 1;
1932 clonedesc->returntype.arraydim = 0;
1933 /* initialize params to "empty", add real params below in
1934 descriptor_params_from_paramtypes */
1935 clonedesc->paramcount = 0;
1936 clonedesc->paramslots = 0;
1937 clonedesc->paramtypes[0].classref = classrefs + 0;
1938 clonedesc->params = NULL;
1940 /* create methodinfo */
1943 MSET(clone, 0, methodinfo, 1);
1945 #if defined(ENABLE_THREADS)
1946 lock_init_object_lock(&clone->header);
1949 /* ATTENTION: if you delete the ACC_NATIVE below, set
1950 clone->maxlocals=1 (interpreter related) */
1952 clone->flags = ACC_PUBLIC | ACC_NATIVE;
1953 clone->name = utf_clone;
1954 clone->descriptor = utf_void__java_lang_Object;
1955 clone->parseddesc = clonedesc;
1958 /* parse the descriptor to get the register allocation */
1960 if (!descriptor_params_from_paramtypes(clonedesc, clone->flags))
1963 clone->code = codegen_generate_stub_native(clone, BUILTIN_clone);
1965 /* XXX: field: length? */
1967 /* array classes are not loaded from class files */
1969 c->state |= CLASS_LOADED;
1970 c->parseddescs = (u1 *) clonedesc;
1971 c->parseddescsize = sizeof(methodinfo);
1972 c->classrefs = classrefs;
1973 c->classrefcount = 1;
1975 /* insert class into the loaded class cache */
1976 /* XXX free classinfo if NULL returned? */
1978 return classcache_store(loader, c, true);
1982 /* loader_close ****************************************************************
1984 Frees all resources.
1986 *******************************************************************************/
1988 void loader_close(void)
1995 * These are local overrides for various environment variables in Emacs.
1996 * Please do not remove this and leave it at the end of the file, where
1997 * Emacs will automagically detect them.
1998 * ---------------------------------------------------------------------
2001 * indent-tabs-mode: t
2005 * vim:noexpandtab:sw=4:ts=4: