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.
27 #include <sys/types.h>
41 #define PREPARE(ptr) ptr
42 #define SCAVENGE(ptr) FALSE
43 #define FOUND(ptr) ptr
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
{
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;
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
;
79 /* hash table containing classes loaded by the boot loader and
80 internally created arrays */
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
) {
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
;
105 Object
*vmdata
= (Object
*)INST_DATA(class_loader
)[ldr_vmdata_offset
];
108 HashTable
**array_data
;
110 if((vmdata
= allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT
: T_LONG
, 1)) == NULL
)
113 table
= sysMalloc(sizeof(HashTable
));
114 initHashTable((*table
), INITSZE
, TRUE
);
116 array_data
= ARRAY_DATA(vmdata
);
119 INST_DATA(class_loader
)[ldr_vmdata_offset
] = (uintptr_t)vmdata
;
121 INST_DATA(class_loader
)[ldr_vmdata_offset
] = (uintptr_t)ARRAY_DATA(vmdata
);
125 table
= *(HashTable
**)ARRAY_DATA(vmdata
);
127 table
= *(HashTable
**)vmdata
;
132 /* Add if absent, no scavenge, locked */
133 findHashEntry((*table
), class, entry
, TRUE
, FALSE
, TRUE
);
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
;
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
;
158 ConstantPool
*constant_pool
;
159 ClassBlock
*classblock
;
160 Class
*class, *found
;
164 //the total size for all methods in this class
165 int methods_size
= 0;
168 READ_U4(magic
, ptr
, len
);
170 if(magic
!= 0xcafebabe) {
171 signalException("java/lang/ClassFormatError", "bad magic");
175 READ_U2(minor_version
, ptr
, len
);
176 READ_U2(major_version
, ptr
, len
);
178 if((class = allocClass()) == 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
++) {
192 READ_U1(tag
, ptr
, len
);
193 CP_TYPE(constant_pool
,i
) = tag
;
197 case CONSTANT_String
:
198 READ_INDEX(CP_INFO(constant_pool
,i
), ptr
, len
);
201 case CONSTANT_Fieldref
:
202 case CONSTANT_Methodref
:
203 case CONSTANT_NameAndType
:
204 case CONSTANT_InterfaceMethodref
:
208 READ_INDEX(idx1
, ptr
, len
);
209 READ_INDEX(idx2
, ptr
, len
);
210 CP_INFO(constant_pool
,i
) = (idx2
<<16)+idx1
;
214 case CONSTANT_Integer
:
215 READ_U4(CP_INFO(constant_pool
,i
), ptr
, len
);
222 READ_U4(val
, ptr
, len
);
223 CP_INFO(constant_pool
,i
) = FLOAT_CONST(val
);
228 READ_U8(*(u8
*)&(CP_INFO(constant_pool
,i
)), ptr
, len
);
229 CP_TYPE(constant_pool
,++i
) = 0;
232 case CONSTANT_Double
:
233 READ_DBL(*(u8
*)&(CP_INFO(constant_pool
,i
)), ptr
, len
);
234 CP_TYPE(constant_pool
,++i
) = 0;
242 READ_U2(length
, ptr
, len
);
243 buff
= sysMalloc(length
+1);
245 memcpy(buff
, ptr
, length
);
249 CP_INFO(constant_pool
,i
) = (uintptr_t) (utf8
= findUtf8String(buff
));
258 signalException("java/lang/ClassFormatError", "bad constant pool tag");
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");
279 if(strcmp(classblock
->name
, "java/lang/Object") == 0) {
280 READ_U2(super_idx
, ptr
, len
);
282 signalException("java/lang/ClassFormatError", "Object has super");
285 classblock
->super_name
= NULL
;
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
++) {
300 READ_TYPE_INDEX(index
, constant_pool
, CONSTANT_Class
, ptr
, len
);
301 interfaces
[i
] = resolveClass(class, index
, FALSE
);
302 if(exceptionOccurred())
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
--) {
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
);
335 if(strcmp(attr_name
, "Signature") == 0) {
337 READ_TYPE_INDEX(signature_idx
, constant_pool
, CONSTANT_Utf8
, ptr
, len
);
338 classblock
->fields
[i
].signature
= CP_UTF8(constant_pool
, signature_idx
);
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
);
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
--) {
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) {
387 READ_U2(method
->max_stack
, ptr
, len
);
388 READ_U2(method
->max_locals
, ptr
, len
);
390 READ_U4(code_length
, ptr
, len
);
392 method
->code
= (char *)sysMalloc(code_length
);
393 memcpy(method
->code
, ptr
, code_length
);
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;
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
--) {
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
);
441 if(strcmp(attr_name
, "Exceptions") == 0) {
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
);
450 if(strcmp(attr_name
, "Signature") == 0) {
452 READ_TYPE_INDEX(signature_idx
, constant_pool
, CONSTANT_Utf8
, ptr
, len
);
453 method
->signature
= CP_UTF8(constant_pool
, signature_idx
);
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
);
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
);
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
);
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
--) {
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) {
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
);
500 if(strcmp(attr_name
, "InnerClasses") == 0) {
502 READ_U2(size
, ptr
, len
);
504 u2 inner_classes
[size
];
505 for(j
= 0; j
< size
; j
++) {
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
) {
513 /* A member class doesn't have an EnclosingMethod attribute, so set
514 the enclosing class to be the same as the declaring class */
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
);
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
));
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
);
541 if(strcmp(attr_name
, "Signature") == 0) {
543 READ_TYPE_INDEX(signature_idx
, constant_pool
, CONSTANT_Utf8
, ptr
, len
);
544 classblock
->signature
= CP_UTF8(constant_pool
, signature_idx
);
546 if(strcmp(attr_name
, "Synthetic") == 0)
547 classblock
->access_flags
|= ACC_SYNTHETIC
;
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
);
559 classblock
->super
= super_idx
? resolveClass(class, super_idx
, FALSE
) : NULL
;
561 if(exceptionOccurred())
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
);
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);
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");
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
)
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
)
629 classblock
->element_class
= CLASS_CB(comp_class
)->element_class
;
630 classblock
->dim
= CLASS_CB(comp_class
)->dim
+ 1;
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
);
639 classblock
->element_class
= findPrimitiveClass(classname
[1]);
641 if(classblock
->element_class
== NULL
)
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
;
658 if((found
= addClassToHash(class, classblock
->class_loader
)) == class) {
660 jam_printf("[Created array class %s]\n", classname
);
665 classblock
->flags
= CLASS_CLASH
;
670 createPrimClass(char *classname
, int index
) {
672 ClassBlock
*classblock
;
674 if((class = allocClass()) == 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
;
684 lockHashTable(loaded_classes
);
685 if(prim_classes
[index
] == NULL
)
686 prim_classes
[index
] = class;
687 unlockHashTable(loaded_classes
);
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) \
710 for(i = 0; i < methods_count; i++, methods++) { \
711 if((methods->access_flags & (ACC_STATIC | ACC_PRIVATE)) || \
712 (methods->name[0] == '<')) \
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
;
736 MethodBlock
*finalizer
;
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
)
747 objectLock((Object
*)class);
749 if(cb
->state
>= CLASS_LINKED
)
753 jam_printf("[Linking class %s]\n", cb
->name
);
756 ClassBlock
*super_cb
= CLASS_CB(super
);
757 if(super_cb
->state
< CLASS_LINKED
)
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
;
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;
780 fb
->static_value
= 0;
782 /* calc field offset */
783 if((*fb
->type
== 'L') || (*fb
->type
== '['))
784 fb
->offset
= field_offset
++;
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'))
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 */
811 char *sig
= mb
->type
;
812 SCAN_SIG(sig
, count
+=2, count
++);
814 if(mb
->access_flags
& ACC_STATIC
)
815 mb
->args_count
= count
;
817 mb
->args_count
= count
+ 1;
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
;
844 /* Set the bottom bit of the pointer to indicate the
845 method is unprepared */
846 mb
->code
= ((char*)mb
->code
) + 1;
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] == '<'))
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
;
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 */
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;
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] == '<'))
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
;
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
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)
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
);
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 */
997 fillinMTable(method_table
, mb
, cb
->methods_count
);
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
;
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");
1054 for(fb
= cb
->fields
, i
= 0; i
< cb
->fields_count
; i
++,fb
++)
1055 if(fb
->offset
> ref_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
;
1063 cb
->flags
|= REFERENCE
;
1066 if(spr_flags
& REFERENCE
) {
1067 if(strcmp(cb
->name
, "java/lang/ref/SoftReference") == 0)
1068 cb
->flags
|= SOFT_REFERENCE
;
1070 if(strcmp(cb
->name
, "java/lang/ref/WeakReference") == 0)
1071 cb
->flags
|= WEAK_REFERENCE
;
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");
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
) {
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
;
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
;
1113 cb
->refs_offsets_size
= spr_rfs_offsts_sze
;
1114 cb
->refs_offsets_table
= spr_rfs_offsts_tbl
;
1117 cb
->state
= CLASS_LINKED
;
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
;
1131 if(cb
->state
>= CLASS_INITED
)
1135 objectLock((Object
*)class);
1137 while(cb
->state
== CLASS_INITING
)
1138 if(cb
->initing_tid
== threadSelf()->id
)
1141 objectWait((Object
*)class, 0, 0);
1143 if(cb
->state
>= CLASS_INITED
)
1146 if(cb
->state
== CLASS_BAD
) {
1147 objectUnlock((Object
*)class);
1148 signalException("java/lang/NoClassDefFoundError", cb
->name
);
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
;
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
));
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
;
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
);
1199 setException(excep
);
1201 objectLock((Object
*)class);
1202 cb
->state
= CLASS_BAD
;
1204 objectLock((Object
*)class);
1205 cb
->state
= CLASS_INITED
;
1209 objectNotifyAll((Object
*)class);
1212 objectUnlock((Object
*)class);
1216 char *findFileEntry(char *path
, int *file_len
) {
1221 if((fd
= fopen(path
, "r")) == 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
);
1232 if(read_len
== *file_len
)
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
;
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
);
1254 data
= findFileEntry(strcat(strcpy(buff
, bootclasspath
[i
].path
), filename
), &file_len
);
1257 signalException("java/lang/NoClassDefFoundError", classname
);
1261 class = defineClass(classname
, data
, 0, file_len
, NULL
);
1264 if(verbose
&& class)
1265 jam_printf("[Loaded %s from %s]\n", classname
, bootclasspath
[i
-1].path
);
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
) {
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
;
1292 Object
*vmdata
= (Object
*)INST_DATA(class_loader
)[ldr_vmdata_offset
];
1298 table
= *(HashTable
**)ARRAY_DATA(vmdata
);
1300 table
= *(HashTable
**)vmdata
;
1304 /* Do not add if absent, no scavenge, locked */
1305 findHashEntry((*table
), classname
, class, FALSE
, FALSE
, TRUE
);
1310 Class
*findSystemClass0(char *classname
) {
1311 Class
*class = findHashedClass(classname
, NULL
);
1314 class = loadSystemClass(classname
);
1316 if(!exceptionOccurred())
1322 Class
*findSystemClass(char *classname
) {
1323 Class
*class = findSystemClass0(classname
);
1325 if(!exceptionOccurred())
1331 Class
*findArrayClassFromClassLoader(char *classname
, Object
*class_loader
) {
1332 Class
*class = findHashedClass(classname
, class_loader
);
1335 if((class = createArrayClass(classname
, class_loader
)) != NULL
)
1336 addInitiatingLoaderToClass(class_loader
, class);
1341 Class
*findPrimitiveClass(char prim_type
) {
1348 classname
= "boolean"; index
= 1;
1351 classname
= "byte"; index
= 2;
1354 classname
= "char"; index
= 3;
1357 classname
= "short"; index
= 4;
1360 classname
= "int"; index
= 5;
1363 classname
= "float"; index
= 6;
1366 classname
= "long"; index
= 7;
1369 classname
= "double"; index
= 8;
1372 classname
= "void"; index
= 0;
1375 signalException("java/lang/NoClassDefFoundError", NULL
);
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
);
1388 char *dot_name
= slash2dots(classname
);
1389 Object
*string
= createString(dot_name
);
1396 if(loadClass_mtbl_idx
== -1) {
1397 MethodBlock
*mb
= lookupMethod(loader
->class, "loadClass",
1398 "(Ljava/lang/String;)Ljava/lang/Class;");
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())) {
1410 signalChainedException("java/lang/NoClassDefFoundError", classname
, excep
);
1414 addInitiatingLoaderToClass(loader
, class);
1416 if(verbose
&& (CLASS_CB(class)->class_loader
== loader
))
1417 jam_printf("[Loaded %s]\n", classname
);
1422 Class
*findClassFromClassLoader(char *classname
, Object
*loader
) {
1423 if(*classname
== '[')
1424 return findArrayClassFromClassLoader(classname
, loader
);
1427 return findNonArrayClassFromClassLoader(classname
, loader
);
1429 return findSystemClass0(classname
);
1432 Object
*getSystemClassLoader() {
1433 Class
*class_loader
= findSystemClass("java/lang/ClassLoader");
1435 if(!exceptionOccurred()) {
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
;
1449 /* gc support for marking classes */
1451 #define ITERATE(ptr) markRoot(ptr)
1453 void markBootClasses() {
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
]);
1464 #define ITERATE(ptr) threadReference((Object**)ptr)
1466 void threadBootClasses() {
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
]);
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
) {
1486 HashTable
**table
= ARRAY_DATA(vmdata
);
1488 HashTable
**table
= (HashTable
**)vmdata
;
1490 hashIterate((**table
));
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
) {
1502 HashTable
**table
= ARRAY_DATA(vmdata
);
1504 HashTable
**table
= (HashTable
**)vmdata
;
1506 hashIterateP((**table
));
1510 void freeClassData(Class
*class) {
1511 ClassBlock
*cb
= CLASS_CB(class);
1515 int methods_size
= 0;
1519 gcPendingFree(cb
->name
);
1520 gcPendingFree(cb
->interfaces
);
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
];
1545 if(!((uintptr_t)mb
->code
& 0x3)) {
1547 if(cb
->state
>= CLASS_LINKED
)
1548 freeMethodInlinedInfo(mb
);
1550 gcPendingFree(mb
->code
);
1552 if(!(mb
->access_flags
& ACC_ABSTRACT
))
1553 gcPendingFree((void*)((uintptr_t)mb
->code
& ~3));
1555 methods_size
+= (mb
->code_size
+ 31) & ~31;
1558 if(!(mb
->access_flags
& ACC_ABSTRACT
))
1559 gcPendingFree(mb
->code
);
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
);
1611 munmap(cb
->methods
[0].code
, (methods_size
+ 4095) & ~4095);
1615 void freeClassLoaderData(Object
*class_loader
) {
1616 Object
*vmdata
= (Object
*)INST_DATA(class_loader
)[ldr_vmdata_offset
];
1618 if(vmdata
!= NULL
) {
1620 HashTable
**table
= ARRAY_DATA(vmdata
);
1622 HashTable
**table
= (HashTable
**)vmdata
;
1624 gcFreeHashTable((**table
));
1625 gcPendingFree(*table
);
1629 int parseBootClassPath(char *cp_var
) {
1630 char *cp
, *pntr
, *start
;
1631 int i
, j
, len
, max
= 0;
1634 cp
= (char*)sysMalloc(strlen(cp_var
)+1);
1637 for(i
= 0, start
= pntr
= cp
; *pntr
; pntr
++) {
1649 bootclasspath
= (BCPEntry
*)sysMalloc(sizeof(BCPEntry
)*i
);
1651 for(j
= 0, pntr
= cp
; i
> 0; i
--) {
1656 pntr
+= (len
= strlen(pntr
))+1;
1658 if(stat(start
, &info
) == 0) {
1659 if(S_ISDIR(info
.st_mode
)) {
1660 bootclasspath
[j
].zip
= NULL
;
1664 if((bootclasspath
[j
].zip
= processArchive(start
)) == NULL
)
1666 bootclasspath
[j
++].path
= start
;
1670 max_cp_element_len
= max
;
1672 return bcp_entries
= j
;
1675 void setClassPath(char *cmdlne_cp
) {
1677 classpath
= cmdlne_cp
? cmdlne_cp
:
1678 ((env
= getenv("CLASSPATH")) ? env
: ".");
1681 char *getClassPath() {
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
;
1699 n
= scandir(dir
, &namelist
, &filter
, &alphasort
);
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
);
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
--) {
1724 char *start
= pntr
+ 1;
1726 scanDirForJars(start
);
1728 *(end
= pntr
) = '\0';
1733 scanDirForJars(dirs
);
1738 char *setBootClassPath(char *cmdlne_bcp
, char bootpathopt
) {
1739 char *endorsed_dirs
;
1742 switch(bootpathopt
) {
1745 bootpath
= sysMalloc(strlen(DFLT_BCP
) + strlen(cmdlne_bcp
) + 2);
1746 if(bootpathopt
== 'a')
1747 strcat(strcat(strcpy(bootpath
, DFLT_BCP
), ":"), cmdlne_bcp
);
1749 strcat(strcat(strcpy(bootpath
, cmdlne_bcp
), ":"), DFLT_BCP
);
1753 bootpath
= sysMalloc(strlen(JAMVM_CLASSES
) + strlen(cmdlne_bcp
) + 2);
1754 strcat(strcat(strcpy(bootpath
, JAMVM_CLASSES
), ":"), cmdlne_bcp
);
1758 bootpath
= sysMalloc(strlen(CLASSPATH_CLASSES
) + strlen(cmdlne_bcp
) + 2);
1759 strcat(strcat(strcpy(bootpath
, cmdlne_bcp
), ":"), CLASSPATH_CLASSES
);
1763 bootpath
= sysMalloc(strlen(cmdlne_bcp
) + 1);
1764 strcpy(bootpath
, cmdlne_bcp
);
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
);
1782 char *getBootClassPath() {
1786 int bootClassPathSize() {
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
== '/')
1799 if(!findArchiveDirEntry(filename
, bootclasspath
[index
].zip
))
1802 sprintf(buff
, "jar:file://%s!/%s", bootclasspath
[index
].path
, filename
);
1806 sprintf(buff
, "file://%s/%s", bootclasspath
[index
].path
, filename
);
1807 if(stat(&buff
[7], &info
) != 0 || S_ISDIR(info
.st_mode
))
1811 return createString(buff
);
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");
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
);