From e22f2e87e891eb8fab75e155188a84348686d31b Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 30 Dec 2024 11:49:52 -0600 Subject: [PATCH] partial support for checkcast and instanceof on object arrays --- c/class_resolver.c | 13 +++++++------ c/class_resolver.h | 5 ----- c/execute.c | 36 ++++++++++++++++++++++++++++++++++++ c/parse_type.c | 34 ++++++++++++++++++++++++++++++++++ c/parse_type.h | 11 +++++++++++ java.mk | 3 ++- p/CheckCastTest.java | 20 +++++++++++++++++++- 7 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 c/parse_type.c create mode 100644 c/parse_type.h diff --git a/c/class_resolver.c b/c/class_resolver.c index 9c17ed8..cb86d84 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -12,6 +12,7 @@ #include "field_size.h" #include "debug.h" #include "fatal.h" +#include "parse_type.h" static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) { @@ -290,18 +291,18 @@ struct class_entry * class_resolver_lookup_class_from_class_index(int class_hash } struct constant * class_constant = &class_entry->class_file->constant_pool[class_index - 1]; - #ifdef DEBUG assert(class_constant->tag == CONSTANT_Class); - #endif struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; - #ifdef DEBUG assert(class_name_constant->tag == CONSTANT_Utf8); - #endif + + struct parse_type_ret parse_type_ret = parse_type(class_name_constant->utf8.bytes, + class_name_constant->utf8.length); + struct class_entry * _class_entry = class_resolver_lookup_class(class_hash_table_length, class_hash_table, - class_name_constant->utf8.bytes, - class_name_constant->utf8.length); + parse_type_ret.bytes, + parse_type_ret.length); if (_class_entry != nullptr) { // cache the result class_entry->attribute_entry[class_index - 1].class_entry = _class_entry; diff --git a/c/class_resolver.h b/c/class_resolver.h index 2d909aa..49a2b85 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -38,11 +38,6 @@ struct class_entry { int32_t * static_fields; int32_t instance_fields_count; - struct { - int length; - struct hash_table_entry * entry; - } interfaces; - struct { int length; struct hash_table_entry * entry; diff --git a/c/execute.c b/c/execute.c index 0748fb7..25a7b33 100644 --- a/c/execute.c +++ b/c/execute.c @@ -5,6 +5,8 @@ #include "execute_helper.h" #include "printf.h" #include "field_size.h" +#include "debug.h" +#include "parse_type.h" void op_aaload(struct vm * vm) { @@ -190,7 +192,25 @@ void op_checkcast(struct vm * vm, uint32_t index) vm->current_frame->class_entry, index); + struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1]; + assert(class_constant->tag == CONSTANT_Class); + struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; + assert(class_name_constant->tag == CONSTANT_Utf8); + + int depth = parse_type_array_depth(class_name_constant->utf8.bytes, class_name_constant->utf8.length); + while (depth-- > 0) { + if (objectref == nullptr || objectref[0] == 0) + assert(!"checkcast on null or zero-length array not implemented"); + objectref = (int32_t *)objectref[1]; + } + if (objectref == nullptr) { + assert(!"checkcast on array with null elements not implemented"); + } + struct class_entry * class_entry = (struct class_entry *)objectref[0]; + debug_print__class_entry__class_name(index_class_entry); + debug_print__class_entry__class_name(class_entry); + while (true) { assert(class_entry != nullptr); if (class_entry == index_class_entry) { @@ -1141,6 +1161,22 @@ void op_instanceof(struct vm * vm, uint32_t index) return; } + struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1]; + assert(class_constant->tag == CONSTANT_Class); + struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; + assert(class_name_constant->tag == CONSTANT_Utf8); + + int depth = parse_type_array_depth(class_name_constant->utf8.bytes, class_name_constant->utf8.length); + printf("depth: %d\n", depth); + while (depth-- > 0) { + if (objectref == nullptr || objectref[0] == 0) + assert(!"instanceof on null or zero-length array not implemented"); + objectref = (int32_t *)objectref[1]; + } + if (objectref == nullptr) { + assert(!"instanceof on array with null elements not implemented"); + } + bool value = false; struct class_entry * class_entry = (struct class_entry *)objectref[0]; while (true) { diff --git a/c/parse_type.c b/c/parse_type.c new file mode 100644 index 0000000..d92500d --- /dev/null +++ b/c/parse_type.c @@ -0,0 +1,34 @@ +#include "assert.h" +#include "parse_type.h" + +struct parse_type_ret parse_type(uint8_t * bytes, uint32_t length) +{ + if (bytes[length - 1] != ';') { + assert(bytes[0] != '['); + return (struct parse_type_ret){ bytes, length }; + } + + int ix = 0; + while (bytes[ix] == '[') { + ix += 1; + } + assert(bytes[ix] == 'L'); + ix += 1; + + return (struct parse_type_ret){ &bytes[ix], length - ix - 1 }; +} + +int parse_type_array_depth(uint8_t * bytes, uint32_t length) +{ + if (bytes[length - 1] != ';') { + assert(bytes[0] != '['); + return 0; + } + + int ix = 0; + while (bytes[ix] == '[') { + ix += 1; + } + assert(bytes[ix] == 'L'); + return ix; +} diff --git a/c/parse_type.h b/c/parse_type.h new file mode 100644 index 0000000..0fda68f --- /dev/null +++ b/c/parse_type.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct parse_type_ret { + uint8_t * bytes; + uint32_t length; +}; + +struct parse_type_ret parse_type(uint8_t * bytes, uint32_t length); +int parse_type_array_depth(uint8_t * bytes, uint32_t length); diff --git a/java.mk b/java.mk index babe4d3..4d1e4bb 100644 --- a/java.mk +++ b/java.mk @@ -19,7 +19,8 @@ OBJ = \ c/unparse.o \ c/native.o \ c/debug.o \ - c/fatal.o + c/fatal.o \ + c/parse_type.o MAIN_DREAMCAST_OBJ = \ c/sh7091_scif.o \ diff --git a/p/CheckCastTest.java b/p/CheckCastTest.java index 661cee8..fa882e7 100644 --- a/p/CheckCastTest.java +++ b/p/CheckCastTest.java @@ -20,7 +20,25 @@ class CheckCastTest { return cc instanceof Cat; } + public static boolean arrayTest() { + Dog[][] d = new Dog[1][1]; + Cat[][] c = new Cat[1][1]; + Animal[][] da = d; + Animal[][] ca = c; + //Cat[][] cc = (Cat[][])da; + Cat[][] cc = (Cat[][])ca; + return cc instanceof Cat[][]; + } + + public static boolean arrayTest2() { + Cat[] c = new Cat[1]; + c[0] = new Cat(); + return c instanceof Cat[]; + } + public static void main() { - test(); + //test(); + arrayTest2(); + //System.out.println(arrayTest()); } }