implement invokeinterface
This commit is contained in:
parent
b6da4ecea7
commit
8768bd516c
@ -382,28 +382,87 @@ 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_entry class_resolver_lookup_method_from_interfacemethodref_index(int class_hash_table_length,
|
||||||
|
struct hash_table_entry * class_hash_table,
|
||||||
|
int32_t interfacemethodref_index,
|
||||||
|
struct class_entry * objectref_class_entry,
|
||||||
|
struct class_entry * origin_class_entry)
|
||||||
|
{
|
||||||
|
struct constant * interfacemethodref_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_index - 1];
|
||||||
|
assert(interfacemethodref_constant->tag == CONSTANT_InterfaceMethodref);
|
||||||
|
struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_constant->interfacemethodref.name_and_type_index - 1];
|
||||||
|
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
||||||
|
struct constant * method_name_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
||||||
|
assert(method_name_constant->tag == CONSTANT_Utf8);
|
||||||
|
struct constant * method_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
|
||||||
|
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
|
||||||
|
|
||||||
|
struct class_entry * class_entry = objectref_class_entry;
|
||||||
|
|
||||||
|
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.length,
|
||||||
|
method_descriptor_constant->utf8.bytes,
|
||||||
|
method_descriptor_constant->utf8.length);
|
||||||
|
if (method_info != nullptr) {
|
||||||
|
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 (struct method_entry){
|
||||||
|
.class_entry = class_entry,
|
||||||
|
.method_info = method_info
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!"invokeinterface method does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length,
|
struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length,
|
||||||
struct hash_table_entry * class_hash_table,
|
struct hash_table_entry * class_hash_table,
|
||||||
int32_t methodref_index,
|
int32_t methodref_index,
|
||||||
struct class_entry * original_class_entry)
|
struct class_entry * origin_class_entry)
|
||||||
{
|
{
|
||||||
if (original_class_entry->attribute_entry[methodref_index - 1].method_entry != nullptr) {
|
if (origin_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 original_class_entry->attribute_entry[methodref_index - 1].method_entry;
|
return origin_class_entry->attribute_entry[methodref_index - 1].method_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct constant * methodref_constant = &original_class_entry->class_file->constant_pool[methodref_index - 1];
|
struct constant * methodref_constant = &origin_class_entry->class_file->constant_pool[methodref_index - 1];
|
||||||
assert(methodref_constant->tag == CONSTANT_Methodref);
|
assert(methodref_constant->tag == CONSTANT_Methodref);
|
||||||
struct constant * nameandtype_constant = &original_class_entry->class_file->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
|
struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
|
||||||
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
||||||
struct constant * method_name_constant = &original_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
struct constant * method_name_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
||||||
assert(method_name_constant->tag == CONSTANT_Utf8);
|
assert(method_name_constant->tag == CONSTANT_Utf8);
|
||||||
struct constant * method_descriptor_constant = &original_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
|
struct constant * method_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
|
||||||
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
|
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
|
||||||
|
|
||||||
struct class_entry * class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length,
|
struct class_entry * class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length,
|
||||||
class_hash_table,
|
class_hash_table,
|
||||||
original_class_entry,
|
origin_class_entry,
|
||||||
methodref_constant->methodref.class_index);
|
methodref_constant->methodref.class_index);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -425,7 +484,7 @@ struct method_entry * class_resolver_lookup_method_from_methodref_index(int clas
|
|||||||
struct method_entry * method_entry = malloc_class_arena((sizeof (struct method_entry)));
|
struct method_entry * method_entry = malloc_class_arena((sizeof (struct method_entry)));
|
||||||
method_entry->class_entry = class_entry;
|
method_entry->class_entry = class_entry;
|
||||||
method_entry->method_info = method_info;
|
method_entry->method_info = method_info;
|
||||||
original_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry;
|
origin_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry;
|
||||||
return method_entry;
|
return method_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +71,15 @@ 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_entry class_resolver_lookup_method_from_interfacemethodref_index(int class_hash_table_length,
|
||||||
|
struct hash_table_entry * class_hash_table,
|
||||||
|
int32_t interfacemethodref_index,
|
||||||
|
struct class_entry * objectref_class_entry,
|
||||||
|
struct class_entry * origin_class_entry);
|
||||||
struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length,
|
struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length,
|
||||||
struct hash_table_entry * class_hash_table,
|
struct hash_table_entry * class_hash_table,
|
||||||
int32_t methodref_index,
|
int32_t methodref_index,
|
||||||
struct class_entry * original_class_entry);
|
struct class_entry * origin_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,
|
||||||
|
13
c/execute.c
13
c/execute.c
@ -1117,7 +1117,18 @@ void op_invokedynamic(struct vm * vm, uint32_t index)
|
|||||||
|
|
||||||
void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
|
void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
|
||||||
{
|
{
|
||||||
assert(!"op_invokeinterface");
|
int32_t * objectref = (int32_t *)operand_stack_peek_u32(vm->current_frame, count);
|
||||||
|
assert(objectref != nullptr);
|
||||||
|
struct class_entry * class_entry = (struct class_entry *)objectref[0];
|
||||||
|
|
||||||
|
struct method_entry method_entry =
|
||||||
|
class_resolver_lookup_method_from_interfacemethodref_index(vm->class_hash_table.length,
|
||||||
|
vm->class_hash_table.entry,
|
||||||
|
index,
|
||||||
|
class_entry,
|
||||||
|
vm->current_frame->class_entry);
|
||||||
|
|
||||||
|
vm_special_method_call(vm, method_entry.class_entry, method_entry.method_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void op_invokespecial(struct vm * vm, uint32_t index)
|
void op_invokespecial(struct vm * vm, uint32_t index)
|
||||||
|
@ -73,6 +73,13 @@ static inline void operand_stack_push_u32(struct frame * frame, uint32_t value)
|
|||||||
frame->operand_stack_ix++;
|
frame->operand_stack_ix++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t operand_stack_peek_u32(struct frame * frame, int index)
|
||||||
|
{
|
||||||
|
assert((frame->operand_stack_ix - index) >= 0);
|
||||||
|
uint32_t value = frame->operand_stack[frame->operand_stack_ix - index];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t operand_stack_pop_u32(struct frame * frame)
|
static inline uint32_t operand_stack_pop_u32(struct frame * frame)
|
||||||
{
|
{
|
||||||
frame->operand_stack_ix--;
|
frame->operand_stack_ix--;
|
||||||
|
21
p/InvokeInterfaceTest.java
Normal file
21
p/InvokeInterfaceTest.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package p;
|
||||||
|
|
||||||
|
interface Op {
|
||||||
|
public int op(int a, int b);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo implements Op {
|
||||||
|
public int op(int a, int b) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InvokeInterfaceTest {
|
||||||
|
static int test(Op operator) {
|
||||||
|
return operator.op(5, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main() {
|
||||||
|
test(new Foo());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user