From 008690543d31637ebcaa81b40a894b3200a00985 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 10 Jan 2025 21:58:43 -0600 Subject: [PATCH] implement java.lang.Class.getName --- c/class_resolver.c | 38 +++++++++++++++++-------------------- c/native.c | 22 ++++++++++++++++++++- c/native/class.c | 23 ++++++++++++++++++++++ c/native/class.h | 7 +++++++ c/native/object.c | 23 ++++++++++++++++++++++ c/native/object.h | 9 +++++++++ c/vm_instance.c | 19 +++++++++++++++++++ c/vm_instance.h | 1 + classes/test/TestClass.java | 8 ++++++++ java.mk | 2 ++ 10 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 c/native/class.c create mode 100644 c/native/class.h create mode 100644 c/native/object.c create mode 100644 c/native/object.h create mode 100644 classes/test/TestClass.java diff --git a/c/class_resolver.c b/c/class_resolver.c index 93661b2..be17819 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -441,13 +441,21 @@ struct method_entry class_resolver_lookup_method_from_interfacemethodref_index(i struct attribute_info * attribute = find_attribute(code_index, method_info->attributes_count, method_info->attributes); - assert(attribute != nullptr); - return (struct method_entry){ - .class_entry = class_entry, - .method_info = method_info, - .code_attribute = attribute->code, - }; + if ((method_info->access_flags & METHOD_ACC_NATIVE) != 0) { + return (struct method_entry){ + .class_entry = class_entry, + .method_info = method_info, + .code_attribute = nullptr, + }; + } else { + assert(attribute != nullptr); + return (struct method_entry){ + .class_entry = class_entry, + .method_info = method_info, + .code_attribute = attribute->code, + }; + } } if (class_entry->class_file->super_class == 0) @@ -606,24 +614,12 @@ struct objectref * class_resolver_lookup_string(struct vm * vm, struct constant * utf8_constant = &class_entry->class_file->constant_pool[string_constant->string.string_index - 1]; assert(utf8_constant->tag == CONSTANT_Utf8); - int32_t count = utf8_constant->utf8.length; - struct arrayref * arrayref = prim_array_allocate(vm, 1, count); - assert(arrayref != nullptr); - arrayref->class_entry = nullptr; // byte[] - arrayref->length = utf8_constant->utf8.length; - for (int i = 0; i < utf8_constant->utf8.length; i++) { - arrayref->u8[i] = utf8_constant->utf8.bytes[i]; - } - - struct objectref * objectref = vm_instance_create(vm, "java/lang/String"); - assert(objectref != nullptr); - assert(objectref->class_entry->instance_fields_count >= 1); - objectref->aref[0] = arrayref; + struct objectref * string_objectref = vm_instance_string_from_constant(vm, utf8_constant); // cache the result - class_entry->attribute_entry[string_index - 1].string_objectref = objectref; + class_entry->attribute_entry[string_index - 1].string_objectref = string_objectref; - return objectref; + return string_objectref; } bool class_resolver_instanceof(int class_hash_table_length, diff --git a/c/native.c b/c/native.c index 81e3637..09752b4 100644 --- a/c/native.c +++ b/c/native.c @@ -3,10 +3,12 @@ #include "string.h" #include "printf.h" #include "native.h" +#include "native/class.h" +#include "native/loader.h" #include "native/math.h" #include "native/memory.h" +#include "native/object.h" #include "native/printstream.h" -#include "native/loader.h" typedef void (* native_func_t)(struct vm * vm, uint32_t * args); @@ -102,6 +104,24 @@ const static struct native_method native_method[] = { .method_descriptor = "()I", .func = native_jvm_internal_loader_getbuffer_0, }, + { + .class_name = "java/lang/Class", + .method_name = "getClassName", + .method_descriptor = "()Ljava/lang/String;", + .func = native_java_lang_class_getclassname_1, + }, + { + .class_name = "java/lang/Object", + .method_name = "getClass", + .method_descriptor = "()Ljava/lang/Class;", + .func = native_java_lang_object_getclass_1, + }, + { + .class_name = "java/lang/Object", + .method_name = "hashCode", + .method_descriptor = "()I", + .func = native_java_lang_object_hashcode_1, + }, }; struct hash_table_entry * native_init_hash_table(int * hash_table_length) diff --git a/c/native/class.c b/c/native/class.c new file mode 100644 index 0000000..b634427 --- /dev/null +++ b/c/native/class.c @@ -0,0 +1,23 @@ +#include "class.h" +#include "printf.h" +#include "vm_instance.h" + +void native_java_lang_class_getclassname_1(struct vm * vm, uint32_t * args) +{ + struct objectref * objectref = (struct objectref *)args[0]; + assert(objectref != nullptr); + + assert(objectref->oref[0] != nullptr); + assert(objectref->oref[0]->class_entry != nullptr); + struct class_file * class_file = objectref->oref[0]->class_entry->class_file; + + struct constant * class_constant = &class_file->constant_pool[class_file->this_class - 1]; + assert(class_constant->tag == CONSTANT_Class); + + struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1]; + assert(class_name_constant->tag == CONSTANT_Utf8); + + struct objectref * string_objectref = vm_instance_string_from_constant(vm, class_name_constant); + + operand_stack_push_ref(vm->current_frame, string_objectref); +} diff --git a/c/native/class.h b/c/native/class.h new file mode 100644 index 0000000..da6d023 --- /dev/null +++ b/c/native/class.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "frame.h" + +void native_java_lang_class_getclassname_1(struct vm * vm, uint32_t * args); diff --git a/c/native/object.c b/c/native/object.c new file mode 100644 index 0000000..1475f66 --- /dev/null +++ b/c/native/object.c @@ -0,0 +1,23 @@ +#include "object.h" +#include "printf.h" +#include "vm_instance.h" + +void native_java_lang_object_getclass_1(struct vm * vm, uint32_t * args) +{ + struct objectref * objectref = (struct objectref *)args[0]; + assert(objectref != nullptr); + + struct objectref * class_objectref = vm_instance_create(vm, "java/lang/Class"); + assert(class_objectref != nullptr); + assert(class_objectref->class_entry->instance_fields_count >= 1); + + class_objectref->oref[0] = objectref; + + operand_stack_push_ref(vm->current_frame, class_objectref); +} + +void native_java_lang_object_hashcode_1(struct vm * vm, uint32_t * args) +{ + struct objectref * objectref = (struct objectref *)args[0]; + operand_stack_push_u32(vm->current_frame, (uint32_t)objectref); // objectref as integer +} diff --git a/c/native/object.h b/c/native/object.h new file mode 100644 index 0000000..fb7e369 --- /dev/null +++ b/c/native/object.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "frame.h" + +void native_java_lang_object_getclass_1(struct vm * vm, uint32_t * args); + +void native_java_lang_object_hashcode_1(struct vm * vm, uint32_t * args); diff --git a/c/vm_instance.c b/c/vm_instance.c index 4776b3e..5ecbdc6 100644 --- a/c/vm_instance.c +++ b/c/vm_instance.c @@ -21,3 +21,22 @@ struct objectref * vm_instance_create(struct vm * vm, const char * class_name) return objectref; } + +struct objectref * vm_instance_string_from_constant(struct vm * vm, struct constant * constant) +{ + int32_t count = constant->utf8.length; + struct arrayref * arrayref = prim_array_allocate(vm, 1, count); + assert(arrayref != nullptr); + arrayref->class_entry = nullptr; // byte[] + arrayref->length = constant->utf8.length; + for (int i = 0; i < constant->utf8.length; i++) { + arrayref->u8[i] = constant->utf8.bytes[i]; + } + + struct objectref * objectref = vm_instance_create(vm, "java/lang/String"); + assert(objectref != nullptr); + assert(objectref->class_entry->instance_fields_count >= 1); + objectref->aref[0] = arrayref; + + return objectref; +} diff --git a/c/vm_instance.h b/c/vm_instance.h index 56d56ba..b2af954 100644 --- a/c/vm_instance.h +++ b/c/vm_instance.h @@ -3,3 +3,4 @@ #include "frame.h" struct objectref * vm_instance_create(struct vm * vm, const char * class_name); +struct objectref * vm_instance_string_from_constant(struct vm * vm, struct constant * constant); diff --git a/classes/test/TestClass.java b/classes/test/TestClass.java new file mode 100644 index 0000000..a193f1a --- /dev/null +++ b/classes/test/TestClass.java @@ -0,0 +1,8 @@ +package test; + +class TestClass { + public static void main() { + TestClass obj = new TestClass(); + System.out.println(obj.getClass().getName()); + } +} diff --git a/java.mk b/java.mk index 7cc38fa..c026a30 100644 --- a/java.mk +++ b/java.mk @@ -21,9 +21,11 @@ OBJ = \ c/malloc.o \ c/memory_allocator.o \ c/native.o \ + c/native/class.o \ c/native/loader.o \ c/native/math.o \ c/native/memory.o \ + c/native/object.o \ c/native/printstream.o \ c/parse.o \ c/parse_type.o \