Fix Java long (64 bit) operations, add missing ones, fix compiler warnings
[jamvm-avr32-jem.git] / src / class.c
blob9987eaa06369ed878c4a50ab8bb6846443566768
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007
3 * Robert Lougher <rob@lougher.org.uk>.
5 * This file is part of JamVM.
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.
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.
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.
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>
29 #include <unistd.h>
30 #include <sys/mman.h>
32 #include "jam.h"
33 #include "sig.h"
34 #include "thread.h"
35 #include "lock.h"
36 #include "hash.h"
37 #include "zip.h"
38 #include "class.h"
39 #include "interp.h"
41 #define PREPARE(ptr) ptr
42 #define SCAVENGE(ptr) FALSE
43 #define FOUND(ptr) ptr
45 static int verbose;
46 static char *bootpath;
47 static char *classpath;
48 static int max_cp_element_len;
50 /* Structures holding the boot loader classpath */
51 typedef struct bcp_entry {
52 char *path;
53 ZipFile *zip;
54 } BCPEntry;
56 static BCPEntry *bootclasspath;
57 static int bcp_entries;
59 /* Cached offsets of fields in java.lang.ref.Reference objects */
60 int ref_referent_offset = -1;
61 int ref_queue_offset;
63 /* Cached offset of vmdata field in java.lang.ClassLoader objects */
64 int ldr_vmdata_offset = -1;
66 /* Instance of java.lang.Class for java.lang.Class */
67 Class *java_lang_Class = NULL;
69 /* Method table index of ClassLoader.loadClass - used when
70 requesting a Java-level class loader to load a class.
71 Cached on first use. */
72 static int loadClass_mtbl_idx = -1;
74 /* Method table index of finalizer method and ClassLoader.enqueue.
75 Used by finalizer and reference handler threads */
76 int finalize_mtbl_idx;
77 int enqueue_mtbl_idx;
79 /* hash table containing classes loaded by the boot loader and
80 internally created arrays */
82 #define INITSZE 1<<8
83 static HashTable loaded_classes;
85 /* Array large enough to hold all primitive classes -
86 * access protected by loaded_classes hash table lock */
87 #define MAX_PRIM_CLASSES 9
88 static Class *prim_classes[MAX_PRIM_CLASSES];
90 /* Bytecode for stub abstract method. If it is invoked
91 we'll get an abstract method error. */
92 static char abstract_method[] = {OPC_ABSTRACT_METHOD_ERROR};
94 static Class *addClassToHash(Class *class, Object *class_loader) {
95 HashTable *table;
96 Class *entry;
98 #define HASH(ptr) utf8Hash(CLASS_CB((Class *)ptr)->name)
99 #define COMPARE(ptr1, ptr2, hash1, hash2) (hash1 == hash2) && \
100 utf8Comp(CLASS_CB((Class *)ptr1)->name, CLASS_CB((Class *)ptr2)->name)
102 if(class_loader == NULL)
103 table = &loaded_classes;
104 else {
105 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
107 if(vmdata == NULL) {
108 HashTable **array_data;
110 if((vmdata = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, 1)) == NULL)
111 return NULL;
113 table = sysMalloc(sizeof(HashTable));
114 initHashTable((*table), INITSZE, TRUE);
116 array_data = ARRAY_DATA(vmdata);
117 *array_data = table;
118 #if JAM_ON_STACK
119 INST_DATA(class_loader)[ldr_vmdata_offset] = (uintptr_t)vmdata;
120 #else
121 INST_DATA(class_loader)[ldr_vmdata_offset] = (uintptr_t)ARRAY_DATA(vmdata);
122 #endif
123 } else {
124 #if JAM_ON_STACK
125 table = *(HashTable**)ARRAY_DATA(vmdata);
126 #else
127 table = *(HashTable**)vmdata;
128 #endif
132 /* Add if absent, no scavenge, locked */
133 findHashEntry((*table), class, entry, TRUE, FALSE, TRUE);
135 return entry;
138 static void prepareClass(Class *class) {
139 ClassBlock *cb = CLASS_CB(class);
141 if(strcmp(cb->name, "java/lang/Class") == 0) {
142 java_lang_Class = class->class = class;
143 cb->flags |= CLASS_CLASS;
144 } else {
145 if(java_lang_Class == NULL)
146 findSystemClass0("java/lang/Class");
147 class->class = java_lang_Class;
151 Class *defineClass(char *classname, char *data, int offset, int len, Object *class_loader) {
152 unsigned char *ptr = (unsigned char *)data+offset;
153 int cp_count, intf_count, i;
154 u2 major_version, minor_version, this_idx, super_idx;
155 u2 attr_count;
156 u4 magic;
158 ConstantPool *constant_pool;
159 ClassBlock *classblock;
160 Class *class, *found;
161 Class **interfaces;
163 #ifdef JEM
164 //the total size for all methods in this class
165 int methods_size = 0;
166 #endif
168 READ_U4(magic, ptr, len);
170 if(magic != 0xcafebabe) {
171 signalException("java/lang/ClassFormatError", "bad magic");
172 return NULL;
175 READ_U2(minor_version, ptr, len);
176 READ_U2(major_version, ptr, len);
178 if((class = allocClass()) == NULL)
179 return NULL;
181 classblock = CLASS_CB(class);
182 READ_U2(cp_count, ptr, len);
184 constant_pool = &classblock->constant_pool;
185 constant_pool->type = (u1 *)sysMalloc(cp_count);
186 constant_pool->info = (ConstantPoolEntry *)
187 sysMalloc(cp_count*sizeof(ConstantPoolEntry));
189 for(i = 1; i < cp_count; i++) {
190 u1 tag;
192 READ_U1(tag, ptr, len);
193 CP_TYPE(constant_pool,i) = tag;
195 switch(tag) {
196 case CONSTANT_Class:
197 case CONSTANT_String:
198 READ_INDEX(CP_INFO(constant_pool,i), ptr, len);
199 break;
201 case CONSTANT_Fieldref:
202 case CONSTANT_Methodref:
203 case CONSTANT_NameAndType:
204 case CONSTANT_InterfaceMethodref:
206 u2 idx1, idx2;
208 READ_INDEX(idx1, ptr, len);
209 READ_INDEX(idx2, ptr, len);
210 CP_INFO(constant_pool,i) = (idx2<<16)+idx1;
211 break;
214 case CONSTANT_Integer:
215 READ_U4(CP_INFO(constant_pool,i), ptr, len);
216 break;
218 case CONSTANT_Float:
220 u4 val;
222 READ_U4(val, ptr, len);
223 CP_INFO(constant_pool,i) = FLOAT_CONST(val);
224 break;
227 case CONSTANT_Long:
228 READ_U8(*(u8 *)&(CP_INFO(constant_pool,i)), ptr, len);
229 CP_TYPE(constant_pool,++i) = 0;
230 break;
232 case CONSTANT_Double:
233 READ_DBL(*(u8 *)&(CP_INFO(constant_pool,i)), ptr, len);
234 CP_TYPE(constant_pool,++i) = 0;
235 break;
237 case CONSTANT_Utf8:
239 int length;
240 char *buff, *utf8;
242 READ_U2(length, ptr, len);
243 buff = sysMalloc(length+1);
245 memcpy(buff, ptr, length);
246 buff[length] = '\0';
247 ptr += length;
249 CP_INFO(constant_pool,i) = (uintptr_t) (utf8 = findUtf8String(buff));
251 if(utf8 != buff)
252 sysFree(buff);
254 break;
257 default:
258 signalException("java/lang/ClassFormatError", "bad constant pool tag");
259 return NULL;
263 /* Set count after constant pool has been initialised -- it is now
264 safe to be scanned by GC */
265 classblock->constant_pool_count = cp_count;
267 READ_U2(classblock->access_flags, ptr, len);
269 READ_TYPE_INDEX(this_idx, constant_pool, CONSTANT_Class, ptr, len);
270 classblock->name = CP_UTF8(constant_pool, CP_CLASS(constant_pool, this_idx));
272 if(classname && (strcmp(classblock->name, classname) != 0)) {
273 signalException("java/lang/NoClassDefFoundError", "class file has wrong name");
274 return NULL;
277 prepareClass(class);
279 if(strcmp(classblock->name, "java/lang/Object") == 0) {
280 READ_U2(super_idx, ptr, len);
281 if(super_idx) {
282 signalException("java/lang/ClassFormatError", "Object has super");
283 return NULL;
285 classblock->super_name = NULL;
286 } else {
287 READ_TYPE_INDEX(super_idx, constant_pool, CONSTANT_Class, ptr, len);
288 classblock->super_name = CP_UTF8(constant_pool, CP_CLASS(constant_pool, super_idx));
291 classblock->class_loader = class_loader;
293 READ_U2(intf_count = classblock->interfaces_count, ptr, len);
294 interfaces = classblock->interfaces =
295 (Class **)sysMalloc(intf_count * sizeof(Class *));
297 memset(interfaces, 0, intf_count * sizeof(Class *));
298 for(i = 0; i < intf_count; i++) {
299 u2 index;
300 READ_TYPE_INDEX(index, constant_pool, CONSTANT_Class, ptr, len);
301 interfaces[i] = resolveClass(class, index, FALSE);
302 if(exceptionOccurred())
303 return NULL;
306 READ_U2(classblock->fields_count, ptr, len);
307 classblock->fields = (FieldBlock *)
308 sysMalloc(classblock->fields_count * sizeof(FieldBlock));
310 for(i = 0; i < classblock->fields_count; i++) {
311 u2 name_idx, type_idx;
313 READ_U2(classblock->fields[i].access_flags, ptr, len);
314 READ_TYPE_INDEX(name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
315 READ_TYPE_INDEX(type_idx, constant_pool, CONSTANT_Utf8, ptr, len);
316 classblock->fields[i].name = CP_UTF8(constant_pool, name_idx);
317 classblock->fields[i].type = CP_UTF8(constant_pool, type_idx);
318 classblock->fields[i].annotations = NULL;
319 classblock->fields[i].signature = NULL;
320 classblock->fields[i].constant = 0;
322 READ_U2(attr_count, ptr, len);
323 for(; attr_count != 0; attr_count--) {
324 u2 attr_name_idx;
325 char *attr_name;
326 u4 attr_length;
328 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
329 attr_name = CP_UTF8(constant_pool, attr_name_idx);
330 READ_U4(attr_length, ptr, len);
332 if(strcmp(attr_name, "ConstantValue") == 0) {
333 READ_INDEX(classblock->fields[i].constant, ptr, len);
334 } else
335 if(strcmp(attr_name, "Signature") == 0) {
336 u2 signature_idx;
337 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
338 classblock->fields[i].signature = CP_UTF8(constant_pool, signature_idx);
339 } else
340 if(strcmp(attr_name, "RuntimeVisibleAnnotations") == 0) {
341 classblock->fields[i].annotations = sysMalloc(sizeof(AnnotationData));
342 classblock->fields[i].annotations->len = attr_length;
343 classblock->fields[i].annotations->data = sysMalloc(attr_length);
344 memcpy(classblock->fields[i].annotations->data, ptr, attr_length);
345 ptr += attr_length;
346 } else
347 ptr += attr_length;
351 READ_U2(classblock->methods_count, ptr, len);
353 classblock->methods = (MethodBlock *)
354 sysMalloc(classblock->methods_count * sizeof(MethodBlock));
356 memset(classblock->methods, 0, classblock->methods_count * sizeof(MethodBlock));
358 for(i = 0; i < classblock->methods_count; i++) {
359 MethodBlock *method = &classblock->methods[i];
360 MethodAnnotationData annos;
361 u2 name_idx, type_idx;
363 memset(&annos, 0, sizeof(MethodAnnotationData));
365 READ_U2(method->access_flags, ptr, len);
366 READ_TYPE_INDEX(name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
367 READ_TYPE_INDEX(type_idx, constant_pool, CONSTANT_Utf8, ptr, len);
369 method->name = CP_UTF8(constant_pool, name_idx);
370 method->type = CP_UTF8(constant_pool, type_idx);
372 READ_U2(attr_count, ptr, len);
373 for(; attr_count != 0; attr_count--) {
374 u2 attr_name_idx;
375 char *attr_name;
376 u4 attr_length;
378 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
379 READ_U4(attr_length, ptr, len);
380 attr_name = CP_UTF8(constant_pool, attr_name_idx);
382 if(strcmp(attr_name, "Code") == 0) {
383 u4 code_length;
384 u2 code_attr_cnt;
385 int j;
387 READ_U2(method->max_stack, ptr, len);
388 READ_U2(method->max_locals, ptr, len);
390 READ_U4(code_length, ptr, len);
391 #ifndef JEM
392 method->code = (char *)sysMalloc(code_length);
393 memcpy(method->code, ptr, code_length);
394 #else
395 /* remember the data pointer here for later use */
396 method->code = (char *)ptr;
397 /* Cache line align */
398 methods_size += (code_length + 31) & ~31;
399 #endif
400 ptr += code_length;
402 method->code_size = code_length;
404 READ_U2(method->exception_table_size, ptr, len);
405 method->exception_table = (ExceptionTableEntry *)
406 sysMalloc(method->exception_table_size*sizeof(ExceptionTableEntry));
408 for(j = 0; j < method->exception_table_size; j++) {
409 ExceptionTableEntry *entry = &method->exception_table[j];
411 READ_U2(entry->start_pc, ptr, len);
412 READ_U2(entry->end_pc, ptr, len);
413 READ_U2(entry->handler_pc, ptr, len);
414 READ_U2(entry->catch_type, ptr, len);
417 READ_U2(code_attr_cnt, ptr, len);
418 for(; code_attr_cnt != 0; code_attr_cnt--) {
419 u2 attr_name_idx;
420 u4 attr_length;
422 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
423 attr_name = CP_UTF8(constant_pool, attr_name_idx);
424 READ_U4(attr_length, ptr, len);
426 if(strcmp(attr_name, "LineNumberTable") == 0) {
427 READ_U2(method->line_no_table_size, ptr, len);
428 method->line_no_table = (LineNoTableEntry *)
429 sysMalloc(method->line_no_table_size*sizeof(LineNoTableEntry));
431 for(j = 0; j < method->line_no_table_size; j++) {
432 LineNoTableEntry *entry = &method->line_no_table[j];
434 READ_U2(entry->start_pc, ptr, len);
435 READ_U2(entry->line_no, ptr, len);
437 } else
438 ptr += attr_length;
440 } else
441 if(strcmp(attr_name, "Exceptions") == 0) {
442 int j;
444 READ_U2(method->throw_table_size, ptr, len);
445 method->throw_table = (u2 *)sysMalloc(method->throw_table_size*sizeof(u2));
446 for(j = 0; j < method->throw_table_size; j++) {
447 READ_U2(method->throw_table[j], ptr, len);
449 } else
450 if(strcmp(attr_name, "Signature") == 0) {
451 u2 signature_idx;
452 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
453 method->signature = CP_UTF8(constant_pool, signature_idx);
454 } else
455 if(strcmp(attr_name, "RuntimeVisibleAnnotations") == 0) {
456 annos.annotations = sysMalloc(sizeof(AnnotationData));
457 annos.annotations->len = attr_length;
458 annos.annotations->data = sysMalloc(attr_length);
459 memcpy(annos.annotations->data, ptr, attr_length);
460 ptr += attr_length;
461 } else
462 if(strcmp(attr_name, "RuntimeVisibleParameterAnnotations") == 0) {
463 annos.parameters = sysMalloc(sizeof(AnnotationData));
464 annos.parameters->len = attr_length;
465 annos.parameters->data = sysMalloc(attr_length);
466 memcpy(annos.parameters->data, ptr, attr_length);
467 ptr += attr_length;
468 } else
469 if(strcmp(attr_name, "AnnotationDefault") == 0) {
470 annos.dft_val = sysMalloc(sizeof(AnnotationData));
471 annos.dft_val->len = attr_length;
472 annos.dft_val->data = sysMalloc(attr_length);
473 memcpy(annos.dft_val->data, ptr, attr_length);
474 ptr += attr_length;
475 } else
476 ptr += attr_length;
478 if(annos.annotations != NULL || annos.parameters != NULL
479 || annos.dft_val != NULL) {
480 method->annotations = sysMalloc(sizeof(MethodAnnotationData));
481 memcpy(method->annotations, &annos, sizeof(MethodAnnotationData));
485 READ_U2(attr_count, ptr, len);
486 for(; attr_count != 0; attr_count--) {
487 u2 attr_name_idx;
488 char *attr_name;
489 u4 attr_length;
491 READ_TYPE_INDEX(attr_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
492 attr_name = CP_UTF8(constant_pool, attr_name_idx);
493 READ_U4(attr_length, ptr, len);
495 if(strcmp(attr_name, "SourceFile") == 0) {
496 u2 file_name_idx;
497 READ_TYPE_INDEX(file_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
498 classblock->source_file_name = CP_UTF8(constant_pool, file_name_idx);
499 } else
500 if(strcmp(attr_name, "InnerClasses") == 0) {
501 int j, size;
502 READ_U2(size, ptr, len);
504 u2 inner_classes[size];
505 for(j = 0; j < size; j++) {
506 int inner, outer;
507 READ_TYPE_INDEX(inner, constant_pool, CONSTANT_Class, ptr, len);
508 READ_TYPE_INDEX(outer, constant_pool, CONSTANT_Class, ptr, len);
510 if(inner == this_idx) {
511 int inner_name_idx;
513 /* A member class doesn't have an EnclosingMethod attribute, so set
514 the enclosing class to be the same as the declaring class */
515 if(outer)
516 classblock->declaring_class = classblock->enclosing_class = outer;
518 READ_TYPE_INDEX(inner_name_idx, constant_pool, CONSTANT_Utf8, ptr, len);
519 if(inner_name_idx == 0)
520 classblock->flags |= ANONYMOUS;
522 READ_U2(classblock->inner_access_flags, ptr, len);
523 } else {
524 ptr += 4;
525 if(outer == this_idx)
526 inner_classes[classblock->inner_class_count++] = inner;
530 if(classblock->inner_class_count) {
531 classblock->inner_classes = sysMalloc(classblock->inner_class_count*sizeof(u2));
532 memcpy(classblock->inner_classes, &inner_classes[0],
533 classblock->inner_class_count*sizeof(u2));
536 } else
537 if(strcmp(attr_name, "EnclosingMethod") == 0) {
538 READ_TYPE_INDEX(classblock->enclosing_class, constant_pool, CONSTANT_Class, ptr, len);
539 READ_TYPE_INDEX(classblock->enclosing_method, constant_pool, CONSTANT_NameAndType, ptr, len);
540 } else
541 if(strcmp(attr_name, "Signature") == 0) {
542 u2 signature_idx;
543 READ_TYPE_INDEX(signature_idx, constant_pool, CONSTANT_Utf8, ptr, len);
544 classblock->signature = CP_UTF8(constant_pool, signature_idx);
545 } else
546 if(strcmp(attr_name, "Synthetic") == 0)
547 classblock->access_flags |= ACC_SYNTHETIC;
548 else
549 if(strcmp(attr_name, "RuntimeVisibleAnnotations") == 0) {
550 classblock->annotations = sysMalloc(sizeof(AnnotationData));
551 classblock->annotations->len = attr_length;
552 classblock->annotations->data = sysMalloc(attr_length);
553 memcpy(classblock->annotations->data, ptr, attr_length);
554 ptr += attr_length;
555 } else
556 ptr += attr_length;
559 classblock->super = super_idx ? resolveClass(class, super_idx, FALSE) : NULL;
561 if(exceptionOccurred())
562 return NULL;
564 #ifdef JEM
565 #include <sys/syscall.h>
566 #include <asm/cachectl.h>
568 char *jem_mbs = mmap(0, (methods_size + 4095) & ~4095,
569 PROT_READ | PROT_WRITE | PROT_EXEC,
570 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
571 char *jem_mb_start = jem_mbs;
573 for (i = 0; i < classblock->methods_count; i++) {
574 MethodBlock *mb = &classblock->methods[i];
575 memcpy(jem_mbs, mb->code, mb->code_size);
576 mb->code = jem_mbs;
577 /* Cache line align */
578 jem_mbs += (mb->code_size + 31) & ~31;
580 /* Clean the data cache, flush the instruction cache */
581 syscall(__NR_cacheflush, CACHE_IFLUSH, jem_mb_start, (methods_size + 4095) & ~4095);
582 #endif
584 classblock->state = CLASS_LOADED;
586 if((found = addClassToHash(class, class_loader)) != class) {
587 classblock->flags = CLASS_CLASH;
588 if(class_loader != NULL) {
589 signalException("java/lang/LinkageError", "duplicate class definition");
590 return NULL;
592 return found;
595 return class;
598 Class *
599 createArrayClass(char *classname, Object *class_loader) {
600 Class *class, *found = NULL;
601 int len = strlen(classname);
602 ClassBlock *elem_cb, *classblock;
604 if((class = allocClass()) == NULL)
605 return NULL;
607 classblock = CLASS_CB(class);
608 classblock->name = strcpy((char*)sysMalloc(len+1), classname);
609 classblock->super_name = "java/lang/Object";
610 classblock->super = findSystemClass("java/lang/Object");
611 classblock->method_table = CLASS_CB(classblock->super)->method_table;
613 classblock->interfaces_count = 2;
614 classblock->interfaces = (Class**)sysMalloc(2*sizeof(Class*));
615 classblock->interfaces[0] = findSystemClass("java/lang/Cloneable");
616 classblock->interfaces[1] = findSystemClass("java/io/Serializable");
618 classblock->state = CLASS_ARRAY;
620 /* Find the array element class and the dimension --
621 this is used to speed up type checking (instanceof) */
623 if(classname[1] == '[') {
624 Class *comp_class = findArrayClassFromClassLoader(classname + 1, class_loader);
626 if(comp_class == NULL)
627 goto error;
629 classblock->element_class = CLASS_CB(comp_class)->element_class;
630 classblock->dim = CLASS_CB(comp_class)->dim + 1;
631 } else {
632 if(classname[1] == 'L') {
633 char element_name[len-2];
635 strcpy(element_name, classname + 2);
636 element_name[len-3] = '\0';
637 classblock->element_class = findClassFromClassLoader(element_name, class_loader);
638 } else
639 classblock->element_class = findPrimitiveClass(classname[1]);
641 if(classblock->element_class == NULL)
642 goto error;
644 classblock->dim = 1;
647 elem_cb = CLASS_CB(classblock->element_class);
649 /* The array's classloader is the loader of the element class */
650 classblock->class_loader = elem_cb->class_loader;
652 /* The array's visibility (i.e. public, etc.) is that of the element */
653 classblock->access_flags = (elem_cb->access_flags & ~ACC_INTERFACE) |
654 ACC_FINAL | ACC_ABSTRACT;
656 prepareClass(class);
658 if((found = addClassToHash(class, classblock->class_loader)) == class) {
659 if(verbose)
660 jam_printf("[Created array class %s]\n", classname);
661 return class;
664 error:
665 classblock->flags = CLASS_CLASH;
666 return found;
669 Class *
670 createPrimClass(char *classname, int index) {
671 Class *class;
672 ClassBlock *classblock;
674 if((class = allocClass()) == NULL)
675 return NULL;
677 classblock = CLASS_CB(class);
678 classblock->name = strcpy((char*)sysMalloc(strlen(classname)+1), classname);
679 classblock->access_flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
680 classblock->state = CLASS_PRIM + index;
682 prepareClass(class);
684 lockHashTable(loaded_classes);
685 if(prim_classes[index] == NULL)
686 prim_classes[index] = class;
687 unlockHashTable(loaded_classes);
689 if(verbose)
690 jam_printf("[Created primitive class %s]\n", classname);
692 return prim_classes[index];
695 #define MRNDA_CACHE_SZE 10
697 #define resizeMTable(method_table, method_table_size, miranda, count) \
699 method_table = (MethodBlock**)sysRealloc(method_table, \
700 (method_table_size + count) * sizeof(MethodBlock*)); \
702 memcpy(&method_table[method_table_size], miranda, \
703 count * sizeof(MethodBlock*)); \
704 method_table_size += count; \
707 #define fillinMTable(method_table, methods, methods_count) \
709 int i; \
710 for(i = 0; i < methods_count; i++, methods++) { \
711 if((methods->access_flags & (ACC_STATIC | ACC_PRIVATE)) || \
712 (methods->name[0] == '<')) \
713 continue; \
714 method_table[methods->method_table_index] = methods; \
718 void linkClass(Class *class) {
719 static MethodBlock *obj_fnlzr_mthd = NULL;
721 ClassBlock *cb = CLASS_CB(class);
722 MethodBlock **method_table = NULL;
723 MethodBlock **spr_mthd_tbl = NULL;
724 ITableEntry *spr_imthd_tbl = NULL;
725 int new_methods_count = 0;
726 int spr_imthd_tbl_sze = 0;
727 int itbl_offset_count = 0;
728 int spr_mthd_tbl_sze = 0;
729 int method_table_size;
730 int new_itable_count;
731 int spr_obj_sze = 0;
732 int refs_end_offset;
733 int itbl_idx, i, j;
734 int spr_flags = 0;
735 int field_offset;
736 MethodBlock *finalizer;
737 MethodBlock *mb;
738 FieldBlock *fb;
739 RefsOffsetsEntry *spr_rfs_offsts_tbl = NULL;
740 int spr_rfs_offsts_sze = 0;
742 Class *super = (cb->access_flags & ACC_INTERFACE) ? NULL : cb->super;
744 if(cb->state >= CLASS_LINKED)
745 return;
747 objectLock((Object *)class);
749 if(cb->state >= CLASS_LINKED)
750 goto unlock;
752 if(verbose)
753 jam_printf("[Linking class %s]\n", cb->name);
755 if(super) {
756 ClassBlock *super_cb = CLASS_CB(super);
757 if(super_cb->state < CLASS_LINKED)
758 linkClass(super);
760 spr_flags = super_cb->flags;
761 spr_obj_sze = super_cb->object_size;
762 spr_mthd_tbl = super_cb->method_table;
763 spr_imthd_tbl = super_cb->imethod_table;
764 spr_mthd_tbl_sze = super_cb->method_table_size;
765 spr_imthd_tbl_sze = super_cb->imethod_table_size;
766 spr_rfs_offsts_sze = super_cb->refs_offsets_size;
767 spr_rfs_offsts_tbl = super_cb->refs_offsets_table;
770 /* prepare fields */
772 field_offset = spr_obj_sze;
774 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++) {
775 if(fb->access_flags & ACC_STATIC) {
776 /* init to default value */
777 if((*fb->type == 'J') || (*fb->type == 'D'))
778 *(long long *)&fb->static_value = 0;
779 else
780 fb->static_value = 0;
781 } else {
782 /* calc field offset */
783 if((*fb->type == 'L') || (*fb->type == '['))
784 fb->offset = field_offset++;
786 fb->class = class;
789 refs_end_offset = field_offset;
791 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++)
792 if(!(fb->access_flags & ACC_STATIC) &&
793 (*fb->type != 'L') && (*fb->type != '[')) {
794 /* calc field offset */
795 fb->offset = field_offset;
796 if((*fb->type == 'J') || (*fb->type == 'D'))
797 field_offset += 2;
798 else
799 field_offset += 1;
802 cb->object_size = field_offset;
804 /* prepare methods */
806 for(mb = cb->methods, i = 0; i < cb->methods_count; i++,mb++) {
808 /* calculate argument count from signature */
810 int count = 0;
811 char *sig = mb->type;
812 SCAN_SIG(sig, count+=2, count++);
814 if(mb->access_flags & ACC_STATIC)
815 mb->args_count = count;
816 else
817 mb->args_count = count + 1;
819 mb->class = class;
821 /* Set abstract method to stub */
822 if(mb->access_flags & ACC_ABSTRACT) {
823 mb->code_size = sizeof(abstract_method);
824 mb->code = abstract_method;
827 if(mb->access_flags & ACC_NATIVE) {
829 /* set up native invoker to wrapper to resolve function
830 on first invocation */
832 mb->native_invoker = (void *) resolveNativeWrapper;
834 /* native methods have no code attribute so these aren't filled
835 in at load time - as these values are used when creating frame
836 set to appropriate values */
838 mb->max_locals = mb->args_count;
839 mb->max_stack = 0;
842 #ifdef DIRECT
843 else {
844 /* Set the bottom bit of the pointer to indicate the
845 method is unprepared */
846 mb->code = ((char*)mb->code) + 1;
848 #endif
850 /* Static, private or init methods aren't dynamically invoked, so
851 don't stick them in the table to save space */
853 if((mb->access_flags & (ACC_STATIC | ACC_PRIVATE)) || (mb->name[0] == '<'))
854 continue;
856 /* if it's overriding an inherited method, replace in method table */
858 for(j = 0; j < spr_mthd_tbl_sze; j++)
859 if(strcmp(mb->name, spr_mthd_tbl[j]->name) == 0 &&
860 strcmp(mb->type, spr_mthd_tbl[j]->type) == 0 &&
861 checkMethodAccess(spr_mthd_tbl[j], class)) {
862 mb->method_table_index = spr_mthd_tbl[j]->method_table_index;
863 break;
866 if(j == spr_mthd_tbl_sze)
867 mb->method_table_index = spr_mthd_tbl_sze + new_methods_count++;
870 /* construct method table */
872 method_table_size = spr_mthd_tbl_sze + new_methods_count;
874 if(!(cb->access_flags & ACC_INTERFACE)) {
875 method_table = (MethodBlock**)sysMalloc(method_table_size * sizeof(MethodBlock*));
877 /* Copy parents method table to the start */
878 memcpy(method_table, spr_mthd_tbl, spr_mthd_tbl_sze * sizeof(MethodBlock*));
880 /* fill in the additional methods -- we use a
881 temporary because fillinMtable alters mb */
882 mb = cb->methods;
883 fillinMTable(method_table, mb, cb->methods_count);
886 /* setup interface method table */
888 /* number of interfaces implemented by this class is those implemented by
889 * parent, plus number of interfaces directly implemented by this class,
890 * and the total number of their superinterfaces */
892 new_itable_count = cb->interfaces_count;
893 for(i = 0; i < cb->interfaces_count; i++)
894 new_itable_count += CLASS_CB(cb->interfaces[i])->imethod_table_size;
896 cb->imethod_table_size = spr_imthd_tbl_sze + new_itable_count;
897 cb->imethod_table = (ITableEntry*)sysMalloc(cb->imethod_table_size * sizeof(ITableEntry));
899 /* copy parent's interface table - the offsets into the method table won't change */
901 memcpy(cb->imethod_table, spr_imthd_tbl, spr_imthd_tbl_sze * sizeof(ITableEntry));
903 /* now run through the extra interfaces implemented by this class,
904 * fill in the interface part, and calculate the number of offsets
905 * needed (i.e. the number of methods defined in the interfaces) */
907 itbl_idx = spr_imthd_tbl_sze;
908 for(i = 0; i < cb->interfaces_count; i++) {
909 Class *intf = cb->interfaces[i];
910 ClassBlock *intf_cb = CLASS_CB(intf);
912 cb->imethod_table[itbl_idx++].interface = intf;
913 itbl_offset_count += intf_cb->method_table_size;
915 for(j = 0; j < intf_cb->imethod_table_size; j++) {
916 Class *spr_intf = intf_cb->imethod_table[j].interface;
918 cb->imethod_table[itbl_idx++].interface = spr_intf;
919 itbl_offset_count += CLASS_CB(spr_intf)->method_table_size;
923 /* if we're an interface all finished - offsets aren't used */
925 if(!(cb->access_flags & ACC_INTERFACE)) {
926 int *offsets_pntr = (int*)sysMalloc(itbl_offset_count * sizeof(int));
927 int old_mtbl_size = method_table_size;
928 MethodBlock *miranda[MRNDA_CACHE_SZE];
929 int miranda_count = 0;
930 int mtbl_idx;
932 /* run through table again, this time filling in the offsets array -
933 * for each new interface, run through it's methods and locate
934 * each method in this classes method table */
936 for(i = spr_imthd_tbl_sze; i < cb->imethod_table_size; i++) {
937 ClassBlock *intf_cb = CLASS_CB(cb->imethod_table[i].interface);
938 cb->imethod_table[i].offsets = offsets_pntr;
940 for(j = 0; j < intf_cb->methods_count; j++) {
941 MethodBlock *intf_mb = &intf_cb->methods[j];
943 if((intf_mb->access_flags & (ACC_STATIC | ACC_PRIVATE)) ||
944 (intf_mb->name[0] == '<'))
945 continue;
947 /* We scan backwards so that we find methods defined in sub-classes
948 before super-classes. This ensures we find non-overridden
949 methods before the inherited non-accessible method */
950 for(mtbl_idx = method_table_size - 1; mtbl_idx >= 0; mtbl_idx--)
951 if(strcmp(intf_mb->name, method_table[mtbl_idx]->name) == 0 &&
952 strcmp(intf_mb->type, method_table[mtbl_idx]->type) == 0) {
953 *offsets_pntr++ = mtbl_idx;
954 break;
957 if(mtbl_idx < 0) {
959 /* didn't find it - add a dummy abstract method (a so-called
960 miranda method). If it's invoked we'll get an abstract
961 method error */
963 int k;
964 for(k = 0; k < miranda_count; k++)
965 if(strcmp(intf_mb->name, miranda[k]->name) == 0 &&
966 strcmp(intf_mb->type, miranda[k]->type) == 0)
967 break;
969 *offsets_pntr++ = method_table_size + k;
971 if(k == miranda_count) {
972 if(miranda_count == MRNDA_CACHE_SZE) {
973 resizeMTable(method_table, method_table_size, miranda, MRNDA_CACHE_SZE);
974 miranda_count = 0;
976 miranda[miranda_count++] = intf_mb;
982 if(miranda_count > 0)
983 resizeMTable(method_table, method_table_size, miranda, miranda_count);
985 if(old_mtbl_size != method_table_size) {
986 /* We've created some abstract methods */
987 int num_mirandas = method_table_size - old_mtbl_size;
989 mb = (MethodBlock *) sysRealloc(cb->methods,
990 (cb->methods_count + num_mirandas) * sizeof(MethodBlock));
992 /* If the realloc of the method list gave us a new pointer, the pointers
993 to them in the method table are now wrong. */
994 if(mb != cb->methods) {
995 /* mb will be left pointing to the end of the methods */
996 cb->methods = mb;
997 fillinMTable(method_table, mb, cb->methods_count);
998 } else
999 mb += cb->methods_count;
1001 cb->methods_count += num_mirandas;
1003 /* Now we've expanded the method list, replace pointers to
1004 the interface methods. */
1006 for(i = old_mtbl_size; i < method_table_size; i++,mb++) {
1007 memcpy(mb, method_table[i], sizeof(MethodBlock));
1008 mb->access_flags |= ACC_MIRANDA;
1009 mb->method_table_index = i;
1010 mb->class = class;
1011 method_table[i] = mb;
1016 cb->method_table = method_table;
1017 cb->method_table_size = method_table_size;
1019 /* Handle finalizer */
1021 /* If this is Object find the finalize method. All subclasses will
1022 have it in the same place in the method table. Note, Object
1023 should always have a valid finalizer -- but check just in case */
1025 if(cb->super == NULL) {
1026 finalizer = findMethod(class, "finalize", "()V");
1027 if(finalizer && !(finalizer->access_flags & (ACC_STATIC | ACC_PRIVATE))) {
1028 finalize_mtbl_idx = finalizer->method_table_index;
1029 obj_fnlzr_mthd = finalizer;
1033 cb->flags |= spr_flags;
1035 /* Store the finalizer only if it's overridden Object's. We don't
1036 want to finalize every object, and Object's imp is empty */
1038 if(super && obj_fnlzr_mthd && (finalizer =
1039 method_table[obj_fnlzr_mthd->method_table_index]) != obj_fnlzr_mthd)
1040 cb->flags |= FINALIZED;
1042 /* Handle reference classes */
1044 if(ref_referent_offset == -1 && strcmp(cb->name, "java/lang/ref/Reference") == 0) {
1045 FieldBlock *ref_fb = findField(class, "referent", "Ljava/lang/Object;");
1046 FieldBlock *queue_fb = findField(class, "queue", "Ljava/lang/ref/ReferenceQueue;");
1047 MethodBlock *enqueue_mb = findMethod(class, "enqueue", "()Z");
1049 if(ref_fb == NULL || queue_fb == NULL || enqueue_mb == NULL) {
1050 jam_fprintf(stderr, "Expected fields/methods missing in java.lang.ref.Reference\n");
1051 exitVM(1);
1054 for(fb = cb->fields, i = 0; i < cb->fields_count; i++,fb++)
1055 if(fb->offset > ref_fb->offset)
1056 fb->offset--;
1058 ref_referent_offset = ref_fb->offset = field_offset - 1;
1059 enqueue_mtbl_idx = enqueue_mb->method_table_index;
1060 ref_queue_offset = queue_fb->offset;
1061 refs_end_offset--;
1063 cb->flags |= REFERENCE;
1066 if(spr_flags & REFERENCE) {
1067 if(strcmp(cb->name, "java/lang/ref/SoftReference") == 0)
1068 cb->flags |= SOFT_REFERENCE;
1069 else
1070 if(strcmp(cb->name, "java/lang/ref/WeakReference") == 0)
1071 cb->flags |= WEAK_REFERENCE;
1072 else
1073 if(strcmp(cb->name, "java/lang/ref/PhantomReference") == 0)
1074 cb->flags |= PHANTOM_REFERENCE;
1077 /* Handle class loader classes */
1079 if(ldr_vmdata_offset == -1 && strcmp(cb->name, "java/lang/ClassLoader") == 0) {
1080 FieldBlock *ldr_fb = findField(class, "vmdata", "Ljava/lang/Object;");
1082 if(ldr_fb == NULL) {
1083 jam_fprintf(stderr, "Expected vmdata field missing in java.lang.ClassLoader\n");
1084 exitVM(1);
1087 ldr_vmdata_offset = ldr_fb->offset;
1088 cb->flags |= CLASS_LOADER;
1091 /* Construct the reference offsets list. This is used to speed up
1092 scanning of an objects references during the mark phase of GC. */
1094 if(refs_end_offset > spr_obj_sze) {
1095 int new_start;
1097 if(spr_rfs_offsts_sze > 0 && spr_rfs_offsts_tbl[spr_rfs_offsts_sze-1].end == spr_obj_sze) {
1098 cb->refs_offsets_size = spr_rfs_offsts_sze;
1099 new_start = spr_rfs_offsts_tbl[spr_rfs_offsts_sze-1].start;
1100 } else {
1101 cb->refs_offsets_size = spr_rfs_offsts_sze + 1;
1102 new_start = spr_obj_sze;
1105 cb->refs_offsets_table = sysMalloc(cb->refs_offsets_size * sizeof(RefsOffsetsEntry));
1107 memcpy(cb->refs_offsets_table, spr_rfs_offsts_tbl,
1108 spr_rfs_offsts_sze * sizeof(RefsOffsetsEntry));
1110 cb->refs_offsets_table[cb->refs_offsets_size-1].start = new_start;
1111 cb->refs_offsets_table[cb->refs_offsets_size-1].end = refs_end_offset;
1112 } else {
1113 cb->refs_offsets_size = spr_rfs_offsts_sze;
1114 cb->refs_offsets_table = spr_rfs_offsts_tbl;
1117 cb->state = CLASS_LINKED;
1119 unlock:
1120 objectUnlock((Object *)class);
1123 Class *initClass(Class *class) {
1124 ClassBlock *cb = CLASS_CB(class);
1125 ConstantPool *cp = &cb->constant_pool;
1126 FieldBlock *fb = cb->fields;
1127 MethodBlock *mb;
1128 Object *excep;
1129 int i;
1131 if(cb->state >= CLASS_INITED)
1132 return class;
1134 linkClass(class);
1135 objectLock((Object *)class);
1137 while(cb->state == CLASS_INITING)
1138 if(cb->initing_tid == threadSelf()->id)
1139 goto unlock;
1140 else
1141 objectWait((Object *)class, 0, 0);
1143 if(cb->state >= CLASS_INITED)
1144 goto unlock;
1146 if(cb->state == CLASS_BAD) {
1147 objectUnlock((Object *)class);
1148 signalException("java/lang/NoClassDefFoundError", cb->name);
1149 return class;
1152 cb->state = CLASS_INITING;
1154 cb->initing_tid = threadSelf()->id;
1156 objectUnlock((Object *)class);
1158 if(!(cb->access_flags & ACC_INTERFACE) && cb->super
1159 && (CLASS_CB(cb->super)->state != CLASS_INITED)) {
1160 initClass(cb->super);
1161 if(exceptionOccurred()) {
1162 objectLock((Object *)class);
1163 cb->state = CLASS_BAD;
1164 goto notify;
1168 /* Never used to bother with this as only static finals use it and
1169 the constant value's copied at compile time. However, separate
1170 compilation can result in a getstatic to a (now) constant field,
1171 and the VM didn't initialise it... */
1173 for(i = 0; i < cb->fields_count; i++,fb++)
1174 if((fb->access_flags & ACC_STATIC) && fb->constant) {
1175 if((*fb->type == 'J') || (*fb->type == 'D'))
1176 *(u8*)&fb->static_value = *(u8*)&(CP_INFO(cp, fb->constant));
1177 else
1178 fb->static_value = resolveSingleConstant(class, fb->constant);
1181 if((mb = findMethod(class, "<clinit>", "()V")) != NULL)
1182 executeStaticMethod(class, mb);
1184 if((excep = exceptionOccurred())) {
1185 Class *error, *eiie;
1186 Object *ob;
1188 clearException();
1190 /* Don't wrap exceptions of type java.lang.Error... */
1191 if((error = findSystemClass0("java/lang/Error"))
1192 && !isInstanceOf(error, excep->class)
1193 && (eiie = findSystemClass("java/lang/ExceptionInInitializerError"))
1194 && (mb = findMethod(eiie, "<init>", "(Ljava/lang/Throwable;)V"))
1195 && (ob = allocObject(eiie))) {
1196 executeMethod(ob, mb, excep);
1197 setException(ob);
1198 } else
1199 setException(excep);
1201 objectLock((Object *)class);
1202 cb->state = CLASS_BAD;
1203 } else {
1204 objectLock((Object *)class);
1205 cb->state = CLASS_INITED;
1208 notify:
1209 objectNotifyAll((Object *)class);
1211 unlock:
1212 objectUnlock((Object *)class);
1213 return class;
1216 char *findFileEntry(char *path, int *file_len) {
1217 int read_len;
1218 char *data;
1219 FILE *fd;
1221 if((fd = fopen(path, "r")) == NULL)
1222 return NULL;
1224 fseek(fd, 0L, SEEK_END);
1225 *file_len = ftell(fd);
1226 fseek(fd, 0L, SEEK_SET);
1228 data = (char *)sysMalloc(*file_len);
1229 read_len = fread(data, sizeof(char), *file_len, fd);
1230 fclose(fd);
1232 if(read_len == *file_len)
1233 return data;
1235 sysFree(data);
1236 return NULL;
1239 Class *loadSystemClass(char *classname) {
1240 int file_len, fname_len = strlen(classname) + 8;
1241 char buff[max_cp_element_len + fname_len];
1242 char filename[fname_len];
1243 Class *class = NULL;
1244 char *data = NULL;
1245 int i;
1247 filename[0] = '/';
1248 strcat(strcpy(&filename[1], classname), ".class");
1250 for(i = 0; i < bcp_entries && data == NULL; i++)
1251 if(bootclasspath[i].zip)
1252 data = findArchiveEntry(filename+1, bootclasspath[i].zip, &file_len);
1253 else
1254 data = findFileEntry(strcat(strcpy(buff, bootclasspath[i].path), filename), &file_len);
1256 if(data == NULL) {
1257 signalException("java/lang/NoClassDefFoundError", classname);
1258 return NULL;
1261 class = defineClass(classname, data, 0, file_len, NULL);
1262 sysFree(data);
1264 if(verbose && class)
1265 jam_printf("[Loaded %s from %s]\n", classname, bootclasspath[i-1].path);
1267 return class;
1270 void addInitiatingLoaderToClass(Object *class_loader, Class *class) {
1271 ClassBlock *cb = CLASS_CB(class);
1273 /* The defining class loader is automatically an initiating
1274 loader so don't add again */
1275 if(cb->class_loader != class_loader)
1276 addClassToHash(class, class_loader);
1279 Class *findHashedClass(char *classname, Object *class_loader) {
1280 HashTable *table;
1281 Class *class;
1283 #undef HASH
1284 #undef COMPARE
1285 #define HASH(ptr) utf8Hash(ptr)
1286 #define COMPARE(ptr1, ptr2, hash1, hash2) (hash1 == hash2) && \
1287 utf8Comp(ptr1, CLASS_CB((Class *)ptr2)->name)
1289 if(class_loader == NULL)
1290 table = &loaded_classes;
1291 else {
1292 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1294 if(vmdata == NULL)
1295 return NULL;
1297 #if JAM_ON_STACK
1298 table = *(HashTable**)ARRAY_DATA(vmdata);
1299 #else
1300 table = *(HashTable**)vmdata;
1301 #endif
1304 /* Do not add if absent, no scavenge, locked */
1305 findHashEntry((*table), classname, class, FALSE, FALSE, TRUE);
1307 return class;
1310 Class *findSystemClass0(char *classname) {
1311 Class *class = findHashedClass(classname, NULL);
1313 if(class == NULL)
1314 class = loadSystemClass(classname);
1316 if(!exceptionOccurred())
1317 linkClass(class);
1319 return class;
1322 Class *findSystemClass(char *classname) {
1323 Class *class = findSystemClass0(classname);
1325 if(!exceptionOccurred())
1326 initClass(class);
1328 return class;
1331 Class *findArrayClassFromClassLoader(char *classname, Object *class_loader) {
1332 Class *class = findHashedClass(classname, class_loader);
1334 if(class == NULL) {
1335 if((class = createArrayClass(classname, class_loader)) != NULL)
1336 addInitiatingLoaderToClass(class_loader, class);
1338 return class;
1341 Class *findPrimitiveClass(char prim_type) {
1342 int index;
1343 Class *prim;
1344 char *classname;
1346 switch(prim_type) {
1347 case 'Z':
1348 classname = "boolean"; index = 1;
1349 break;
1350 case 'B':
1351 classname = "byte"; index = 2;
1352 break;
1353 case 'C':
1354 classname = "char"; index = 3;
1355 break;
1356 case 'S':
1357 classname = "short"; index = 4;
1358 break;
1359 case 'I':
1360 classname = "int"; index = 5;
1361 break;
1362 case 'F':
1363 classname = "float"; index = 6;
1364 break;
1365 case 'J':
1366 classname = "long"; index = 7;
1367 break;
1368 case 'D':
1369 classname = "double"; index = 8;
1370 break;
1371 case 'V':
1372 classname = "void"; index = 0;
1373 break;
1374 default:
1375 signalException("java/lang/NoClassDefFoundError", NULL);
1376 return NULL;
1377 break;
1380 prim = prim_classes[index];
1381 return prim ? prim : createPrimClass(classname, index);
1384 Class *findNonArrayClassFromClassLoader(char *classname, Object *loader) {
1385 Class *class = findHashedClass(classname, loader);
1387 if(class == NULL) {
1388 char *dot_name = slash2dots(classname);
1389 Object *string = createString(dot_name);
1390 Object *excep;
1392 sysFree(dot_name);
1393 if(string == NULL)
1394 return NULL;
1396 if(loadClass_mtbl_idx == -1) {
1397 MethodBlock *mb = lookupMethod(loader->class, "loadClass",
1398 "(Ljava/lang/String;)Ljava/lang/Class;");
1399 if(mb == NULL)
1400 return NULL;
1402 loadClass_mtbl_idx = mb->method_table_index;
1405 class = *(Class**)executeMethod(loader,
1406 CLASS_CB(loader->class)->method_table[loadClass_mtbl_idx], string);
1408 if((excep = exceptionOccurred())) {
1409 clearException();
1410 signalChainedException("java/lang/NoClassDefFoundError", classname, excep);
1411 return NULL;
1414 addInitiatingLoaderToClass(loader, class);
1416 if(verbose && (CLASS_CB(class)->class_loader == loader))
1417 jam_printf("[Loaded %s]\n", classname);
1419 return class;
1422 Class *findClassFromClassLoader(char *classname, Object *loader) {
1423 if(*classname == '[')
1424 return findArrayClassFromClassLoader(classname, loader);
1426 if(loader != NULL)
1427 return findNonArrayClassFromClassLoader(classname, loader);
1429 return findSystemClass0(classname);
1432 Object *getSystemClassLoader() {
1433 Class *class_loader = findSystemClass("java/lang/ClassLoader");
1435 if(!exceptionOccurred()) {
1436 MethodBlock *mb;
1438 if((mb = findMethod(class_loader, "getSystemClassLoader",
1439 "()Ljava/lang/ClassLoader;")) != NULL) {
1440 Object *system_loader = *(Object**)executeStaticMethod(class_loader, mb);
1442 if(!exceptionOccurred())
1443 return system_loader;
1446 return NULL;
1449 /* gc support for marking classes */
1451 #define ITERATE(ptr) markRoot(ptr)
1453 void markBootClasses() {
1454 int i;
1456 hashIterate(loaded_classes);
1458 for(i = 0; i < MAX_PRIM_CLASSES; i++)
1459 if(prim_classes[i] != NULL)
1460 markRoot((Object*)prim_classes[i]);
1463 #undef ITERATE
1464 #define ITERATE(ptr) threadReference((Object**)ptr)
1466 void threadBootClasses() {
1467 int i;
1469 hashIterateP(loaded_classes);
1471 for(i = 0; i < MAX_PRIM_CLASSES; i++)
1472 if(prim_classes[i] != NULL)
1473 threadReference((Object**)&prim_classes[i]);
1476 #undef ITERATE
1477 #define ITERATE(ptr) \
1478 if(CLASS_CB((Class *)ptr)->class_loader == class_loader) \
1479 markObject(ptr, mark, mark_soft_refs)
1481 void markLoaderClasses(Object *class_loader, int mark, int mark_soft_refs) {
1482 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1484 if(vmdata != NULL) {
1485 #if JAM_ON_STACK
1486 HashTable **table = ARRAY_DATA(vmdata);
1487 #else
1488 HashTable **table = (HashTable**)vmdata;
1489 #endif
1490 hashIterate((**table));
1494 #undef ITERATE
1495 #define ITERATE(ptr) threadReference((Object**)ptr)
1497 void threadLoaderClasses(Object *class_loader) {
1498 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1500 if(vmdata != NULL) {
1501 #if JAM_ON_STACK
1502 HashTable **table = ARRAY_DATA(vmdata);
1503 #else
1504 HashTable **table = (HashTable**)vmdata;
1505 #endif
1506 hashIterateP((**table));
1510 void freeClassData(Class *class) {
1511 ClassBlock *cb = CLASS_CB(class);
1512 int i;
1514 #ifdef JEM
1515 int methods_size = 0;
1516 #endif
1518 if(IS_ARRAY(cb)) {
1519 gcPendingFree(cb->name);
1520 gcPendingFree(cb->interfaces);
1521 return;
1524 gcPendingFree((void*)cb->constant_pool.type);
1525 gcPendingFree(cb->constant_pool.info);
1527 gcPendingFree(cb->interfaces);
1529 for(i = 0; i < cb->fields_count; i++) {
1530 FieldBlock *fb = &cb->fields[i];
1532 if(fb->annotations != NULL) {
1533 gcPendingFree(fb->annotations->data);
1534 gcPendingFree(fb->annotations);
1538 gcPendingFree(cb->fields);
1540 for(i = 0; i < cb->methods_count; i++) {
1541 MethodBlock *mb = &cb->methods[i];
1543 #ifdef DIRECT
1544 #ifndef JEM
1545 if(!((uintptr_t)mb->code & 0x3)) {
1546 #ifdef INLINING
1547 if(cb->state >= CLASS_LINKED)
1548 freeMethodInlinedInfo(mb);
1549 #endif
1550 gcPendingFree(mb->code);
1551 } else
1552 if(!(mb->access_flags & ACC_ABSTRACT))
1553 gcPendingFree((void*)((uintptr_t)mb->code & ~3));
1554 #else
1555 methods_size += (mb->code_size + 31) & ~31;
1556 #endif
1557 #else
1558 if(!(mb->access_flags & ACC_ABSTRACT))
1559 gcPendingFree(mb->code);
1560 #endif
1562 gcPendingFree(mb->exception_table);
1563 gcPendingFree(mb->line_no_table);
1564 gcPendingFree(mb->throw_table);
1566 if(mb->annotations != NULL) {
1567 if(mb->annotations->annotations != NULL) {
1568 gcPendingFree(mb->annotations->annotations->data);
1569 gcPendingFree(mb->annotations->annotations);
1571 if(mb->annotations->parameters != NULL) {
1572 gcPendingFree(mb->annotations->parameters->data);
1573 gcPendingFree(mb->annotations->parameters);
1575 if(mb->annotations->dft_val != NULL) {
1576 gcPendingFree(mb->annotations->dft_val->data);
1577 gcPendingFree(mb->annotations->dft_val);
1579 gcPendingFree(mb->annotations);
1583 gcPendingFree(cb->methods);
1584 gcPendingFree(cb->inner_classes);
1586 if(cb->annotations != NULL) {
1587 gcPendingFree(cb->annotations->data);
1588 gcPendingFree(cb->annotations);
1591 if(cb->state >= CLASS_LINKED) {
1592 ClassBlock *super_cb = CLASS_CB(cb->super);
1594 /* interfaces do not have a method table, or
1595 imethod table offsets */
1596 if(!IS_INTERFACE(cb)) {
1597 int spr_imthd_sze = super_cb->imethod_table_size;
1599 gcPendingFree(cb->method_table);
1600 if(cb->imethod_table_size > spr_imthd_sze)
1601 gcPendingFree(cb->imethod_table[spr_imthd_sze].offsets);
1604 gcPendingFree(cb->imethod_table);
1606 if(cb->refs_offsets_table != super_cb->refs_offsets_table)
1607 gcPendingFree(cb->refs_offsets_table);
1610 #ifdef JEM
1611 munmap(cb->methods[0].code, (methods_size + 4095) & ~4095);
1612 #endif
1615 void freeClassLoaderData(Object *class_loader) {
1616 Object *vmdata = (Object*)INST_DATA(class_loader)[ldr_vmdata_offset];
1618 if(vmdata != NULL) {
1619 #if JAM_ON_STACK
1620 HashTable **table = ARRAY_DATA(vmdata);
1621 #else
1622 HashTable **table = (HashTable**)vmdata;
1623 #endif
1624 gcFreeHashTable((**table));
1625 gcPendingFree(*table);
1629 int parseBootClassPath(char *cp_var) {
1630 char *cp, *pntr, *start;
1631 int i, j, len, max = 0;
1632 struct stat info;
1634 cp = (char*)sysMalloc(strlen(cp_var)+1);
1635 strcpy(cp, cp_var);
1637 for(i = 0, start = pntr = cp; *pntr; pntr++) {
1638 if(*pntr == ':') {
1639 if(start != pntr) {
1640 *pntr = '\0';
1641 i++;
1643 start = pntr+1;
1646 if(start != pntr)
1647 i++;
1649 bootclasspath = (BCPEntry *)sysMalloc(sizeof(BCPEntry)*i);
1651 for(j = 0, pntr = cp; i > 0; i--) {
1652 while(*pntr == ':')
1653 pntr++;
1655 start = pntr;
1656 pntr += (len = strlen(pntr))+1;
1658 if(stat(start, &info) == 0) {
1659 if(S_ISDIR(info.st_mode)) {
1660 bootclasspath[j].zip = NULL;
1661 if(len > max)
1662 max = len;
1663 } else
1664 if((bootclasspath[j].zip = processArchive(start)) == NULL)
1665 continue;
1666 bootclasspath[j++].path = start;
1670 max_cp_element_len = max;
1672 return bcp_entries = j;
1675 void setClassPath(char *cmdlne_cp) {
1676 char *env;
1677 classpath = cmdlne_cp ? cmdlne_cp :
1678 ((env = getenv("CLASSPATH")) ? env : ".");
1681 char *getClassPath() {
1682 return classpath;
1685 int filter(const struct dirent *entry) {
1686 int len = strlen(entry->d_name);
1687 const char *ext = &entry->d_name[len-4];
1689 return len >= 4 && (strcasecmp(ext, ".zip") == 0 ||
1690 strcasecmp(ext, ".jar") == 0);
1693 void scanDirForJars(char *dir) {
1694 int bootpathlen = strlen(bootpath) + 1;
1695 int dirlen = strlen(dir);
1696 struct dirent **namelist;
1697 int n;
1699 n = scandir(dir, &namelist, &filter, &alphasort);
1701 if(n >= 0) {
1702 while(--n >= 0) {
1703 char *buff;
1704 bootpathlen += strlen(namelist[n]->d_name) + dirlen + 2;
1705 buff = sysMalloc(bootpathlen);
1707 strcat(strcat(strcat(strcat(strcpy(buff, dir), "/"), namelist[n]->d_name), ":"), bootpath);
1709 sysFree(bootpath);
1710 bootpath = buff;
1711 free(namelist[n]);
1713 free(namelist);
1717 void scanDirsForJars(char *directories) {
1718 int dirslen = strlen(directories);
1719 char *pntr, *end, *dirs = sysMalloc(dirslen + 1);
1720 strcpy(dirs, directories);
1722 for(end = pntr = &dirs[dirslen]; pntr != dirs; pntr--) {
1723 if(*pntr == ':') {
1724 char *start = pntr + 1;
1725 if(start != end)
1726 scanDirForJars(start);
1728 *(end = pntr) = '\0';
1732 if(end != dirs)
1733 scanDirForJars(dirs);
1735 sysFree(dirs);
1738 char *setBootClassPath(char *cmdlne_bcp, char bootpathopt) {
1739 char *endorsed_dirs;
1741 if(cmdlne_bcp)
1742 switch(bootpathopt) {
1743 case 'a':
1744 case 'p':
1745 bootpath = sysMalloc(strlen(DFLT_BCP) + strlen(cmdlne_bcp) + 2);
1746 if(bootpathopt == 'a')
1747 strcat(strcat(strcpy(bootpath, DFLT_BCP), ":"), cmdlne_bcp);
1748 else
1749 strcat(strcat(strcpy(bootpath, cmdlne_bcp), ":"), DFLT_BCP);
1750 break;
1752 case 'c':
1753 bootpath = sysMalloc(strlen(JAMVM_CLASSES) + strlen(cmdlne_bcp) + 2);
1754 strcat(strcat(strcpy(bootpath, JAMVM_CLASSES), ":"), cmdlne_bcp);
1755 break;
1757 case 'v':
1758 bootpath = sysMalloc(strlen(CLASSPATH_CLASSES) + strlen(cmdlne_bcp) + 2);
1759 strcat(strcat(strcpy(bootpath, cmdlne_bcp), ":"), CLASSPATH_CLASSES);
1760 break;
1762 default:
1763 bootpath = sysMalloc(strlen(cmdlne_bcp) + 1);
1764 strcpy(bootpath, cmdlne_bcp);
1766 else {
1767 char *env = getenv("BOOTCLASSPATH");
1768 char *path = env ? env : DFLT_BCP;
1769 bootpath = sysMalloc(strlen(path) + 1);
1770 strcpy(bootpath, path);
1773 endorsed_dirs = getCommandLineProperty("java.endorsed.dirs");
1774 if(endorsed_dirs == NULL)
1775 endorsed_dirs = INSTALL_DIR"/share/jamvm/endorsed";
1777 scanDirsForJars(endorsed_dirs);
1779 return bootpath;
1782 char *getBootClassPath() {
1783 return bootpath;
1786 int bootClassPathSize() {
1787 return bcp_entries;
1790 Object *bootClassPathResource(char *filename, int index) {
1791 if(index < bcp_entries) {
1792 /* Alloc enough space for Jar file URL -- jar:file://<path>!/<filename> */
1793 char buff[strlen(filename) + strlen(bootclasspath[index].path) + 14];
1795 if(bootclasspath[index].zip) {
1796 while(*filename == '/')
1797 filename++;
1799 if(!findArchiveDirEntry(filename, bootclasspath[index].zip))
1800 return NULL;
1802 sprintf(buff, "jar:file://%s!/%s", bootclasspath[index].path, filename);
1803 } else {
1804 struct stat info;
1806 sprintf(buff, "file://%s/%s", bootclasspath[index].path, filename);
1807 if(stat(&buff[7], &info) != 0 || S_ISDIR(info.st_mode))
1808 return NULL;
1811 return createString(buff);
1814 return NULL;
1817 void initialiseClass(InitArgs *args) {
1818 char *bcp = setBootClassPath(args->bootpath, args->bootpathopt);
1820 if(!(bcp && parseBootClassPath(bcp))) {
1821 jam_fprintf(stderr, "bootclasspath is empty!\n");
1822 exitVM(1);
1825 verbose = args->verboseclass;
1826 setClassPath(args->classpath);
1828 /* Init hash table, and create lock */
1829 initHashTable(loaded_classes, INITSZE, TRUE);
1831 /* Register the address of where the java.lang.Class ref _will_ be */
1832 registerStaticClassRef(&java_lang_Class);