jamvm
view src/class.c @ 403:907df5a02819
Fix storage of protection domain for OpenJDK.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* src/class.c,
* src/jam.h:
Change signature of defineClass to include
protection domain.
* src/jni.c: Fix call to defineClass to send
NULL protection domain as HotSpot does.
* src/natives.c: Send protection domain directly
to defineClass on OpenJDK as there is no field to
inject it into.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* src/class.c,
* src/jam.h:
Change signature of defineClass to include
protection domain.
* src/jni.c: Fix call to defineClass to send
NULL protection domain as HotSpot does.
* src/natives.c: Send protection domain directly
to defineClass on OpenJDK as there is no field to
inject it into.
| author | andrew |
|---|---|
| date | Tue Aug 05 06:03:08 2008 +0100 (2008-08-05) |
| parents | 24373fc1d951 |
| children |
line source
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 * Robert Lougher <rob@lougher.org.uk>.
4 *
5 * This file is part of JamVM.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <dirent.h>
30 #include "jam.h"
31 #include "sig.h"
32 #include "thread.h"
33 #include "lock.h"
34 #include "hash.h"
35 #include "zip.h"
36 #include "class.h"
37 #include "interp.h"
38 #include "symbol.h"
39 #include "excep.h"
41 #define PREPARE(ptr) ptr
42 #define SCAVENGE(ptr) FALSE
43 #define FOUND(ptr) ptr
45 /* Trace classfile parsing */
46 #ifdef TRACECLASS
47 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
48 #define TRACE(fmt, ...)
49 #endif
51 static int verbose;
52 static char *bootpath;
53 static char *classpath;
54 static int max_cp_element_len;
56 /* Structures holding the boot loader classpath */
57 typedef struct bcp_entry {
58 char *path;
59 ZipFile *zip;
60 } BCPEntry;
62 static BCPEntry *bootclasspath;
63 static int bcp_entries;
65 /* Cached offsets of fields in java.lang.ref.Reference objects */
66 int ref_referent_offset = -1;
67 int ref_queue_offset;
69 /* Cached offset of vmdata field in java.lang.ClassLoader objects */
70 int ldr_vmdata_offset = -1;
73 static Class *loader_data_class = NULL;
74 static MethodBlock *ldr_new_unloader;
75 static int ldr_data_tbl_offset;
77 /* Instance of java.lang.Class for java.lang.Class */
78 Class *java_lang_Class = NULL;
80 /* Method table index of ClassLoader.loadClass - used when
81 requesting a Java-level class loader to load a class.
82 Cached on first use. */
83 static int loadClass_mtbl_idx = -1;
85 /* Method table index of finalizer method and ClassLoader.enqueue.
86 Used by finalizer and reference handler threads */
87 int finalize_mtbl_idx;
88 int enqueue_mtbl_idx;
90 /* hash table containing classes loaded by the boot loader and
91 internally created arrays */
93 #define INITSZE 1<<8
94 static HashTable loaded_classes;
96 /* Array large enough to hold all primitive classes -
97 * access protected by loaded_classes hash table lock */
98 #define MAX_PRIM_CLASSES 9
99 static Class *prim_classes[MAX_PRIM_CLASSES];
101 /* Bytecode for stub abstract method. If it is invoked
102 we'll get an abstract method error. */
103 static char abstract_method[] = {OPC_ABSTRACT_METHOD_ERROR};
105 static Class *addClassToHash(Class *class, Object *class_loader) {
106 HashTable *table;
107 Class *entry;
109 #define HASH(ptr) utf8Hash(CLASS_CB((Class *)ptr)->name)
110 #define COMPARE(ptr1, ptr2, hash1, hash2) (hash1 == hash2) && \
111 CLASS_CB((Class *)ptr1)->name == CLASS_CB((Class *)ptr2)->name
113 if(class_loader == NULL)
114 table = &loaded_classes;
115 else {
116 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
118 if(vmdata == NULL) {
119 objectLock(class_loader);
120 vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
122 if(vmdata == NULL) {
123 if((vmdata = allocObject(loader_data_class)) == NULL) {
124 objectUnlock(class_loader);
125 return NULL;
126 }
128 table = sysMalloc(sizeof(HashTable));
129 initHashTable((*table), INITSZE, TRUE);
131 INST_DATA(vmdata)[ldr_data_tbl_offset] = (uintptr_t)table;
132 INST_DATA(class_loader)[ldr_vmdata_offset] = (uintptr_t)vmdata;
134 objectUnlock(class_loader);
135 }
136 }
138 table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
139 }
141 /* Add if absent, no scavenge, locked */
142 findHashEntry((*table), class, entry, TRUE, FALSE, TRUE);
144 return entry;
145 }
147 static void prepareClass(Class *class) {
148 ClassBlock *cb = CLASS_CB(class);
150 if(cb->name == SYMBOL(java_lang_Class)) {
151 java_lang_Class = class->class = class;
152 cb->flags |= CLASS_CLASS;
153 } else {
154 if(java_lang_Class == NULL)
155 findSystemClass0(SYMBOL(java_lang_Class));
156 class->class = java_lang_Class;
157 }
158 }
160 Class *defineClass(char *classname, char *data, int offset, int len, Object *class_loader, Object* pd) {
161 unsigned char *ptr = (unsigned char *)data+offset;
162 int cp_count, intf_count, i;
163 u2 major_version, minor_version, this_idx, super_idx;
164 u2 attr_count;
165 u4 magic;
167 ConstantPool *constant_pool;
168 ClassBlock *classblock;
169 Class *class, *found;
170 Class **interfaces;
172 TRACE("<CLASS: Defining class %s>\n", classname);
173 READ_U4(magic, ptr, len);
175 if(magic != 0xcafebabe) {
176 signalException(java_lang_ClassFormatError, "bad magic");
177 return NULL;
178 }
180 READ_U2(minor_version, ptr, len);
181 READ_U2(major_version, ptr, len);
183 if((class = allocClass()) == NULL)
184 return NULL;
186 classblock = CLASS_CB(class);
187 READ_U2(cp_count, ptr, len);
189 constant_pool = &classblock->constant_pool;
190 constant_pool->type = (u1 *)sysMalloc(cp_count);
191 constant_pool->info = (ConstantPoolEntry *)
192 sysMalloc(cp_count*sizeof(ConstantPoolEntry));
194 for(i = 1; i < cp_count; i++) {
195 u1 tag;
197 READ_U1(tag, ptr, len);
198 CP_TYPE(constant_pool,i) = tag;
200 switch(tag) {
201 case CONSTANT_Class:
202 case CONSTANT_String:
203 READ_INDEX(CP_INFO(constant_pool,i), ptr, len);
204 break;
206 case CONSTANT_Fieldref:
207 case CONSTANT_Methodref:
208 case CONSTANT_NameAndType:
209 case CONSTANT_InterfaceMethodref:
210 {
211 u2 idx1, idx2;
213 READ_INDEX(idx1, ptr, len);
214 READ_INDEX(idx2, ptr, len);
215 CP_INFO(constant_pool,i) = (idx2<<16)+idx1;
216 break;
217 }
219 case CONSTANT_Integer:
220 READ_U4(CP_INFO(constant_pool,i), ptr, len);
221 break;
223 case CONSTANT_Float:
224 {
225 u4 val;
227 READ_U4(val, ptr, len);
228 CP_INFO(constant_pool,i) = FLOAT_CONST(val);
229 break;
230 }
232 case CONSTANT_Long:
233 READ_U8(*(u8 *)&(CP_INFO(constant_pool,i)), ptr, len);
234 CP_TYPE(constant_pool,++i) = 0;
235 break;
237 case CONSTANT_Double:
238 READ_DBL(*(u8 *)&(CP_INFO(constant_pool,i)), ptr, len);
239 CP_TYPE(constant_pool,++i) = 0;
240 break;
242 case CONSTANT_Utf8:
243 {
244 int length;
245 char *buff, *utf8;
247 READ_U2(length, ptr, len);
248 buff = sysMalloc(length+1);
250 memcpy(buff, ptr, length);
251 buff[length] = '\0';
252 ptr += length;
254 CP_INFO(constant_pool,i) = (uintptr_t) (utf8 = newUtf8(buff));
256 if(utf8 != buff)
257 sysFree(buff);
259 break;
260 }
262 default:
263 signalException(java_lang_ClassFormatError, "bad constant pool tag");
264 return NULL;
265 }
266 }
268 /* Set count after constant pool has been initialised -- it is now
269 safe to be scanned by GC */
270 classblock->constant_pool_count = cp_count;
272 READ_U2(classblock->access_flags, ptr, len);
274 READ_TYPE_INDEX(this_idx, constant_pool, CONSTANT_Class, ptr, len);
275 classblock->name = CP_UTF8(constant_pool, CP_CLASS(constant_pool, this_idx));
277 if(classname && strcmp(classblock->name, classname) != 0) {
278 signalException(java_lang_NoClassDefFoundError, "class file has wrong name");
279 return NULL;
280 }
282 prepareClass(class);
284 if(classblock->name == SYMBOL(java_lang_Object)) {
285 READ_U2(super_idx, ptr, len);
286 if(super_idx) {
287 signalException(java_lang_ClassFormatError, "Object has super");
288 return NULL;
289 }
290 classblock->super_name = NULL;
291 } else {
292 READ_TYPE_INDEX(super_idx, constant_pool, CONSTANT_Class, ptr, len);
293 classblock->super_name = CP_UTF8(constant_pool, CP_CLASS(constant_pool, super_idx));
294 }
296 classblock->class_loader = class_loader;
297 classblock->protection_domain = pd;
299 READ_U2(intf_count = classblock->interfaces_count, ptr, len);
300 interfaces = classblock->interfaces =
301 (Class **)sysMalloc(intf_count * sizeof(Class *));
303 memset(interfaces, 0, intf_count * sizeof(Class *));
304 for(i = 0; i < intf_count; i++) {
305 u2 index;
306 READ_TYPE_INDEX(index, constant_pool, CONSTANT_Class, ptr, len);
307 interfaces[i] = resolveClass(class, index, FALSE);
308 if(exceptionOccurred())
309 return NULL;
310 }
312 READ_U2(classblock->fields_count, ptr, len);
313 classblock->fields = (FieldBlock *)
314 sysMalloc(classblock->fields_count * sizeof(FieldBlock));
316 for(i = 0; i < classblock->fields_count; i++) {
317 u2 name_idx, type_idx;
319 READ_U2(classblock->fields[i].access_flags, ptr, len);
320 READ_TYPE_INDEX(name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
321 READ_TYPE_INDEX(type_idx, constant_pool, CONSTANT_Utf8, ptr, len);
322 classblock->fields[i].name = CP_UTF8(constant_pool, name_idx);
323 classblock->fields[i].type = CP_UTF8(constant_pool, type_idx);
324 classblock->fields[i].annotations = NULL;
325 classblock->fields[i].signature = NULL;
326 classblock->fields[i].constant = 0;
328 READ_U2(attr_count, ptr, len);
329 for(; attr_count != 0; attr_count--) {
330 u2 attr_name_idx;
331 char *attr_name;
332 u4 attr_length;
334 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
335 attr_name = CP_UTF8(constant_pool, attr_name_idx);
336 READ_U4(attr_length, ptr, len);
338 if(attr_name == SYMBOL(ConstantValue)) {
339 READ_INDEX(classblock->fields[i].constant, ptr, len);
340 } else
341 if(attr_name == SYMBOL(Signature)) {
342 u2 signature_idx;
343 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
344 classblock->fields[i].signature = CP_UTF8(constant_pool, signature_idx);
345 } else
346 if(attr_name == SYMBOL(RuntimeVisibleAnnotations)) {
347 classblock->fields[i].annotations = sysMalloc(sizeof(AnnotationData));
348 classblock->fields[i].annotations->len = attr_length;
349 classblock->fields[i].annotations->data = sysMalloc(attr_length);
350 memcpy(classblock->fields[i].annotations->data, ptr, attr_length);
351 ptr += attr_length;
352 } else
353 ptr += attr_length;
354 }
355 }
357 READ_U2(classblock->methods_count, ptr, len);
359 classblock->methods = (MethodBlock *)
360 sysMalloc(classblock->methods_count * sizeof(MethodBlock));
362 memset(classblock->methods, 0, classblock->methods_count * sizeof(MethodBlock));
364 for(i = 0; i < classblock->methods_count; i++) {
365 MethodBlock *method = &classblock->methods[i];
366 MethodAnnotationData annos;
367 u2 name_idx, type_idx;
369 memset(&annos, 0, sizeof(MethodAnnotationData));
371 READ_U2(method->access_flags, ptr, len);
372 READ_TYPE_INDEX(name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
373 READ_TYPE_INDEX(type_idx, constant_pool, CONSTANT_Utf8, ptr, len);
375 method->name = CP_UTF8(constant_pool, name_idx);
376 method->type = CP_UTF8(constant_pool, type_idx);
378 READ_U2(attr_count, ptr, len);
379 for(; attr_count != 0; attr_count--) {
380 u2 attr_name_idx;
381 char *attr_name;
382 u4 attr_length;
384 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
385 READ_U4(attr_length, ptr, len);
386 attr_name = CP_UTF8(constant_pool, attr_name_idx);
388 if(attr_name == SYMBOL(Code)) {
389 u4 code_length;
390 u2 code_attr_cnt;
391 int j;
393 READ_U2(method->max_stack, ptr, len);
394 READ_U2(method->max_locals, ptr, len);
396 READ_U4(code_length, ptr, len);
397 method->code = (char *)sysMalloc(code_length);
398 memcpy(method->code, ptr, code_length);
399 ptr += code_length;
401 method->code_size = code_length;
403 READ_U2(method->exception_table_size, ptr, len);
404 method->exception_table = (ExceptionTableEntry *)
405 sysMalloc(method->exception_table_size*sizeof(ExceptionTableEntry));
407 for(j = 0; j < method->exception_table_size; j++) {
408 ExceptionTableEntry *entry = &method->exception_table[j];
410 READ_U2(entry->start_pc, ptr, len);
411 READ_U2(entry->end_pc, ptr, len);
412 READ_U2(entry->handler_pc, ptr, len);
413 READ_U2(entry->catch_type, ptr, len);
414 }
416 READ_U2(code_attr_cnt, ptr, len);
417 for(; code_attr_cnt != 0; code_attr_cnt--) {
418 u2 attr_name_idx;
419 u4 attr_length;
421 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
422 attr_name = CP_UTF8(constant_pool, attr_name_idx);
423 READ_U4(attr_length, ptr, len);
425 if(attr_name == SYMBOL(LineNumberTable)) {
426 READ_U2(method->line_no_table_size, ptr, len);
427 method->line_no_table = (LineNoTableEntry *)
428 sysMalloc(method->line_no_table_size*sizeof(LineNoTableEntry));
430 for(j = 0; j < method->line_no_table_size; j++) {
431 LineNoTableEntry *entry = &method->line_no_table[j];
433 READ_U2(entry->start_pc, ptr, len);
434 READ_U2(entry->line_no, ptr, len);
435 }
436 } else
437 ptr += attr_length;
438 }
439 } else
440 if(attr_name == SYMBOL(Exceptions)) {
441 int j;
443 READ_U2(method->throw_table_size, ptr, len);
444 method->throw_table = (u2 *)sysMalloc(method->throw_table_size*sizeof(u2));
445 for(j = 0; j < method->throw_table_size; j++) {
446 READ_U2(method->throw_table[j], ptr, len);
447 }
448 } else
449 if(attr_name == SYMBOL(Signature)) {
450 u2 signature_idx;
451 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
452 method->signature = CP_UTF8(constant_pool, signature_idx);
453 } else
454 if(attr_name == SYMBOL(RuntimeVisibleAnnotations)) {
455 annos.annotations = sysMalloc(sizeof(AnnotationData));
456 annos.annotations->len = attr_length;
457 annos.annotations->data = sysMalloc(attr_length);
458 memcpy(annos.annotations->data, ptr, attr_length);
459 ptr += attr_length;
460 } else
461 if(attr_name == SYMBOL(RuntimeVisibleParameterAnnotations)) {
462 annos.parameters = sysMalloc(sizeof(AnnotationData));
463 annos.parameters->len = attr_length;
464 annos.parameters->data = sysMalloc(attr_length);
465 memcpy(annos.parameters->data, ptr, attr_length);
466 ptr += attr_length;
467 } else
468 if(attr_name == SYMBOL(AnnotationDefault)) {
469 annos.dft_val = sysMalloc(sizeof(AnnotationData));
470 annos.dft_val->len = attr_length;
471 annos.dft_val->data = sysMalloc(attr_length);
472 memcpy(annos.dft_val->data, ptr, attr_length);
473 ptr += attr_length;
474 } else
475 ptr += attr_length;
476 }
477 if(annos.annotations != NULL || annos.parameters != NULL
478 || annos.dft_val != NULL) {
479 method->annotations = sysMalloc(sizeof(MethodAnnotationData));
480 memcpy(method->annotations, &annos, sizeof(MethodAnnotationData));
481 }
482 }
484 READ_U2(attr_count, ptr, len);
485 for(; attr_count != 0; attr_count--) {
486 u2 attr_name_idx;
487 char *attr_name;
488 u4 attr_length;
490 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
491 attr_name = CP_UTF8(constant_pool, attr_name_idx);
492 READ_U4(attr_length, ptr, len);
494 if(attr_name == SYMBOL(SourceFile)) {
495 u2 file_name_idx;
496 READ_TYPE_INDEX(file_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
497 classblock->source_file_name = CP_UTF8(constant_pool, file_name_idx);
498 } else
499 if(attr_name == SYMBOL(InnerClasses)) {
500 int j, size;
501 READ_U2(size, ptr, len);
502 {
503 u2 inner_classes[size];
504 for(j = 0; j < size; j++) {
505 int inner, outer;
506 READ_TYPE_INDEX(inner, constant_pool, CONSTANT_Class, ptr, len);
507 READ_TYPE_INDEX(outer, constant_pool, CONSTANT_Class, ptr, len);
509 if(inner == this_idx) {
510 int inner_name_idx;
512 /* A member class doesn't have an EnclosingMethod attribute, so set
513 the enclosing class to be the same as the declaring class */
514 if(outer)
515 classblock->declaring_class = classblock->enclosing_class = outer;
517 READ_TYPE_INDEX(inner_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
518 if(inner_name_idx == 0)
519 classblock->flags |= ANONYMOUS;
521 READ_U2(classblock->inner_access_flags, ptr, len);
522 } else {
523 ptr += 4;
524 if(outer == this_idx)
525 inner_classes[classblock->inner_class_count++] = inner;
526 }
527 }
529 if(classblock->inner_class_count) {
530 classblock->inner_classes = sysMalloc(classblock->inner_class_count*sizeof(u2));
531 memcpy(classblock->inner_classes, &inner_classes[0],
532 classblock->inner_class_count*sizeof(u2));
533 }
534 }
535 } else
536 if(attr_name == SYMBOL(EnclosingMethod)) {
537 READ_TYPE_INDEX(classblock->enclosing_class, constant_pool, CONSTANT_Class, ptr, len);
538 READ_TYPE_INDEX(classblock->enclosing_method, constant_pool, CONSTANT_NameAndType, ptr, len);
539 } else
540 if(attr_name == SYMBOL(Signature)) {
541 u2 signature_idx;
542 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
543 classblock->signature = CP_UTF8(constant_pool, signature_idx);
544 } else
545 if(attr_name == SYMBOL(Synthetic))
546 classblock->access_flags |= ACC_SYNTHETIC;
547 else
548 if(attr_name == SYMBOL(RuntimeVisibleAnnotations)) {
549 classblock->annotations = sysMalloc(sizeof(AnnotationData));
550 classblock->annotations->len = attr_length;
551 classblock->annotations->data = sysMalloc(attr_length);
552 memcpy(classblock->annotations->data, ptr, attr_length);
553 ptr += attr_length;
554 } else
555 ptr += attr_length;
556 }
558 classblock->super = super_idx ? resolveClass(class, super_idx, FALSE) : NULL;
560 if(exceptionOccurred())
561 {
562 TRACE("<CLASS: Exception %s occurred in defining class %s>\n",
563 CLASS_CB(getExecEnv()->exception->class)->name, classname);
564 return NULL;
565 }
567 classblock->state = CLASS_LOADED;
569 if((found = addClassToHash(class, class_loader)) != class) {
570 classblock->flags = CLASS_CLASH;
571 if(class_loader != NULL) {
572 signalException(java_lang_LinkageError, "duplicate class definition");
573 return NULL;
574 }
575 return found;
576 }
578 return class;
579 }
581 Class *createArrayClass(char *classname, Object *class_loader) {
582 ClassBlock *elem_cb, *classblock;
583 Class *class, *found = NULL;
584 int len = strlen(classname);
586 if((class = allocClass()) == NULL)
587 return NULL;
589 classblock = CLASS_CB(class);
591 classblock->name = copyUtf8(classname);
592 classblock->super_name = SYMBOL(java_lang_Object);
593 classblock->super = findSystemClass0(SYMBOL(java_lang_Object));
594 classblock->method_table = CLASS_CB(classblock->super)->method_table;
596 classblock->interfaces_count = 2;
597 classblock->interfaces = (Class**)sysMalloc(2*sizeof(Class*));
598 classblock->interfaces[0] = findSystemClass0(SYMBOL(java_lang_Cloneable));
599 classblock->interfaces[1] = findSystemClass0(SYMBOL(java_io_Serializable));
601 classblock->state = CLASS_ARRAY;
603 /* Find the array element class and the dimension --
604 this is used to speed up type checking (instanceof) */
606 if(classname[1] == '[') {
607 Class *comp_class = findArrayClassFromClassLoader(classname + 1, class_loader);
609 if(comp_class == NULL)
610 goto error;
612 classblock->element_class = CLASS_CB(comp_class)->element_class;
613 classblock->dim = CLASS_CB(comp_class)->dim + 1;
614 } else {
615 if(classname[1] == 'L') {
616 char element_name[len-2];
618 strcpy(element_name, classname + 2);
619 element_name[len-3] = '\0';
620 classblock->element_class = findClassFromClassLoader(element_name, class_loader);
621 } else
622 classblock->element_class = findPrimitiveClass(classname[1]);
624 if(classblock->element_class == NULL)
625 goto error;
627 classblock->dim = 1;
628 }
630 elem_cb = CLASS_CB(classblock->element_class);
632 /* The array's classloader is the loader of the element class */
633 classblock->class_loader = elem_cb->class_loader;
635 /* The array's visibility (i.e. public, etc.) is that of the element */
636 classblock->access_flags = (elem_cb->access_flags & ~ACC_INTERFACE) |
637 ACC_FINAL | ACC_ABSTRACT;
639 prepareClass(class);
641 if((found = addClassToHash(class, classblock->class_loader)) == class) {
642 if(verbose)
643 jam_printf("[Created array class %s]\n", classname);
644 return class;
645 }
647 error:
648 classblock->flags = CLASS_CLASH;
649 return found;
650 }
652 Class *
653 createPrimClass(char *classname, int index) {
654 Class *class;
655 ClassBlock *classblock;
657 if((class = allocClass()) == NULL)
658 return NULL;
660 classblock = CLASS_CB(class);
661 classblock->name = classname;
662 classblock->state = CLASS_PRIM + index;
663 classblock->access_flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
665 prepareClass(class);
667 lockHashTable(loaded_classes);
668 if(prim_classes[index] == NULL)
669 prim_classes[index] = class;
670 unlockHashTable(loaded_classes);
672 if(verbose)
673 jam_printf("[Created primitive class %s]\n", classname);
675 return prim_classes[index];
676 }
678 #define MRNDA_CACHE_SZE 10
680 #define resizeMTable(method_table, method_table_size, miranda, count) \
681 { \
682 method_table = (MethodBlock**)sysRealloc(method_table, \
683 (method_table_size + count) * sizeof(MethodBlock*)); \
684 \
685 memcpy(&method_table[method_table_size], miranda, \
686 count * sizeof(MethodBlock*)); \
687 method_table_size += count; \
688 }
690 #define fillinMTable(method_table, methods, methods_count) \
691 { \
692 int i; \
693 for(i = 0; i < methods_count; i++, methods++) { \
694 if((methods->access_flags & (ACC_STATIC | ACC_PRIVATE)) || \
695 (methods->name[0] == '<')) \
696 continue; \
697 method_table[methods->method_table_index] = methods; \
698 } \
699 }
701 void linkClass(Class *class) {
702 static MethodBlock *obj_fnlzr_mthd = NULL;
704 ClassBlock *cb = CLASS_CB(class);
705 Class *super = (cb->access_flags & ACC_INTERFACE) ? NULL : cb->super;
707 RefsOffsetsEntry *spr_rfs_offsts_tbl = NULL;
708 ITableEntry *spr_imthd_tbl = NULL;
709 MethodBlock **method_table = NULL;
710 MethodBlock **spr_mthd_tbl = NULL;
711 MethodBlock *finalizer;
712 MethodBlock *mb;
713 FieldBlock *fb;
715 int spr_rfs_offsts_sze = 0;
716 int new_methods_count = 0;
717 int spr_imthd_tbl_sze = 0;
718 int itbl_offset_count = 0;
719 int spr_mthd_tbl_sze = 0;
720 int method_table_size;
721 int new_itable_count;
722 int spr_obj_sze = 0;
723 int refs_end_offset;
724 int itbl_idx, i, j;
725 int spr_flags = 0;
726 int field_offset;
728 if(cb->state >= CLASS_LINKED)
729 return;
731 objectLock((Object *)class);
733 if(cb->state >= CLASS_LINKED)
734 goto unlock;
736 if(verbose)
737 jam_printf("[Linking class %s]\n", cb->name);
739 if(super) {
740 ClassBlock *super_cb = CLASS_CB(super);
741 if(super_cb->state < CLASS_LINKED)
742 linkClass(super);
744 spr_flags = super_cb->flags;
745 spr_obj_sze = super_cb->object_size;
746 spr_mthd_tbl = super_cb->method_table;
747 spr_imthd_tbl = super_cb->imethod_table;
748 spr_mthd_tbl_sze = super_cb->method_table_size;
749 spr_imthd_tbl_sze = super_cb->imethod_table_size;
750 spr_rfs_offsts_sze = super_cb->refs_offsets_size;
751 spr_rfs_offsts_tbl = super_cb->refs_offsets_table;
752 }
754 /* prepare fields */
756 field_offset = spr_obj_sze;
758 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++) {
759 if(fb->access_flags & ACC_STATIC) {
760 /* init to default value */
761 if((*fb->type == 'J') || (*fb->type == 'D'))
762 *(long long *)&fb->static_value = 0;
763 else
764 fb->static_value = 0;
765 } else {
766 /* calc field offset */
767 if((*fb->type == 'L') || (*fb->type == '['))
768 fb->offset = field_offset++;
769 }
770 fb->class = class;
771 }
773 refs_end_offset = field_offset;
775 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++)
776 if(!(fb->access_flags & ACC_STATIC) &&
777 (*fb->type != 'L') && (*fb->type != '[')) {
778 /* calc field offset */
779 fb->offset = field_offset;
780 if((*fb->type == 'J') || (*fb->type == 'D'))
781 field_offset += 2;
782 else
783 field_offset += 1;
784 }
786 cb->object_size = field_offset;
788 /* prepare methods */
790 for(mb = cb->methods, i = 0; i < cb->methods_count; i++,mb++) {
792 /* calculate argument count from signature */
794 int count = 0;
795 char *sig = mb->type;
796 SCAN_SIG(sig, count+=2, count++);
798 if(mb->access_flags & ACC_STATIC)
799 mb->args_count = count;
800 else
801 mb->args_count = count + 1;
803 mb->class = class;
805 /* Set abstract method to stub */
806 if(mb->access_flags & ACC_ABSTRACT) {
807 mb->code_size = sizeof(abstract_method);
808 mb->code = abstract_method;
809 }
811 if(mb->access_flags & ACC_NATIVE) {
813 /* set up native invoker to wrapper to resolve function
814 on first invocation */
816 mb->native_invoker = (void *) resolveNativeWrapper;
818 /* native methods have no code attribute so these aren't filled
819 in at load time - as these values are used when creating frame
820 set to appropriate values */
822 mb->max_locals = mb->args_count;
823 mb->max_stack = 0;
824 }
826 #ifdef DIRECT
827 else {
828 /* Set the bottom bit of the pointer to indicate the
829 method is unprepared */
830 mb->code = ((char*)mb->code) + 1;
831 }
832 #endif
834 /* Static, private or init methods aren't dynamically invoked, so
835 don't stick them in the table to save space */
837 if((mb->access_flags & (ACC_STATIC | ACC_PRIVATE)) || (mb->name[0] == '<'))
838 continue;
840 /* if it's overriding an inherited method, replace in method table */
842 for(j = 0; j < spr_mthd_tbl_sze; j++)
843 if(mb->name == spr_mthd_tbl[j]->name &&
844 mb->type == spr_mthd_tbl[j]->type &&
845 checkMethodAccess(spr_mthd_tbl[j], class)) {
846 mb->method_table_index = spr_mthd_tbl[j]->method_table_index;
847 break;
848 }
850 if(j == spr_mthd_tbl_sze)
851 mb->method_table_index = spr_mthd_tbl_sze + new_methods_count++;
852 }
854 /* construct method table */
856 method_table_size = spr_mthd_tbl_sze + new_methods_count;
858 if(!(cb->access_flags & ACC_INTERFACE)) {
859 method_table = (MethodBlock**)sysMalloc(method_table_size * sizeof(MethodBlock*));
861 /* Copy parents method table to the start */
862 memcpy(method_table, spr_mthd_tbl, spr_mthd_tbl_sze * sizeof(MethodBlock*));
864 /* fill in the additional methods -- we use a
865 temporary because fillinMtable alters mb */
866 mb = cb->methods;
867 fillinMTable(method_table, mb, cb->methods_count);
868 }
870 /* setup interface method table */
872 /* number of interfaces implemented by this class is those implemented by
873 * parent, plus number of interfaces directly implemented by this class,
874 * and the total number of their superinterfaces */
876 new_itable_count = cb->interfaces_count;
877 for(i = 0; i < cb->interfaces_count; i++)
878 new_itable_count += CLASS_CB(cb->interfaces[i])->imethod_table_size;
880 cb->imethod_table_size = spr_imthd_tbl_sze + new_itable_count;
881 cb->imethod_table = (ITableEntry*)sysMalloc(cb->imethod_table_size * sizeof(ITableEntry));
883 /* copy parent's interface table - the offsets into the method table won't change */
885 memcpy(cb->imethod_table, spr_imthd_tbl, spr_imthd_tbl_sze * sizeof(ITableEntry));
887 /* now run through the extra interfaces implemented by this class,
888 * fill in the interface part, and calculate the number of offsets
889 * needed (i.e. the number of methods defined in the interfaces) */
891 itbl_idx = spr_imthd_tbl_sze;
892 for(i = 0; i < cb->interfaces_count; i++) {
893 Class *intf = cb->interfaces[i];
894 ClassBlock *intf_cb = CLASS_CB(intf);
896 cb->imethod_table[itbl_idx++].interface = intf;
897 itbl_offset_count += intf_cb->method_table_size;
899 for(j = 0; j < intf_cb->imethod_table_size; j++) {
900 Class *spr_intf = intf_cb->imethod_table[j].interface;
902 cb->imethod_table[itbl_idx++].interface = spr_intf;
903 itbl_offset_count += CLASS_CB(spr_intf)->method_table_size;
904 }
905 }
907 /* if we're an interface all finished - offsets aren't used */
909 if(!(cb->access_flags & ACC_INTERFACE)) {
910 int *offsets_pntr = (int*)sysMalloc(itbl_offset_count * sizeof(int));
911 int old_mtbl_size = method_table_size;
912 MethodBlock *miranda[MRNDA_CACHE_SZE];
913 int miranda_count = 0;
914 int mtbl_idx;
916 /* run through table again, this time filling in the offsets array -
917 * for each new interface, run through it's methods and locate
918 * each method in this classes method table */
920 for(i = spr_imthd_tbl_sze; i < cb->imethod_table_size; i++) {
921 ClassBlock *intf_cb = CLASS_CB(cb->imethod_table[i].interface);
922 cb->imethod_table[i].offsets = offsets_pntr;
924 for(j = 0; j < intf_cb->methods_count; j++) {
925 MethodBlock *intf_mb = &intf_cb->methods[j];
927 if((intf_mb->access_flags & (ACC_STATIC | ACC_PRIVATE)) ||
928 (intf_mb->name[0] == '<'))
929 continue;
931 /* We scan backwards so that we find methods defined in sub-classes
932 before super-classes. This ensures we find non-overridden
933 methods before the inherited non-accessible method */
934 for(mtbl_idx = method_table_size - 1; mtbl_idx >= 0; mtbl_idx--)
935 if(intf_mb->name == method_table[mtbl_idx]->name &&
936 intf_mb->type == method_table[mtbl_idx]->type) {
937 *offsets_pntr++ = mtbl_idx;
938 break;
939 }
941 if(mtbl_idx < 0) {
943 /* didn't find it - add a dummy abstract method (a so-called
944 miranda method). If it's invoked we'll get an abstract
945 method error */
947 int k;
948 for(k = 0; k < miranda_count; k++)
949 if(intf_mb->name == miranda[k]->name &&
950 intf_mb->type == miranda[k]->type)
951 break;
953 *offsets_pntr++ = method_table_size + k;
955 if(k == miranda_count) {
956 if(miranda_count == MRNDA_CACHE_SZE) {
957 resizeMTable(method_table, method_table_size, miranda, MRNDA_CACHE_SZE);
958 miranda_count = 0;
959 }
960 miranda[miranda_count++] = intf_mb;
961 }
962 }
963 }
964 }
966 if(miranda_count > 0)
967 resizeMTable(method_table, method_table_size, miranda, miranda_count);
969 if(old_mtbl_size != method_table_size) {
970 /* We've created some abstract methods */
971 int num_mirandas = method_table_size - old_mtbl_size;
973 mb = (MethodBlock *) sysRealloc(cb->methods,
974 (cb->methods_count + num_mirandas) * sizeof(MethodBlock));
976 /* If the realloc of the method list gave us a new pointer, the pointers
977 to them in the method table are now wrong. */
978 if(mb != cb->methods) {
979 /* mb will be left pointing to the end of the methods */
980 cb->methods = mb;
981 fillinMTable(method_table, mb, cb->methods_count);
982 } else
983 mb += cb->methods_count;
985 cb->methods_count += num_mirandas;
987 /* Now we've expanded the method list, replace pointers to
988 the interface methods. */
990 for(i = old_mtbl_size; i < method_table_size; i++,mb++) {
991 memcpy(mb, method_table[i], sizeof(MethodBlock));
992 mb->access_flags |= ACC_MIRANDA;
993 mb->method_table_index = i;
994 mb->class = class;
995 method_table[i] = mb;
996 }
997 }
998 }
1000 cb->method_table = method_table;
1001 cb->method_table_size = method_table_size;
1003 /* Handle finalizer */
1005 /* If this is Object find the finalize method. All subclasses will
1006 have it in the same place in the method table. Note, Object
1007 should always have a valid finalizer -- but check just in case */
1009 if(cb->super == NULL) {
1010 finalizer = findMethod(class, SYMBOL(finalize), SYMBOL(___V));
1011 if(finalizer && !(finalizer->access_flags & (ACC_STATIC | ACC_PRIVATE))) {
1012 finalize_mtbl_idx = finalizer->method_table_index;
1013 obj_fnlzr_mthd = finalizer;
1014 }
1015 }
1017 cb->flags |= spr_flags;
1019 /* Store the finalizer only if it's overridden Object's. We don't
1020 want to finalize every object, and Object's imp is empty */
1022 if(super && obj_fnlzr_mthd && (finalizer =
1023 method_table[obj_fnlzr_mthd->method_table_index]) != obj_fnlzr_mthd)
1024 cb->flags |= FINALIZED;
1026 /* Handle reference classes */
1028 if(ref_referent_offset == -1 && cb->name == SYMBOL(java_lang_ref_Reference)) {
1029 FieldBlock *ref_fb = findField(class, SYMBOL(referent), SYMBOL(sig_java_lang_Object));
1030 FieldBlock *queue_fb = findField(class, SYMBOL(queue), SYMBOL(sig_java_lang_ref_ReferenceQueue));
1031 MethodBlock *enqueue_mb = findMethod(class, SYMBOL(enqueue), SYMBOL(___Z));
1033 if(ref_fb == NULL || queue_fb == NULL || enqueue_mb == NULL) {
1034 jam_fprintf(stderr, "Expected fields/methods missing in java.lang.ref.Reference\n");
1035 exitVM(1);
1036 }
1038 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++)
1039 if(fb->offset > ref_fb->offset)
1040 fb->offset--;
1042 ref_referent_offset = ref_fb->offset = field_offset - 1;
1043 enqueue_mtbl_idx = enqueue_mb->method_table_index;
1044 ref_queue_offset = queue_fb->offset;
1045 refs_end_offset--;
1047 cb->flags |= REFERENCE;
1048 }
1050 if(spr_flags & REFERENCE) {
1051 if(cb->name == SYMBOL(java_lang_ref_SoftReference))
1052 cb->flags |= SOFT_REFERENCE;
1053 else
1054 if(cb->name == SYMBOL(java_lang_ref_WeakReference))
1055 cb->flags |= WEAK_REFERENCE;
1056 else
1057 if(cb->name == SYMBOL(java_lang_ref_PhantomReference))
1058 cb->flags |= PHANTOM_REFERENCE;
1059 }
1061 /* Handle class loader classes */
1063 if(ldr_vmdata_offset == -1 && cb->name == SYMBOL(java_lang_ClassLoader)) {
1064 FieldBlock *ldr_fb = findField(class, SYMBOL(vmdata), SYMBOL(sig_java_lang_Object));
1066 if(ldr_fb == NULL) {
1067 jam_fprintf(stderr, "Expected vmdata field missing in java.lang.ClassLoader\n");
1068 exitVM(1);
1069 }
1071 ldr_vmdata_offset = ldr_fb->offset;
1072 cb->flags |= CLASS_LOADER;
1073 }
1075 /* Construct the reference offsets list. This is used to speed up
1076 scanning of an objects references during the mark phase of GC. */
1078 if(refs_end_offset > spr_obj_sze) {
1079 int new_start;
1081 if(spr_rfs_offsts_sze > 0 && spr_rfs_offsts_tbl[spr_rfs_offsts_sze-1].end == spr_obj_sze) {
1082 cb->refs_offsets_size = spr_rfs_offsts_sze;
1083 new_start = spr_rfs_offsts_tbl[spr_rfs_offsts_sze-1].start;
1084 } else {
1085 cb->refs_offsets_size = spr_rfs_offsts_sze + 1;
1086 new_start = spr_obj_sze;
1087 }
1089 cb->refs_offsets_table = sysMalloc(cb->refs_offsets_size * sizeof(RefsOffsetsEntry));
1091 memcpy(cb->refs_offsets_table, spr_rfs_offsts_tbl,
1092 spr_rfs_offsts_sze * sizeof(RefsOffsetsEntry));
1094 cb->refs_offsets_table[cb->refs_offsets_size-1].start = new_start;
1095 cb->refs_offsets_table[cb->refs_offsets_size-1].end = refs_end_offset;
1096 } else {
1097 cb->refs_offsets_size = spr_rfs_offsts_sze;
1098 cb->refs_offsets_table = spr_rfs_offsts_tbl;
1099 }
1101 cb->state = CLASS_LINKED;
1103 unlock:
1104 objectUnlock((Object *)class);
1105 }
1107 Class *initClass(Class *class) {
1108 ClassBlock *cb = CLASS_CB(class);
1109 ConstantPool *cp = &cb->constant_pool;
1110 FieldBlock *fb = cb->fields;
1111 MethodBlock *mb;
1112 Object *excep;
1113 int state, i;
1115 if(cb->state >= CLASS_INITED)
1116 return class;
1118 linkClass(class);
1119 objectLock((Object *)class);
1121 while(cb->state == CLASS_INITING)
1122 if(cb->initing_tid == threadSelf()->id) {
1123 objectUnlock((Object *)class);
1124 return class;
1125 } else {
1126 /* FALSE means this wait is non-interruptible.
1127 An interrupt will appear as if the initialiser
1128 failed (below), and clearing will lose the
1129 interrupt status */
1130 objectWait0((Object *)class, 0, 0, FALSE);
1131 }
1133 if(cb->state >= CLASS_INITED) {
1134 objectUnlock((Object *)class);
1135 return class;
1136 }
1138 if(cb->state == CLASS_BAD) {
1139 objectUnlock((Object *)class);
1140 signalException(java_lang_NoClassDefFoundError, cb->name);
1141 return NULL;
1142 }
1144 cb->state = CLASS_INITING;
1145 cb->initing_tid = threadSelf()->id;
1147 objectUnlock((Object *)class);
1149 if(!(cb->access_flags & ACC_INTERFACE) && cb->super
1150 && (CLASS_CB(cb->super)->state != CLASS_INITED)) {
1151 initClass(cb->super);
1152 if(exceptionOccurred()) {
1153 state = CLASS_BAD;
1154 goto set_state_and_notify;
1155 }
1156 }
1158 /* Never used to bother with this as only static finals use it and
1159 the constant value's copied at compile time. However, separate
1160 compilation can result in a getstatic to a (now) constant field,
1161 and the VM didn't initialise it... */
1163 for(i = 0; i < cb->fields_count; i++,fb++)
1164 if((fb->access_flags & ACC_STATIC) && fb->constant) {
1165 if((*fb->type == 'J') || (*fb->type == 'D'))
1166 *(u8*)&fb->static_value = *(u8*)&(CP_INFO(cp, fb->constant));
1167 else
1168 fb->static_value = resolveSingleConstant(class, fb->constant);
1169 }
1171 if((mb = findMethod(class, SYMBOL(class_init), SYMBOL(___V))) != NULL)
1172 executeStaticMethod(class, mb);
1174 if((excep = exceptionOccurred())) {
1175 Class *error, *eiie;
1177 clearException();
1179 /* Don't wrap exceptions of type java.lang.Error... */
1180 if((error = findSystemClass0(SYMBOL(java_lang_Error)))
1181 && !isInstanceOf(error, excep->class)
1182 && (eiie = findSystemClass(SYMBOL(java_lang_ExceptionInInitializerError)))
1183 && (mb = findMethod(eiie, SYMBOL(object_init), SYMBOL(_java_lang_Throwable__V)))) {
1185 Object *ob = allocObject(eiie);
1187 if(ob != NULL) {
1188 executeMethod(ob, mb, excep);
1189 setException(ob);
1190 }
1191 } else
1192 setException(excep);
1194 state = CLASS_BAD;
1195 } else
1196 state = CLASS_INITED;
1198 set_state_and_notify:
1199 objectLock((Object *)class);
1200 cb->state = state;
1202 objectNotifyAll((Object *)class);
1203 objectUnlock((Object *)class);
1205 return state == CLASS_BAD ? NULL : class;
1206 }
1208 char *findFileEntry(char *path, int *file_len) {
1209 int read_len;
1210 char *data;
1211 FILE *fd;
1213 if((fd = fopen(path, "r")) == NULL)
1214 return NULL;
1216 fseek(fd, 0L, SEEK_END);
1217 *file_len = ftell(fd);
1218 fseek(fd, 0L, SEEK_SET);
1220 data = (char *)sysMalloc(*file_len);
1221 read_len = fread(data, sizeof(char), *file_len, fd);
1222 fclose(fd);
1224 if(read_len == *file_len)
1225 return data;
1227 sysFree(data);
1228 return NULL;
1229 }
1231 Class *loadSystemClass(char *classname) {
1232 int file_len, fname_len = strlen(classname) + 8;
1233 char buff[max_cp_element_len + fname_len];
1234 char filename[fname_len];
1235 Class *class = NULL;
1236 char *data = NULL;
1237 int i;
1239 filename[0] = '/';
1240 strcat(strcpy(&filename[1], classname), ".class");
1242 for(i = 0; i < bcp_entries && data == NULL; i++)
1243 if(bootclasspath[i].zip)
1244 data = findArchiveEntry(filename+1, bootclasspath[i].zip, &file_len);
1245 else
1246 data = findFileEntry(strcat(strcpy(buff, bootclasspath[i].path), filename), &file_len);
1248 if(data == NULL) {
1249 signalException(java_lang_NoClassDefFoundError, classname);
1250 return NULL;
1251 }
1253 class = defineClass(classname, data, 0, file_len, NULL, NULL);
1254 sysFree(data);
1256 if(verbose && class)
1257 jam_printf("[Loaded %s from %s]\n", classname, bootclasspath[i-1].path);
1259 return class;
1260 }
1262 void addInitiatingLoaderToClass(Object *class_loader, Class *class) {
1263 ClassBlock *cb = CLASS_CB(class);
1265 /* The defining class loader is automatically an initiating
1266 loader so don't add again */
1267 if(cb->class_loader != class_loader)
1268 addClassToHash(class, class_loader);
1269 }
1271 Class *findHashedClass(char *classname, Object *class_loader) {
1272 HashTable *table;
1273 Class *class;
1274 char *name;
1276 /* If the class name is not in the utf8 table it can't
1277 have been loaded */
1278 if((name = findUtf8(classname)) == NULL)
1279 return NULL;
1281 if(class_loader == NULL)
1282 table = &loaded_classes;
1283 else {
1284 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1286 if(vmdata == NULL)
1287 return NULL;
1289 table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1290 }
1292 #undef HASH
1293 #undef COMPARE
1294 #define HASH(ptr) utf8Hash(ptr)
1295 #define COMPARE(ptr1, ptr2, hash1, hash2) (hash1 == hash2) && \
1296 (ptr1 == CLASS_CB((Class *)ptr2)->name)
1298 /* Do not add if absent, no scavenge, locked */
1299 findHashEntry((*table), name, class, FALSE, FALSE, TRUE);
1301 return class;
1302 }
1304 Class *findSystemClass0(char *classname) {
1305 Class *class = findHashedClass(classname, NULL);
1307 if(class == NULL)
1308 class = loadSystemClass(classname);
1310 if(!exceptionOccurred())
1311 linkClass(class);
1313 return class;
1314 }
1316 Class *findSystemClass(char *classname) {
1317 Class *class = findSystemClass0(classname);
1319 if(!exceptionOccurred())
1320 initClass(class);
1322 return class;
1323 }
1325 Class *findArrayClassFromClassLoader(char *classname, Object *class_loader) {
1326 Class *class = findHashedClass(classname, class_loader);
1328 if(class == NULL) {
1329 if((class = createArrayClass(classname, class_loader)) != NULL)
1330 addInitiatingLoaderToClass(class_loader, class);
1331 }
1332 return class;
1333 }
1335 Class *findPrimitiveClass(char prim_type) {
1336 int index;
1337 Class *prim;
1338 char *classname;
1340 switch(prim_type) {
1341 case 'Z':
1342 classname = SYMBOL(boolean); index = 1;
1343 break;
1344 case 'B':
1345 classname = SYMBOL(byte); index = 2;
1346 break;
1347 case 'C':
1348 classname = SYMBOL(char); index = 3;
1349 break;
1350 case 'S':
1351 classname = SYMBOL(short); index = 4;
1352 break;
1353 case 'I':
1354 classname = SYMBOL(int); index = 5;
1355 break;
1356 case 'F':
1357 classname = SYMBOL(float); index = 6;
1358 break;
1359 case 'J':
1360 classname = SYMBOL(long); index = 7;
1361 break;
1362 case 'D':
1363 classname = SYMBOL(double); index = 8;
1364 break;
1365 case 'V':
1366 classname = SYMBOL(void); index = 0;
1367 break;
1368 default:
1369 signalException(java_lang_NoClassDefFoundError, NULL);
1370 return NULL;
1371 break;
1372 }
1374 prim = prim_classes[index];
1375 return prim ? prim : createPrimClass(classname, index);
1376 }
1378 Class *findNonArrayClassFromClassLoader(char *classname, Object *loader) {
1379 Class *class = findHashedClass(classname, loader);
1381 if(class == NULL) {
1382 char *dot_name = slash2dots(classname);
1383 Object *string = createString(dot_name);
1384 Object *excep;
1386 sysFree(dot_name);
1387 if(string == NULL)
1388 return NULL;
1390 if(loadClass_mtbl_idx == -1) {
1391 MethodBlock *mb = lookupMethod(loader->class, SYMBOL(loadClass),
1392 SYMBOL(_java_lang_String__java_lang_Class));
1393 if(mb == NULL)
1394 return NULL;
1396 loadClass_mtbl_idx = mb->method_table_index;
1397 }
1399 /* The public loadClass is not synchronized.
1400 Lock the class-loader to be thread-safe */
1401 objectLock(loader);
1402 class = *(Class**)executeMethod(loader,
1403 CLASS_CB(loader->class)->method_table[loadClass_mtbl_idx], string);
1404 objectUnlock(loader);
1406 if((excep = exceptionOccurred()) || class == NULL) {
1407 clearException();
1408 signalChainedException(java_lang_NoClassDefFoundError, classname, excep);
1409 return NULL;
1410 }
1412 addInitiatingLoaderToClass(loader, class);
1414 if(verbose && (CLASS_CB(class)->class_loader == loader))
1415 jam_printf("[Loaded %s]\n", classname);
1416 }
1417 return class;
1418 }
1420 Class *findClassFromClassLoader(char *classname, Object *loader) {
1421 if(*classname == '[')
1422 return findArrayClassFromClassLoader(classname, loader);
1424 if(loader != NULL)
1425 return findNonArrayClassFromClassLoader(classname, loader);
1427 return findSystemClass0(classname);
1428 }
1430 Object *getSystemClassLoader() {
1431 Class *class_loader = findSystemClass(SYMBOL(java_lang_ClassLoader));
1433 if(!exceptionOccurred()) {
1434 MethodBlock *mb;
1436 if((mb = findMethod(class_loader, SYMBOL(getSystemClassLoader),
1437 SYMBOL(___java_lang_ClassLoader))) != NULL) {
1438 Object *system_loader = *(Object**)executeStaticMethod(class_loader, mb);
1440 if(!exceptionOccurred())
1441 return system_loader;
1442 }
1443 }
1444 return NULL;
1445 }
1447 /* gc support for marking classes */
1449 #define ITERATE(ptr) markRoot(ptr)
1451 void markBootClasses() {
1452 int i;
1454 hashIterate(loaded_classes);
1456 for(i = 0; i < MAX_PRIM_CLASSES; i++)
1457 if(prim_classes[i] != NULL)
1458 markRoot((Object*)prim_classes[i]);
1459 }
1461 #undef ITERATE
1462 #define ITERATE(ptr) threadReference((Object**)ptr)
1464 void threadBootClasses() {
1465 int i;
1467 hashIterateP(loaded_classes);
1469 for(i = 0; i < MAX_PRIM_CLASSES; i++)
1470 if(prim_classes[i] != NULL)
1471 threadReference((Object**)&prim_classes[i]);
1472 }
1474 #undef ITERATE
1475 #define ITERATE(ptr) \
1476 if(CLASS_CB((Class *)ptr)->class_loader == class_loader) \
1477 markObject(ptr, mark, mark_soft_refs)
1479 void markLoaderClasses(Object *class_loader, int mark, int mark_soft_refs) {
1480 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1482 if(vmdata != NULL) {
1483 HashTable *table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1484 hashIterate((*table));
1485 }
1486 }
1488 #undef ITERATE
1489 #define ITERATE(ptr) threadReference((Object**)ptr)
1491 void threadLoaderClasses(Object *class_loader) {
1492 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1494 if(vmdata != NULL) {
1495 HashTable *table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1496 hashIterateP((*table));
1497 }
1498 }
1500 void freeClassData(Class *class) {
1501 ClassBlock *cb = CLASS_CB(class);
1502 int i;
1504 if(IS_ARRAY(cb)) {
1505 gcPendingFree(cb->interfaces);
1506 return;
1507 }
1509 gcPendingFree((void*)cb->constant_pool.type);
1510 gcPendingFree(cb->constant_pool.info);
1511 gcPendingFree(cb->interfaces);
1513 for(i = 0; i < cb->fields_count; i++) {
1514 FieldBlock *fb = &cb->fields[i];
1516 if(fb->annotations != NULL) {
1517 gcPendingFree(fb->annotations->data);
1518 gcPendingFree(fb->annotations);
1519 }
1520 }
1522 gcPendingFree(cb->fields);
1524 for(i = 0; i < cb->methods_count; i++) {
1525 MethodBlock *mb = &cb->methods[i];
1527 #ifdef DIRECT
1528 if(!((uintptr_t)mb->code & 0x3)) {
1529 #ifdef INLINING
1530 if(cb->state >= CLASS_LINKED)
1531 freeMethodInlinedInfo(mb);
1532 #endif
1533 gcPendingFree(mb->code);
1534 } else
1535 if(!(mb->access_flags & ACC_ABSTRACT))
1536 gcPendingFree((void*)((uintptr_t)mb->code & ~3));
1537 #else
1538 if(!(mb->access_flags & ACC_ABSTRACT))
1539 gcPendingFree(mb->code);
1540 #endif
1542 gcPendingFree(mb->exception_table);
1543 gcPendingFree(mb->line_no_table);
1544 gcPendingFree(mb->throw_table);
1546 if(mb->annotations != NULL) {
1547 if(mb->annotations->annotations != NULL) {
1548 gcPendingFree(mb->annotations->annotations->data);
1549 gcPendingFree(mb->annotations->annotations);
1550 }
1551 if(mb->annotations->parameters != NULL) {
1552 gcPendingFree(mb->annotations->parameters->data);
1553 gcPendingFree(mb->annotations->parameters);
1554 }
1555 if(mb->annotations->dft_val != NULL) {
1556 gcPendingFree(mb->annotations->dft_val->data);
1557 gcPendingFree(mb->annotations->dft_val);
1558 }
1559 gcPendingFree(mb->annotations);
1560 }
1561 }
1563 gcPendingFree(cb->methods);
1564 gcPendingFree(cb->inner_classes);
1566 if(cb->annotations != NULL) {
1567 gcPendingFree(cb->annotations->data);
1568 gcPendingFree(cb->annotations);
1569 }
1571 if(cb->state >= CLASS_LINKED) {
1572 ClassBlock *super_cb = CLASS_CB(cb->super);
1574 /* interfaces do not have a method table, or
1575 imethod table offsets */
1576 if(!IS_INTERFACE(cb)) {
1577 int spr_imthd_sze = super_cb->imethod_table_size;
1579 gcPendingFree(cb->method_table);
1580 if(cb->imethod_table_size > spr_imthd_sze)
1581 gcPendingFree(cb->imethod_table[spr_imthd_sze].offsets);
1582 }
1584 gcPendingFree(cb->imethod_table);
1586 if(cb->refs_offsets_table != super_cb->refs_offsets_table)
1587 gcPendingFree(cb->refs_offsets_table);
1588 }
1589 }
1591 void freeClassLoaderData(Object *class_loader) {
1592 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1594 if(vmdata != NULL) {
1595 HashTable *table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1596 gcFreeHashTable((*table));
1597 gcPendingFree(table);
1598 }
1599 }
1601 /* Add a library unloader object to the class loader for the
1602 library contained within entry. The library has an unload
1603 function, which will be called from the unloader finalizer
1604 when the class loader is garbage collected */
1605 void newLibraryUnloader(Object *class_loader, void *entry) {
1606 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1608 if(vmdata != NULL)
1609 executeMethod(vmdata, ldr_new_unloader, (long long)(uintptr_t)entry);
1610 }
1612 int parseBootClassPath(char *cp_var) {
1613 char *cp, *pntr, *start;
1614 int i, j, len, max = 0;
1615 struct stat info;
1617 cp = (char*)sysMalloc(strlen(cp_var)+1);
1618 strcpy(cp, cp_var);
1620 for(i = 0, start = pntr = cp; *pntr; pntr++) {
1621 if(*pntr == ':') {
1622 if(start != pntr) {
1623 *pntr = '\0';
1624 i++;
1625 }
1626 start = pntr+1;
1627 }
1628 }
1629 if(start != pntr)
1630 i++;
1632 bootclasspath = (BCPEntry *)sysMalloc(sizeof(BCPEntry)*i);
1634 for(j = 0, pntr = cp; i > 0; i--) {
1635 while(*pntr == ':')
1636 pntr++;
1638 start = pntr;
1639 pntr += (len = strlen(pntr))+1;
1641 if(stat(start, &info) == 0) {
1642 if(S_ISDIR(info.st_mode)) {
1643 bootclasspath[j].zip = NULL;
1644 if(len > max)
1645 max = len;
1646 } else
1647 if((bootclasspath[j].zip = processArchive(start)) == NULL)
1648 continue;
1649 bootclasspath[j++].path = start;
1650 }
1651 }
1653 max_cp_element_len = max;
1655 return bcp_entries = j;
1656 }
1658 void setClassPath(char *cmdlne_cp) {
1659 char *env;
1660 classpath = cmdlne_cp ? cmdlne_cp :
1661 ((env = getenv("CLASSPATH")) ? env : ".");
1662 }
1664 char *getClassPath() {
1665 return classpath;
1666 }
1668 int filter(struct dirent *entry) {
1669 int len = strlen(entry->d_name);
1670 char *ext = &entry->d_name[len-4];
1672 return len >= 4 && (strcasecmp(ext, ".zip") == 0 ||
1673 strcasecmp(ext, ".jar") == 0);
1674 }
1676 void scanDirForJars(char *dir) {
1677 int bootpathlen = strlen(bootpath) + 1;
1678 int dirlen = strlen(dir);
1679 struct dirent **namelist;
1680 int n;
1682 n = scandir(dir, &namelist, &filter, &alphasort);
1684 if(n >= 0) {
1685 while(--n >= 0) {
1686 char *buff;
1687 bootpathlen += strlen(namelist[n]->d_name) + dirlen + 2;
1688 buff = sysMalloc(bootpathlen);
1690 strcat(strcat(strcat(strcat(strcpy(buff, dir), "/"),
1691 namelist[n]->d_name), ":"), bootpath);
1693 sysFree(bootpath);
1694 bootpath = buff;
1695 free(namelist[n]);
1696 }
1697 free(namelist);
1698 }
1699 }
1701 void scanDirsForJars(char *directories) {
1702 int dirslen = strlen(directories);
1703 char *pntr, *end, *dirs = sysMalloc(dirslen + 1);
1704 strcpy(dirs, directories);
1706 for(end = pntr = &dirs[dirslen]; pntr != dirs; pntr--) {
1707 if(*pntr == ':') {
1708 char *start = pntr + 1;
1709 if(start != end)
1710 scanDirForJars(start);
1712 *(end = pntr) = '\0';
1713 }
1714 }
1716 if(end != dirs)
1717 scanDirForJars(dirs);
1719 sysFree(dirs);
1720 }
1722 char *setBootClassPath(char *cmdlne_bcp, char bootpathopt) {
1723 char *endorsed_dirs;
1725 if(cmdlne_bcp)
1726 switch(bootpathopt) {
1727 case 'a':
1728 case 'p':
1729 bootpath = sysMalloc(strlen(DFLT_BCP) + strlen(cmdlne_bcp) + 2);
1730 if(bootpathopt == 'a')
1731 strcat(strcat(strcpy(bootpath, DFLT_BCP), ":"), cmdlne_bcp);
1732 else
1733 strcat(strcat(strcpy(bootpath, cmdlne_bcp), ":"), DFLT_BCP);
1734 break;
1736 case 'c':
1737 bootpath = sysMalloc(strlen(JAMVM_CLASSES) + strlen(cmdlne_bcp) + 2);
1738 strcat(strcat(strcpy(bootpath, JAMVM_CLASSES), ":"), cmdlne_bcp);
1739 break;
1741 case 'v':
1742 bootpath = sysMalloc(strlen(CLASSPATH_CLASSES) + strlen(cmdlne_bcp) + 2);
1743 strcat(strcat(strcpy(bootpath, cmdlne_bcp), ":"), CLASSPATH_CLASSES);
1744 break;
1746 default:
1747 bootpath = sysMalloc(strlen(cmdlne_bcp) + 1);
1748 strcpy(bootpath, cmdlne_bcp);
1749 }
1750 else {
1751 char *env = getenv("BOOTCLASSPATH");
1752 char *path = env ? env : DFLT_BCP;
1753 bootpath = sysMalloc(strlen(path) + 1);
1754 strcpy(bootpath, path);
1755 }
1757 endorsed_dirs = getCommandLineProperty("java.endorsed.dirs");
1758 if(endorsed_dirs == NULL)
1759 endorsed_dirs = INSTALL_DIR"/share/jamvm/endorsed";
1761 scanDirsForJars(endorsed_dirs);
1763 return bootpath;
1764 }
1766 char *getBootClassPath() {
1767 return bootpath;
1768 }
1770 int bootClassPathSize() {
1771 return bcp_entries;
1772 }
1774 Object *bootClassPathResource(char *filename, int index) {
1775 if(index < bcp_entries) {
1776 /* Alloc enough space for Jar file URL -- jar:file://<path>!/<filename> */
1777 char buff[strlen(filename) + strlen(bootclasspath[index].path) + 14];
1779 if(bootclasspath[index].zip) {
1780 while(*filename == '/')
1781 filename++;
1783 if(!findArchiveDirEntry(filename, bootclasspath[index].zip))
1784 return NULL;
1786 sprintf(buff, "jar:file://%s!/%s", bootclasspath[index].path, filename);
1787 } else {
1788 struct stat info;
1790 sprintf(buff, "file://%s/%s", bootclasspath[index].path, filename);
1791 if(stat(&buff[7], &info) != 0 || S_ISDIR(info.st_mode))
1792 return NULL;
1793 }
1795 return createString(buff);
1796 }
1798 return NULL;
1799 }
1801 void initialiseClass(InitArgs *args) {
1802 char *bcp = setBootClassPath(args->bootpath, args->bootpathopt);
1803 FieldBlock *hashtable = NULL;
1805 if(!(bcp && parseBootClassPath(bcp))) {
1806 jam_fprintf(stderr, "bootclasspath is empty!\n");
1807 exitVM(1);
1808 }
1810 verbose = args->verboseclass;
1811 setClassPath(args->classpath);
1813 /* Init hash table, and create lock */
1814 initHashTable(loaded_classes, INITSZE, TRUE);
1816 loader_data_class = findSystemClass0(SYMBOL(jamvm_java_lang_VMClassLoaderData));
1817 registerStaticClassRef(&loader_data_class);
1819 if(loader_data_class != NULL) {
1820 ldr_new_unloader = findMethod(loader_data_class, SYMBOL(newLibraryUnloader),
1821 SYMBOL(_J__V));
1822 hashtable = findField(loader_data_class, SYMBOL(hashtable), SYMBOL(I));
1823 }
1825 if(hashtable == NULL || ldr_new_unloader == NULL) {
1826 jam_fprintf(stderr, "Fatal error: Bad VMClassLoaderData (missing or corrupt)\n");
1827 exitVM(1);
1828 }
1829 ldr_data_tbl_offset = hashtable->offset;
1831 /* Register the address of where the java.lang.Class ref _will_ be */
1832 registerStaticClassRef(&java_lang_Class);
1833 }
