From cb26d8cadfe884a26a80f759496b62b44bd6ab0e Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 29 Dec 2024 07:14:26 -0600 Subject: [PATCH] implement superclass instance field lookup --- c/class_resolver.c | 148 ++++++++++++++++++++++++++--------- c/class_resolver.h | 1 + c/debug_class_file.c | 9 ++- c/execute.c | 6 +- c/hash_table.c | 8 +- c/native.c | 2 + example/DreamcastVideo2.java | 5 +- p/InheritanceTest.java | 64 +++++++++++++++ 8 files changed, 196 insertions(+), 47 deletions(-) create mode 100644 p/InheritanceTest.java diff --git a/c/class_resolver.c b/c/class_resolver.c index cacd8a4..561f331 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -11,19 +11,6 @@ #include "printf.h" #include "field_size.h" -static void class_resolver_create_interfaces_hash_table(struct class_entry * class_entry) -{ - /* - struct class_file * class_file = class_entry->class_file; - - uint32_t interfaces_hash_table_size = (sizeof (struct hash_table_entry)) * class_file->interfaces_count * 3 / 2; - struct hash_table_entry * interfaces_hash_table = malloc_class_arena(interfaces_hash_table_size); - for (int i = 0; i < class_file->interfaces_count; i++) { - - } - */ -} - static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) { struct constant * field_descriptor_constant = &class_file->constant_pool[field_info->descriptor_index - 1]; @@ -33,37 +20,109 @@ static int field_info_field_size(struct class_file * class_file, struct field_in return field_size(field_descriptor_constant->utf8.bytes[0]); } -static int32_t class_resolver_create_fields_hash_table(struct class_entry * class_entry) +static int32_t count_superclass_instance_fields(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + struct class_entry * class_entry) { - struct class_file * class_file = class_entry->class_file; - int fields_hash_table_length = hash_table_next_power_of_two(class_file->fields_count * 2); + struct class_entry * subclass_entry = class_entry; + + int instance_field_count = 0; + while (class_entry->class_file->super_class != 0) { + class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length, + class_hash_table, + class_entry, + class_entry->class_file->super_class); + assert(class_entry != nullptr); + + for (int i = 0; i < class_entry->class_file->fields_count; i++) { + struct field_info * field_info = &class_entry->class_file->fields[i]; + if (!(field_info->access_flags & FIELD_ACC_STATIC)) { + instance_field_count += 1; + } + } + } + + struct constant * class_constant = &subclass_entry->class_file->constant_pool[subclass_entry->class_file->this_class - 1]; + assert(class_constant->tag == CONSTANT_Class); + struct constant * class_name_constant = &subclass_entry->class_file->constant_pool[class_constant->class.name_index - 1]; + assert(class_name_constant->tag == CONSTANT_Utf8); + debugf("count_superclass_instance_fields: "); + print_utf8_string(class_name_constant); + debugf(": %d\n", instance_field_count); + + return instance_field_count; +} + +static void add_superclass_instance_fields(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + int fields_hash_table_length, + struct hash_table_entry * fields_hash_table, + struct class_entry * class_entry, + struct field_entry * field_entry, + int instance_index) +{ + while (class_entry->class_file->super_class != 0) { + class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length, + class_hash_table, + class_entry, + class_entry->class_file->super_class); + assert(class_entry != nullptr); + + for (int i = 0; i < class_entry->class_file->fields_count; i++) { + struct field_info * field_info = &class_entry->class_file->fields[i]; + if (!(field_info->access_flags & FIELD_ACC_STATIC)) { + field_entry[i].instance_index = instance_index; + field_entry[i].field_info = field_info; + instance_index += field_info_field_size(class_entry->class_file, field_info); + + struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1]; + assert(name_constant->tag == CONSTANT_Utf8); + debugf("hash table entry for field: "); + print_utf8_string(name_constant); + debugf(": %d\n", instance_index); + hash_table_add(fields_hash_table_length, + fields_hash_table, + name_constant->utf8.bytes, + name_constant->utf8.length, + (void *)&field_entry[i]); + } + } + } +} + +static int32_t class_resolver_create_fields_hash_table(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + struct class_entry * class_entry) +{ + int total_fields_count = class_entry->class_file->fields_count + count_superclass_instance_fields(class_hash_table_length, + class_hash_table, + class_entry); + int fields_hash_table_length = hash_table_next_power_of_two(class_entry->class_file->fields_count * 2); uint32_t fields_hash_table_size = (sizeof (struct hash_table_entry)) * fields_hash_table_length; struct hash_table_entry * fields_hash_table = malloc_class_arena(fields_hash_table_size); - uint32_t field_entry_size = (sizeof (struct field_entry)) * class_file->fields_count; + + uint32_t field_entry_size = (sizeof (struct field_entry)) * total_fields_count; struct field_entry * field_entry = malloc_class_arena(field_entry_size); int32_t static_index = 0; int32_t instance_index = 0; - for (int i = 0; i < class_file->fields_count; i++) { - u2 name_index = class_file->fields[i].name_index; - struct constant * name_constant = &class_file->constant_pool[name_index - 1]; - assert(name_constant->tag == CONSTANT_Utf8); - debugf("hash table entry for field: "); - print_utf8_string(name_constant); - debugf("\n"); - - struct field_info * field_info = &class_file->fields[i]; - + for (int i = 0; i < class_entry->class_file->fields_count; i++) { + struct field_info * field_info = &class_entry->class_file->fields[i]; if (field_info->access_flags & FIELD_ACC_STATIC) { field_entry[i].static_index = static_index; - static_index += field_info_field_size(class_file, field_info); + static_index += field_info_field_size(class_entry->class_file, field_info); } else { field_entry[i].instance_index = instance_index; - instance_index += field_info_field_size(class_file, field_info); + instance_index += field_info_field_size(class_entry->class_file, field_info); } field_entry[i].field_info = field_info; + struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1]; + assert(name_constant->tag == CONSTANT_Utf8); + debugf("hash table entry for field: "); + print_utf8_string(name_constant); + debugf(": %d\n", i); hash_table_add(fields_hash_table_length, fields_hash_table, name_constant->utf8.bytes, @@ -73,6 +132,15 @@ static int32_t class_resolver_create_fields_hash_table(struct class_entry * clas class_entry->fields.length = fields_hash_table_length; class_entry->fields.entry = fields_hash_table; + class_entry->instance_fields_count = instance_index; + + add_superclass_instance_fields(class_hash_table_length, + class_hash_table, + fields_hash_table_length, + fields_hash_table, + class_entry, + &field_entry[class_entry->class_file->fields_count], + instance_index); return static_index; } @@ -142,6 +210,7 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buff uint32_t class_entry_size = (sizeof (struct class_entry)) * length; struct class_entry * class_entry = malloc_class_arena(class_entry_size); + // populate class_hash_table first, to allow for superclass lookups for (int i = 0; i < length; i++) { struct class_file * class_file = class_file_parse(buffers[i]); @@ -154,7 +223,6 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buff assert(class_constant->tag == CONSTANT_Class); struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1]; assert(class_name_constant->tag == CONSTANT_Utf8); - debugf("hash table entry for class: "); print_utf8_string(class_name_constant); debugf("\n"); @@ -165,22 +233,24 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buff class_name_constant->utf8.length, &class_entry[i]); - // make hash table for interfaces - class_resolver_create_interfaces_hash_table(&class_entry[i]); - - // make hash table for fields - int32_t static_field_count = class_resolver_create_fields_hash_table(&class_entry[i]); - // make hash table for methods class_resolver_create_methods_hash_table(&class_entry[i]); - // allocate static fields - class_resolver_allocate_static_fields(&class_entry[i], static_field_count); - // allocate attribute_entry class_resolver_allocate_attribute_entry(&class_entry[i]); }; + // these functions may reference class_hash_table for superclass lookups + for (int i = 0; i < length; i++) { + // make hash table for fields + int32_t static_field_count = class_resolver_create_fields_hash_table(class_hash_table_length, + class_hash_table, + &class_entry[i]); + + // allocate static fields + class_resolver_allocate_static_fields(&class_entry[i], static_field_count); + } + *hash_table_length = class_hash_table_length; return class_hash_table; diff --git a/c/class_resolver.h b/c/class_resolver.h index c30619a..1da8b21 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -31,6 +31,7 @@ struct class_entry { enum initialization_state initialization_state; union attribute_entry * attribute_entry; int32_t * static_fields; + int32_t instance_fields_count; struct { int length; diff --git a/c/debug_class_file.c b/c/debug_class_file.c index 847583c..80a161a 100644 --- a/c/debug_class_file.c +++ b/c/debug_class_file.c @@ -232,7 +232,14 @@ void print_class_file(struct class_file * class_file) debugf("interfaces:\n"); for (int i = 0; i < class_file->interfaces_count; i++) { - debugf("% 3d: %d\n", i + 1, class_file->interfaces[i]); + debugf(" interface %3d:\n", i); + int interface_index = class_file->interfaces[i]; + debugs(" "); + struct constant * class_constant = &class_file->constant_pool[interface_index - 1]; + print_constant(class_constant); + debugs(" "); + struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1]; + print_constant(class_name_constant); } debugf("fields_count %d\n", class_file->fields_count); diff --git a/c/execute.c b/c/execute.c index b75cef7..e6d7da8 100644 --- a/c/execute.c +++ b/c/execute.c @@ -10,7 +10,7 @@ void op_aaload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assertvm(vm, arrayref[0] > 0 && index < arrayref[0]); + assert(arrayref[0] > 0 && index < arrayref[0]); uint32_t * referencearray = (uint32_t *)&arrayref[1]; uint32_t value = referencearray[index]; operand_stack_push_u32(vm->current_frame, value); @@ -684,7 +684,7 @@ void op_getfield(struct vm * vm, uint32_t index) &field_entry, &field_descriptor_constant); - debugf("putfield instance_index %d\n", field_entry->instance_index); + debugf("getfield instance_index %d\n", field_entry->instance_index); int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame); assert(objectref != nullptr); @@ -1684,7 +1684,7 @@ void op_new(struct vm * vm, uint32_t index) initialized to their default initial values (§2.3, §2.4). The objectref, a reference to the instance, is pushed onto the operand stack. */ - int fields_count = class_entry->class_file->fields_count; + int fields_count = class_entry->instance_fields_count; int32_t * objectref = memory_allocate(fields_count * 2 * 4 + 4); assert(objectref != nullptr); objectref[0] = (int32_t)class_entry; diff --git a/c/hash_table.c b/c/hash_table.c index 05a0791..3b8fa59 100644 --- a/c/hash_table.c +++ b/c/hash_table.c @@ -79,7 +79,9 @@ struct hash_table_entry * hash_table_find(int hash_table_length, const uint8_t * key, int key_length) { - assert(hash_table_length != 0); + if (hash_table_length == 0) + return nullptr; + assert((hash_table_length & (hash_table_length - 1)) == 0); uint32_t hash = fnv_1(fnv_offset_basis, key, key_length) & (hash_table_length - 1); struct hash_table_entry * e = &entry[hash]; @@ -151,7 +153,9 @@ struct hash_table_entry * hash_table_find2(int hash_table_length, const uint8_t * key2, int key2_length) { - assert(hash_table_length != 0); + if (hash_table_length == 0) + return nullptr; + assert((hash_table_length & (hash_table_length - 1)) == 0); uint32_t hash = fnv_offset_basis; hash = fnv_1(hash, key1, key1_length); diff --git a/c/native.c b/c/native.c index f464758..763c2e0 100644 --- a/c/native.c +++ b/c/native.c @@ -118,6 +118,8 @@ uint32_t java_misc_resource_getresource_1(uint32_t * args) uint32_t resource = find_resource(name, name_length); return resource; #else + (void)name; + (void)name_length; return 0; #endif } diff --git a/example/DreamcastVideo2.java b/example/DreamcastVideo2.java index 8df3640..46bf2ee 100644 --- a/example/DreamcastVideo2.java +++ b/example/DreamcastVideo2.java @@ -199,7 +199,7 @@ class DreamcastVideo2 { Memory.putSQ1(vt0, MemoryMap.ta_fifo_polygon_converter); vt0.parameter_control_word = TAParameter.para_control__para_type__vertex_parameter - | TAParameter.para_control__end_of_strip; + | TAParameter.para_control__end_of_strip; vt0.x = quad[2].x; vt0.y = quad[2].y; vt0.u = quad_uv[2].x; @@ -293,7 +293,8 @@ class DreamcastVideo2 { framebuffer_width); Core.wait_end_of_render_tsp(); - while ((CoreBits.spg_status__vsync(Memory.getU4(Holly.SPG_STATUS)) != 0)); + while ((CoreBits.spg_status__vsync(Memory.getU4(Holly.SPG_STATUS)) == 0)); + while (!(CoreBits.spg_status__vsync(Memory.getU4(Holly.SPG_STATUS)) == 0)); Core.fb_r_enable(); Memory.putU4(Holly.FB_R_SOF1, TextureMemoryAllocation.framebuffer_start[0]); } diff --git a/p/InheritanceTest.java b/p/InheritanceTest.java new file mode 100644 index 0000000..7a6ce1e --- /dev/null +++ b/p/InheritanceTest.java @@ -0,0 +1,64 @@ +package p; + +class A { + int egg; + static int baz = 3; + static int bleh = 4; + + /* + public int foo(int a, int b) { + return a + b; + } + */ +} + +class B extends A { + static int baz = 5; + int horse; + + /* + public int bar(int a) { + return a * egg; + } + */ +} + +class InheritanceTest { + static int test() { + B b = new B(); + b.egg = 2; + //return b.bar(b.foo(4, 3)); + + return B.baz * A.baz; + } + + static void static_test() { + System.out.println("A:"); + System.out.println(A.baz); + System.out.println(A.bleh); + System.out.println("B:"); + System.out.println(B.baz); + System.out.println(B.bleh); + } + + static int instance_test() { + B b = new B(); + b.egg = 1; + b.horse = 2; + + System.out.println(b.egg); + System.out.println(b.horse); + + b.egg = 3; + b.horse = 4; + + System.out.println(b.egg); + System.out.println(b.horse); + + return b.egg * b.horse; + } + + public static void main() { + instance_test(); + } +}