implement superclass method lookup

This commit is contained in:
Zack Buhman 2024-12-29 08:48:10 -06:00
parent cb26d8cadf
commit b6da4ecea7
9 changed files with 152 additions and 85 deletions

View File

@ -10,6 +10,7 @@
#include "memory_allocator.h" #include "memory_allocator.h"
#include "printf.h" #include "printf.h"
#include "field_size.h" #include "field_size.h"
#include "debug.h"
static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) static int field_info_field_size(struct class_file * class_file, struct field_info * field_info)
{ {
@ -328,7 +329,7 @@ struct field_entry * class_resolver_lookup_field_from_fieldref_index(int fields_
int fieldref_index) int fieldref_index)
{ {
if (class_entry->attribute_entry[fieldref_index - 1].field_entry != nullptr) { if (class_entry->attribute_entry[fieldref_index - 1].field_entry != nullptr) {
debugf("class_resolver_lookup_method_from_fieldref_index %d: [cached]\n", fieldref_index); debugf("class_resolver_lookup_field_from_fieldref_index %d: [cached]\n", fieldref_index);
return class_entry->attribute_entry[fieldref_index - 1].field_entry; return class_entry->attribute_entry[fieldref_index - 1].field_entry;
} }
@ -381,44 +382,71 @@ struct method_info * class_resolver_lookup_method(int methods_hash_table_length,
return (struct method_info *)e->value; return (struct method_info *)e->value;
} }
struct method_info * class_resolver_lookup_method_from_methodref_index(int methods_hash_table_length, struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length,
struct hash_table_entry * methods_hash_table, struct hash_table_entry * class_hash_table,
struct class_entry * class_entry, int32_t methodref_index,
int methodref_index) struct class_entry * original_class_entry)
{ {
if (class_entry->attribute_entry[methodref_index - 1].method_info != nullptr) { if (original_class_entry->attribute_entry[methodref_index - 1].method_entry != nullptr) {
debugf("class_resolver_lookup_method_from_methodref_index %d: [cached]\n", methodref_index); debugf("class_resolver_lookup_method_from_methodref_index %d: [cached]\n", methodref_index);
return class_entry->attribute_entry[methodref_index - 1].method_info; return original_class_entry->attribute_entry[methodref_index - 1].method_entry;
} }
struct constant * methodref_constant = &class_entry->class_file->constant_pool[methodref_index - 1]; struct constant * methodref_constant = &original_class_entry->class_file->constant_pool[methodref_index - 1];
#ifdef DEBUG
assert(methodref_constant->tag == CONSTANT_Methodref); assert(methodref_constant->tag == CONSTANT_Methodref);
#endif struct constant * nameandtype_constant = &original_class_entry->class_file->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
struct constant * nameandtype_constant = &class_entry->class_file->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType); assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif struct constant * method_name_constant = &original_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
struct constant * method_name_constant = &class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(method_name_constant->tag == CONSTANT_Utf8); assert(method_name_constant->tag == CONSTANT_Utf8);
#endif struct constant * method_descriptor_constant = &original_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
struct constant * method_descriptor_constant = &class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG
assert(method_descriptor_constant->tag == CONSTANT_Utf8); assert(method_descriptor_constant->tag == CONSTANT_Utf8);
#endif
struct method_info * method_info = class_resolver_lookup_method(methods_hash_table_length, struct class_entry * class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length,
methods_hash_table, class_hash_table,
original_class_entry,
methodref_constant->methodref.class_index);
while (true) {
struct method_info * method_info = class_resolver_lookup_method(class_entry->methods.length,
class_entry->methods.entry,
method_name_constant->utf8.bytes, method_name_constant->utf8.bytes,
method_name_constant->utf8.length, method_name_constant->utf8.length,
method_descriptor_constant->utf8.bytes, method_descriptor_constant->utf8.bytes,
method_descriptor_constant->utf8.length); method_descriptor_constant->utf8.length);
if (method_info != nullptr) {
// cache the result // cache the result
class_entry->attribute_entry[methodref_index - 1].method_info = method_info; debugf("method resolved:\n");
debugf(" class: ");
debug_print__class_entry__class_name(class_entry);
debugf("\n method: ");
debug_print__method_info__method_name(class_entry, method_info);
debugc('\n');
return method_info; struct method_entry * method_entry = malloc_class_arena((sizeof (struct method_entry)));
method_entry->class_entry = class_entry;
method_entry->method_info = method_info;
original_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry;
return method_entry;
}
if (class_entry->class_file->super_class == 0)
break;
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->super_class - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
print_utf8_string(class_name_constant);
debugf("\n");
// lookup the method from the superclass
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);
}
return nullptr;
} }
int32_t * class_resolver_lookup_string(int class_hash_table_length, int32_t * class_resolver_lookup_string(int class_hash_table_length,

View File

@ -11,9 +11,14 @@ enum initialization_state {
CLASS_INITIALIZED, CLASS_INITIALIZED,
}; };
union attribute_entry { struct method_entry {
struct class_entry * class_entry; struct class_entry * class_entry;
struct method_info * method_info; struct method_info * method_info;
};
union attribute_entry {
struct class_entry * class_entry;
struct method_entry * method_entry;
struct field_entry * field_entry; struct field_entry * field_entry;
int32_t * string_objectref; int32_t * string_objectref;
}; };
@ -66,10 +71,10 @@ struct method_info * class_resolver_lookup_method(int methods_hash_table_length,
int method_name_length, int method_name_length,
const uint8_t * method_descriptor, const uint8_t * method_descriptor,
int method_descriptor_length); int method_descriptor_length);
struct method_info * class_resolver_lookup_method_from_methodref_index(int methods_hash_table_length, struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length,
struct hash_table_entry * methods_hash_table, struct hash_table_entry * class_hash_table,
struct class_entry * class_entry, int32_t methodref_index,
int methodref_index); struct class_entry * original_class_entry);
struct field_entry * class_resolver_lookup_field(int fields_hash_table_length, struct field_entry * class_resolver_lookup_field(int fields_hash_table_length,
struct hash_table_entry * fields_hash_table, struct hash_table_entry * fields_hash_table,
const uint8_t * field_name, const uint8_t * field_name,

32
c/debug.c Normal file
View File

@ -0,0 +1,32 @@
#include "printf.h"
#include "debug.h"
#include "assert.h"
void debug_print__constant__utf8_string(struct constant * constant)
{
for (int i = 0; i < constant->utf8.length; i++) {
debugc(constant->utf8.bytes[i]);
}
}
void debug_print__class_entry__class_name(struct class_entry * class_entry)
{
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(class_name_constant);
}
void debug_print__method_info__method_name(struct class_entry * class_entry, struct method_info * method_info)
{
struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_info->name_index - 1];
assert(method_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(method_name_constant);
debugc(' ');
struct constant * method_descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(method_descriptor_constant);
}

8
c/debug.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "class_file.h"
#include "class_resolver.h"
void debug_print__constant__utf8_string(struct constant * constant);
void debug_print__class_entry__class_name(struct class_entry * class_entry);
void debug_print__method_info__method_name(struct class_entry * class_entry, struct method_info * method_info);

View File

@ -1122,39 +1122,39 @@ void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
void op_invokespecial(struct vm * vm, uint32_t index) void op_invokespecial(struct vm * vm, uint32_t index)
{ {
struct class_entry * class_entry; struct method_entry * method_entry =
struct method_info * method_info; class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length,
class_entry_method_info_from_constant_index(vm, index, vm->class_hash_table.entry,
&class_entry, index,
&method_info); vm->current_frame->class_entry);
vm_special_method_call(vm, class_entry, method_info); vm_special_method_call(vm, method_entry->class_entry, method_entry->method_info);
} }
void op_invokestatic(struct vm * vm, uint32_t index) void op_invokestatic(struct vm * vm, uint32_t index)
{ {
struct class_entry * class_entry; struct method_entry * method_entry =
struct method_info * method_info; class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length,
class_entry_method_info_from_constant_index(vm, index, vm->class_hash_table.entry,
&class_entry, index,
&method_info); vm->current_frame->class_entry);
/* On successful resolution of the method, the class or interface that /* On successful resolution of the method, the class or interface that
declared the resolved method is initialized if that class or interface has declared the resolved method is initialized if that class or interface has
not already been initialized (§5.5). */ not already been initialized (§5.5). */
vm_static_method_call(vm, class_entry, method_info); vm_static_method_call(vm, method_entry->class_entry, method_entry->method_info);
} }
void op_invokevirtual(struct vm * vm, uint32_t index) void op_invokevirtual(struct vm * vm, uint32_t index)
{ {
struct class_entry * class_entry; struct method_entry * method_entry =
struct method_info * method_info; class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length,
class_entry_method_info_from_constant_index(vm, index, vm->class_hash_table.entry,
&class_entry, index,
&method_info); vm->current_frame->class_entry);
vm_special_method_call(vm, class_entry, method_info); vm_special_method_call(vm, method_entry->class_entry, method_entry->method_info);
} }
void op_ior(struct vm * vm) void op_ior(struct vm * vm)

View File

@ -36,29 +36,3 @@ static inline void class_entry_field_entry_from_constant_index(struct vm * vm,
assert((*field_descriptor_constant)->tag == CONSTANT_Utf8); assert((*field_descriptor_constant)->tag == CONSTANT_Utf8);
#endif #endif
} }
static inline void class_entry_method_info_from_constant_index(struct vm * vm,
int32_t index,
struct class_entry ** class_entry,
struct method_info ** method_info)
{
struct constant * methodref_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG
assert(methodref_constant->tag == CONSTANT_Methodref);
#endif
*class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
methodref_constant->methodref.class_index);
assert(*class_entry != nullptr);
int methods_hash_table_length = (*class_entry)->methods.length;
struct hash_table_entry * methods_hash_table = (*class_entry)->methods.entry;
*method_info = class_resolver_lookup_method_from_methodref_index(methods_hash_table_length,
methods_hash_table,
vm->current_frame->class_entry,
index);
assert(*method_info != nullptr);
}

View File

@ -17,7 +17,8 @@ OBJ = \
c/printf.o \ c/printf.o \
c/parse.o \ c/parse.o \
c/unparse.o \ c/unparse.o \
c/native.o c/native.o \
c/debug.o
MAIN_DREAMCAST_OBJ = \ MAIN_DREAMCAST_OBJ = \
c/sh7091_scif.o \ c/sh7091_scif.o \

View File

@ -5,22 +5,18 @@ class A {
static int baz = 3; static int baz = 3;
static int bleh = 4; static int bleh = 4;
/* public int foo(int a) {
public int foo(int a, int b) { return a + baz;
return a + b;
} }
*/
} }
class B extends A { class B extends A {
static int baz = 5; static int baz = 5;
int horse; int horse;
/*
public int bar(int a) { public int bar(int a) {
return a * egg; return a * egg;
} }
*/
} }
class InheritanceTest { class InheritanceTest {
@ -58,7 +54,13 @@ class InheritanceTest {
return b.egg * b.horse; return b.egg * b.horse;
} }
static int method_test() {
B b = new B();
b.egg = 5;
return b.foo(b.bar(6));
}
public static void main() { public static void main() {
instance_test(); method_test();
} }
} }

17
p/InterfaceTest.java Normal file
View File

@ -0,0 +1,17 @@
package p;
class InterfaceTest implements Interface
{
public static int test()
{
InterfaceTest it = new InterfaceTest();
System.out.println(it.a);
Interface.a = "1234";
return (int)it.a.getBytes()[0];
}
public static void main()
{
test();
}
}