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