diff --git a/Makefile b/Makefile index 5704539..e5f3bf1 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protec CFLAGS += -I$(MAKEFILE_PATH)/ CFLAGS += -I$(MAKEFILE_PATH)/c 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 1822134..75ac6e4 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -20,9 +20,7 @@ static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) { struct constant * field_descriptor_constant = &class_file->constant_pool[field_info->descriptor_index - 1]; - #ifdef DEBUG assert(field_descriptor_constant->tag == CONSTANT_Utf8); - #endif return field_size(field_descriptor_constant->utf8.bytes[0]); } @@ -86,6 +84,7 @@ static int add_superclass_instance_fields(int class_hash_table_length, struct field_entry * field_entry = malloc_class_arena((sizeof (struct field_entry))); field_entry->instance_index = instance_index; field_entry->field_info = field_info; + field_entry->class_entry = class_entry; struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1]; assert(name_constant->tag == CONSTANT_Utf8); @@ -126,6 +125,7 @@ static int32_t class_resolver_create_fields_hash_table(int class_hash_table_leng struct field_entry * field_entry = malloc_class_arena((sizeof (struct field_entry))); field_entry->static_index = static_index; field_entry->field_info = field_info; + field_entry->class_entry = class_entry; static_index += field_info_field_size(class_entry->class_file, field_info); struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1]; @@ -332,49 +332,83 @@ struct field_entry * class_resolver_lookup_field(int fields_hash_table_length, int field_name_length) { debugf("class_resolver_lookup_field: "); - for (int i = 0; i < field_name_length; i++) { debugc(field_name[i]); } + debug_print__string(field_name, field_name_length); debugc('\n'); struct hash_table_entry * e = hash_table_find(fields_hash_table_length, fields_hash_table, field_name, field_name_length); - assert(e != nullptr); - debugf("%p\n", e->value); - - return (struct field_entry *)e->value; + if (e == nullptr) + return nullptr; + else + return (struct field_entry *)e->value; } -struct field_entry * class_resolver_lookup_field_from_fieldref_index(int fields_hash_table_length, - struct hash_table_entry * fields_hash_table, - struct class_entry * class_entry, - int fieldref_index) +struct field_entry * resolve_field_entry_from_superclasses(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + struct class_entry * class_entry, + struct constant * field_name_constant) { - if (class_entry->attribute_entry[fieldref_index - 1].field_entry != nullptr) { - debugf("class_resolver_lookup_field_from_fieldref_index %d: [cached]\n", fieldref_index); - return class_entry->attribute_entry[fieldref_index - 1].field_entry; + while (true) { + struct field_entry * field_entry = class_resolver_lookup_field(class_entry->fields.length, + class_entry->fields.entry, + field_name_constant->utf8.bytes, + field_name_constant->utf8.length); + if (field_entry != nullptr) + return field_entry; + + 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); + + // lookup the field 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); } - struct constant * fieldref_constant = &class_entry->class_file->constant_pool[fieldref_index - 1]; - #ifdef DEBUG - assert(fieldref_constant->tag == CONSTANT_Fieldref); - #endif - struct constant * nameandtype_constant = &class_entry->class_file->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1]; - #ifdef DEBUG - assert(nameandtype_constant->tag == CONSTANT_NameAndType); - #endif - struct constant * field_name_constant = &class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1]; - #ifdef DEBUG - assert(field_name_constant->tag == CONSTANT_Utf8); - #endif + return nullptr; +} - struct field_entry * field_entry = class_resolver_lookup_field(fields_hash_table_length, - fields_hash_table, - field_name_constant->utf8.bytes, - field_name_constant->utf8.length); +struct field_entry * class_resolver_lookup_field_from_fieldref_index(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + struct class_entry * origin_class_entry, + int fieldref_index) +{ + if (origin_class_entry->attribute_entry[fieldref_index - 1].field_entry != nullptr) { + debugf("class_resolver_lookup_field_from_fieldref_index %d: [cached]\n", fieldref_index); + return origin_class_entry->attribute_entry[fieldref_index - 1].field_entry; + } + + struct constant * fieldref_constant = &origin_class_entry->class_file->constant_pool[fieldref_index - 1]; + assert(fieldref_constant->tag == CONSTANT_Fieldref); + struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1]; + assert(nameandtype_constant->tag == CONSTANT_NameAndType); + struct constant * field_name_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1]; + assert(field_name_constant->tag == CONSTANT_Utf8); + + struct class_entry * field_class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length, + class_hash_table, + origin_class_entry, + fieldref_constant->fieldref.class_index); + + assert(field_class_entry != nullptr); + + struct field_entry * field_entry = resolve_field_entry_from_superclasses(class_hash_table_length, + class_hash_table, + field_class_entry, + field_name_constant); + assert(field_entry != nullptr); // cache the result - class_entry->attribute_entry[fieldref_index - 1].field_entry = field_entry; + origin_class_entry->attribute_entry[fieldref_index - 1].field_entry = field_entry; return field_entry; } @@ -404,59 +438,66 @@ struct method_info * class_resolver_lookup_method(int methods_hash_table_length, 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) +static struct Code_attribute * resolve_code_attribute(struct class_entry * class_entry, + struct method_info * method_info) { - struct constant * interfacemethodref_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_index - 1]; - assert(interfacemethodref_constant->tag == CONSTANT_InterfaceMethodref || interfacemethodref_constant->tag == CONSTANT_Methodref); - 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); + if ((method_info->access_flags & METHOD_ACC_NATIVE) != 0) { + return nullptr; + } - struct class_entry * class_entry = objectref_class_entry; + 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 attribute->code; +} + +static void resolve_method_entry(struct class_entry * class_entry, + struct constant * method_name_constant, + struct constant * method_descriptor_constant, + struct method_entry * method_entry) +{ + 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) + return; + + method_entry->class_entry = class_entry; + method_entry->method_info = method_info; + method_entry->code_attribute = resolve_code_attribute(class_entry, method_info); + + debugf("method resolved:\n"); + debugf(" class: "); + debug_print__class_file__class_name(class_entry->class_file); + debugf("\n method: "); + debug_print__method_info__method_name(class_entry->class_file, method_info); + debugc('\n'); +} + +static void resolve_method_entry_from_superclasses(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + struct class_entry * class_entry, + struct constant * method_name_constant, + struct constant * method_descriptor_constant, + struct method_entry * method_entry) +{ + assert(method_entry != nullptr); + + method_entry->method_info = nullptr; 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_file__class_name(class_entry->class_file); - debugf("\n method: "); - debug_print__method_info__method_name(class_entry->class_file, 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); - - 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, - }; - } - } + resolve_method_entry(class_entry, + method_name_constant, + method_descriptor_constant, + method_entry); + if (method_entry->method_info != nullptr) + break; if (class_entry->class_file->super_class == 0) break; @@ -465,8 +506,6 @@ 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); - debug_print__constant__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, @@ -475,19 +514,44 @@ struct method_entry class_resolver_lookup_method_from_interfacemethodref_index(i class_entry->class_file->super_class); assert(class_entry != nullptr); } - - print__class_file__class_name(objectref_class_entry->class_file); - printc('\n'); - assert(!"interfacemethodref method does not exist"); } -struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length, - 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_objectref_class(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + int32_t methodref_index, + struct class_entry * objectref_class_entry, + struct class_entry * origin_class_entry) +{ + struct constant * methodref_constant = &origin_class_entry->class_file->constant_pool[methodref_index - 1]; + assert(methodref_constant->tag == CONSTANT_InterfaceMethodref || methodref_constant->tag == CONSTANT_Methodref); + 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); + 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; + + struct method_entry method_entry; + + resolve_method_entry_from_superclasses(class_hash_table_length, + class_hash_table, + class_entry, + method_name_constant, + method_descriptor_constant, + &method_entry); + + return method_entry; +} + +struct method_entry * class_resolver_lookup_method_from_origin_class(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + int32_t methodref_index, + struct class_entry * origin_class_entry) { 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_origin_class %d: [cached]\n", methodref_index); return origin_class_entry->attribute_entry[methodref_index - 1].method_entry; } @@ -505,61 +569,20 @@ struct method_entry * class_resolver_lookup_method_from_methodref_index(int clas origin_class_entry, methodref_constant->methodref.class_index); - 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) { - // cache the result - debugf("method resolved:\n"); - debugf(" class: "); - debug_print__class_file__class_name(class_entry->class_file); - debugf("\n method: "); - debug_print__method_info__method_name(class_entry->class_file, method_info); - debugc('\n'); + 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->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); - if ((method_info->access_flags & METHOD_ACC_NATIVE) != 0) { - assert(attribute == nullptr); - method_entry->code_attribute = nullptr; - } else { - assert(attribute != nullptr); - method_entry->code_attribute = attribute->code; - } + resolve_method_entry_from_superclasses(class_hash_table_length, + class_hash_table, + class_entry, + method_name_constant, + method_descriptor_constant, + method_entry); - origin_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry; - return method_entry; - } + assert(method_entry->method_info != nullptr); - if (class_entry->class_file->super_class == 0) - break; + origin_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry; - 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); - debug_print__constant__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(!"methodref method does not exist"); + return method_entry; } struct method_entry class_resolver_lookup_method_from_method_name_method_descriptor(struct class_entry * class_entry, diff --git a/c/class_resolver.h b/c/class_resolver.h index a25de62..36a9c20 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -26,6 +26,7 @@ union attribute_entry { }; struct field_entry { + struct class_entry * class_entry; struct field_info * field_info; union { int32_t instance_index; @@ -63,15 +64,17 @@ 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_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 hash_table_entry * class_hash_table, - int32_t methodref_index, - struct class_entry * origin_class_entry); + +struct method_entry class_resolver_lookup_method_from_objectref_class(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + int32_t methodref_index, + struct class_entry * objectref_class_entry, + struct class_entry * origin_class_entry); +struct method_entry * class_resolver_lookup_method_from_origin_class(int class_hash_table_length, + 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, diff --git a/c/execute.c b/c/execute.c index 107d883..ef05551 100644 --- a/c/execute.c +++ b/c/execute.c @@ -734,20 +734,19 @@ void op_fsub(struct vm * vm) void op_getfield(struct vm * vm, uint32_t index) { - struct class_entry * class_entry; - struct field_entry * field_entry; - struct constant * field_descriptor_constant; - class_entry_field_entry_from_constant_index(vm, index, - &class_entry, - &field_entry, - &field_descriptor_constant); - - debugf("getfield instance_index %d\n", field_entry->instance_index); - struct objectref * objectref = operand_stack_pop_ref(vm->current_frame); if (objectref == nullptr) return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); + struct constant * field_descriptor_constant; + struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length, + vm->class_hash_table.entry, + vm->current_frame->class_entry, + index, + &field_descriptor_constant); + + debugf("getfield instance_index %d\n", field_entry->instance_index); + switch (field_descriptor_constant->utf8.bytes[0]) { case 'B': [[fallthrough]]; case 'C': [[fallthrough]]; @@ -778,18 +777,19 @@ void op_getfield(struct vm * vm, uint32_t index) void op_getstatic(struct vm * vm, uint32_t index) { - struct class_entry * class_entry; - struct field_entry * field_entry; struct constant * field_descriptor_constant; - class_entry_field_entry_from_constant_index(vm, index, - &class_entry, - &field_entry, - &field_descriptor_constant); + struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length, + vm->class_hash_table.entry, + vm->current_frame->class_entry, + index, + &field_descriptor_constant); /* On successful resolution of the field, the class or interface that declared the resolved field is initialized if that class or interface has not already been initialized (§5.5). */ + struct class_entry * class_entry = field_entry->class_entry; + if (!vm_initialize_class(vm, class_entry)) return; @@ -1184,14 +1184,13 @@ void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count) struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, count); if (objectref == nullptr) return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); - struct class_entry * class_entry = objectref->class_entry; 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); + class_resolver_lookup_method_from_objectref_class(vm->class_hash_table.length, + vm->class_hash_table.entry, + index, + objectref->class_entry, + vm->current_frame->class_entry); vm_special_method_call(vm, method_entry.class_entry, &method_entry); } @@ -1200,9 +1199,9 @@ void op_invokespecial(struct vm * vm, uint32_t index) { struct class_entry * origin_class_entry = vm->current_frame->class_entry; - struct constant * interfacemethodref_constant = &origin_class_entry->class_file->constant_pool[index - 1]; - assert(interfacemethodref_constant->tag == CONSTANT_Methodref); - struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_constant->interfacemethodref.name_and_type_index - 1]; + struct constant * methodref_constant = &origin_class_entry->class_file->constant_pool[index - 1]; + assert(methodref_constant->tag == CONSTANT_Methodref); + 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); 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); @@ -1216,10 +1215,10 @@ void op_invokespecial(struct vm * vm, uint32_t index) return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); struct method_entry * method_entry = - class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length, - vm->class_hash_table.entry, - index, - vm->current_frame->class_entry); + class_resolver_lookup_method_from_origin_class(vm->class_hash_table.length, + vm->class_hash_table.entry, + index, + vm->current_frame->class_entry); vm_special_method_call(vm, method_entry->class_entry, method_entry); } @@ -1227,10 +1226,10 @@ void op_invokespecial(struct vm * vm, uint32_t index) void op_invokestatic(struct vm * vm, uint32_t index) { struct method_entry * method_entry = - class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length, - vm->class_hash_table.entry, - index, - vm->current_frame->class_entry); + class_resolver_lookup_method_from_origin_class(vm->class_hash_table.length, + vm->class_hash_table.entry, + index, + vm->current_frame->class_entry); /* On successful resolution of the method, the class or interface that declared the resolved method is initialized if that class or interface has @@ -1257,14 +1256,13 @@ void op_invokevirtual(struct vm * vm, uint32_t index) struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, nargs + 1); if (objectref == nullptr) return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); - struct class_entry * class_entry = objectref->class_entry; 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); + class_resolver_lookup_method_from_objectref_class(vm->class_hash_table.length, + vm->class_hash_table.entry, + index, + objectref->class_entry, + vm->current_frame->class_entry); vm_special_method_call(vm, method_entry.class_entry, &method_entry); } @@ -1893,14 +1891,12 @@ void op_pop2(struct vm * vm) void op_putfield(struct vm * vm, uint32_t index) { - struct class_entry * class_entry; - struct field_entry * field_entry; struct constant * field_descriptor_constant; - class_entry_field_entry_from_constant_index(vm, - index, - &class_entry, - &field_entry, - &field_descriptor_constant); + struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length, + vm->class_hash_table.entry, + vm->current_frame->class_entry, + index, + &field_descriptor_constant); /* The type of a value stored by a putfield instruction must be compatible with the descriptor of the referenced field (§4.3.2). If the field descriptor @@ -1948,13 +1944,12 @@ void op_putfield(struct vm * vm, uint32_t index) void op_putstatic(struct vm * vm, uint32_t index) { - struct class_entry * class_entry; - struct field_entry * field_entry; struct constant * field_descriptor_constant; - class_entry_field_entry_from_constant_index(vm, index, - &class_entry, - &field_entry, - &field_descriptor_constant); + struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length, + vm->class_hash_table.entry, + vm->current_frame->class_entry, + index, + &field_descriptor_constant); /* The type of a value stored by a putstatic instruction must be compatible with the descriptor of the referenced field (§4.3.2). If the field @@ -1968,6 +1963,8 @@ void op_putstatic(struct vm * vm, uint32_t index) the resolved field is initialized if that class or interface has not already been initialized (§5.5). */ + struct class_entry * class_entry = field_entry->class_entry; + if (!vm_initialize_class(vm, class_entry)) return; diff --git a/c/execute_helper.h b/c/execute_helper.h index 6f9107e..0465454 100644 --- a/c/execute_helper.h +++ b/c/execute_helper.h @@ -3,39 +3,24 @@ struct objectref * class_resolver_lookup_string(struct vm * vm, struct class_entry * class_entry, const int string_index); -static inline void class_entry_field_entry_from_constant_index(struct vm * vm, - int32_t index, - struct class_entry ** class_entry, - struct field_entry ** field_entry, - struct constant ** field_descriptor_constant) +static inline struct field_entry * field_entry_from_constant_index(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + struct class_entry * origin_class_entry, + int32_t index, + struct constant ** field_descriptor_constant) { - struct constant * fieldref_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1]; - #ifdef DEBUG + struct field_entry * field_entry = class_resolver_lookup_field_from_fieldref_index(class_hash_table_length, + class_hash_table, + origin_class_entry, + index); + assert(field_entry != nullptr); + + struct constant * fieldref_constant = &origin_class_entry->class_file->constant_pool[index - 1]; assert(fieldref_constant->tag == CONSTANT_Fieldref); - #endif - - *class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length, - vm->class_hash_table.entry, - vm->current_frame->class_entry, - fieldref_constant->fieldref.class_index); - - assert(*class_entry != nullptr); - - int fields_hash_table_length = (*class_entry)->fields.length; - struct hash_table_entry * fields_hash_table = (*class_entry)->fields.entry; - - *field_entry = class_resolver_lookup_field_from_fieldref_index(fields_hash_table_length, - fields_hash_table, - vm->current_frame->class_entry, - index); - assert(*field_entry != nullptr); - - struct constant * nameandtype_constant = &vm->current_frame->class_entry->class_file->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1]; - #ifdef DEBUG + struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1]; assert(nameandtype_constant->tag == CONSTANT_NameAndType); - #endif - *field_descriptor_constant = &vm->current_frame->class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; - #ifdef DEBUG + *field_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; assert((*field_descriptor_constant)->tag == CONSTANT_Utf8); - #endif + + return field_entry; } diff --git a/c/frame.c b/c/frame.c index 12fd445..974cd88 100644 --- a/c/frame.c +++ b/c/frame.c @@ -110,14 +110,11 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) struct constant * name_constant = &class_file->constant_pool[field_info->name_index - 1]; assert(name_constant->tag == CONSTANT_Utf8); - int fields_hash_table_length = class_entry->fields.length; - struct hash_table_entry * fields_hash_table = class_entry->fields.entry; - - struct field_entry * field_entry = class_resolver_lookup_field(fields_hash_table_length, - fields_hash_table, + struct field_entry * field_entry = class_resolver_lookup_field(class_entry->fields.length, + class_entry->fields.entry, name_constant->utf8.bytes, name_constant->utf8.length); - assert(field_info != nullptr); + assert(field_entry != nullptr); class_entry->static_fields[field_entry->static_index] = constantvalue->integer.bytes; debugf(" constantvalue: %d\n", constantvalue->integer.bytes); break; diff --git a/classes/p/InheritanceTest.java b/classes/test/TestInheritance.java similarity index 56% rename from classes/p/InheritanceTest.java rename to classes/test/TestInheritance.java index 11fe675..60631ad 100644 --- a/classes/p/InheritanceTest.java +++ b/classes/test/TestInheritance.java @@ -1,10 +1,14 @@ -package p; +package test; class A { int egg; static int baz = 3; static int bleh = 4; + public A() { + egg = -1; + } + public int foo(int a) { return a + baz; } @@ -19,14 +23,7 @@ class B extends A { } } -class InheritanceTest { - static int test() { - B b = new B(); - b.egg = 2; - //return b.bar(b.foo(4, 3)); - - return B.baz * A.baz; - } +class TestInheritance { static void static_test() { System.out.println("A:"); @@ -35,10 +32,36 @@ class InheritanceTest { System.out.println("B:"); System.out.println(B.baz); System.out.println(B.bleh); + + B.bleh = 33; + B.baz = 99; + System.out.println("A:"); + System.out.println(A.baz); + System.out.println(A.bleh); + System.out.println("B:"); + System.out.println(B.baz); + System.out.println(B.bleh); + + /* + static_test: + A: + 3 + 4 + B: + 5 + 4 + A: + 3 + 33 + B: + 99 + 33 + */ } static int instance_test() { B b = new B(); + System.out.println(b.egg); b.egg = 1; b.horse = 2; @@ -61,6 +84,13 @@ class InheritanceTest { } public static void main() { + System.out.println("static_test:"); + static_test(); + /* + System.out.println("instance_test:"); + System.out.println(instance_test()); + System.out.println("method_test:"); method_test(); + */ } }