implement superclass method lookup
This commit is contained in:
parent
cb26d8cadf
commit
b6da4ecea7
@ -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,
|
||||||
|
@ -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
32
c/debug.c
Normal 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
8
c/debug.h
Normal 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);
|
36
c/execute.c
36
c/execute.c
@ -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)
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
3
java.mk
3
java.mk
@ -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 \
|
||||||
|
@ -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
17
p/InterfaceTest.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user