class_resolver: resolve static fields from superclasses
This commit is contained in:
parent
ec525bbfbc
commit
a9b40c9521
2
Makefile
2
Makefile
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
101
c/execute.c
101
c/execute.c
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user