class_resolver: resolve static fields from superclasses

This commit is contained in:
Zack Buhman 2025-01-11 16:25:10 -06:00
parent ec525bbfbc
commit a9b40c9521
7 changed files with 285 additions and 250 deletions

View File

@ -10,7 +10,7 @@ CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protec
CFLAGS += -I$(MAKEFILE_PATH)/ CFLAGS += -I$(MAKEFILE_PATH)/
CFLAGS += -I$(MAKEFILE_PATH)/c CFLAGS += -I$(MAKEFILE_PATH)/c
CFLAGS += -DDEBUG CFLAGS += -DDEBUG
CFLAGS += -DDEBUG_PRINT #CFLAGS += -DDEBUG_PRINT
LDFLAGS = -lm LDFLAGS = -lm
OPT ?= -O0 OPT ?= -O0
DEPFLAGS = -MMD -MP DEPFLAGS = -MMD -MP

View File

@ -20,9 +20,7 @@
static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) 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]; struct constant * field_descriptor_constant = &class_file->constant_pool[field_info->descriptor_index - 1];
#ifdef DEBUG
assert(field_descriptor_constant->tag == CONSTANT_Utf8); assert(field_descriptor_constant->tag == CONSTANT_Utf8);
#endif
return field_size(field_descriptor_constant->utf8.bytes[0]); 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))); struct field_entry * field_entry = malloc_class_arena((sizeof (struct field_entry)));
field_entry->instance_index = instance_index; field_entry->instance_index = instance_index;
field_entry->field_info = field_info; 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]; struct constant * name_constant = &class_entry->class_file->constant_pool[field_info->name_index - 1];
assert(name_constant->tag == CONSTANT_Utf8); 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))); struct field_entry * field_entry = malloc_class_arena((sizeof (struct field_entry)));
field_entry->static_index = static_index; field_entry->static_index = static_index;
field_entry->field_info = field_info; field_entry->field_info = field_info;
field_entry->class_entry = class_entry;
static_index += field_info_field_size(class_entry->class_file, field_info); 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]; 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) int field_name_length)
{ {
debugf("class_resolver_lookup_field: "); 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'); debugc('\n');
struct hash_table_entry * e = hash_table_find(fields_hash_table_length, struct hash_table_entry * e = hash_table_find(fields_hash_table_length,
fields_hash_table, fields_hash_table,
field_name, field_name,
field_name_length); field_name_length);
assert(e != nullptr); if (e == nullptr)
debugf("%p\n", e->value); return nullptr;
else
return (struct field_entry *)e->value; return (struct field_entry *)e->value;
} }
struct field_entry * class_resolver_lookup_field_from_fieldref_index(int fields_hash_table_length, struct field_entry * resolve_field_entry_from_superclasses(int class_hash_table_length,
struct hash_table_entry * fields_hash_table, struct hash_table_entry * class_hash_table,
struct class_entry * class_entry, struct class_entry * class_entry,
int fieldref_index) struct constant * field_name_constant)
{ {
if (class_entry->attribute_entry[fieldref_index - 1].field_entry != nullptr) { while (true) {
debugf("class_resolver_lookup_field_from_fieldref_index %d: [cached]\n", fieldref_index); struct field_entry * field_entry = class_resolver_lookup_field(class_entry->fields.length,
return class_entry->attribute_entry[fieldref_index - 1].field_entry; 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]; return nullptr;
#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
struct field_entry * field_entry = class_resolver_lookup_field(fields_hash_table_length, struct field_entry * class_resolver_lookup_field_from_fieldref_index(int class_hash_table_length,
fields_hash_table, struct hash_table_entry * class_hash_table,
field_name_constant->utf8.bytes, struct class_entry * origin_class_entry,
field_name_constant->utf8.length); 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 // 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; 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; return (struct method_info *)e->value;
} }
struct method_entry class_resolver_lookup_method_from_interfacemethodref_index(int class_hash_table_length, static struct Code_attribute * resolve_code_attribute(struct class_entry * class_entry,
struct hash_table_entry * class_hash_table, struct method_info * method_info)
int32_t interfacemethodref_index,
struct class_entry * objectref_class_entry,
struct class_entry * origin_class_entry)
{ {
struct constant * interfacemethodref_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_index - 1]; if ((method_info->access_flags & METHOD_ACC_NATIVE) != 0) {
assert(interfacemethodref_constant->tag == CONSTANT_InterfaceMethodref || interfacemethodref_constant->tag == CONSTANT_Methodref); return nullptr;
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);
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) { while (true) {
struct method_info * method_info = class_resolver_lookup_method(class_entry->methods.length, resolve_method_entry(class_entry,
class_entry->methods.entry, method_name_constant,
method_name_constant->utf8.bytes, method_descriptor_constant,
method_name_constant->utf8.length, method_entry);
method_descriptor_constant->utf8.bytes, if (method_entry->method_info != nullptr)
method_descriptor_constant->utf8.length); break;
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,
};
}
}
if (class_entry->class_file->super_class == 0) if (class_entry->class_file->super_class == 0)
break; break;
@ -465,8 +506,6 @@ struct method_entry class_resolver_lookup_method_from_interfacemethodref_index(i
assert(class_constant->tag == CONSTANT_Class); assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8); assert(class_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(class_name_constant);
debugf("\n");
// lookup the method from the superclass // lookup the method from the superclass
class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length, 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); class_entry->class_file->super_class);
assert(class_entry != nullptr); 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 method_entry class_resolver_lookup_method_from_objectref_class(int class_hash_table_length,
struct hash_table_entry * class_hash_table, struct hash_table_entry * class_hash_table,
int32_t methodref_index, int32_t methodref_index,
struct class_entry * origin_class_entry) 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) { 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; 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, origin_class_entry,
methodref_constant->methodref.class_index); methodref_constant->methodref.class_index);
while (true) { struct method_entry * method_entry = malloc_class_arena((sizeof (struct 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) {
// 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))); resolve_method_entry_from_superclasses(class_hash_table_length,
method_entry->class_entry = class_entry; class_hash_table,
method_entry->method_info = method_info; class_entry,
int code_index = find_code_name_index(class_entry->class_file); method_name_constant,
assert(code_index != 0); method_descriptor_constant,
struct attribute_info * attribute = find_attribute(code_index, method_entry);
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;
}
origin_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry; assert(method_entry->method_info != nullptr);
return method_entry;
}
if (class_entry->class_file->super_class == 0) origin_class_entry->attribute_entry[methodref_index - 1].method_entry = method_entry;
break;
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->super_class - 1]; return method_entry;
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");
} }
struct method_entry class_resolver_lookup_method_from_method_name_method_descriptor(struct class_entry * class_entry, struct method_entry class_resolver_lookup_method_from_method_name_method_descriptor(struct class_entry * class_entry,

View File

@ -26,6 +26,7 @@ union attribute_entry {
}; };
struct field_entry { struct field_entry {
struct class_entry * class_entry;
struct field_info * field_info; struct field_info * field_info;
union { union {
int32_t instance_index; 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 hash_table_entry * class_hash_table,
struct class_entry * class_entry, struct class_entry * class_entry,
int32_t class_index); 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, struct method_entry class_resolver_lookup_method_from_objectref_class(int class_hash_table_length,
int32_t interfacemethodref_index, struct hash_table_entry * class_hash_table,
struct class_entry * objectref_class_entry, int32_t methodref_index,
struct class_entry * origin_class_entry); struct class_entry * objectref_class_entry,
struct method_entry * class_resolver_lookup_method_from_methodref_index(int class_hash_table_length, struct class_entry * origin_class_entry);
struct hash_table_entry * class_hash_table, struct method_entry * class_resolver_lookup_method_from_origin_class(int class_hash_table_length,
int32_t methodref_index, struct hash_table_entry * class_hash_table,
struct class_entry * origin_class_entry); 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, struct method_entry class_resolver_lookup_method_from_method_name_method_descriptor(struct class_entry * class_entry,
const uint8_t * method_name, const uint8_t * method_name,
int method_name_length, int method_name_length,

View File

@ -734,20 +734,19 @@ void op_fsub(struct vm * vm)
void op_getfield(struct vm * vm, uint32_t index) 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); struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
if (objectref == nullptr) if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); 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]) { switch (field_descriptor_constant->utf8.bytes[0]) {
case 'B': [[fallthrough]]; case 'B': [[fallthrough]];
case 'C': [[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) void op_getstatic(struct vm * vm, uint32_t index)
{ {
struct class_entry * class_entry;
struct field_entry * field_entry;
struct constant * field_descriptor_constant; struct constant * field_descriptor_constant;
class_entry_field_entry_from_constant_index(vm, index, struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length,
&class_entry, vm->class_hash_table.entry,
&field_entry, vm->current_frame->class_entry,
&field_descriptor_constant); index,
&field_descriptor_constant);
/* On successful resolution of the field, the class or interface that /* On successful resolution of the field, the class or interface that
declared the resolved field is initialized if that class or interface has declared the resolved field is initialized if that class or interface has
not already been initialized (§5.5). */ not already been initialized (§5.5). */
struct class_entry * class_entry = field_entry->class_entry;
if (!vm_initialize_class(vm, class_entry)) if (!vm_initialize_class(vm, class_entry))
return; 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); struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, count);
if (objectref == nullptr) if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
struct class_entry * class_entry = objectref->class_entry;
struct method_entry method_entry = struct method_entry method_entry =
class_resolver_lookup_method_from_interfacemethodref_index(vm->class_hash_table.length, class_resolver_lookup_method_from_objectref_class(vm->class_hash_table.length,
vm->class_hash_table.entry, vm->class_hash_table.entry,
index, index,
class_entry, objectref->class_entry,
vm->current_frame->class_entry); vm->current_frame->class_entry);
vm_special_method_call(vm, method_entry.class_entry, &method_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 class_entry * origin_class_entry = vm->current_frame->class_entry;
struct constant * interfacemethodref_constant = &origin_class_entry->class_file->constant_pool[index - 1]; struct constant * methodref_constant = &origin_class_entry->class_file->constant_pool[index - 1];
assert(interfacemethodref_constant->tag == CONSTANT_Methodref); assert(methodref_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 * nameandtype_constant = &origin_class_entry->class_file->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
assert(nameandtype_constant->tag == CONSTANT_NameAndType); assert(nameandtype_constant->tag == CONSTANT_NameAndType);
struct constant * method_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; 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); 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")); return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
struct method_entry * method_entry = struct method_entry * method_entry =
class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length, class_resolver_lookup_method_from_origin_class(vm->class_hash_table.length,
vm->class_hash_table.entry, vm->class_hash_table.entry,
index, index,
vm->current_frame->class_entry); vm->current_frame->class_entry);
vm_special_method_call(vm, method_entry->class_entry, method_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) void op_invokestatic(struct vm * vm, uint32_t index)
{ {
struct method_entry * method_entry = struct method_entry * method_entry =
class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length, class_resolver_lookup_method_from_origin_class(vm->class_hash_table.length,
vm->class_hash_table.entry, vm->class_hash_table.entry,
index, index,
vm->current_frame->class_entry); vm->current_frame->class_entry);
/* On successful resolution of the method, the class or interface that /* On successful resolution of the method, the class or interface that
declared the resolved method is initialized if that class or interface has 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); struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, nargs + 1);
if (objectref == nullptr) if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException")); return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
struct class_entry * class_entry = objectref->class_entry;
struct method_entry method_entry = struct method_entry method_entry =
class_resolver_lookup_method_from_interfacemethodref_index(vm->class_hash_table.length, class_resolver_lookup_method_from_objectref_class(vm->class_hash_table.length,
vm->class_hash_table.entry, vm->class_hash_table.entry,
index, index,
class_entry, objectref->class_entry,
vm->current_frame->class_entry); vm->current_frame->class_entry);
vm_special_method_call(vm, method_entry.class_entry, &method_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) void op_putfield(struct vm * vm, uint32_t index)
{ {
struct class_entry * class_entry;
struct field_entry * field_entry;
struct constant * field_descriptor_constant; struct constant * field_descriptor_constant;
class_entry_field_entry_from_constant_index(vm, struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length,
index, vm->class_hash_table.entry,
&class_entry, vm->current_frame->class_entry,
&field_entry, index,
&field_descriptor_constant); &field_descriptor_constant);
/* The type of a value stored by a putfield instruction must be compatible /* 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 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) void op_putstatic(struct vm * vm, uint32_t index)
{ {
struct class_entry * class_entry;
struct field_entry * field_entry;
struct constant * field_descriptor_constant; struct constant * field_descriptor_constant;
class_entry_field_entry_from_constant_index(vm, index, struct field_entry * field_entry = field_entry_from_constant_index(vm->class_hash_table.length,
&class_entry, vm->class_hash_table.entry,
&field_entry, vm->current_frame->class_entry,
&field_descriptor_constant); index,
&field_descriptor_constant);
/* The type of a value stored by a putstatic instruction must be compatible /* 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 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 the resolved field is initialized if that class or interface has not
already been initialized (§5.5). */ already been initialized (§5.5). */
struct class_entry * class_entry = field_entry->class_entry;
if (!vm_initialize_class(vm, class_entry)) if (!vm_initialize_class(vm, class_entry))
return; return;

View File

@ -3,39 +3,24 @@ struct objectref * class_resolver_lookup_string(struct vm * vm,
struct class_entry * class_entry, struct class_entry * class_entry,
const int string_index); const int string_index);
static inline void class_entry_field_entry_from_constant_index(struct vm * vm, static inline struct field_entry * field_entry_from_constant_index(int class_hash_table_length,
int32_t index, struct hash_table_entry * class_hash_table,
struct class_entry ** class_entry, struct class_entry * origin_class_entry,
struct field_entry ** field_entry, int32_t index,
struct constant ** field_descriptor_constant) struct constant ** field_descriptor_constant)
{ {
struct constant * fieldref_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1]; struct field_entry * field_entry = class_resolver_lookup_field_from_fieldref_index(class_hash_table_length,
#ifdef DEBUG 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); assert(fieldref_constant->tag == CONSTANT_Fieldref);
#endif struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
*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
assert(nameandtype_constant->tag == CONSTANT_NameAndType); assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif *field_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
*field_descriptor_constant = &vm->current_frame->class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG
assert((*field_descriptor_constant)->tag == CONSTANT_Utf8); assert((*field_descriptor_constant)->tag == CONSTANT_Utf8);
#endif
return field_entry;
} }

View File

@ -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]; struct constant * name_constant = &class_file->constant_pool[field_info->name_index - 1];
assert(name_constant->tag == CONSTANT_Utf8); assert(name_constant->tag == CONSTANT_Utf8);
int fields_hash_table_length = class_entry->fields.length; struct field_entry * field_entry = class_resolver_lookup_field(class_entry->fields.length,
struct hash_table_entry * fields_hash_table = class_entry->fields.entry; class_entry->fields.entry,
struct field_entry * field_entry = class_resolver_lookup_field(fields_hash_table_length,
fields_hash_table,
name_constant->utf8.bytes, name_constant->utf8.bytes,
name_constant->utf8.length); name_constant->utf8.length);
assert(field_info != nullptr); assert(field_entry != nullptr);
class_entry->static_fields[field_entry->static_index] = constantvalue->integer.bytes; class_entry->static_fields[field_entry->static_index] = constantvalue->integer.bytes;
debugf(" constantvalue: %d\n", constantvalue->integer.bytes); debugf(" constantvalue: %d\n", constantvalue->integer.bytes);
break; break;

View File

@ -1,10 +1,14 @@
package p; package test;
class A { class A {
int egg; int egg;
static int baz = 3; static int baz = 3;
static int bleh = 4; static int bleh = 4;
public A() {
egg = -1;
}
public int foo(int a) { public int foo(int a) {
return a + baz; return a + baz;
} }
@ -19,14 +23,7 @@ class B extends A {
} }
} }
class InheritanceTest { class TestInheritance {
static int test() {
B b = new B();
b.egg = 2;
//return b.bar(b.foo(4, 3));
return B.baz * A.baz;
}
static void static_test() { static void static_test() {
System.out.println("A:"); System.out.println("A:");
@ -35,10 +32,36 @@ class InheritanceTest {
System.out.println("B:"); System.out.println("B:");
System.out.println(B.baz); System.out.println(B.baz);
System.out.println(B.bleh); 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() { static int instance_test() {
B b = new B(); B b = new B();
System.out.println(b.egg);
b.egg = 1; b.egg = 1;
b.horse = 2; b.horse = 2;
@ -61,6 +84,13 @@ class InheritanceTest {
} }
public static void main() { 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(); method_test();
*/
} }
} }