implement class instances

This commit is contained in:
Zack Buhman 2024-12-25 04:36:46 -06:00
parent d0edd6b12b
commit bba08c9a3e
7 changed files with 349 additions and 124 deletions

View File

@ -7,7 +7,10 @@
struct field_entry { struct field_entry {
struct field_info * field_info; struct field_info * field_info;
uint32_t value; union {
uint64_t value64;
uint32_t value32;
};
}; };
enum initialization_state { enum initialization_state {

View File

@ -4,6 +4,7 @@
#include "memory_allocator.h" #include "memory_allocator.h"
#include "bswap.h" #include "bswap.h"
#include "class_resolver.h" #include "class_resolver.h"
#include "execute_helper.h"
void op_aaload(struct vm * vm) void op_aaload(struct vm * vm)
{ {
@ -610,42 +611,55 @@ void op_fsub(struct vm * vm)
void op_getfield(struct vm * vm, uint32_t index) void op_getfield(struct vm * vm, uint32_t index)
{ {
assert(!"op_getfield"); 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);
assert(field_descriptor_constant->utf8.length == 1);
uint32_t field_index = field_entry->field_info - class_entry->class_file->fields;
printf("putfield field_index %d\n", field_index);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
switch (field_descriptor_constant->utf8.bytes[0]) {
case 'Z': [[fallthrough]];
case 'B': [[fallthrough]];
case 'C': [[fallthrough]];
case 'S': [[fallthrough]];
case 'I': [[fallthrough]];
case 'F':
{
uint32_t value = objectref[field_index];
operand_stack_push_u32(vm->current_frame, value);
}
break;
case 'D': [[fallthrough]];
case 'J':
{
uint32_t low = objectref[field_index * 2];
uint32_t high = objectref[field_index * 2 + 1];
operand_stack_push_u32(vm->current_frame, low);
operand_stack_push_u32(vm->current_frame, high);
}
break;
default:
assert(false);
}
} }
void op_getstatic(struct vm * vm, uint32_t index) void op_getstatic(struct vm * vm, uint32_t index)
{ {
struct constant * fieldref_constant = &vm->current_thread.current_class->constant_pool[index - 1]; struct class_entry * class_entry;
#ifdef DEBUG struct field_entry * field_entry;
assert(fieldref_constant->tag == CONSTANT_Fieldref); struct constant * field_descriptor_constant;
#endif class_entry_field_entry_from_constant_index(vm, index,
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.class_index - 1]; &class_entry,
#ifdef DEBUG &field_entry,
assert(class_constant->tag == CONSTANT_Class); &field_descriptor_constant);
#endif
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * field_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(field_name_constant->tag == CONSTANT_Utf8);
#endif
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
assert(class_entry != nullptr);
struct field_entry * field_entry = class_resolver_lookup_field(class_entry,
field_name_constant->utf8.bytes,
field_name_constant->utf8.length);
assert(field_entry != nullptr);
/* 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
@ -654,9 +668,31 @@ void op_getstatic(struct vm * vm, uint32_t index)
if (!vm_initialize_class(vm, class_entry)) if (!vm_initialize_class(vm, class_entry))
return; return;
uint32_t value = field_entry->value; assert(field_descriptor_constant->utf8.length == 1);
switch (field_descriptor_constant->utf8.bytes[0]) {
case 'Z': [[fallthrough]];
case 'B': [[fallthrough]];
case 'C': [[fallthrough]];
case 'S': [[fallthrough]];
case 'I': [[fallthrough]];
case 'F':
{
uint32_t value = field_entry->value32;
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
break;
case 'D': [[fallthrough]];
case 'J':
{
uint64_t value = field_entry->value64;
operand_stack_push_u64(vm->current_frame, value);
}
break;
default:
assert(false);
}
}
void op_goto(struct vm * vm, int32_t branch) void op_goto(struct vm * vm, int32_t branch)
{ {
@ -996,48 +1032,22 @@ void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
void op_invokespecial(struct vm * vm, uint32_t index) void op_invokespecial(struct vm * vm, uint32_t index)
{ {
assert(!"op_invokespecial"); struct class_entry * class_entry;
struct method_info * method_info;
class_entry_method_info_from_constant_index(vm, index,
&class_entry,
&method_info);
vm_special_method_call(vm, class_entry->class_file, method_info);
} }
void op_invokestatic(struct vm * vm, uint32_t index) void op_invokestatic(struct vm * vm, uint32_t index)
{ {
struct constant * methodref_constant = &vm->current_thread.current_class->constant_pool[index - 1]; struct class_entry * class_entry;
#ifdef DEBUG struct method_info * method_info;
assert(methodref_constant->tag == CONSTANT_Methodref); class_entry_method_info_from_constant_index(vm, index,
#endif &class_entry,
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.class_index - 1]; &method_info);
#ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class);
#endif
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * method_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(method_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * method_descriptor_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
#endif
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
assert(class_entry != nullptr);
struct method_info * method_info = class_resolver_lookup_method(class_entry,
method_name_constant->utf8.bytes,
method_name_constant->utf8.length,
method_descriptor_constant->utf8.bytes,
method_descriptor_constant->utf8.length);
assert(method_info != nullptr);
/* 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
@ -1048,7 +1058,13 @@ void op_invokestatic(struct vm * vm, uint32_t index)
void op_invokevirtual(struct vm * vm, uint32_t index) void op_invokevirtual(struct vm * vm, uint32_t index)
{ {
assert(!"op_invokevirtual"); struct class_entry * class_entry;
struct method_info * method_info;
class_entry_method_info_from_constant_index(vm, index,
&class_entry,
&method_info);
vm_special_method_call(vm, class_entry->class_file, method_info);
} }
void op_ior(struct vm * vm) void op_ior(struct vm * vm)
@ -1273,7 +1289,7 @@ void op_lconst_1(struct vm * vm)
void op_ldc(struct vm * vm, uint32_t index) void op_ldc(struct vm * vm, uint32_t index)
{ {
struct constant * constant = &vm->current_thread.current_class->constant_pool[index - 1]; struct constant * constant = &vm->current_frame->class->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(constant->tag == CONSTANT_Integer || constant->tag == CONSTANT_Float); assert(constant->tag == CONSTANT_Integer || constant->tag == CONSTANT_Float);
#endif #endif
@ -1283,7 +1299,7 @@ void op_ldc(struct vm * vm, uint32_t index)
void op_ldc2_w(struct vm * vm, uint32_t index) void op_ldc2_w(struct vm * vm, uint32_t index)
{ {
struct constant * constant = &vm->current_thread.current_class->constant_pool[index - 1]; struct constant * constant = &vm->current_frame->class->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(constant->tag == CONSTANT_Long || constant->tag == CONSTANT_Double); assert(constant->tag == CONSTANT_Long || constant->tag == CONSTANT_Double);
#endif #endif
@ -1486,11 +1502,11 @@ void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions)
void op_new(struct vm * vm, uint32_t index) void op_new(struct vm * vm, uint32_t index)
{ {
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[index - 1]; struct constant * class_constant = &vm->current_frame->class->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class); assert(class_constant->tag == CONSTANT_Class);
#endif #endif
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1]; struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8); assert(class_name_constant->tag == CONSTANT_Utf8);
#endif #endif
@ -1517,9 +1533,13 @@ void op_new(struct vm * vm, uint32_t index)
int fields_count = class_entry->class_file->fields_count; int fields_count = class_entry->class_file->fields_count;
(void)fields_count; (void)fields_count;
//int32_t * arrayref = memory_allocate(); int32_t * objectref = memory_allocate(fields_count * 2 * 4);
for (int i = 0; i < fields_count; i++) {
objectref[i * 2] = 0;
objectref[i * 2 + 1] = 0;
}
assert(!"op_new"); operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
} }
enum ARRAY_TYPE { enum ARRAY_TYPE {
@ -1594,42 +1614,72 @@ void op_pop2(struct vm * vm)
void op_putfield(struct vm * vm, uint32_t index) void op_putfield(struct vm * vm, uint32_t index)
{ {
assert(!"op_putfield"); 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);
/* 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
type is boolean, byte, char, short, or int, then the value must be an int. If
the field descriptor type is float, long, or double, then the value must be a
float, long, or double, respectively. If the field descriptor type is a class
type or an array type, then the value must be a value of the field descriptor
type. */
assert(field_descriptor_constant->utf8.length == 1);
uint32_t field_index = field_entry->field_info - class_entry->class_file->fields;
printf("putfield field_index %d\n", field_index);
switch (field_descriptor_constant->utf8.bytes[0]) {
case 'Z': [[fallthrough]];
case 'B': [[fallthrough]];
case 'C': [[fallthrough]];
case 'S': [[fallthrough]];
case 'I': [[fallthrough]];
case 'F':
{
uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
objectref[field_index] = value;
}
break;
case 'D': [[fallthrough]];
case 'J':
{
uint32_t high = operand_stack_pop_u32(vm->current_frame);
uint32_t low = operand_stack_pop_u32(vm->current_frame);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
objectref[field_index * 2 + 1] = high;
objectref[field_index * 2] = low;
}
break;
default:
assert(false);
}
} }
void op_putstatic(struct vm * vm, uint32_t index) void op_putstatic(struct vm * vm, uint32_t index)
{ {
struct constant * fieldref_constant = &vm->current_thread.current_class->constant_pool[index - 1]; struct class_entry * class_entry;
#ifdef DEBUG struct field_entry * field_entry;
assert(fieldref_constant->tag == CONSTANT_Fieldref); struct constant * field_descriptor_constant;
#endif class_entry_field_entry_from_constant_index(vm, index,
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.class_index - 1]; &class_entry,
#ifdef DEBUG &field_entry,
assert(class_constant->tag == CONSTANT_Class); &field_descriptor_constant);
#endif
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * field_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(field_name_constant->tag == CONSTANT_Utf8);
#endif
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length, /* The type of a value stored by a putstatic instruction must be compatible
vm->class_hash_table.entry, with the descriptor of the referenced field (§4.3.2). If the field
class_name_constant->utf8.bytes, descriptor type is boolean, byte, char, short, or int, then the value must
class_name_constant->utf8.length); be an int. If the field descriptor type is float, long, or double, then the
assert(class_entry != nullptr); value must be a float, long, or double, respectively. If the field
descriptor type is a class type or an array type, then the value must be a
struct field_entry * field_entry = class_resolver_lookup_field(class_entry, value of the field descriptor type. */
field_name_constant->utf8.bytes,
field_name_constant->utf8.length);
assert(field_entry != nullptr);
/* On successful resolution of the field, the class or interface that declared /* On successful resolution of the field, the class or interface that declared
the resolved field is initialized if that class or interface has not the resolved field is initialized if that class or interface has not
@ -1638,8 +1688,30 @@ void op_putstatic(struct vm * vm, uint32_t index)
if (!vm_initialize_class(vm, class_entry)) if (!vm_initialize_class(vm, class_entry))
return; return;
assert(field_descriptor_constant->utf8.length == 1);
switch (field_descriptor_constant->utf8.bytes[0]) {
case 'Z': [[fallthrough]];
case 'B': [[fallthrough]];
case 'C': [[fallthrough]];
case 'S': [[fallthrough]];
case 'I': [[fallthrough]];
case 'F':
{
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
field_entry->value = value; field_entry->value32 = value;
}
break;
case 'D': [[fallthrough]];
case 'J':
{
uint64_t value = operand_stack_pop_u64(vm->current_frame);
field_entry->value64 = value;
}
break;
default:
assert(false);
}
} }
void op_ret(struct vm * vm, uint32_t index) void op_ret(struct vm * vm, uint32_t index)

88
c/execute_helper.h Normal file
View File

@ -0,0 +1,88 @@
#include "debug_class_file.h"
static inline void class_entry_field_entry_from_constant_index(struct vm * vm,
uint32_t index,
struct class_entry ** class_entry,
struct field_entry ** field_entry,
struct constant ** field_descriptor_constant)
{
struct constant * fieldref_constant = &vm->current_frame->class->constant_pool[index - 1];
#ifdef DEBUG
assert(fieldref_constant->tag == CONSTANT_Fieldref);
#endif
struct constant * class_constant = &vm->current_frame->class->constant_pool[fieldref_constant->fieldref.class_index - 1];
#ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class);
#endif
struct constant * nameandtype_constant = &vm->current_frame->class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * field_name_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(field_name_constant->tag == CONSTANT_Utf8);
#endif
*field_descriptor_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG
assert((*field_descriptor_constant)->tag == CONSTANT_Utf8);
#endif
*class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
assert(*class_entry != nullptr);
*field_entry = class_resolver_lookup_field(*class_entry,
field_name_constant->utf8.bytes,
field_name_constant->utf8.length);
assert(*field_entry != nullptr);
}
static inline void class_entry_method_info_from_constant_index(struct vm * vm,
uint32_t index,
struct class_entry ** class_entry,
struct method_info ** method_info)
{
struct constant * methodref_constant = &vm->current_frame->class->constant_pool[index - 1];
#ifdef DEBUG
assert(methodref_constant->tag == CONSTANT_Methodref);
#endif
struct constant * class_constant = &vm->current_frame->class->constant_pool[methodref_constant->methodref.class_index - 1];
#ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class);
#endif
struct constant * nameandtype_constant = &vm->current_frame->class->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * method_name_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(method_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * method_descriptor_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
#endif
*class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
assert(*class_entry != nullptr);
*method_info = class_resolver_lookup_method(*class_entry,
method_name_constant->utf8.bytes,
method_name_constant->utf8.length,
method_descriptor_constant->utf8.bytes,
method_descriptor_constant->utf8.length);
assert(*method_info != nullptr);
}

View File

@ -87,7 +87,7 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry)
return true; return true;
if (class_entry->initialization_state == CLASS_INITIALIZING) { if (class_entry->initialization_state == CLASS_INITIALIZING) {
if (vm->current_thread.current_class == class_entry->class_file) if (vm->current_frame->class == class_entry->class_file)
return true; return true;
else else
assert(false); // possible infinite initialization loop assert(false); // possible infinite initialization loop
@ -154,6 +154,52 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry)
return true; return true;
} }
void vm_special_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info)
{
/* 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
the method being invoked. The nargs argument values are consecutively made
the values of local variables of the new frame, with arg1 in local variable
0 (or, if arg1 is of type long or double, in local variables 0 and 1) and
so on. The new frame is then made current, and the Java Virtual Machine pc
is set to the opcode of the first instruction of the method to be
invoked. Execution continues with the first instruction of the method.
*/
int code_name_index = find_code_name_index(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);
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->operand_stack_ix = 0;
struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1];
int nargs = descriptor_nargs(descriptor_constant);
nargs += 1;
printf("nargs+1: %d\n", nargs);
for (int i = 0; i < nargs; i++) {
uint32_t value = operand_stack_pop_u32(old_frame);
printf("local[%d] = %x\n", nargs - i - 1, value);
vm->current_frame->local_variable[nargs - i - 1] = value;
}
vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1];
vm->current_frame->pc = 0;
vm->current_frame->class = class_file;
vm->current_frame->method = method_info;
printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
}
void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info) void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info)
{ {
/* If the method is not native, the nargs argument values are popped from the /* If the method is not native, the nargs argument values are popped from the
@ -193,8 +239,8 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc
vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1]; vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1];
vm->current_frame->pc = 0; vm->current_frame->pc = 0;
vm->current_thread.current_class = class_file; vm->current_frame->class = class_file;
vm->current_thread.current_method = method_info; vm->current_frame->method = method_info;
printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix); printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
} }
@ -261,6 +307,7 @@ void vm_method_return(struct vm * vm)
break; break;
} }
assert(old_frame->operand_stack_ix == 0); assert(old_frame->operand_stack_ix == 0);
printf("vm_method_return\n");
} }
static void print_vm_stack(struct vm * vm) static void print_vm_stack(struct vm * vm)
@ -287,13 +334,13 @@ void vm_execute(struct vm * vm)
print_vm_stack(vm); print_vm_stack(vm);
decode_print_instruction(vm->current_frame->code->code, vm->current_frame->pc); decode_print_instruction(vm->current_frame->code->code, vm->current_frame->pc);
uint32_t old_pc = vm->current_frame->pc; uint32_t old_pc = vm->current_frame->pc;
struct method_info * old_method = vm->current_thread.current_method; struct method_info * old_method = vm->current_frame->method;
decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc); decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc);
if (vm->frame_stack.ix == 1) { if (vm->frame_stack.ix == 1) {
printf("terminate\n"); printf("terminate\n");
break; break;
} }
if (vm->current_thread.current_method == old_method && vm->current_frame->pc == old_pc) { if (vm->current_frame->method == old_method && vm->current_frame->pc == old_pc) {
// if the instruction did not branch, increment 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;
} }

View File

@ -6,6 +6,8 @@
#include "class_resolver.h" #include "class_resolver.h"
struct frame { struct frame {
struct class_file * class;
struct method_info * method;
struct Code_attribute * code; struct Code_attribute * code;
uint32_t * local_variable; uint32_t * local_variable;
uint32_t * operand_stack; uint32_t * operand_stack;
@ -15,11 +17,6 @@ struct frame {
uint8_t return_type; uint8_t return_type;
}; };
struct thread {
struct class_file * current_class;
struct method_info * current_method;
};
struct stack { struct stack {
union { union {
struct frame * frame; struct frame * frame;
@ -32,7 +29,6 @@ struct stack {
struct vm { struct vm {
struct stack frame_stack; struct stack frame_stack;
struct stack data_stack; struct stack data_stack;
struct thread current_thread;
struct frame * current_frame; struct frame * current_frame;
struct { struct {
int length; int length;
@ -148,6 +144,7 @@ static inline double operand_stack_pop_f64(struct frame * frame)
} }
bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry); bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry);
void vm_special_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info);
void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info); void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info);
void vm_method_return(struct vm * vm); void vm_method_return(struct vm * vm);
void vm_execute(struct vm * vm); void vm_execute(struct vm * vm);

5
java/lang/Object.java Normal file
View File

@ -0,0 +1,5 @@
package java.lang;
class Object {
public Object() {}
}

13
p/LongStaticField.java Normal file
View File

@ -0,0 +1,13 @@
package p;
class LongStaticField {
static long foo = 10;
static long test() {
return foo;
}
public static void main() {
test();
}
}