From 867a10ac2b3a461ccc9ab7402a5551036a693167 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 30 Dec 2024 09:04:12 -0600 Subject: [PATCH] implement instanceof superclass behavior --- Makefile | 2 +- c/class_resolver.c | 13 +++++++---- c/execute.c | 53 +++++++++++++++++++++++++++---------------- c/fatal.c | 11 +++++++++ c/fatal.h | 5 ++++ c/frame.c | 11 ++++----- c/frame.h | 4 ++-- java.mk | 3 ++- p/TestInstanceof.java | 11 +++++++++ 9 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 c/fatal.c create mode 100644 c/fatal.h create mode 100644 p/TestInstanceof.java diff --git a/Makefile b/Makefile index da83501..04e6d61 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CC ?= gcc ARCH = -m32 CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g CFLAGS += -DDEBUG -CFLAGS += -DDEBUG_PRINT +#CFLAGS += -DDEBUG_PRINT LDFLAGS = -lm OPT ?= -O0 DEPFLAGS = -MMD -MP diff --git a/c/class_resolver.c b/c/class_resolver.c index f32adc7..aeaf892 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -11,6 +11,7 @@ #include "printf.h" #include "field_size.h" #include "debug.h" +#include "fatal.h" static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) { @@ -270,7 +271,10 @@ struct class_entry * class_resolver_lookup_class(int class_hash_table_length, class_hash_table, class_name, class_name_length); - assert(e != nullptr); + if (e == nullptr) { + fatal_print__class_lookup_failed__from_string(class_name, class_name_length); + assert(e != nullptr); + } return (struct class_entry *)e->value; } @@ -298,9 +302,10 @@ struct class_entry * class_resolver_lookup_class_from_class_index(int class_hash class_hash_table, class_name_constant->utf8.bytes, class_name_constant->utf8.length); - - // cache the result - class_entry->attribute_entry[class_index - 1].class_entry = _class_entry; + if (_class_entry != nullptr) { + // cache the result + class_entry->attribute_entry[class_index - 1].class_entry = _class_entry; + } return _class_entry; } diff --git a/c/execute.c b/c/execute.c index cac7f4a..83be34e 100644 --- a/c/execute.c +++ b/c/execute.c @@ -1094,20 +1094,42 @@ void op_ineg(struct vm * vm) void op_instanceof(struct vm * vm, uint32_t index) { - struct class_entry * class_entry = + struct class_entry * index_class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length, vm->class_hash_table.entry, vm->current_frame->class_entry, index); - assert(class_entry != nullptr); + assert(index_class_entry != nullptr); int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - if (objectref == nullptr) { - operand_stack_push_u32(vm->current_frame, 0); - } else { - int32_t value = objectref[0] == (int32_t)class_entry; - operand_stack_push_u32(vm->current_frame, value); + bool value = false; + if (objectref != nullptr) { + struct class_entry * class_entry = (struct class_entry *)objectref[0]; + while (true) { + assert(class_entry != nullptr); + if (class_entry == index_class_entry) { + value = true; + break; + } + 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"); + + // superclass lookup + class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length, + vm->class_hash_table.entry, + class_entry, + class_entry->class_file->super_class); + } } + operand_stack_push_u32(vm->current_frame, (uint32_t)value); } void op_invokedynamic(struct vm * vm, uint32_t index) @@ -1688,19 +1710,10 @@ void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions) void op_new(struct vm * vm, uint32_t index) { - struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1]; - #ifdef DEBUG - assert(class_constant->tag == CONSTANT_Class); - #endif - struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; - #ifdef DEBUG - assert(class_name_constant->tag == CONSTANT_Utf8); - #endif - - struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length, - vm->class_hash_table.entry, - class_name_constant->utf8.bytes, - class_name_constant->utf8.length); + struct class_entry * class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length, + vm->class_hash_table.entry, + vm->current_frame->class_entry, + index); assert(class_entry != nullptr); /* On successful resolution of the class, it is initialized if it has not diff --git a/c/fatal.c b/c/fatal.c new file mode 100644 index 0000000..7cb1459 --- /dev/null +++ b/c/fatal.c @@ -0,0 +1,11 @@ +#include "printf.h" +#include "fatal.h" + +void fatal_print__class_lookup_failed__from_string(const uint8_t * name, int length) +{ + printf("class lookup failed: "); + for (int i = 0; i < length; i++) { + printc(name[i]); + } + printc('\n'); +} diff --git a/c/fatal.h b/c/fatal.h new file mode 100644 index 0000000..13431d4 --- /dev/null +++ b/c/fatal.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void fatal_print__class_lookup_failed__from_string(const uint8_t * name, int length); diff --git a/c/frame.c b/c/frame.c index b033308..3b5b39a 100644 --- a/c/frame.c +++ b/c/frame.c @@ -10,6 +10,7 @@ #include "printf.h" #include "string.h" #include "native.h" +#include "fatal.h" struct Code_attribute * get_code_attribute(int code_name_index, int attributes_count, @@ -525,15 +526,13 @@ void vm_execute(struct vm * vm) void vm_start(int class_hash_table_length, struct hash_table_entry * class_hash_table, - const uint8_t * main_class, - int main_class_length) + const uint8_t * main_class_name, + int main_class_name_length) { struct class_entry * class_entry = class_resolver_lookup_class(class_hash_table_length, class_hash_table, - main_class, - main_class_length); - - assert(class_entry != nullptr); + main_class_name, + main_class_name_length); const char * method_name = "main"; int method_name_length = string_length(method_name); diff --git a/c/frame.h b/c/frame.h index 7eeb09d..111090d 100644 --- a/c/frame.h +++ b/c/frame.h @@ -162,6 +162,6 @@ void vm_method_return(struct vm * vm); void vm_execute(struct vm * vm); void vm_start(int class_hash_table_length, struct hash_table_entry * class_hash_table, - const uint8_t * main_class, - int main_class_length); + const uint8_t * main_class_name, + int main_class_name_length); int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type); diff --git a/java.mk b/java.mk index a8e2510..babe4d3 100644 --- a/java.mk +++ b/java.mk @@ -18,7 +18,8 @@ OBJ = \ c/parse.o \ c/unparse.o \ c/native.o \ - c/debug.o + c/debug.o \ + c/fatal.o MAIN_DREAMCAST_OBJ = \ c/sh7091_scif.o \ diff --git a/p/TestInstanceof.java b/p/TestInstanceof.java new file mode 100644 index 0000000..1e60c07 --- /dev/null +++ b/p/TestInstanceof.java @@ -0,0 +1,11 @@ +package p; + +class TestInstanceof { + public static boolean test() { + TestInstanceof t = new TestInstanceof(); + return t instanceof Object; + } + public static void main() { + System.out.println(test()); + } +}