From d101710e0ff17b4e44954b7f3c0674575f741c68 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 5 Jan 2025 16:37:44 -0600 Subject: [PATCH] backtrace / code_attribute / method_entry refactor --- .gitignore | 15 +- c/backtrace.c | 36 ++++ c/backtrace.h | 5 + c/bytes.h | 20 ++- c/class_file.c | 47 +++-- c/class_file.h | 14 +- c/class_resolver.c | 79 ++++++-- c/class_resolver.h | 12 +- c/debug.c | 57 ++++-- c/debug.h | 8 +- c/debug_class_file.c | 378 +++++++++++++++++++++------------------ c/debug_class_file.h | 3 - c/execute.c | 14 +- c/execute_helper.h | 2 - c/find_attribute.c | 55 ++++++ c/find_attribute.h | 10 ++ c/frame.c | 172 ++++++------------ c/frame.h | 8 +- c/main_hosted.c | 4 + java.mk | 4 +- java/lang/Exception.java | 20 +++ java/lang/Throwable.java | 23 +++ p/TestException.java | 11 ++ 23 files changed, 638 insertions(+), 359 deletions(-) create mode 100644 c/backtrace.c create mode 100644 c/backtrace.h create mode 100644 c/find_attribute.c create mode 100644 c/find_attribute.h create mode 100644 java/lang/Exception.java create mode 100644 java/lang/Throwable.java create mode 100644 p/TestException.java diff --git a/.gitignore b/.gitignore index 0ee25c7..36f4b7b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,17 @@ main print_class __pycache__ -classes.txt \ No newline at end of file +classes.txt +*.4ct +*.dvi +*.lg +*.log +*.tmp +*.toc +*.xref +doc/*.pdf +doc/*.css +doc/*.html +*.idv +*.aux +*.4tc diff --git a/c/backtrace.c b/c/backtrace.c new file mode 100644 index 0000000..71708b0 --- /dev/null +++ b/c/backtrace.c @@ -0,0 +1,36 @@ +#include "backtrace.h" +#include "printf.h" +#include "debug.h" +#include "find_attribute.h" + +void backtrace_print(struct vm * vm) +{ + for (int i = (vm->frame_stack.ix - 1); i >= 0; i--) { + printf("ix %d\n", i); + struct frame * frame = &vm->frame_stack.frame[i]; + printf(" class: "); + print__class_entry__class_name(frame->class_entry); + printc('\n'); + printf(" method: "); + print__method_info__method_name(frame->class_entry, frame->method_info); + printc('\n'); + printf(" pc: %d\n", frame->pc); + + int linenumbertable_name_index = find_linenumbertable_name_index(frame->class_entry->class_file); + struct attribute_info * attribute_info = find_attribute(linenumbertable_name_index, + frame->code_attribute->attributes_count, + frame->code_attribute->attributes); + assert(attribute_info != nullptr); + int line_number_table_length = attribute_info->line_number_table->line_number_table_length; + struct line_number_table * line_number_table = attribute_info->line_number_table->line_number_table; + int line_number = 0; + for (int i = 0; i < line_number_table_length; i++) { + if (frame->pc >= line_number_table[i].start_pc) { + line_number = line_number_table[i].line_number; + } else { + break; + } + } + printf(" line_number: %d\n", line_number); + } +} diff --git a/c/backtrace.h b/c/backtrace.h new file mode 100644 index 0000000..2eb9099 --- /dev/null +++ b/c/backtrace.h @@ -0,0 +1,5 @@ +#pragma once + +#include "frame.h" + +void backtrace_print(struct vm * vm); diff --git a/c/bytes.h b/c/bytes.h index 0943767..10ea517 100644 --- a/c/bytes.h +++ b/c/bytes.h @@ -69,7 +69,7 @@ static inline void * parse_bytes(const uint8_t ** buf, int length) return dest; } -static inline bool bytes_equal(int length, const uint8_t * a, const char * b) +static inline bool bytes_equal_string(int length, const uint8_t * a, const char * b) { int i; for (i = 0; i < length; i++) { @@ -78,3 +78,21 @@ static inline bool bytes_equal(int length, const uint8_t * a, const char * b) } return b[i] == 0; } + +static inline bool bytes_equal_bytes(const uint8_t * a, int a_length, const uint8_t * b, int b_length) +{ + if (a_length != b_length) + return false; + + for (int i = 0; i < a_length; i++) { + if ((a[i]) != (b[i])) + return false; + } + return true; +} + +static inline bool constant_equal(struct constant * constant, const char * s) +{ + assert(constant->tag == CONSTANT_Utf8); + return bytes_equal_string(constant->utf8.length, constant->utf8.bytes, s); +} diff --git a/c/class_file.c b/c/class_file.c index a0fd380..6f6eee0 100644 --- a/c/class_file.c +++ b/c/class_file.c @@ -12,11 +12,11 @@ void * attribute_info_parse_info(const uint8_t * buf, struct attribute_info * at assert(attribute_name->tag == CONSTANT_Utf8); #endif - if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "ConstantValue")) { + if (constant_equal(attribute_name, "ConstantValue")) { struct ConstantValue_attribute * constantvalue = malloc_class_arena((sizeof (struct ConstantValue_attribute))); constantvalue->constantvalue_index = parse_u2(&buf); return constantvalue; - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "Code")) { + } else if (constant_equal(attribute_name, "Code")) { // parse Code struct Code_attribute * code = malloc_class_arena((sizeof (struct Code_attribute))); @@ -40,34 +40,33 @@ void * attribute_info_parse_info(const uint8_t * buf, struct attribute_info * at code->attributes = attribute_info_parse(&buf, code->attributes_count, constant_pool); return code; - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { + } else if (constant_equal(attribute_name, "BootstrapMethods")) { // parse BootstrapMethods - struct BootstrapMethods_attribute * bootstrapmethods = malloc_class_arena((sizeof (struct BootstrapMethods_attribute))); + struct BootstrapMethods_attribute * bootstrap_methods = malloc_class_arena((sizeof (struct BootstrapMethods_attribute))); - bootstrapmethods->num_bootstrap_methods = parse_u2(&buf); + bootstrap_methods->num_bootstrap_methods = parse_u2(&buf); - uint32_t bootstrap_methods_size = (sizeof (struct bootstrap_method)) * bootstrapmethods->num_bootstrap_methods; - bootstrapmethods->bootstrap_methods = malloc_class_arena(bootstrap_methods_size); + uint32_t bootstrap_methods_size = (sizeof (struct bootstrap_method)) * bootstrap_methods->num_bootstrap_methods; + bootstrap_methods->bootstrap_methods = malloc_class_arena(bootstrap_methods_size); - for (int i = 0; i < bootstrapmethods->num_bootstrap_methods; i++) { - bootstrapmethods->bootstrap_methods[i].bootstrap_method_ref = parse_u2(&buf); - bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments = parse_u2(&buf); + for (int i = 0; i < bootstrap_methods->num_bootstrap_methods; i++) { + bootstrap_methods->bootstrap_methods[i].bootstrap_method_ref = parse_u2(&buf); + bootstrap_methods->bootstrap_methods[i].num_bootstrap_arguments = parse_u2(&buf); - uint32_t bootstrap_arguments_size = (sizeof (u2)) * bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; - bootstrapmethods->bootstrap_methods[i].bootstrap_arguments = malloc_class_arena(bootstrap_arguments_size); - for (int j = 0; j < bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; j++) { - bootstrapmethods->bootstrap_methods[i].bootstrap_arguments[j] = parse_u2(&buf); + uint32_t bootstrap_arguments_size = (sizeof (u2)) * bootstrap_methods->bootstrap_methods[i].num_bootstrap_arguments; + bootstrap_methods->bootstrap_methods[i].bootstrap_arguments = malloc_class_arena(bootstrap_arguments_size); + for (int j = 0; j < bootstrap_methods->bootstrap_methods[i].num_bootstrap_arguments; j++) { + bootstrap_methods->bootstrap_methods[i].bootstrap_arguments[j] = parse_u2(&buf); } } - return bootstrapmethods; - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestHost")) { + return bootstrap_methods; + } else if (constant_equal(attribute_name, "NestHost")) { struct NestHost_attribute * nesthost = malloc_class_arena((sizeof (struct NestHost_attribute))); nesthost->host_class_index = parse_u2(&buf); return nesthost; - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestMembers")) { + } else if (constant_equal(attribute_name, "NestMembers")) { struct NestMembers_attribute * nestmembers = malloc_class_arena((sizeof (struct NestMembers_attribute))); nestmembers->number_of_classes = parse_u2(&buf); @@ -79,6 +78,18 @@ void * attribute_info_parse_info(const uint8_t * buf, struct attribute_info * at } return nestmembers; + } else if (constant_equal(attribute_name, "LineNumberTable")) { + struct LineNumberTable_attribute * line_number_table = malloc_class_arena((sizeof (struct LineNumberTable_attribute))); + line_number_table->line_number_table_length = parse_u2(&buf); + + uint32_t line_number_table_size = (sizeof (struct line_number_table)) * line_number_table->line_number_table_length; + line_number_table->line_number_table = malloc_class_arena(line_number_table_size); + + for (int i = 0; i < line_number_table->line_number_table_length; i++) { + line_number_table->line_number_table[i].start_pc = parse_u2(&buf); + line_number_table->line_number_table[i].line_number = parse_u2(&buf); + } + return line_number_table; } else { return nullptr; } diff --git a/c/class_file.h b/c/class_file.h index 5f53b0b..1868c79 100644 --- a/c/class_file.h +++ b/c/class_file.h @@ -135,6 +135,7 @@ struct BootstrapMethods_attribute; struct NestHost_attribute; struct NestMembers_attribute; struct PermittedSubclasses_attribute; +struct LineNumberTable_attribute; struct attribute_info { u2 attribute_name_index; @@ -144,10 +145,11 @@ struct attribute_info { struct ConstantValue_attribute * constantvalue; struct Code_attribute * code; //struct StackMapTable_attribute * stackmaptable; - struct BootstrapMethods_attribute * bootstrapmethods; + struct BootstrapMethods_attribute * bootstrap_methods; struct NestHost_attribute * nesthost; struct NestMembers_attribute * nestmembers; //struct PermittedSubclasses_attribute * permittedsubclasses; + struct LineNumberTable_attribute * line_number_table; }; }; @@ -193,6 +195,16 @@ struct NestMembers_attribute { u2 * classes; }; +struct line_number_table { + u2 start_pc; + u2 line_number; +}; + +struct LineNumberTable_attribute { + u2 line_number_table_length; + struct line_number_table * line_number_table; +}; + enum FIELD_ACC { FIELD_ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package. FIELD_ACC_PRIVATE = 0x0002, // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). diff --git a/c/class_resolver.c b/c/class_resolver.c index c617203..078b45d 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -6,13 +6,13 @@ #include "malloc.h" #include "class_resolver.h" #include "string.h" -#include "debug_class_file.h" #include "memory_allocator.h" #include "printf.h" #include "field_size.h" #include "debug.h" #include "fatal.h" #include "parse_type.h" +#include "find_attribute.h" static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) { @@ -50,7 +50,7 @@ static int32_t count_superclass_instance_fields(int class_hash_table_length, struct constant * class_name_constant = &subclass_entry->class_file->constant_pool[class_constant->class.name_index - 1]; assert(class_name_constant->tag == CONSTANT_Utf8); debugf("count_superclass_instance_fields: "); - print_utf8_string(class_name_constant); + debug_print__constant__utf8_string(class_name_constant); debugf(": %d\n", instance_field_count); return instance_field_count; @@ -87,7 +87,7 @@ static int add_superclass_instance_fields(int class_hash_table_length, struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1]; assert(name_constant->tag == CONSTANT_Utf8); debugf("hash table entry for instance field: "); - print_utf8_string(name_constant); + debug_print__constant__utf8_string(name_constant); debugf(": %d %p\n", instance_index, field_entry); hash_table_add(fields_hash_table_length, fields_hash_table, @@ -106,10 +106,11 @@ static int32_t class_resolver_create_fields_hash_table(int class_hash_table_leng struct hash_table_entry * class_hash_table, struct class_entry * class_entry) { - int total_fields_count = class_entry->class_file->fields_count + count_superclass_instance_fields(class_hash_table_length, - class_hash_table, - class_entry); - int fields_hash_table_length = hash_table_next_power_of_two(class_entry->class_file->fields_count * 2); + int total_fields_count = class_entry->class_file->fields_count + + count_superclass_instance_fields(class_hash_table_length, + class_hash_table, + class_entry); + int fields_hash_table_length = hash_table_next_power_of_two(total_fields_count * 2); uint32_t fields_hash_table_size = (sizeof (struct hash_table_entry)) * fields_hash_table_length; struct hash_table_entry * fields_hash_table = malloc_class_arena(fields_hash_table_size); hash_table_init(fields_hash_table_length, fields_hash_table); @@ -127,7 +128,7 @@ static int32_t class_resolver_create_fields_hash_table(int class_hash_table_leng struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1]; assert(name_constant->tag == CONSTANT_Utf8); debugf("hash table entry for static field: "); - print_utf8_string(name_constant); + debug_print__constant__utf8_string(name_constant); debugf(": %d %p\n", static_index, field_entry); hash_table_add(fields_hash_table_length, @@ -204,7 +205,7 @@ static void class_resolver_allocate_attribute_entry(struct class_entry * class_e uint32_t attribute_entry_size = (sizeof (union attribute_entry)) * class_file->constant_pool_count; union attribute_entry * attribute_entry = malloc_class_arena(attribute_entry_size); - for (int i = 0; i < class_file->constant_pool_count; i++) { + for (int i = 0; i < class_file->constant_pool_count - 1; i++) { attribute_entry[i].class_entry = nullptr; } @@ -237,7 +238,7 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buff struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1]; assert(class_name_constant->tag == CONSTANT_Utf8); debugf("hash table entry for class: "); - print_utf8_string(class_name_constant); + debug_print__constant__utf8_string(class_name_constant); debugf(" %p\n", &class_entry[i]); hash_table_add(class_hash_table_length, @@ -431,9 +432,17 @@ struct method_entry class_resolver_lookup_method_from_interfacemethodref_index(i debug_print__method_info__method_name(class_entry, method_info); debugc('\n'); + int code_index = find_code_name_index(class_entry->class_file); + assert(code_index != 0); + 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 + .method_info = method_info, + .code_attribute = attribute->code, }; } @@ -444,7 +453,7 @@ struct method_entry class_resolver_lookup_method_from_interfacemethodref_index(i 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); + debug_print__constant__utf8_string(class_name_constant); debugf("\n"); // lookup the method from the superclass @@ -501,6 +510,14 @@ struct method_entry * class_resolver_lookup_method_from_methodref_index(int clas struct method_entry * method_entry = malloc_class_arena((sizeof (struct method_entry))); method_entry->class_entry = class_entry; method_entry->method_info = method_info; + int code_index = find_code_name_index(class_entry->class_file); + assert(code_index != 0); + struct attribute_info * attribute = find_attribute(code_index, + method_info->attributes_count, + method_info->attributes); + assert(attribute != nullptr); + method_entry->code_attribute = attribute->code; + origin_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry; return method_entry; } @@ -512,7 +529,7 @@ struct method_entry * class_resolver_lookup_method_from_methodref_index(int clas 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); + debug_print__constant__utf8_string(class_name_constant); debugf("\n"); // lookup the method from the superclass @@ -526,6 +543,42 @@ struct method_entry * class_resolver_lookup_method_from_methodref_index(int clas assert(!"methodref method does not exist"); } +struct method_entry class_resolver_lookup_method_from_method_name_method_descriptor(struct class_entry * class_entry, + const uint8_t * method_name, + int method_name_length, + const uint8_t * method_descriptor, + int method_descriptor_length) +{ + struct method_info * method_info = class_resolver_lookup_method(class_entry->methods.length, + class_entry->methods.entry, + method_name, + method_name_length, + method_descriptor, + method_descriptor_length); + + if (method_info != nullptr) { + int code_index = find_code_name_index(class_entry->class_file); + assert(code_index != 0); + debugf("code_index: %d\n", code_index); + 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, + }; + } else { + return (struct method_entry){ + .class_entry = nullptr, + .method_info = nullptr, + .code_attribute = nullptr, + }; + } +} + int32_t * class_resolver_lookup_string(int class_hash_table_length, struct hash_table_entry * class_hash_table, struct class_entry * class_entry, diff --git a/c/class_resolver.h b/c/class_resolver.h index 49a2b85..2f01de3 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -14,6 +14,7 @@ enum initialization_state { struct method_entry { struct class_entry * class_entry; struct method_info * method_info; + struct Code_attribute * code_attribute; }; union attribute_entry { @@ -60,12 +61,6 @@ struct class_entry * class_resolver_lookup_class_from_class_index(int class_hash struct hash_table_entry * class_hash_table, struct class_entry * class_entry, int32_t class_index); -struct method_info * class_resolver_lookup_method(int methods_hash_table_length, - struct hash_table_entry * methods_hash_table, - const uint8_t * method_name, - int method_name_length, - const uint8_t * method_descriptor, - 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, @@ -75,6 +70,11 @@ struct method_entry * class_resolver_lookup_method_from_methodref_index(int clas struct hash_table_entry * class_hash_table, int32_t methodref_index, struct class_entry * origin_class_entry); +struct method_entry class_resolver_lookup_method_from_method_name_method_descriptor(struct class_entry * class_entry, + const uint8_t * method_name, + int method_name_length, + const uint8_t * method_descriptor, + int method_descriptor_length); struct field_entry * class_resolver_lookup_field(int fields_hash_table_length, struct hash_table_entry * fields_hash_table, const uint8_t * field_name, diff --git a/c/debug.c b/c/debug.c index 905bde5..dc10baf 100644 --- a/c/debug.c +++ b/c/debug.c @@ -2,8 +2,16 @@ #include "debug.h" #include "assert.h" +void debug_print__string(const uint8_t * bytes, int length) +{ + for (int i = 0; i < length; i++) { + debugc(bytes[i]); + } +} + void debug_print__constant__utf8_string(struct constant * constant) { + assert(constant->tag == CONSTANT_Utf8); for (int i = 0; i < constant->utf8.length; i++) { debugc(constant->utf8.bytes[i]); } @@ -14,28 +22,49 @@ 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__constant__method_name(struct constant * name_constant, struct constant * descriptor_constant) +{ + debug_print__constant__utf8_string(name_constant); + debugc(' '); + debug_print__constant__utf8_string(descriptor_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); + debug_print__constant__method_name(method_name_constant, method_descriptor_constant); } -void debug_print__constant__method_name(struct constant * name_constant, struct constant * descriptor_constant) +void print__constant__utf8_string(struct constant * constant) { - assert(name_constant->tag == CONSTANT_Utf8); - debug_print__constant__utf8_string(name_constant); - debugc(' '); - assert(descriptor_constant->tag == CONSTANT_Utf8); - debug_print__constant__utf8_string(descriptor_constant); + assert(constant->tag == CONSTANT_Utf8); + for (int i = 0; i < constant->utf8.length; i++) { + printc(constant->utf8.bytes[i]); + } +} + +void 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]; + print__constant__utf8_string(class_name_constant); +} + +void print__constant__method_name(struct constant * name_constant, struct constant * descriptor_constant) +{ + print__constant__utf8_string(name_constant); + printc(' '); + print__constant__utf8_string(descriptor_constant); +} + +void 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]; + struct constant * method_descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1]; + print__constant__method_name(method_name_constant, method_descriptor_constant); } diff --git a/c/debug.h b/c/debug.h index e2ac9c5..408fa37 100644 --- a/c/debug.h +++ b/c/debug.h @@ -3,7 +3,13 @@ #include "class_file.h" #include "class_resolver.h" +void debug_print__string(const uint8_t * bytes, int length); 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); void debug_print__constant__method_name(struct constant * name_constant, struct constant * descriptor_constant); +void debug_print__method_info__method_name(struct class_entry * class_entry, struct method_info * method_info); + +void print__constant__utf8_string(struct constant * constant); +void print__class_entry__class_name(struct class_entry * class_entry); +void print__constant__method_name(struct constant * name_constant, struct constant * descriptor_constant); +void print__method_info__method_name(struct class_entry * class_entry, struct method_info * method_info); diff --git a/c/debug_class_file.c b/c/debug_class_file.c index 80a161a..9e1860d 100644 --- a/c/debug_class_file.c +++ b/c/debug_class_file.c @@ -7,284 +7,322 @@ #include "debug_class_file.h" #include "printf.h" #include "string.h" +#include "debug.h" -void print_utf8_string(struct constant * constant) -{ - for (int i = 0; i < constant->utf8.length; i++) { - debugc(constant->utf8.bytes[i]); - } -} +static void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool); -void print_constant(struct constant * constant) +static void print_constant(struct constant * constant) { switch (constant->tag) { case CONSTANT_Class: - debugf("CONSTANT_Class name_index=%d\n", + printf("CONSTANT_Class name_index=%d\n", constant->class.name_index); break; case CONSTANT_Fieldref: - debugf("CONSTANT_Fieldref class_index=%d name_and_type_index=%d\n", + printf("CONSTANT_Fieldref class_index=%d name_and_type_index=%d\n", constant->fieldref.class_index, constant->fieldref.name_and_type_index); break; case CONSTANT_Methodref: - debugf("CONSTANT_Methodref class_index=%d name_and_type_index=%d\n", + printf("CONSTANT_Methodref class_index=%d name_and_type_index=%d\n", constant->methodref.class_index, constant->methodref.name_and_type_index); break; case CONSTANT_InterfaceMethodref: - debugf("CONSTANT_InterfaceMethodref class_index=%d name_and_type_index=%d\n", + printf("CONSTANT_InterfaceMethodref class_index=%d name_and_type_index=%d\n", constant->interfacemethodref.class_index, constant->interfacemethodref.name_and_type_index); break; case CONSTANT_String: - debugf("CONSTANT_String string_index=%d\n", + printf("CONSTANT_String string_index=%d\n", constant->string.string_index); break; case CONSTANT_Integer: - debugf("CONSTANT_Integer bytes=%d\n", + printf("CONSTANT_Integer bytes=%d\n", constant->integer.bytes); break; case CONSTANT_Float: - debugf("CONSTANT_Float bytes=%f\n", + printf("CONSTANT_Float bytes=%f\n", *(float *)(&constant->_float.bytes)); break; case CONSTANT_Long: - debugf("CONSTANT_Long bytes=%l\n", + printf("CONSTANT_Long bytes=%l\n", constant->_long.bytes); break; case CONSTANT_Double: - debugf("CONSTANT_Double bytes=%f\n", + printf("CONSTANT_Double bytes=%f\n", *(double *)(&constant->_double.bytes)); break; case CONSTANT_NameAndType: - debugf("CONSTANT_NameAndType %d %d\n", + printf("CONSTANT_NameAndType name_index=%d descriptor_index=%d\n", constant->nameandtype.name_index, constant->nameandtype.descriptor_index); break; case CONSTANT_Utf8: - debugf("CONSTANT_Utf8 length=%d bytes=", + printf("CONSTANT_Utf8 length=%d bytes=", constant->utf8.length); - print_utf8_string(constant); - debugf("\n"); + print__constant__utf8_string(constant); + printf("\n"); break; case CONSTANT_MethodHandle: - debugf("CONSTANT_MethodHandle reference_kind=%d reference_index=%d\n", + printf("CONSTANT_MethodHandle reference_kind=%d reference_index=%d\n", constant->methodhandle.reference_kind, constant->methodhandle.reference_index); break; case CONSTANT_MethodType: - debugf("CONSTANT_MethodType descriptor_index=%d\n", + printf("CONSTANT_MethodType descriptor_index=%d\n", constant->methodtype.descriptor_index); break; case CONSTANT_Dynamic: - debugf("CONSTANT_Dynamic bootstrap_method_attr_index=%d name_and_type_index=%d\n", + printf("CONSTANT_Dynamic bootstrap_method_attr_index=%d name_and_type_index=%d\n", constant->dynamic.bootstrap_method_attr_index, constant->dynamic.name_and_type_index); break; case CONSTANT_InvokeDynamic: - debugf("CONSTANT_InvokeDynamic bootstrap_method_attr_index=%d name_and_type_index=%d\n", + printf("CONSTANT_InvokeDynamic bootstrap_method_attr_index=%d name_and_type_index=%d\n", constant->invokedynamic.bootstrap_method_attr_index, constant->invokedynamic.name_and_type_index); break; case CONSTANT_Module: - debugf("CONSTANT_Module name_index=%d\n", + printf("CONSTANT_Module name_index=%d\n", constant->module.name_index); break; case CONSTANT_Package: - debugf("CONSTANT_Package name_index=%d\n", + printf("CONSTANT_Package name_index=%d\n", constant->package.name_index); break; } } -void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +static void print_bootstrap_methods(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) { - debugs(indent); - debugf("attribute_name_index: %d\n", attribute->attribute_name_index); + prints(indent); + printf("num_bootstrap_methods: %d\n", attribute->bootstrap_methods->num_bootstrap_methods); + prints(indent); + printf("bootstrap methods:\n"); + for (int i = 0; i < attribute->bootstrap_methods->num_bootstrap_methods; i++) { + prints(indent); + printf(" bootstrap_method %d:\n", i); + prints(indent); + printf(" bootstrap_method_ref: %d\n", attribute->bootstrap_methods->bootstrap_methods[i].bootstrap_method_ref); + prints(indent); + printf(" num_bootstrap_arguments: %d\n", attribute->bootstrap_methods->bootstrap_methods[i].num_bootstrap_arguments); + prints(indent); + printf(" bootstrap_arguments:\n"); + for (int j = 0; j < attribute->bootstrap_methods->bootstrap_methods[i].num_bootstrap_arguments; j++) { + prints(indent); + printf(" bootstrap_argument %d: %d\n", j, attribute->bootstrap_methods->bootstrap_methods[i].bootstrap_arguments[j]); + } + } +} + +static void print_nestmembers(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + prints(indent); + printf("number_of_classes: %d\n", attribute->nestmembers->number_of_classes); + prints(indent); + printf("classes:\n"); + for (int i = 0; i < attribute->nestmembers->number_of_classes; i++) { + prints(indent); + printf(" class %d:\n", i); + prints(indent); + prints(" "); + print_constant(&constant_pool[attribute->nestmembers->classes[i] - 1]); + int ix = constant_pool[attribute->nestmembers->classes[i] - 1].class.name_index; + prints(indent); + prints(" "); + print_constant(&constant_pool[ix - 1]); + } +} + +static void print_nesthost(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + prints(indent); + printf("host_class_index: %d\n", attribute->nesthost->host_class_index); +} + +static void print_constantvalue(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + prints(indent); + printf("constantvalue_index %d\n", attribute->constantvalue->constantvalue_index); + + + struct constant * value = &constant_pool[attribute->constantvalue->constantvalue_index - 1]; + prints(indent); + prints(" "); + print_constant(value); + if (value->tag == CONSTANT_String) { + prints(indent); + prints(" "); + print_constant(&constant_pool[value->string.string_index - 1]); + } +} + +static void print_code(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + // print code + prints(indent); + printf("max_stack %d\n", attribute->code->max_stack); + prints(indent); + printf("max_locals %d\n", attribute->code->max_locals); + prints(indent); + printf("code_length %d\n", attribute->code->code_length); + + // dump code + prints(indent); + printf("code:\n"); + uint32_t pc = 0; + while (pc < attribute->code->code_length) { + prints(indent); + prints(" "); + pc = decode_print_instruction(attribute->code->code, pc); + } + + + prints(indent); + printf("exception_table_length: %d\n", attribute->code->exception_table_length); + prints(indent); + printf("exceptions:\n"); + for (int i = 0; i < attribute->code->exception_table_length; i++) { + prints(indent); + printf(" exception %d:\n", i); + prints(indent); + printf(" start_pc: %d\n", attribute->code->exception_table[i].start_pc); + prints(indent); + printf(" end_pc: %d\n", attribute->code->exception_table[i].end_pc); + prints(indent); + printf(" handler_pc: %d\n", attribute->code->exception_table[i].handler_pc); + prints(indent); + printf(" catch_type: %d\n", attribute->code->exception_table[i].catch_type); + } + prints(indent); + printf("attributes_count: %d\n", attribute->code->attributes_count); + prints(indent); + printf("attributes:\n"); + for (int i = 0; i < attribute->code->attributes_count; i++) { + char indent2[string_length(indent) + 2 + 1]; + string_copy(indent2, indent); + string_copy(indent2 + string_length(indent), " "); + prints(indent); + printf(" attribute %d:\n", i); + print_attribute(indent2, &attribute->code->attributes[i], constant_pool); + } + +} + +static void print_line_number_table(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + prints(indent); + printf("line_number_table_length: %d\n", attribute->line_number_table->line_number_table_length); + prints(indent); + printf("line_number_table:\n"); + for (int i = 0; i < attribute->line_number_table->line_number_table_length; i++) { + prints(indent); + printf(" start_pc=%d line_number=%d\n", + attribute->line_number_table->line_number_table[i].start_pc, + attribute->line_number_table->line_number_table[i].line_number); + } +} + +static void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + prints(indent); + printf("attribute_name_index: %d\n", attribute->attribute_name_index); struct constant * attribute_name = &constant_pool[attribute->attribute_name_index - 1]; - debugs(indent); - debugs(" "); + prints(indent); + prints(" "); print_constant(attribute_name); - if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "ConstantValue")) { - debugs(indent); - debugf("constantvalue_index %d\n", attribute->constantvalue->constantvalue_index); - - - struct constant * value = &constant_pool[attribute->constantvalue->constantvalue_index - 1]; - debugs(indent); - debugs(" "); - print_constant(value); - if (value->tag == CONSTANT_String) { - debugs(indent); - debugs(" "); - print_constant(&constant_pool[value->string.string_index - 1]); - } - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "Code")) { - // print code - debugs(indent); - debugf("max_stack %d\n", attribute->code->max_stack); - debugs(indent); - debugf("max_locals %d\n", attribute->code->max_locals); - debugs(indent); - debugf("code_length %d\n", attribute->code->code_length); - - // dump code - debugs(indent); - debugf("code:\n"); - uint32_t pc = 0; - while (pc < attribute->code->code_length) { - debugs(indent); - debugs(" "); - pc = decode_print_instruction(attribute->code->code, pc); - } - - - debugs(indent); - debugf("exception_table_length: %d\n", attribute->code->exception_table_length); - debugs(indent); - debugf("exceptions:\n"); - for (int i = 0; i < attribute->code->exception_table_length; i++) { - debugs(indent); - debugf(" exception %d:\n", i); - debugs(indent); - debugf(" start_pc: %d\n", attribute->code->exception_table[i].start_pc); - debugs(indent); - debugf(" end_pc: %d\n", attribute->code->exception_table[i].end_pc); - debugs(indent); - debugf(" handler_pc: %d\n", attribute->code->exception_table[i].handler_pc); - debugs(indent); - debugf(" catch_type: %d\n", attribute->code->exception_table[i].catch_type); - } - debugs(indent); - debugf("attributes_count: %d\n", attribute->code->attributes_count); - debugs(indent); - debugf("attributes:\n"); - for (int i = 0; i < attribute->code->attributes_count; i++) { - char indent2[string_length(indent) + 2 + 1]; - string_copy(indent2, indent); - string_copy(indent2 + string_length(indent), " "); - debugs(indent); - debugf(" attribute %d:\n", i); - print_attribute(indent2, &attribute->code->attributes[i], constant_pool); - } - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { - debugs(indent); - debugf("num_bootstrap_methods: %d\n", attribute->bootstrapmethods->num_bootstrap_methods); - debugs(indent); - debugf("bootstrap methods:\n"); - for (int i = 0; i < attribute->bootstrapmethods->num_bootstrap_methods; i++) { - debugs(indent); - debugf(" bootstrap_method %d:\n", i); - debugs(indent); - debugf(" bootstrap_method_ref: %d\n", attribute->bootstrapmethods->bootstrap_methods[i].bootstrap_method_ref); - debugs(indent); - debugf(" num_bootstrap_arguments: %d\n", attribute->bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments); - debugs(indent); - debugf(" bootstrap_arguments:\n"); - for (int j = 0; j < attribute->bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; j++) { - debugs(indent); - debugf(" bootstrap_argument %d: %d\n", j, attribute->bootstrapmethods->bootstrap_methods[i].bootstrap_arguments[j]); - } - } - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestHost")) { - debugs(indent); - debugf("host_class_index: %d\n", attribute->nesthost->host_class_index); - } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestMembers")) { - debugs(indent); - debugf("number_of_classes: %d\n", attribute->nestmembers->number_of_classes); - debugs(indent); - debugf("classes:\n"); - for (int i = 0; i < attribute->nestmembers->number_of_classes; i++) { - debugs(indent); - debugf(" class %d:\n", i); - debugs(indent); - debugs(" "); - print_constant(&constant_pool[attribute->nestmembers->classes[i] - 1]); - int ix = constant_pool[attribute->nestmembers->classes[i] - 1].class.name_index; - debugs(indent); - debugs(" "); - print_constant(&constant_pool[ix - 1]); - } + if (constant_equal(attribute_name, "ConstantValue")) { + print_constantvalue(indent, attribute, constant_pool); + } else if (constant_equal(attribute_name, "Code")) { + print_code(indent, attribute, constant_pool); + } else if (constant_equal(attribute_name, "BootstrapMethods")) { + print_bootstrap_methods(indent, attribute, constant_pool); + } else if (constant_equal(attribute_name, "NestHost")) { + print_nesthost(indent, attribute, constant_pool); + } else if (constant_equal(attribute_name, "NestMembers")) { + print_nestmembers(indent, attribute, constant_pool); + } else if (constant_equal(attribute_name, "LineNumberTable")) { + print_line_number_table(indent, attribute, constant_pool); } } void print_class_file(struct class_file * class_file) { - debugf("magic %08x\n", class_file->magic); - debugf("minor_version %d\n", class_file->minor_version); - debugf("major_version %d\n", class_file->major_version); - debugf("constant_pool_count %d\n", class_file->constant_pool_count); + printf("magic %08x\n", class_file->magic); + printf("minor_version %d\n", class_file->minor_version); + printf("major_version %d\n", class_file->major_version); + printf("constant_pool_count %d\n", class_file->constant_pool_count); - debugf("constants:\n"); + printf("constants:\n"); for (int i = 0; i < class_file->constant_pool_count - 1; i++) { if (class_file->constant_pool[i].tag != 0) { - debugf("%4d: ", i + 1); + printf("%4d: ", i + 1); print_constant(&class_file->constant_pool[i]); } } - debugf("access_flags %04x\n", class_file->access_flags); - debugf("this_class %d\n", class_file->this_class); - debugf("super_class %d\n", class_file->super_class); - debugf("interfaces_count %d\n", class_file->interfaces_count); + printf("access_flags %04x\n", class_file->access_flags); + printf("this_class %d\n", class_file->this_class); + printf("super_class %d\n", class_file->super_class); + printf("interfaces_count %d\n", class_file->interfaces_count); - debugf("interfaces:\n"); + printf("interfaces:\n"); for (int i = 0; i < class_file->interfaces_count; i++) { - debugf(" interface %3d:\n", i); + printf(" interface %3d:\n", i); int interface_index = class_file->interfaces[i]; - debugs(" "); + prints(" "); struct constant * class_constant = &class_file->constant_pool[interface_index - 1]; print_constant(class_constant); - debugs(" "); + prints(" "); struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1]; print_constant(class_name_constant); } - debugf("fields_count %d\n", class_file->fields_count); - debugf("fields:\n"); + printf("fields_count %d\n", class_file->fields_count); + printf("fields:\n"); for (int i = 0; i < class_file->fields_count; i++) { - debugf(" field %d:\n", i); - debugf(" access_flags %d\n", class_file->fields[i].access_flags); - debugf(" name_index %d\n", class_file->fields[i].name_index); - debugf(" "); + printf(" field %d:\n", i); + printf(" access_flags %d\n", class_file->fields[i].access_flags); + printf(" name_index %d\n", class_file->fields[i].name_index); + printf(" "); print_constant(&class_file->constant_pool[class_file->fields[i].name_index - 1]); - debugf(" descriptor_index %d\n", class_file->fields[i].descriptor_index); - debugf(" "); + printf(" descriptor_index %d\n", class_file->fields[i].descriptor_index); + printf(" "); print_constant(&class_file->constant_pool[class_file->fields[i].descriptor_index - 1]); - debugf(" attributes_count %d\n", class_file->fields[i].attributes_count); - debugf(" attributes:\n"); + printf(" attributes_count %d\n", class_file->fields[i].attributes_count); + printf(" attributes:\n"); for (int j = 0; j < class_file->fields[i].attributes_count; j++) { - debugf(" attribute %d:\n", j); + printf(" attribute %d:\n", j); print_attribute(" ", &class_file->fields[i].attributes[j], class_file->constant_pool); } } - debugf("methods_count %d\n", class_file->methods_count); - debugf("methods:\n"); + printf("methods_count %d\n", class_file->methods_count); + printf("methods:\n"); for (int i = 0; i < class_file->methods_count; i++) { - debugf(" method %d:\n", i); - debugf(" access_flags %04x\n", class_file->methods[i].access_flags); - debugf(" name_index %d\n", class_file->methods[i].name_index); - debugf(" "); + printf(" method %d:\n", i); + printf(" access_flags %04x\n", class_file->methods[i].access_flags); + printf(" name_index %d\n", class_file->methods[i].name_index); + printf(" "); print_constant(&class_file->constant_pool[class_file->methods[i].name_index - 1]); - debugf(" descriptor_index %d\n", class_file->methods[i].descriptor_index); - debugf(" "); + printf(" descriptor_index %d\n", class_file->methods[i].descriptor_index); + printf(" "); print_constant(&class_file->constant_pool[class_file->methods[i].descriptor_index - 1]); - debugf(" attributes_count %d\n", class_file->methods[i].attributes_count); - debugf(" attributes:\n"); + printf(" attributes_count %d\n", class_file->methods[i].attributes_count); + printf(" attributes:\n"); for (int j = 0; j < class_file->methods[i].attributes_count; j++) { - debugf(" attribute %d:\n", j); + printf(" attribute %d:\n", j); print_attribute(" ", &class_file->methods[i].attributes[j], class_file->constant_pool); } } - debugf("attributes_count %d\n", class_file->attributes_count); - debugf("attributes:\n"); + printf("attributes_count %d\n", class_file->attributes_count); + printf("attributes:\n"); for (int i = 0; i < class_file->attributes_count; i++) { - debugf(" attribute %d:\n", i); + printf(" attribute %d:\n", i); print_attribute(" ", &class_file->attributes[i], class_file->constant_pool); } } diff --git a/c/debug_class_file.h b/c/debug_class_file.h index 4a543d7..d992ab8 100644 --- a/c/debug_class_file.h +++ b/c/debug_class_file.h @@ -2,7 +2,4 @@ #include "class_file.h" -void print_utf8_string(struct constant * constant); -void print_constant(struct constant * constant); -void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool); void print_class_file(struct class_file * class_file); diff --git a/c/execute.c b/c/execute.c index 7f9abff..13ffd92 100644 --- a/c/execute.c +++ b/c/execute.c @@ -7,6 +7,7 @@ #include "field_size.h" #include "debug.h" #include "parse_type.h" +#include "backtrace.h" void op_aaload(struct vm * vm) { @@ -125,6 +126,7 @@ void op_astore_3(struct vm * vm) void op_athrow(struct vm * vm) { + backtrace_print(vm); assert(!"op_athrow"); } @@ -224,7 +226,7 @@ void op_checkcast(struct vm * vm, uint32_t index) 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); + debug_print__constant__utf8_string(class_name_constant); debugf("\n"); // superclass lookup @@ -1193,7 +1195,7 @@ void op_instanceof(struct vm * vm, uint32_t index) 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); + debug_print__constant__utf8_string(class_name_constant); debugf("\n"); // superclass lookup @@ -1223,7 +1225,7 @@ void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count) class_entry, vm->current_frame->class_entry); - vm_special_method_call(vm, method_entry.class_entry, method_entry.method_info); + vm_special_method_call(vm, method_entry.class_entry, &method_entry); } void op_invokespecial(struct vm * vm, uint32_t index) @@ -1234,7 +1236,7 @@ void op_invokespecial(struct vm * vm, uint32_t index) index, vm->current_frame->class_entry); - vm_special_method_call(vm, method_entry->class_entry, method_entry->method_info); + vm_special_method_call(vm, method_entry->class_entry, method_entry); } void op_invokestatic(struct vm * vm, uint32_t index) @@ -1249,7 +1251,7 @@ void op_invokestatic(struct vm * vm, uint32_t index) declared the resolved method is initialized if that class or interface has not already been initialized (§5.5). */ - vm_static_method_call(vm, method_entry->class_entry, method_entry->method_info); + vm_static_method_call(vm, method_entry->class_entry, method_entry); } #include "debug.h" @@ -1283,7 +1285,7 @@ void op_invokevirtual(struct vm * vm, uint32_t index) class_entry, vm->current_frame->class_entry); - vm_special_method_call(vm, method_entry.class_entry, method_entry.method_info); + vm_special_method_call(vm, method_entry.class_entry, &method_entry); } void op_ior(struct vm * vm) diff --git a/c/execute_helper.h b/c/execute_helper.h index cf6ac7a..929a7a9 100644 --- a/c/execute_helper.h +++ b/c/execute_helper.h @@ -1,5 +1,3 @@ -#include "debug_class_file.h" - static inline void class_entry_field_entry_from_constant_index(struct vm * vm, int32_t index, struct class_entry ** class_entry, diff --git a/c/find_attribute.c b/c/find_attribute.c new file mode 100644 index 0000000..f7ca750 --- /dev/null +++ b/c/find_attribute.c @@ -0,0 +1,55 @@ +#include "assert.h" +#include "class_file.h" +#include "bytes.h" +#include "debug.h" +#include "printf.h" + +int find_code_name_index(struct class_file * class_file) +{ + for (int i = 0; i < class_file->constant_pool_count - 1; i++) { + struct constant * constant = &class_file->constant_pool[i]; + if (constant->tag == CONSTANT_Utf8) { + if (constant_equal(constant, "Code")) { + return i + 1; + } + } + } + return 0; +} + +int find_constantvalue_name_index(struct class_file * class_file) +{ + for (int i = 0; i < class_file->constant_pool_count - 1; i++) { + struct constant * constant = &class_file->constant_pool[i]; + if (constant->tag == CONSTANT_Utf8) { + if (constant_equal(constant, "ConstantValue")) { + return i + 1; + } + } + } + return 0; +} + +int find_linenumbertable_name_index(struct class_file * class_file) +{ + for (int i = 0; i < class_file->constant_pool_count - 1; i++) { + struct constant * constant = &class_file->constant_pool[i]; + if (constant->tag == CONSTANT_Utf8) { + if (constant_equal(constant, "LineNumberTable")) { + return i + 1; + } + } + } + return 0; +} + +struct attribute_info * find_attribute(int name_index, + int attributes_count, + struct attribute_info * attributes) +{ + for (int i = 0; i < attributes_count; i++) { + if (attributes[i].attribute_name_index == name_index) + return &attributes[i]; + } + return nullptr; +} diff --git a/c/find_attribute.h b/c/find_attribute.h new file mode 100644 index 0000000..bffbca6 --- /dev/null +++ b/c/find_attribute.h @@ -0,0 +1,10 @@ +#pragma once + +#include "class_file.h" + +int find_code_name_index(struct class_file * class_file); +int find_constantvalue_name_index(struct class_file * class_file); +int find_linenumbertable_name_index(struct class_file * class_file); +struct attribute_info * find_attribute(int name_index, + int attributes_count, + struct attribute_info * attributes); diff --git a/c/frame.c b/c/frame.c index b9ed2f9..de6dd1d 100644 --- a/c/frame.c +++ b/c/frame.c @@ -2,7 +2,6 @@ #include "assert.h" #include "class_file.h" -#include "debug_class_file.h" #include "bytes.h" #include "decode.h" #include "frame.h" @@ -11,43 +10,8 @@ #include "string.h" #include "native.h" #include "fatal.h" - -struct Code_attribute * get_code_attribute(int code_name_index, - int attributes_count, - struct attribute_info * attributes) -{ - for (int i = 0; i < attributes_count; i++) { - if (attributes[i].attribute_name_index == code_name_index) - return attributes[i].code; - } - return nullptr; -} - -int find_code_name_index(struct class_file * class_file) -{ - for (int i = 0; i < class_file->constant_pool_count; i++) { - struct constant * constant = &class_file->constant_pool[i]; - if (constant->tag == CONSTANT_Utf8) { - if (bytes_equal(constant->utf8.length, constant->utf8.bytes, "Code")) { - return i + 1; - } - } - } - return 0; -} - -int find_constantvalue_name_index(struct class_file * class_file) -{ - for (int i = 0; i < class_file->constant_pool_count; i++) { - struct constant * constant = &class_file->constant_pool[i]; - if (constant->tag == CONSTANT_Utf8) { - if (bytes_equal(constant->utf8.length, constant->utf8.bytes, "ConstantValue")) { - return i + 1; - } - } - } - return 0; -} +#include "debug.h" +#include "find_attribute.h" int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type) { @@ -56,7 +20,7 @@ int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_typ assert(descriptor_constant->utf8.bytes[0] == '('); debugf("method descriptor: "); - print_utf8_string(descriptor_constant); + debug_print__constant__utf8_string(descriptor_constant); debugf("\n"); int i = 1; @@ -107,7 +71,7 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) #ifdef DEBUG assert(class_name_constant->tag == CONSTANT_Utf8); #endif - print_constant(class_name_constant); + debug_print__constant__utf8_string(class_name_constant); debugf("\n"); if (class_entry->initialization_state == CLASS_INITIALIZED) @@ -164,27 +128,25 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) /* Next, if C declares a class or interface initialization method, execute that method. */ const uint8_t * method_name = (const uint8_t *)""; - int method_name_length = 8; + int method_name_length = string_length((const char *)method_name); const uint8_t * method_descriptor = (const uint8_t *)"()V"; - int method_descriptor_length = 3; + int method_descriptor_length = string_length((const char *)method_descriptor); - int methods_hash_table_length = class_entry->methods.length; - struct hash_table_entry * methods_hash_table = class_entry->methods.entry; + struct method_entry method_entry = + class_resolver_lookup_method_from_method_name_method_descriptor(class_entry, + method_name, + method_name_length, + method_descriptor, + method_descriptor_length); - struct method_info * method_info = class_resolver_lookup_method(methods_hash_table_length, - methods_hash_table, - method_name, - method_name_length, - method_descriptor, - method_descriptor_length); - if (method_info != nullptr) { - assert((method_info->access_flags & METHOD_ACC_STATIC) != 0); + if (method_entry.method_info != nullptr) { + assert((method_entry.method_info->access_flags & METHOD_ACC_STATIC) != 0); debugf("\n"); // tamper with next_pc vm->current_frame->next_pc = vm->current_frame->pc; - vm_static_method_call(vm, class_entry, method_info); + vm_static_method_call(vm, class_entry, &method_entry); vm->current_frame->initialization_frame = 1; return false; @@ -196,9 +158,9 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) return true; } -void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info, int nargs, uint8_t return_type) +void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry, int nargs, uint8_t return_type) { - debugf("vm_static_native_method_call: nargs %d\n", nargs); + debugf("vm_native_method_call: nargs %d\n", nargs); uint32_t args[nargs]; for (int i = 0; i < nargs; i++) { @@ -210,10 +172,10 @@ void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, str debugf("native:\n "); struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1]; struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; - print_constant(class_name_constant); + debug_print__constant__utf8_string(class_name_constant); debugf(" "); - struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_info->name_index - 1]; - print_constant(method_name_constant); + struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_entry->method_info->name_index - 1]; + debug_print__constant__utf8_string(method_name_constant); int java_lang_math_length = 14; @@ -360,22 +322,15 @@ void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, str assert(false); } -void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info, int nargs, uint8_t return_type) +void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry, int nargs, uint8_t return_type) { - int code_name_index = find_code_name_index(class_entry->class_file); - assert(code_name_index > 0); - - struct Code_attribute * code = get_code_attribute(code_name_index, - method_info->attributes_count, - method_info->attributes); - assert(code != nullptr); + assert(method_entry->code_attribute != nullptr); struct frame * old_frame = vm->current_frame; vm->current_frame = stack_push_frame(&vm->frame_stack, 1); - vm->current_frame->code = code; - vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals); - vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack); + vm->current_frame->local_variable = stack_push_data(&vm->data_stack, method_entry->code_attribute->max_locals); + vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, method_entry->code_attribute->max_stack); vm->current_frame->operand_stack_ix = 0; vm->current_frame->initialization_frame = 0; vm->current_frame->return_type = return_type; @@ -389,12 +344,13 @@ void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct met vm->current_frame->pc = 0; vm->current_frame->next_pc = 0; vm->current_frame->class_entry = class_entry; - vm->current_frame->method = method_info; + vm->current_frame->method_info = method_entry->method_info; + vm->current_frame->code_attribute = method_entry->code_attribute; debugf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix); } -void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info) +void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry) { /* If the method is not native, the nargs argument values are popped from the operand stack. A new frame is created on the Java Virtual Machine stack for @@ -407,19 +363,19 @@ void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, st */ uint8_t return_type; - struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1]; + struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_entry->method_info->descriptor_index - 1]; int nargs = descriptor_nargs(descriptor_constant, &return_type); nargs += 1; debugf("nargs+1: %d\n", nargs); - if (method_info->access_flags & METHOD_ACC_NATIVE) { - vm_native_method_call(vm, class_entry, method_info, nargs, return_type); + if (method_entry->method_info->access_flags & METHOD_ACC_NATIVE) { + vm_native_method_call(vm, class_entry, method_entry, nargs, return_type); } else { - vm_method_call(vm, class_entry, method_info, nargs, return_type); + vm_method_call(vm, class_entry, method_entry, nargs, return_type); } } -void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info) +void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry) { /* If the method is not native, the nargs argument values are popped from the operand stack. A new frame is created on the Java Virtual Machine stack for @@ -432,14 +388,14 @@ void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, str */ uint8_t return_type; - struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1]; + struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_entry->method_info->descriptor_index - 1]; int nargs = descriptor_nargs(descriptor_constant, &return_type); debugf("nargs %d\n", nargs); - if (method_info->access_flags & METHOD_ACC_NATIVE) { - vm_native_method_call(vm, class_entry, method_info, nargs, return_type); + if (method_entry->method_info->access_flags & METHOD_ACC_NATIVE) { + vm_native_method_call(vm, class_entry, method_entry, nargs, return_type); } else { - vm_method_call(vm, class_entry, method_info, nargs, return_type); + vm_method_call(vm, class_entry, method_entry, nargs, return_type); } } @@ -453,8 +409,8 @@ void vm_method_return(struct vm * vm) struct frame * old_frame = vm->current_frame; - stack_pop_data(&vm->data_stack, old_frame->code->max_locals); - stack_pop_data(&vm->data_stack, old_frame->code->max_stack); + stack_pop_data(&vm->data_stack, old_frame->code_attribute->max_locals); + stack_pop_data(&vm->data_stack, old_frame->code_attribute->max_stack); vm->current_frame = stack_pop_frame(&vm->frame_stack, 1); assert(vm->current_frame != old_frame); @@ -537,22 +493,14 @@ static void print_vm_stack(struct vm * vm) void vm_execute(struct vm * vm) { while (true) { - assert(vm->current_frame->pc < vm->current_frame->code->code_length); + assert(vm->current_frame->pc < vm->current_frame->code_attribute->code_length); print_vm_stack(vm); - decode_print_instruction(vm->current_frame->code->code, vm->current_frame->pc); - //uint32_t old_pc = vm->current_frame->pc; - //struct method_info * old_method = vm->current_frame->method; - decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc); - if (vm->frame_stack.ix == 1) { + decode_print_instruction(vm->current_frame->code_attribute->code, vm->current_frame->pc); + decode_execute_instruction(vm, vm->current_frame->code_attribute->code, vm->current_frame->pc); + if (vm->frame_stack.ix == 0) { debugf("terminate\n"); break; } - /* - if (vm->current_frame->method == old_method && vm->current_frame->pc == old_pc) { - // if the instruction did not branch, increment pc - vm->current_frame->pc = vm->current_frame->next_pc; - } - */ vm->current_frame->pc = vm->current_frame->next_pc; } } @@ -567,21 +515,18 @@ struct vm * vm_start(int class_hash_table_length, main_class_name, main_class_name_length); - const char * method_name = "main"; - int method_name_length = string_length(method_name); - const char * method_descriptor = "()V"; - int method_descriptor_length = string_length(method_descriptor); + const uint8_t * method_name = (const uint8_t *)"main"; + int method_name_length = string_length((const char *)method_name); + const uint8_t * method_descriptor = (const uint8_t *)"()V"; + int method_descriptor_length = string_length((const char *)method_descriptor); - int methods_hash_table_length = class_entry->methods.length; - struct hash_table_entry * methods_hash_table = class_entry->methods.entry; - - struct method_info * method_info = class_resolver_lookup_method(methods_hash_table_length, - methods_hash_table, - (const uint8_t *)method_name, - method_name_length, - (const uint8_t *)method_descriptor, - method_descriptor_length); - assert(method_info != nullptr); + struct method_entry method_entry = + class_resolver_lookup_method_from_method_name_method_descriptor(class_entry, + method_name, + method_name_length, + method_descriptor, + method_descriptor_length); + assert(method_entry.method_info != nullptr); static struct vm vm; vm.class_hash_table.entry = class_hash_table; @@ -597,16 +542,7 @@ struct vm * vm_start(int class_hash_table_length, uint32_t data[vm.data_stack.capacity]; vm.data_stack.data = data; - struct frame * entry_frame = stack_push_frame(&vm.frame_stack, 1); - struct Code_attribute code; - code.max_locals = 0; - code.max_stack = 0; - entry_frame->code = &code; - entry_frame->local_variable = 0; - entry_frame->operand_stack = 0; - entry_frame->operand_stack_ix = 0; - - vm_static_method_call(&vm, class_entry, method_info); + vm_static_method_call(&vm, class_entry, &method_entry); return &vm; } diff --git a/c/frame.h b/c/frame.h index 89064dd..b0a90a8 100644 --- a/c/frame.h +++ b/c/frame.h @@ -6,8 +6,8 @@ struct frame { struct class_entry * class_entry; - struct method_info * method; - struct Code_attribute * code; + struct method_info * method_info; + struct Code_attribute * code_attribute; uint32_t * local_variable; uint32_t * operand_stack; uint32_t pc; @@ -156,8 +156,8 @@ static inline double operand_stack_pop_f64(struct frame * frame) } bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry); -void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info); -void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info); +void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry); +void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry); void vm_method_return(struct vm * vm); void vm_execute(struct vm * vm); struct vm * vm_start(int class_hash_table_length, diff --git a/c/main_hosted.c b/c/main_hosted.c index 065d657..101a367 100644 --- a/c/main_hosted.c +++ b/c/main_hosted.c @@ -8,6 +8,7 @@ #include "file.h" #include "malloc.h" #include "memory_allocator.h" +#include "backtrace.h" static struct hash_table_entry * load_from_filenames(const char * filenames[], int length, int * hash_table_length) { @@ -53,5 +54,8 @@ int main(int argc, const char * argv[]) class_hash_table, main_class, main_class_length); + + backtrace_print(vm); + vm_execute(vm); } diff --git a/java.mk b/java.mk index 1b42f7c..38cad90 100644 --- a/java.mk +++ b/java.mk @@ -20,7 +20,9 @@ OBJ = \ c/native.o \ c/debug.o \ c/fatal.o \ - c/parse_type.o + c/parse_type.o \ + c/backtrace.o \ + c/find_attribute.o MAIN_DREAMCAST_OBJ = \ c/main_dreamcast.o \ diff --git a/java/lang/Exception.java b/java/lang/Exception.java new file mode 100644 index 0000000..ffb2e8a --- /dev/null +++ b/java/lang/Exception.java @@ -0,0 +1,20 @@ +package java.lang; + +public class Exception extends Throwable { + + public Exception() { + super(); + } + + public Exception(String message) { + super(message); + } + + public Exception(String message, Throwable cause) { + super(message, cause); + } + + public Exception(Throwable cause) { + super(cause); + } +} diff --git a/java/lang/Throwable.java b/java/lang/Throwable.java new file mode 100644 index 0000000..1d9398e --- /dev/null +++ b/java/lang/Throwable.java @@ -0,0 +1,23 @@ +package java.lang; + +public class Throwable { + + private String message; + private Throwable cause = this; + + public Throwable() { + } + + public Throwable(String message) { + this.message = message; + } + + public Throwable(String message, Throwable cause) { + this.message = message; + this.cause = cause; + } + + public Throwable(Throwable cause) { + this.cause = cause; + } +} diff --git a/p/TestException.java b/p/TestException.java new file mode 100644 index 0000000..90d094b --- /dev/null +++ b/p/TestException.java @@ -0,0 +1,11 @@ +package p; + +class TestException { + static void test() throws Exception { + throw new Exception("asdf"); + } + + public static void main() throws Exception { + test(); + } +}