jamvm

view src/class.c @ 402:24373fc1d951

Add additional tracing support.

2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>

* .hgignore: Updated with autogen.sh output.
* configure.ac: Add new trace options.
* src/class.c,
* src/excep.c,
* src/natives.c,
* src/resolve.c: Add trace support.
* src/jam.h,
* src/dll.c,
* src/os/linux/os.c: Add support for reporting
the linking error using dlerror.
author andrew
date Tue Aug 05 05:46:09 2008 +0100 (2008-08-05)
parents 9d6ee66a21c3
children 907df5a02819
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) {
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;
298 READ_U2(intf_count = classblock->interfaces_count, ptr, len);
299 interfaces = classblock->interfaces =
300 (Class **)sysMalloc(intf_count * sizeof(Class *));
302 memset(interfaces, 0, intf_count * sizeof(Class *));
303 for(i = 0; i < intf_count; i++) {
304 u2 index;
305 READ_TYPE_INDEX(index, constant_pool, CONSTANT_Class, ptr, len);
306 interfaces[i] = resolveClass(class, index, FALSE);
307 if(exceptionOccurred())
308 return NULL;
309 }
311 READ_U2(classblock->fields_count, ptr, len);
312 classblock->fields = (FieldBlock *)
313 sysMalloc(classblock->fields_count * sizeof(FieldBlock));
315 for(i = 0; i < classblock->fields_count; i++) {
316 u2 name_idx, type_idx;
318 READ_U2(classblock->fields[i].access_flags, ptr, len);
319 READ_TYPE_INDEX(name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
320 READ_TYPE_INDEX(type_idx, constant_pool, CONSTANT_Utf8, ptr, len);
321 classblock->fields[i].name = CP_UTF8(constant_pool, name_idx);
322 classblock->fields[i].type = CP_UTF8(constant_pool, type_idx);
323 classblock->fields[i].annotations = NULL;
324 classblock->fields[i].signature = NULL;
325 classblock->fields[i].constant = 0;
327 READ_U2(attr_count, ptr, len);
328 for(; attr_count != 0; attr_count--) {
329 u2 attr_name_idx;
330 char *attr_name;
331 u4 attr_length;
333 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
334 attr_name = CP_UTF8(constant_pool, attr_name_idx);
335 READ_U4(attr_length, ptr, len);
337 if(attr_name == SYMBOL(ConstantValue)) {
338 READ_INDEX(classblock->fields[i].constant, ptr, len);
339 } else
340 if(attr_name == SYMBOL(Signature)) {
341 u2 signature_idx;
342 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
343 classblock->fields[i].signature = CP_UTF8(constant_pool, signature_idx);
344 } else
345 if(attr_name == SYMBOL(RuntimeVisibleAnnotations)) {
346 classblock->fields[i].annotations = sysMalloc(sizeof(AnnotationData));
347 classblock->fields[i].annotations->len = attr_length;
348 classblock->fields[i].annotations->data = sysMalloc(attr_length);
349 memcpy(classblock->fields[i].annotations->data, ptr, attr_length);
350 ptr += attr_length;
351 } else
352 ptr += attr_length;
353 }
354 }
356 READ_U2(classblock->methods_count, ptr, len);
358 classblock->methods = (MethodBlock *)
359 sysMalloc(classblock->methods_count * sizeof(MethodBlock));
361 memset(classblock->methods, 0, classblock->methods_count * sizeof(MethodBlock));
363 for(i = 0; i < classblock->methods_count; i++) {
364 MethodBlock *method = &classblock->methods[i];
365 MethodAnnotationData annos;
366 u2 name_idx, type_idx;
368 memset(&annos, 0, sizeof(MethodAnnotationData));
370 READ_U2(method->access_flags, ptr, len);
371 READ_TYPE_INDEX(name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
372 READ_TYPE_INDEX(type_idx, constant_pool, CONSTANT_Utf8, ptr, len);
374 method->name = CP_UTF8(constant_pool, name_idx);
375 method->type = CP_UTF8(constant_pool, type_idx);
377 READ_U2(attr_count, ptr, len);
378 for(; attr_count != 0; attr_count--) {
379 u2 attr_name_idx;
380 char *attr_name;
381 u4 attr_length;
383 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
384 READ_U4(attr_length, ptr, len);
385 attr_name = CP_UTF8(constant_pool, attr_name_idx);
387 if(attr_name == SYMBOL(Code)) {
388 u4 code_length;
389 u2 code_attr_cnt;
390 int j;
392 READ_U2(method->max_stack, ptr, len);
393 READ_U2(method->max_locals, ptr, len);
395 READ_U4(code_length, ptr, len);
396 method->code = (char *)sysMalloc(code_length);
397 memcpy(method->code, ptr, code_length);
398 ptr += code_length;
400 method->code_size = code_length;
402 READ_U2(method->exception_table_size, ptr, len);
403 method->exception_table = (ExceptionTableEntry *)
404 sysMalloc(method->exception_table_size*sizeof(ExceptionTableEntry));
406 for(j = 0; j < method->exception_table_size; j++) {
407 ExceptionTableEntry *entry = &method->exception_table[j];
409 READ_U2(entry->start_pc, ptr, len);
410 READ_U2(entry->end_pc, ptr, len);
411 READ_U2(entry->handler_pc, ptr, len);
412 READ_U2(entry->catch_type, ptr, len);
413 }
415 READ_U2(code_attr_cnt, ptr, len);
416 for(; code_attr_cnt != 0; code_attr_cnt--) {
417 u2 attr_name_idx;
418 u4 attr_length;
420 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
421 attr_name = CP_UTF8(constant_pool, attr_name_idx);
422 READ_U4(attr_length, ptr, len);
424 if(attr_name == SYMBOL(LineNumberTable)) {
425 READ_U2(method->line_no_table_size, ptr, len);
426 method->line_no_table = (LineNoTableEntry *)
427 sysMalloc(method->line_no_table_size*sizeof(LineNoTableEntry));
429 for(j = 0; j < method->line_no_table_size; j++) {
430 LineNoTableEntry *entry = &method->line_no_table[j];
432 READ_U2(entry->start_pc, ptr, len);
433 READ_U2(entry->line_no, ptr, len);
434 }
435 } else
436 ptr += attr_length;
437 }
438 } else
439 if(attr_name == SYMBOL(Exceptions)) {
440 int j;
442 READ_U2(method->throw_table_size, ptr, len);
443 method->throw_table = (u2 *)sysMalloc(method->throw_table_size*sizeof(u2));
444 for(j = 0; j < method->throw_table_size; j++) {
445 READ_U2(method->throw_table[j], ptr, len);
446 }
447 } else
448 if(attr_name == SYMBOL(Signature)) {
449 u2 signature_idx;
450 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
451 method->signature = CP_UTF8(constant_pool, signature_idx);
452 } else
453 if(attr_name == SYMBOL(RuntimeVisibleAnnotations)) {
454 annos.annotations = sysMalloc(sizeof(AnnotationData));
455 annos.annotations->len = attr_length;
456 annos.annotations->data = sysMalloc(attr_length);
457 memcpy(annos.annotations->data, ptr, attr_length);
458 ptr += attr_length;
459 } else
460 if(attr_name == SYMBOL(RuntimeVisibleParameterAnnotations)) {
461 annos.parameters = sysMalloc(sizeof(AnnotationData));
462 annos.parameters->len = attr_length;
463 annos.parameters->data = sysMalloc(attr_length);
464 memcpy(annos.parameters->data, ptr, attr_length);
465 ptr += attr_length;
466 } else
467 if(attr_name == SYMBOL(AnnotationDefault)) {
468 annos.dft_val = sysMalloc(sizeof(AnnotationData));
469 annos.dft_val->len = attr_length;
470 annos.dft_val->data = sysMalloc(attr_length);
471 memcpy(annos.dft_val->data, ptr, attr_length);
472 ptr += attr_length;
473 } else
474 ptr += attr_length;
475 }
476 if(annos.annotations != NULL || annos.parameters != NULL
477 || annos.dft_val != NULL) {
478 method->annotations = sysMalloc(sizeof(MethodAnnotationData));
479 memcpy(method->annotations, &annos, sizeof(MethodAnnotationData));
480 }
481 }
483 READ_U2(attr_count, ptr, len);
484 for(; attr_count != 0; attr_count--) {
485 u2 attr_name_idx;
486 char *attr_name;
487 u4 attr_length;
489 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
490 attr_name = CP_UTF8(constant_pool, attr_name_idx);
491 READ_U4(attr_length, ptr, len);
493 if(attr_name == SYMBOL(SourceFile)) {
494 u2 file_name_idx;
495 READ_TYPE_INDEX(file_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
496 classblock->source_file_name = CP_UTF8(constant_pool, file_name_idx);
497 } else
498 if(attr_name == SYMBOL(InnerClasses)) {
499 int j, size;
500 READ_U2(size, ptr, len);
501 {
502 u2 inner_classes[size];
503 for(j = 0; j < size; j++) {
504 int inner, outer;
505 READ_TYPE_INDEX(inner, constant_pool, CONSTANT_Class, ptr, len);
506 READ_TYPE_INDEX(outer, constant_pool, CONSTANT_Class, ptr, len);
508 if(inner == this_idx) {
509 int inner_name_idx;
511 /* A member class doesn't have an EnclosingMethod attribute, so set
512 the enclosing class to be the same as the declaring class */
513 if(outer)
514 classblock->declaring_class = classblock->enclosing_class = outer;
516 READ_TYPE_INDEX(inner_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
517 if(inner_name_idx == 0)
518 classblock->flags |= ANONYMOUS;
520 READ_U2(classblock->inner_access_flags, ptr, len);
521 } else {
522 ptr += 4;
523 if(outer == this_idx)
524 inner_classes[classblock->inner_class_count++] = inner;
525 }
526 }
528 if(classblock->inner_class_count) {
529 classblock->inner_classes = sysMalloc(classblock->inner_class_count*sizeof(u2));
530 memcpy(classblock->inner_classes, &inner_classes[0],
531 classblock->inner_class_count*sizeof(u2));
532 }
533 }
534 } else
535 if(attr_name == SYMBOL(EnclosingMethod)) {
536 READ_TYPE_INDEX(classblock->enclosing_class, constant_pool, CONSTANT_Class, ptr, len);
537 READ_TYPE_INDEX(classblock->enclosing_method, constant_pool, CONSTANT_NameAndType, ptr, len);
538 } else
539 if(attr_name == SYMBOL(Signature)) {
540 u2 signature_idx;
541 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
542 classblock->signature = CP_UTF8(constant_pool, signature_idx);
543 } else
544 if(attr_name == SYMBOL(Synthetic))
545 classblock->access_flags |= ACC_SYNTHETIC;
546 else
547 if(attr_name == SYMBOL(RuntimeVisibleAnnotations)) {
548 classblock->annotations = sysMalloc(sizeof(AnnotationData));
549 classblock->annotations->len = attr_length;
550 classblock->annotations->data = sysMalloc(attr_length);
551 memcpy(classblock->annotations->data, ptr, attr_length);
552 ptr += attr_length;
553 } else
554 ptr += attr_length;
555 }
557 classblock->super = super_idx ? resolveClass(class, super_idx, FALSE) : NULL;
559 if(exceptionOccurred())
560 {
561 TRACE("<CLASS: Exception %s occurred in defining class %s>\n",
562 CLASS_CB(getExecEnv()->exception->class)->name, classname);
563 return NULL;
564 }
566 classblock->state = CLASS_LOADED;
568 if((found = addClassToHash(class, class_loader)) != class) {
569 classblock->flags = CLASS_CLASH;
570 if(class_loader != NULL) {
571 signalException(java_lang_LinkageError, "duplicate class definition");
572 return NULL;
573 }
574 return found;
575 }
577 return class;
578 }
580 Class *createArrayClass(char *classname, Object *class_loader) {
581 ClassBlock *elem_cb, *classblock;
582 Class *class, *found = NULL;
583 int len = strlen(classname);
585 if((class = allocClass()) == NULL)
586 return NULL;
588 classblock = CLASS_CB(class);
590 classblock->name = copyUtf8(classname);
591 classblock->super_name = SYMBOL(java_lang_Object);
592 classblock->super = findSystemClass0(SYMBOL(java_lang_Object));
593 classblock->method_table = CLASS_CB(classblock->super)->method_table;
595 classblock->interfaces_count = 2;
596 classblock->interfaces = (Class**)sysMalloc(2*sizeof(Class*));
597 classblock->interfaces[0] = findSystemClass0(SYMBOL(java_lang_Cloneable));
598 classblock->interfaces[1] = findSystemClass0(SYMBOL(java_io_Serializable));
600 classblock->state = CLASS_ARRAY;
602 /* Find the array element class and the dimension --
603 this is used to speed up type checking (instanceof) */
605 if(classname[1] == '[') {
606 Class *comp_class = findArrayClassFromClassLoader(classname + 1, class_loader);
608 if(comp_class == NULL)
609 goto error;
611 classblock->element_class = CLASS_CB(comp_class)->element_class;
612 classblock->dim = CLASS_CB(comp_class)->dim + 1;
613 } else {
614 if(classname[1] == 'L') {
615 char element_name[len-2];
617 strcpy(element_name, classname + 2);
618 element_name[len-3] = '\0';
619 classblock->element_class = findClassFromClassLoader(element_name, class_loader);
620 } else
621 classblock->element_class = findPrimitiveClass(classname[1]);
623 if(classblock->element_class == NULL)
624 goto error;
626 classblock->dim = 1;
627 }
629 elem_cb = CLASS_CB(classblock->element_class);
631 /* The array's classloader is the loader of the element class */
632 classblock->class_loader = elem_cb->class_loader;
634 /* The array's visibility (i.e. public, etc.) is that of the element */
635 classblock->access_flags = (elem_cb->access_flags & ~ACC_INTERFACE) |
636 ACC_FINAL | ACC_ABSTRACT;
638 prepareClass(class);
640 if((found = addClassToHash(class, classblock->class_loader)) == class) {
641 if(verbose)
642 jam_printf("[Created array class %s]\n", classname);
643 return class;
644 }
646 error:
647 classblock->flags = CLASS_CLASH;
648 return found;
649 }
651 Class *
652 createPrimClass(char *classname, int index) {
653 Class *class;
654 ClassBlock *classblock;
656 if((class = allocClass()) == NULL)
657 return NULL;
659 classblock = CLASS_CB(class);
660 classblock->name = classname;
661 classblock->state = CLASS_PRIM + index;
662 classblock->access_flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
664 prepareClass(class);
666 lockHashTable(loaded_classes);
667 if(prim_classes[index] == NULL)
668 prim_classes[index] = class;
669 unlockHashTable(loaded_classes);
671 if(verbose)
672 jam_printf("[Created primitive class %s]\n", classname);
674 return prim_classes[index];
675 }
677 #define MRNDA_CACHE_SZE 10
679 #define resizeMTable(method_table, method_table_size, miranda, count) \
680 { \
681 method_table = (MethodBlock**)sysRealloc(method_table, \
682 (method_table_size + count) * sizeof(MethodBlock*)); \
683 \
684 memcpy(&method_table[method_table_size], miranda, \
685 count * sizeof(MethodBlock*)); \
686 method_table_size += count; \
687 }
689 #define fillinMTable(method_table, methods, methods_count) \
690 { \
691 int i; \
692 for(i = 0; i < methods_count; i++, methods++) { \
693 if((methods->access_flags & (ACC_STATIC | ACC_PRIVATE)) || \
694 (methods->name[0] == '<')) \
695 continue; \
696 method_table[methods->method_table_index] = methods; \
697 } \
698 }
700 void linkClass(Class *class) {
701 static MethodBlock *obj_fnlzr_mthd = NULL;
703 ClassBlock *cb = CLASS_CB(class);
704 Class *super = (cb->access_flags & ACC_INTERFACE) ? NULL : cb->super;
706 RefsOffsetsEntry *spr_rfs_offsts_tbl = NULL;
707 ITableEntry *spr_imthd_tbl = NULL;
708 MethodBlock **method_table = NULL;
709 MethodBlock **spr_mthd_tbl = NULL;
710 MethodBlock *finalizer;
711 MethodBlock *mb;
712 FieldBlock *fb;
714 int spr_rfs_offsts_sze = 0;
715 int new_methods_count = 0;
716 int spr_imthd_tbl_sze = 0;
717 int itbl_offset_count = 0;
718 int spr_mthd_tbl_sze = 0;
719 int method_table_size;
720 int new_itable_count;
721 int spr_obj_sze = 0;
722 int refs_end_offset;
723 int itbl_idx, i, j;
724 int spr_flags = 0;
725 int field_offset;
727 if(cb->state >= CLASS_LINKED)
728 return;
730 objectLock((Object *)class);
732 if(cb->state >= CLASS_LINKED)
733 goto unlock;
735 if(verbose)
736 jam_printf("[Linking class %s]\n", cb->name);
738 if(super) {
739 ClassBlock *super_cb = CLASS_CB(super);
740 if(super_cb->state < CLASS_LINKED)
741 linkClass(super);
743 spr_flags = super_cb->flags;
744 spr_obj_sze = super_cb->object_size;
745 spr_mthd_tbl = super_cb->method_table;
746 spr_imthd_tbl = super_cb->imethod_table;
747 spr_mthd_tbl_sze = super_cb->method_table_size;
748 spr_imthd_tbl_sze = super_cb->imethod_table_size;
749 spr_rfs_offsts_sze = super_cb->refs_offsets_size;
750 spr_rfs_offsts_tbl = super_cb->refs_offsets_table;
751 }
753 /* prepare fields */
755 field_offset = spr_obj_sze;
757 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++) {
758 if(fb->access_flags & ACC_STATIC) {
759 /* init to default value */
760 if((*fb->type == 'J') || (*fb->type == 'D'))
761 *(long long *)&fb->static_value = 0;
762 else
763 fb->static_value = 0;
764 } else {
765 /* calc field offset */
766 if((*fb->type == 'L') || (*fb->type == '['))
767 fb->offset = field_offset++;
768 }
769 fb->class = class;
770 }
772 refs_end_offset = field_offset;
774 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++)
775 if(!(fb->access_flags & ACC_STATIC) &&
776 (*fb->type != 'L') && (*fb->type != '[')) {
777 /* calc field offset */
778 fb->offset = field_offset;
779 if((*fb->type == 'J') || (*fb->type == 'D'))
780 field_offset += 2;
781 else
782 field_offset += 1;
783 }
785 cb->object_size = field_offset;
787 /* prepare methods */
789 for(mb = cb->methods, i = 0; i < cb->methods_count; i++,mb++) {
791 /* calculate argument count from signature */
793 int count = 0;
794 char *sig = mb->type;
795 SCAN_SIG(sig, count+=2, count++);
797 if(mb->access_flags & ACC_STATIC)
798 mb->args_count = count;
799 else
800 mb->args_count = count + 1;
802 mb->class = class;
804 /* Set abstract method to stub */
805 if(mb->access_flags & ACC_ABSTRACT) {
806 mb->code_size = sizeof(abstract_method);
807 mb->code = abstract_method;
808 }
810 if(mb->access_flags & ACC_NATIVE) {
812 /* set up native invoker to wrapper to resolve function
813 on first invocation */
815 mb->native_invoker = (void *) resolveNativeWrapper;
817 /* native methods have no code attribute so these aren't filled
818 in at load time - as these values are used when creating frame
819 set to appropriate values */
821 mb->max_locals = mb->args_count;
822 mb->max_stack = 0;
823 }
825 #ifdef DIRECT
826 else {
827 /* Set the bottom bit of the pointer to indicate the
828 method is unprepared */
829 mb->code = ((char*)mb->code) + 1;
830 }
831 #endif
833 /* Static, private or init methods aren't dynamically invoked, so
834 don't stick them in the table to save space */
836 if((mb->access_flags & (ACC_STATIC | ACC_PRIVATE)) || (mb->name[0] == '<'))
837 continue;
839 /* if it's overriding an inherited method, replace in method table */
841 for(j = 0; j < spr_mthd_tbl_sze; j++)
842 if(mb->name == spr_mthd_tbl[j]->name &&
843 mb->type == spr_mthd_tbl[j]->type &&
844 checkMethodAccess(spr_mthd_tbl[j], class)) {
845 mb->method_table_index = spr_mthd_tbl[j]->method_table_index;
846 break;
847 }
849 if(j == spr_mthd_tbl_sze)
850 mb->method_table_index = spr_mthd_tbl_sze + new_methods_count++;
851 }
853 /* construct method table */
855 method_table_size = spr_mthd_tbl_sze + new_methods_count;
857 if(!(cb->access_flags & ACC_INTERFACE)) {
858 method_table = (MethodBlock**)sysMalloc(method_table_size * sizeof(MethodBlock*));
860 /* Copy parents method table to the start */
861 memcpy(method_table, spr_mthd_tbl, spr_mthd_tbl_sze * sizeof(MethodBlock*));
863 /* fill in the additional methods -- we use a
864 temporary because fillinMtable alters mb */
865 mb = cb->methods;
866 fillinMTable(method_table, mb, cb->methods_count);
867 }
869 /* setup interface method table */
871 /* number of interfaces implemented by this class is those implemented by
872 * parent, plus number of interfaces directly implemented by this class,
873 * and the total number of their superinterfaces */
875 new_itable_count = cb->interfaces_count;
876 for(i = 0; i < cb->interfaces_count; i++)
877 new_itable_count += CLASS_CB(cb->interfaces[i])->imethod_table_size;
879 cb->imethod_table_size = spr_imthd_tbl_sze + new_itable_count;
880 cb->imethod_table = (ITableEntry*)sysMalloc(cb->imethod_table_size * sizeof(ITableEntry));
882 /* copy parent's interface table - the offsets into the method table won't change */
884 memcpy(cb->imethod_table, spr_imthd_tbl, spr_imthd_tbl_sze * sizeof(ITableEntry));
886 /* now run through the extra interfaces implemented by this class,
887 * fill in the interface part, and calculate the number of offsets
888 * needed (i.e. the number of methods defined in the interfaces) */
890 itbl_idx = spr_imthd_tbl_sze;
891 for(i = 0; i < cb->interfaces_count; i++) {
892 Class *intf = cb->interfaces[i];
893 ClassBlock *intf_cb = CLASS_CB(intf);
895 cb->imethod_table[itbl_idx++].interface = intf;
896 itbl_offset_count += intf_cb->method_table_size;
898 for(j = 0; j < intf_cb->imethod_table_size; j++) {
899 Class *spr_intf = intf_cb->imethod_table[j].interface;
901 cb->imethod_table[itbl_idx++].interface = spr_intf;
902 itbl_offset_count += CLASS_CB(spr_intf)->method_table_size;
903 }
904 }
906 /* if we're an interface all finished - offsets aren't used */
908 if(!(cb->access_flags & ACC_INTERFACE)) {
909 int *offsets_pntr = (int*)sysMalloc(itbl_offset_count * sizeof(int));
910 int old_mtbl_size = method_table_size;
911 MethodBlock *miranda[MRNDA_CACHE_SZE];
912 int miranda_count = 0;
913 int mtbl_idx;
915 /* run through table again, this time filling in the offsets array -
916 * for each new interface, run through it's methods and locate
917 * each method in this classes method table */
919 for(i = spr_imthd_tbl_sze; i < cb->imethod_table_size; i++) {
920 ClassBlock *intf_cb = CLASS_CB(cb->imethod_table[i].interface);
921 cb->imethod_table[i].offsets = offsets_pntr;
923 for(j = 0; j < intf_cb->methods_count; j++) {
924 MethodBlock *intf_mb = &intf_cb->methods[j];
926 if((intf_mb->access_flags & (ACC_STATIC | ACC_PRIVATE)) ||
927 (intf_mb->name[0] == '<'))
928 continue;
930 /* We scan backwards so that we find methods defined in sub-classes
931 before super-classes. This ensures we find non-overridden
932 methods before the inherited non-accessible method */
933 for(mtbl_idx = method_table_size - 1; mtbl_idx >= 0; mtbl_idx--)
934 if(intf_mb->name == method_table[mtbl_idx]->name &&
935 intf_mb->type == method_table[mtbl_idx]->type) {
936 *offsets_pntr++ = mtbl_idx;
937 break;
938 }
940 if(mtbl_idx < 0) {
942 /* didn't find it - add a dummy abstract method (a so-called
943 miranda method). If it's invoked we'll get an abstract
944 method error */
946 int k;
947 for(k = 0; k < miranda_count; k++)
948 if(intf_mb->name == miranda[k]->name &&
949 intf_mb->type == miranda[k]->type)
950 break;
952 *offsets_pntr++ = method_table_size + k;
954 if(k == miranda_count) {
955 if(miranda_count == MRNDA_CACHE_SZE) {
956 resizeMTable(method_table, method_table_size, miranda, MRNDA_CACHE_SZE);
957 miranda_count = 0;
958 }
959 miranda[miranda_count++] = intf_mb;
960 }
961 }
962 }
963 }
965 if(miranda_count > 0)
966 resizeMTable(method_table, method_table_size, miranda, miranda_count);
968 if(old_mtbl_size != method_table_size) {
969 /* We've created some abstract methods */
970 int num_mirandas = method_table_size - old_mtbl_size;
972 mb = (MethodBlock *) sysRealloc(cb->methods,
973 (cb->methods_count + num_mirandas) * sizeof(MethodBlock));
975 /* If the realloc of the method list gave us a new pointer, the pointers
976 to them in the method table are now wrong. */
977 if(mb != cb->methods) {
978 /* mb will be left pointing to the end of the methods */
979 cb->methods = mb;
980 fillinMTable(method_table, mb, cb->methods_count);
981 } else
982 mb += cb->methods_count;
984 cb->methods_count += num_mirandas;
986 /* Now we've expanded the method list, replace pointers to
987 the interface methods. */
989 for(i = old_mtbl_size; i < method_table_size; i++,mb++) {
990 memcpy(mb, method_table[i], sizeof(MethodBlock));
991 mb->access_flags |= ACC_MIRANDA;
992 mb->method_table_index = i;
993 mb->class = class;
994 method_table[i] = mb;
995 }
996 }
997 }
999 cb->method_table = method_table;
1000 cb->method_table_size = method_table_size;
1002 /* Handle finalizer */
1004 /* If this is Object find the finalize method. All subclasses will
1005 have it in the same place in the method table. Note, Object
1006 should always have a valid finalizer -- but check just in case */
1008 if(cb->super == NULL) {
1009 finalizer = findMethod(class, SYMBOL(finalize), SYMBOL(___V));
1010 if(finalizer && !(finalizer->access_flags & (ACC_STATIC | ACC_PRIVATE))) {
1011 finalize_mtbl_idx = finalizer->method_table_index;
1012 obj_fnlzr_mthd = finalizer;
1016 cb->flags |= spr_flags;
1018 /* Store the finalizer only if it's overridden Object's. We don't
1019 want to finalize every object, and Object's imp is empty */
1021 if(super && obj_fnlzr_mthd && (finalizer =
1022 method_table[obj_fnlzr_mthd->method_table_index]) != obj_fnlzr_mthd)
1023 cb->flags |= FINALIZED;
1025 /* Handle reference classes */
1027 if(ref_referent_offset == -1 && cb->name == SYMBOL(java_lang_ref_Reference)) {
1028 FieldBlock *ref_fb = findField(class, SYMBOL(referent), SYMBOL(sig_java_lang_Object));
1029 FieldBlock *queue_fb = findField(class, SYMBOL(queue), SYMBOL(sig_java_lang_ref_ReferenceQueue));
1030 MethodBlock *enqueue_mb = findMethod(class, SYMBOL(enqueue), SYMBOL(___Z));
1032 if(ref_fb == NULL || queue_fb == NULL || enqueue_mb == NULL) {
1033 jam_fprintf(stderr, "Expected fields/methods missing in java.lang.ref.Reference\n");
1034 exitVM(1);
1037 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++)
1038 if(fb->offset > ref_fb->offset)
1039 fb->offset--;
1041 ref_referent_offset = ref_fb->offset = field_offset - 1;
1042 enqueue_mtbl_idx = enqueue_mb->method_table_index;
1043 ref_queue_offset = queue_fb->offset;
1044 refs_end_offset--;
1046 cb->flags |= REFERENCE;
1049 if(spr_flags & REFERENCE) {
1050 if(cb->name == SYMBOL(java_lang_ref_SoftReference))
1051 cb->flags |= SOFT_REFERENCE;
1052 else
1053 if(cb->name == SYMBOL(java_lang_ref_WeakReference))
1054 cb->flags |= WEAK_REFERENCE;
1055 else
1056 if(cb->name == SYMBOL(java_lang_ref_PhantomReference))
1057 cb->flags |= PHANTOM_REFERENCE;
1060 /* Handle class loader classes */
1062 if(ldr_vmdata_offset == -1 && cb->name == SYMBOL(java_lang_ClassLoader)) {
1063 FieldBlock *ldr_fb = findField(class, SYMBOL(vmdata), SYMBOL(sig_java_lang_Object));
1065 if(ldr_fb == NULL) {
1066 jam_fprintf(stderr, "Expected vmdata field missing in java.lang.ClassLoader\n");
1067 exitVM(1);
1070 ldr_vmdata_offset = ldr_fb->offset;
1071 cb->flags |= CLASS_LOADER;
1074 /* Construct the reference offsets list. This is used to speed up
1075 scanning of an objects references during the mark phase of GC. */
1077 if(refs_end_offset > spr_obj_sze) {
1078 int new_start;
1080 if(spr_rfs_offsts_sze > 0 && spr_rfs_offsts_tbl[spr_rfs_offsts_sze-1].end == spr_obj_sze) {
1081 cb->refs_offsets_size = spr_rfs_offsts_sze;
1082 new_start = spr_rfs_offsts_tbl[spr_rfs_offsts_sze-1].start;
1083 } else {
1084 cb->refs_offsets_size = spr_rfs_offsts_sze + 1;
1085 new_start = spr_obj_sze;
1088 cb->refs_offsets_table = sysMalloc(cb->refs_offsets_size * sizeof(RefsOffsetsEntry));
1090 memcpy(cb->refs_offsets_table, spr_rfs_offsts_tbl,
1091 spr_rfs_offsts_sze * sizeof(RefsOffsetsEntry));
1093 cb->refs_offsets_table[cb->refs_offsets_size-1].start = new_start;
1094 cb->refs_offsets_table[cb->refs_offsets_size-1].end = refs_end_offset;
1095 } else {
1096 cb->refs_offsets_size = spr_rfs_offsts_sze;
1097 cb->refs_offsets_table = spr_rfs_offsts_tbl;
1100 cb->state = CLASS_LINKED;
1102 unlock:
1103 objectUnlock((Object *)class);
1106 Class *initClass(Class *class) {
1107 ClassBlock *cb = CLASS_CB(class);
1108 ConstantPool *cp = &cb->constant_pool;
1109 FieldBlock *fb = cb->fields;
1110 MethodBlock *mb;
1111 Object *excep;
1112 int state, i;
1114 if(cb->state >= CLASS_INITED)
1115 return class;
1117 linkClass(class);
1118 objectLock((Object *)class);
1120 while(cb->state == CLASS_INITING)
1121 if(cb->initing_tid == threadSelf()->id) {
1122 objectUnlock((Object *)class);
1123 return class;
1124 } else {
1125 /* FALSE means this wait is non-interruptible.
1126 An interrupt will appear as if the initialiser
1127 failed (below), and clearing will lose the
1128 interrupt status */
1129 objectWait0((Object *)class, 0, 0, FALSE);
1132 if(cb->state >= CLASS_INITED) {
1133 objectUnlock((Object *)class);
1134 return class;
1137 if(cb->state == CLASS_BAD) {
1138 objectUnlock((Object *)class);
1139 signalException(java_lang_NoClassDefFoundError, cb->name);
1140 return NULL;
1143 cb->state = CLASS_INITING;
1144 cb->initing_tid = threadSelf()->id;
1146 objectUnlock((Object *)class);
1148 if(!(cb->access_flags & ACC_INTERFACE) && cb->super
1149 && (CLASS_CB(cb->super)->state != CLASS_INITED)) {
1150 initClass(cb->super);
1151 if(exceptionOccurred()) {
1152 state = CLASS_BAD;
1153 goto set_state_and_notify;
1157 /* Never used to bother with this as only static finals use it and
1158 the constant value's copied at compile time. However, separate
1159 compilation can result in a getstatic to a (now) constant field,
1160 and the VM didn't initialise it... */
1162 for(i = 0; i < cb->fields_count; i++,fb++)
1163 if((fb->access_flags & ACC_STATIC) && fb->constant) {
1164 if((*fb->type == 'J') || (*fb->type == 'D'))
1165 *(u8*)&fb->static_value = *(u8*)&(CP_INFO(cp, fb->constant));
1166 else
1167 fb->static_value = resolveSingleConstant(class, fb->constant);
1170 if((mb = findMethod(class, SYMBOL(class_init), SYMBOL(___V))) != NULL)
1171 executeStaticMethod(class, mb);
1173 if((excep = exceptionOccurred())) {
1174 Class *error, *eiie;
1176 clearException();
1178 /* Don't wrap exceptions of type java.lang.Error... */
1179 if((error = findSystemClass0(SYMBOL(java_lang_Error)))
1180 && !isInstanceOf(error, excep->class)
1181 && (eiie = findSystemClass(SYMBOL(java_lang_ExceptionInInitializerError)))
1182 && (mb = findMethod(eiie, SYMBOL(object_init), SYMBOL(_java_lang_Throwable__V)))) {
1184 Object *ob = allocObject(eiie);
1186 if(ob != NULL) {
1187 executeMethod(ob, mb, excep);
1188 setException(ob);
1190 } else
1191 setException(excep);
1193 state = CLASS_BAD;
1194 } else
1195 state = CLASS_INITED;
1197 set_state_and_notify:
1198 objectLock((Object *)class);
1199 cb->state = state;
1201 objectNotifyAll((Object *)class);
1202 objectUnlock((Object *)class);
1204 return state == CLASS_BAD ? NULL : class;
1207 char *findFileEntry(char *path, int *file_len) {
1208 int read_len;
1209 char *data;
1210 FILE *fd;
1212 if((fd = fopen(path, "r")) == NULL)
1213 return NULL;
1215 fseek(fd, 0L, SEEK_END);
1216 *file_len = ftell(fd);
1217 fseek(fd, 0L, SEEK_SET);
1219 data = (char *)sysMalloc(*file_len);
1220 read_len = fread(data, sizeof(char), *file_len, fd);
1221 fclose(fd);
1223 if(read_len == *file_len)
1224 return data;
1226 sysFree(data);
1227 return NULL;
1230 Class *loadSystemClass(char *classname) {
1231 int file_len, fname_len = strlen(classname) + 8;
1232 char buff[max_cp_element_len + fname_len];
1233 char filename[fname_len];
1234 Class *class = NULL;
1235 char *data = NULL;
1236 int i;
1238 filename[0] = '/';
1239 strcat(strcpy(&filename[1], classname), ".class");
1241 for(i = 0; i < bcp_entries && data == NULL; i++)
1242 if(bootclasspath[i].zip)
1243 data = findArchiveEntry(filename+1, bootclasspath[i].zip, &file_len);
1244 else
1245 data = findFileEntry(strcat(strcpy(buff, bootclasspath[i].path), filename), &file_len);
1247 if(data == NULL) {
1248 signalException(java_lang_NoClassDefFoundError, classname);
1249 return NULL;
1252 class = defineClass(classname, data, 0, file_len, NULL);
1253 sysFree(data);
1255 if(verbose && class)
1256 jam_printf("[Loaded %s from %s]\n", classname, bootclasspath[i-1].path);
1258 return class;
1261 void addInitiatingLoaderToClass(Object *class_loader, Class *class) {
1262 ClassBlock *cb = CLASS_CB(class);
1264 /* The defining class loader is automatically an initiating
1265 loader so don't add again */
1266 if(cb->class_loader != class_loader)
1267 addClassToHash(class, class_loader);
1270 Class *findHashedClass(char *classname, Object *class_loader) {
1271 HashTable *table;
1272 Class *class;
1273 char *name;
1275 /* If the class name is not in the utf8 table it can't
1276 have been loaded */
1277 if((name = findUtf8(classname)) == NULL)
1278 return NULL;
1280 if(class_loader == NULL)
1281 table = &loaded_classes;
1282 else {
1283 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1285 if(vmdata == NULL)
1286 return NULL;
1288 table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1291 #undef HASH
1292 #undef COMPARE
1293 #define HASH(ptr) utf8Hash(ptr)
1294 #define COMPARE(ptr1, ptr2, hash1, hash2) (hash1 == hash2) && \
1295 (ptr1 == CLASS_CB((Class *)ptr2)->name)
1297 /* Do not add if absent, no scavenge, locked */
1298 findHashEntry((*table), name, class, FALSE, FALSE, TRUE);
1300 return class;
1303 Class *findSystemClass0(char *classname) {
1304 Class *class = findHashedClass(classname, NULL);
1306 if(class == NULL)
1307 class = loadSystemClass(classname);
1309 if(!exceptionOccurred())
1310 linkClass(class);
1312 return class;
1315 Class *findSystemClass(char *classname) {
1316 Class *class = findSystemClass0(classname);
1318 if(!exceptionOccurred())
1319 initClass(class);
1321 return class;
1324 Class *findArrayClassFromClassLoader(char *classname, Object *class_loader) {
1325 Class *class = findHashedClass(classname, class_loader);
1327 if(class == NULL) {
1328 if((class = createArrayClass(classname, class_loader)) != NULL)
1329 addInitiatingLoaderToClass(class_loader, class);
1331 return class;
1334 Class *findPrimitiveClass(char prim_type) {
1335 int index;
1336 Class *prim;
1337 char *classname;
1339 switch(prim_type) {
1340 case 'Z':
1341 classname = SYMBOL(boolean); index = 1;
1342 break;
1343 case 'B':
1344 classname = SYMBOL(byte); index = 2;
1345 break;
1346 case 'C':
1347 classname = SYMBOL(char); index = 3;
1348 break;
1349 case 'S':
1350 classname = SYMBOL(short); index = 4;
1351 break;
1352 case 'I':
1353 classname = SYMBOL(int); index = 5;
1354 break;
1355 case 'F':
1356 classname = SYMBOL(float); index = 6;
1357 break;
1358 case 'J':
1359 classname = SYMBOL(long); index = 7;
1360 break;
1361 case 'D':
1362 classname = SYMBOL(double); index = 8;
1363 break;
1364 case 'V':
1365 classname = SYMBOL(void); index = 0;
1366 break;
1367 default:
1368 signalException(java_lang_NoClassDefFoundError, NULL);
1369 return NULL;
1370 break;
1373 prim = prim_classes[index];
1374 return prim ? prim : createPrimClass(classname, index);
1377 Class *findNonArrayClassFromClassLoader(char *classname, Object *loader) {
1378 Class *class = findHashedClass(classname, loader);
1380 if(class == NULL) {
1381 char *dot_name = slash2dots(classname);
1382 Object *string = createString(dot_name);
1383 Object *excep;
1385 sysFree(dot_name);
1386 if(string == NULL)
1387 return NULL;
1389 if(loadClass_mtbl_idx == -1) {
1390 MethodBlock *mb = lookupMethod(loader->class, SYMBOL(loadClass),
1391 SYMBOL(_java_lang_String__java_lang_Class));
1392 if(mb == NULL)
1393 return NULL;
1395 loadClass_mtbl_idx = mb->method_table_index;
1398 /* The public loadClass is not synchronized.
1399 Lock the class-loader to be thread-safe */
1400 objectLock(loader);
1401 class = *(Class**)executeMethod(loader,
1402 CLASS_CB(loader->class)->method_table[loadClass_mtbl_idx], string);
1403 objectUnlock(loader);
1405 if((excep = exceptionOccurred()) || class == NULL) {
1406 clearException();
1407 signalChainedException(java_lang_NoClassDefFoundError, classname, excep);
1408 return NULL;
1411 addInitiatingLoaderToClass(loader, class);
1413 if(verbose && (CLASS_CB(class)->class_loader == loader))
1414 jam_printf("[Loaded %s]\n", classname);
1416 return class;
1419 Class *findClassFromClassLoader(char *classname, Object *loader) {
1420 if(*classname == '[')
1421 return findArrayClassFromClassLoader(classname, loader);
1423 if(loader != NULL)
1424 return findNonArrayClassFromClassLoader(classname, loader);
1426 return findSystemClass0(classname);
1429 Object *getSystemClassLoader() {
1430 Class *class_loader = findSystemClass(SYMBOL(java_lang_ClassLoader));
1432 if(!exceptionOccurred()) {
1433 MethodBlock *mb;
1435 if((mb = findMethod(class_loader, SYMBOL(getSystemClassLoader),
1436 SYMBOL(___java_lang_ClassLoader))) != NULL) {
1437 Object *system_loader = *(Object**)executeStaticMethod(class_loader, mb);
1439 if(!exceptionOccurred())
1440 return system_loader;
1443 return NULL;
1446 /* gc support for marking classes */
1448 #define ITERATE(ptr) markRoot(ptr)
1450 void markBootClasses() {
1451 int i;
1453 hashIterate(loaded_classes);
1455 for(i = 0; i < MAX_PRIM_CLASSES; i++)
1456 if(prim_classes[i] != NULL)
1457 markRoot((Object*)prim_classes[i]);
1460 #undef ITERATE
1461 #define ITERATE(ptr) threadReference((Object**)ptr)
1463 void threadBootClasses() {
1464 int i;
1466 hashIterateP(loaded_classes);
1468 for(i = 0; i < MAX_PRIM_CLASSES; i++)
1469 if(prim_classes[i] != NULL)
1470 threadReference((Object**)&prim_classes[i]);
1473 #undef ITERATE
1474 #define ITERATE(ptr) \
1475 if(CLASS_CB((Class *)ptr)->class_loader == class_loader) \
1476 markObject(ptr, mark, mark_soft_refs)
1478 void markLoaderClasses(Object *class_loader, int mark, int mark_soft_refs) {
1479 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1481 if(vmdata != NULL) {
1482 HashTable *table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1483 hashIterate((*table));
1487 #undef ITERATE
1488 #define ITERATE(ptr) threadReference((Object**)ptr)
1490 void threadLoaderClasses(Object *class_loader) {
1491 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1493 if(vmdata != NULL) {
1494 HashTable *table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1495 hashIterateP((*table));
1499 void freeClassData(Class *class) {
1500 ClassBlock *cb = CLASS_CB(class);
1501 int i;
1503 if(IS_ARRAY(cb)) {
1504 gcPendingFree(cb->interfaces);
1505 return;
1508 gcPendingFree((void*)cb->constant_pool.type);
1509 gcPendingFree(cb->constant_pool.info);
1510 gcPendingFree(cb->interfaces);
1512 for(i = 0; i < cb->fields_count; i++) {
1513 FieldBlock *fb = &cb->fields[i];
1515 if(fb->annotations != NULL) {
1516 gcPendingFree(fb->annotations->data);
1517 gcPendingFree(fb->annotations);
1521 gcPendingFree(cb->fields);
1523 for(i = 0; i < cb->methods_count; i++) {
1524 MethodBlock *mb = &cb->methods[i];
1526 #ifdef DIRECT
1527 if(!((uintptr_t)mb->code & 0x3)) {
1528 #ifdef INLINING
1529 if(cb->state >= CLASS_LINKED)
1530 freeMethodInlinedInfo(mb);
1531 #endif
1532 gcPendingFree(mb->code);
1533 } else
1534 if(!(mb->access_flags & ACC_ABSTRACT))
1535 gcPendingFree((void*)((uintptr_t)mb->code & ~3));
1536 #else
1537 if(!(mb->access_flags & ACC_ABSTRACT))
1538 gcPendingFree(mb->code);
1539 #endif
1541 gcPendingFree(mb->exception_table);
1542 gcPendingFree(mb->line_no_table);
1543 gcPendingFree(mb->throw_table);
1545 if(mb->annotations != NULL) {
1546 if(mb->annotations->annotations != NULL) {
1547 gcPendingFree(mb->annotations->annotations->data);
1548 gcPendingFree(mb->annotations->annotations);
1550 if(mb->annotations->parameters != NULL) {
1551 gcPendingFree(mb->annotations->parameters->data);
1552 gcPendingFree(mb->annotations->parameters);
1554 if(mb->annotations->dft_val != NULL) {
1555 gcPendingFree(mb->annotations->dft_val->data);
1556 gcPendingFree(mb->annotations->dft_val);
1558 gcPendingFree(mb->annotations);
1562 gcPendingFree(cb->methods);
1563 gcPendingFree(cb->inner_classes);
1565 if(cb->annotations != NULL) {
1566 gcPendingFree(cb->annotations->data);
1567 gcPendingFree(cb->annotations);
1570 if(cb->state >= CLASS_LINKED) {
1571 ClassBlock *super_cb = CLASS_CB(cb->super);
1573 /* interfaces do not have a method table, or
1574 imethod table offsets */
1575 if(!IS_INTERFACE(cb)) {
1576 int spr_imthd_sze = super_cb->imethod_table_size;
1578 gcPendingFree(cb->method_table);
1579 if(cb->imethod_table_size > spr_imthd_sze)
1580 gcPendingFree(cb->imethod_table[spr_imthd_sze].offsets);
1583 gcPendingFree(cb->imethod_table);
1585 if(cb->refs_offsets_table != super_cb->refs_offsets_table)
1586 gcPendingFree(cb->refs_offsets_table);
1590 void freeClassLoaderData(Object *class_loader) {
1591 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1593 if(vmdata != NULL) {
1594 HashTable *table = (HashTable*)INST_DATA(vmdata)[ldr_data_tbl_offset];
1595 gcFreeHashTable((*table));
1596 gcPendingFree(table);
1600 /* Add a library unloader object to the class loader for the
1601 library contained within entry. The library has an unload
1602 function, which will be called from the unloader finalizer
1603 when the class loader is garbage collected */
1604 void newLibraryUnloader(Object *class_loader, void *entry) {
1605 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1607 if(vmdata != NULL)
1608 executeMethod(vmdata, ldr_new_unloader, (long long)(uintptr_t)entry);
1611 int parseBootClassPath(char *cp_var) {
1612 char *cp, *pntr, *start;
1613 int i, j, len, max = 0;
1614 struct stat info;
1616 cp = (char*)sysMalloc(strlen(cp_var)+1);
1617 strcpy(cp, cp_var);
1619 for(i = 0, start = pntr = cp; *pntr; pntr++) {
1620 if(*pntr == ':') {
1621 if(start != pntr) {
1622 *pntr = '\0';
1623 i++;
1625 start = pntr+1;
1628 if(start != pntr)
1629 i++;
1631 bootclasspath = (BCPEntry *)sysMalloc(sizeof(BCPEntry)*i);
1633 for(j = 0, pntr = cp; i > 0; i--) {
1634 while(*pntr == ':')
1635 pntr++;
1637 start = pntr;
1638 pntr += (len = strlen(pntr))+1;
1640 if(stat(start, &info) == 0) {
1641 if(S_ISDIR(info.st_mode)) {
1642 bootclasspath[j].zip = NULL;
1643 if(len > max)
1644 max = len;
1645 } else
1646 if((bootclasspath[j].zip = processArchive(start)) == NULL)
1647 continue;
1648 bootclasspath[j++].path = start;
1652 max_cp_element_len = max;
1654 return bcp_entries = j;
1657 void setClassPath(char *cmdlne_cp) {
1658 char *env;
1659 classpath = cmdlne_cp ? cmdlne_cp :
1660 ((env = getenv("CLASSPATH")) ? env : ".");
1663 char *getClassPath() {
1664 return classpath;
1667 int filter(struct dirent *entry) {
1668 int len = strlen(entry->d_name);
1669 char *ext = &entry->d_name[len-4];
1671 return len >= 4 && (strcasecmp(ext, ".zip") == 0 ||
1672 strcasecmp(ext, ".jar") == 0);
1675 void scanDirForJars(char *dir) {
1676 int bootpathlen = strlen(bootpath) + 1;
1677 int dirlen = strlen(dir);
1678 struct dirent **namelist;
1679 int n;
1681 n = scandir(dir, &namelist, &filter, &alphasort);
1683 if(n >= 0) {
1684 while(--n >= 0) {
1685 char *buff;
1686 bootpathlen += strlen(namelist[n]->d_name) + dirlen + 2;
1687 buff = sysMalloc(bootpathlen);
1689 strcat(strcat(strcat(strcat(strcpy(buff, dir), "/"),
1690 namelist[n]->d_name), ":"), bootpath);
1692 sysFree(bootpath);
1693 bootpath = buff;
1694 free(namelist[n]);
1696 free(namelist);
1700 void scanDirsForJars(char *directories) {
1701 int dirslen = strlen(directories);
1702 char *pntr, *end, *dirs = sysMalloc(dirslen + 1);
1703 strcpy(dirs, directories);
1705 for(end = pntr = &dirs[dirslen]; pntr != dirs; pntr--) {
1706 if(*pntr == ':') {
1707 char *start = pntr + 1;
1708 if(start != end)
1709 scanDirForJars(start);
1711 *(end = pntr) = '\0';
1715 if(end != dirs)
1716 scanDirForJars(dirs);
1718 sysFree(dirs);
1721 char *setBootClassPath(char *cmdlne_bcp, char bootpathopt) {
1722 char *endorsed_dirs;
1724 if(cmdlne_bcp)
1725 switch(bootpathopt) {
1726 case 'a':
1727 case 'p':
1728 bootpath = sysMalloc(strlen(DFLT_BCP) + strlen(cmdlne_bcp) + 2);
1729 if(bootpathopt == 'a')
1730 strcat(strcat(strcpy(bootpath, DFLT_BCP), ":"), cmdlne_bcp);
1731 else
1732 strcat(strcat(strcpy(bootpath, cmdlne_bcp), ":"), DFLT_BCP);
1733 break;
1735 case 'c':
1736 bootpath = sysMalloc(strlen(JAMVM_CLASSES) + strlen(cmdlne_bcp) + 2);
1737 strcat(strcat(strcpy(bootpath, JAMVM_CLASSES), ":"), cmdlne_bcp);
1738 break;
1740 case 'v':
1741 bootpath = sysMalloc(strlen(CLASSPATH_CLASSES) + strlen(cmdlne_bcp) + 2);
1742 strcat(strcat(strcpy(bootpath, cmdlne_bcp), ":"), CLASSPATH_CLASSES);
1743 break;
1745 default:
1746 bootpath = sysMalloc(strlen(cmdlne_bcp) + 1);
1747 strcpy(bootpath, cmdlne_bcp);
1749 else {
1750 char *env = getenv("BOOTCLASSPATH");
1751 char *path = env ? env : DFLT_BCP;
1752 bootpath = sysMalloc(strlen(path) + 1);
1753 strcpy(bootpath, path);
1756 endorsed_dirs = getCommandLineProperty("java.endorsed.dirs");
1757 if(endorsed_dirs == NULL)
1758 endorsed_dirs = INSTALL_DIR"/share/jamvm/endorsed";
1760 scanDirsForJars(endorsed_dirs);
1762 return bootpath;
1765 char *getBootClassPath() {
1766 return bootpath;
1769 int bootClassPathSize() {
1770 return bcp_entries;
1773 Object *bootClassPathResource(char *filename, int index) {
1774 if(index < bcp_entries) {
1775 /* Alloc enough space for Jar file URL -- jar:file://<path>!/<filename> */
1776 char buff[strlen(filename) + strlen(bootclasspath[index].path) + 14];
1778 if(bootclasspath[index].zip) {
1779 while(*filename == '/')
1780 filename++;
1782 if(!findArchiveDirEntry(filename, bootclasspath[index].zip))
1783 return NULL;
1785 sprintf(buff, "jar:file://%s!/%s", bootclasspath[index].path, filename);
1786 } else {
1787 struct stat info;
1789 sprintf(buff, "file://%s/%s", bootclasspath[index].path, filename);
1790 if(stat(&buff[7], &info) != 0 || S_ISDIR(info.st_mode))
1791 return NULL;
1794 return createString(buff);
1797 return NULL;
1800 void initialiseClass(InitArgs *args) {
1801 char *bcp = setBootClassPath(args->bootpath, args->bootpathopt);
1802 FieldBlock *hashtable = NULL;
1804 if(!(bcp && parseBootClassPath(bcp))) {
1805 jam_fprintf(stderr, "bootclasspath is empty!\n");
1806 exitVM(1);
1809 verbose = args->verboseclass;
1810 setClassPath(args->classpath);
1812 /* Init hash table, and create lock */
1813 initHashTable(loaded_classes, INITSZE, TRUE);
1815 loader_data_class = findSystemClass0(SYMBOL(jamvm_java_lang_VMClassLoaderData));
1816 registerStaticClassRef(&loader_data_class);
1818 if(loader_data_class != NULL) {
1819 ldr_new_unloader = findMethod(loader_data_class, SYMBOL(newLibraryUnloader),
1820 SYMBOL(_J__V));
1821 hashtable = findField(loader_data_class, SYMBOL(hashtable), SYMBOL(I));
1824 if(hashtable == NULL || ldr_new_unloader == NULL) {
1825 jam_fprintf(stderr, "Fatal error: Bad VMClassLoaderData (missing or corrupt)\n");
1826 exitVM(1);
1828 ldr_data_tbl_offset = hashtable->offset;
1830 /* Register the address of where the java.lang.Class ref _will_ be */
1831 registerStaticClassRef(&java_lang_Class);