implement return/ireturn

This commit is contained in:
Zack Buhman 2024-12-24 00:49:05 -06:00
parent 932a7c82aa
commit d09d712f1b
7 changed files with 524 additions and 262 deletions

View File

@ -3,4 +3,4 @@
#include "frame.h" #include "frame.h"
uint32_t decode_print_instruction(const uint8_t * code, uint32_t pc); uint32_t decode_print_instruction(const uint8_t * code, uint32_t pc);
uint32_t decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc); void decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc);

File diff suppressed because it is too large Load Diff

View File

@ -488,7 +488,7 @@ void op_getstatic(struct vm * vm, uint32_t index)
void op_goto(struct vm * vm, int32_t branch) void op_goto(struct vm * vm, int32_t branch)
{ {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
void op_goto_w(struct vm * vm, int32_t branch) void op_goto_w(struct vm * vm, int32_t branch)
@ -626,7 +626,7 @@ void op_if_icmpeq(struct vm * vm, int32_t branch)
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value1 == value2) { if (value1 == value2) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -635,7 +635,7 @@ void op_if_icmpge(struct vm * vm, int32_t branch)
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value1 >= value2) { if (value1 >= value2) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -644,7 +644,7 @@ void op_if_icmpgt(struct vm * vm, int32_t branch)
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value1 > value2) { if (value1 > value2) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -653,7 +653,7 @@ void op_if_icmple(struct vm * vm, int32_t branch)
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value1 <= value2) { if (value1 <= value2) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -662,7 +662,7 @@ void op_if_icmplt(struct vm * vm, int32_t branch)
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value1 < value2) { if (value1 < value2) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -671,7 +671,7 @@ void op_if_icmpne(struct vm * vm, int32_t branch)
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value1 != value2) { if (value1 != value2) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -679,7 +679,7 @@ void op_ifeq(struct vm * vm, int32_t branch)
{ {
int32_t value = operand_stack_pop_u32(vm->current_frame); int32_t value = operand_stack_pop_u32(vm->current_frame);
if (value == 0) { if (value == 0) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -687,7 +687,7 @@ void op_ifge(struct vm * vm, int32_t branch)
{ {
int32_t value = operand_stack_pop_u32(vm->current_frame); int32_t value = operand_stack_pop_u32(vm->current_frame);
if (value >= 0) { if (value >= 0) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -695,7 +695,7 @@ void op_ifgt(struct vm * vm, int32_t branch)
{ {
int32_t value = operand_stack_pop_u32(vm->current_frame); int32_t value = operand_stack_pop_u32(vm->current_frame);
if (value > 0) { if (value > 0) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -703,7 +703,7 @@ void op_ifle(struct vm * vm, int32_t branch)
{ {
int32_t value = operand_stack_pop_u32(vm->current_frame); int32_t value = operand_stack_pop_u32(vm->current_frame);
if (value <= 0) { if (value <= 0) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -711,7 +711,7 @@ void op_iflt(struct vm * vm, int32_t branch)
{ {
int32_t value = operand_stack_pop_u32(vm->current_frame); int32_t value = operand_stack_pop_u32(vm->current_frame);
if (value < 0) { if (value < 0) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -719,7 +719,7 @@ void op_ifne(struct vm * vm, int32_t branch)
{ {
int32_t value = operand_stack_pop_u32(vm->current_frame); int32_t value = operand_stack_pop_u32(vm->current_frame);
if (value != 0) { if (value != 0) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -727,7 +727,7 @@ void op_ifnonnull(struct vm * vm, int32_t branch)
{ {
void * value = (void *)operand_stack_pop_u32(vm->current_frame); void * value = (void *)operand_stack_pop_u32(vm->current_frame);
if (value != nullptr) { if (value != nullptr) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -735,7 +735,7 @@ void op_ifnull(struct vm * vm, int32_t branch)
{ {
void * value = (void *)operand_stack_pop_u32(vm->current_frame); void * value = (void *)operand_stack_pop_u32(vm->current_frame);
if (value == nullptr) { if (value == nullptr) {
vm->current_thread.pc = vm->current_thread.pc + branch; vm->current_frame->pc = vm->current_frame->pc + branch;
} }
} }
@ -889,7 +889,17 @@ void op_ireturn(struct vm * vm)
boolean by taking the bitwise AND of value and 1. */ boolean by taking the bitwise AND of value and 1. */
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
printf("return %d\n", value); switch (vm->current_frame->return_type) {
case 'I':
break;
default:
fprintf(stderr, "conversion not implemented: %c\n", vm->current_frame->return_type);
assert(false);
break;
}
operand_stack_push_u32(vm->current_frame, value);
vm_method_return(vm);
} }
void op_ishl(struct vm * vm) void op_ishl(struct vm * vm)
@ -1220,12 +1230,11 @@ void op_newarray(struct vm * vm, uint32_t atype)
void op_nop(struct vm * vm) void op_nop(struct vm * vm)
{ {
assert(!"op_nop");
} }
void op_pop(struct vm * vm) void op_pop(struct vm * vm)
{ {
assert(!"op_pop"); operand_stack_pop_u32(vm->current_frame);
} }
void op_pop2(struct vm * vm) void op_pop2(struct vm * vm)
@ -1250,7 +1259,7 @@ void op_ret(struct vm * vm, uint32_t index)
void op_return(struct vm * vm) void op_return(struct vm * vm)
{ {
assert(!"op_return"); vm_method_return(vm);
} }
void op_saload(struct vm * vm) void op_saload(struct vm * vm)
@ -1265,7 +1274,7 @@ void op_sastore(struct vm * vm)
void op_sipush(struct vm * vm, int32_t byte) void op_sipush(struct vm * vm, int32_t byte)
{ {
assert(!"op_sipush"); assert(!"op_sipush2");
} }
void op_swap(struct vm * vm) void op_swap(struct vm * vm)
@ -1277,10 +1286,10 @@ void op_tableswitch(struct vm * vm, int32_t defaultbyte, int32_t lowbyte, int32_
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
if (index < lowbyte || index > highbyte) { if (index < lowbyte || index > highbyte) {
vm->current_thread.pc = vm->current_thread.pc + defaultbyte; vm->current_frame->pc = vm->current_frame->pc + defaultbyte;
} else { } else {
int32_t offset = BE_BSWAP32(table[index - lowbyte]); int32_t offset = BE_BSWAP32(table[index - lowbyte]);
vm->current_thread.pc = vm->current_thread.pc + offset; vm->current_frame->pc = vm->current_frame->pc + offset;
} }
} }

View File

@ -23,7 +23,7 @@ struct frame * stack_pop_frame(struct stack * stack, int num_frames)
{ {
stack->ix -= num_frames; stack->ix -= num_frames;
assert(stack->ix >= 0); assert(stack->ix >= 0);
struct frame * frame = &stack->frame[stack->ix]; struct frame * frame = &stack->frame[stack->ix - 1];
return frame; return frame;
} }
@ -122,41 +122,72 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc
uint32_t value = operand_stack_pop_u32(old_frame); uint32_t value = operand_stack_pop_u32(old_frame);
vm->current_frame->local_variable[nargs - i - 1] = value; vm->current_frame->local_variable[nargs - i - 1] = value;
} }
vm->current_thread.pc = 0; vm->current_frame->return_type = descriptor_constant->utf8.bytes[nargs + 2];
vm->current_frame->pc = 0;
vm->current_thread.current_class = class_file; vm->current_thread.current_class = class_file;
vm->current_thread.current_method = method_info; vm->current_thread.current_method = method_info;
} }
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);
vm->current_frame = stack_pop_frame(&vm->frame_stack, 1);
assert(vm->current_frame != old_frame);
vm->current_frame->pc = vm->current_frame->next_pc;
switch (old_frame->return_type) {
case 'I':
uint32_t value = operand_stack_pop_u32(old_frame);
operand_stack_push_u32(vm->current_frame, value);
break;
case 'V':
break;
default:
fprintf(stderr, "return type not implemented: %c\n", old_frame->return_type);
break;
}
assert(old_frame->operand_stack_ix == 0);
}
static void print_vm_stack(struct vm * vm)
{
printf("[ ");
for (int i = 5; i > 0; i--) {
if (i > vm->current_frame->operand_stack_ix) {
printf(" ");
continue;
}
int32_t value = vm->current_frame->operand_stack[vm->current_frame->operand_stack_ix - i];
if (value > 65536)
printf("0x%08x ", value);
else
printf("%10d ", value);
}
printf("]\n");
}
void vm_execute(struct vm * vm) void vm_execute(struct vm * vm)
{ {
printf("execute:\n");
while (true) { while (true) {
printf("[ "); print_vm_stack(vm);
for (int i = 5; i > 0; i--) { decode_print_instruction(vm->current_frame->code->code, vm->current_frame->pc);
if (i > vm->current_frame->operand_stack_ix) { uint32_t old_pc = vm->current_frame->pc;
printf(" "); struct method_info * old_method = vm->current_thread.current_method;
continue; decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc);
} //if (vm->current_frame->pc >= vm->current_frame->code->code_length) {
int32_t value = vm->current_frame->operand_stack[vm->current_frame->operand_stack_ix - i]; if (vm->frame_stack.ix == 1) {
if (value > 65536)
printf("0x%08x ", value);
else
printf("%10d ", value);
}
printf("]\n");
decode_print_instruction(vm->current_frame->code->code, vm->current_thread.pc);
uint32_t old_pc = vm->current_thread.pc;
uint32_t next_pc = decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_thread.pc);
if (vm->current_thread.pc == old_pc) {
// if the instruction did not branch, increment pc
vm->current_thread.pc = next_pc;
}
if (vm->current_thread.pc >= vm->current_frame->code->code_length) {
printf("terminate\n"); printf("terminate\n");
break; break;
} }
if (vm->current_thread.current_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;
}
} }
} }
@ -177,7 +208,7 @@ int main(int argc, const char * argv[])
(const uint8_t *)main_class, (const uint8_t *)main_class,
string_length(main_class)); string_length(main_class));
const char * method_name = "test"; const char * method_name = "main";
int method_name_length = string_length(method_name); int method_name_length = string_length(method_name);
struct method_info * method_info = class_resolver_lookup_method(class_entry, struct method_info * method_info = class_resolver_lookup_method(class_entry,
(const uint8_t *)method_name, (const uint8_t *)method_name,
@ -197,6 +228,15 @@ int main(int argc, const char * argv[])
uint32_t data[vm.data_stack.capacity]; uint32_t data[vm.data_stack.capacity];
vm.data_stack.data = data; 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->class_file, method_info); vm_static_method_call(&vm, class_entry->class_file, method_info);
vm_execute(&vm); vm_execute(&vm);
} }

View File

@ -8,11 +8,13 @@ struct frame {
struct Code_attribute * code; struct Code_attribute * code;
uint32_t * local_variable; uint32_t * local_variable;
uint32_t * operand_stack; uint32_t * operand_stack;
uint32_t pc;
uint32_t next_pc;
uint16_t operand_stack_ix; uint16_t operand_stack_ix;
uint8_t return_type;
}; };
struct thread { struct thread {
uint32_t pc;
struct class_file * current_class; struct class_file * current_class;
struct method_info * current_method; struct method_info * current_method;
}; };
@ -59,3 +61,4 @@ static inline void operand_stack_dup_u32(struct frame * frame)
} }
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);

View File

@ -156,6 +156,7 @@ def generate_execute_fixed_width_instruction(instruction):
conversion = sign_type_table[(argument.signed, argument.size)] conversion = sign_type_table[(argument.signed, argument.size)]
yield f"{c_type} {argument.name} = {conversion}(&code[pc + {offset}]);" yield f"{c_type} {argument.name} = {conversion}(&code[pc + {offset}]);"
offset += argument.size offset += argument.size
yield f"vm->current_frame->next_pc = pc + {1 + instruction.arguments_size};"
argument_values = ", ".join( argument_values = ", ".join(
argument.name argument.name
for argument in instruction.arguments for argument in instruction.arguments
@ -163,10 +164,10 @@ def generate_execute_fixed_width_instruction(instruction):
if argument_values: if argument_values:
argument_values = ", " + argument_values argument_values = ", " + argument_values
yield f"op_{instruction.mnemonic}(vm{argument_values});" yield f"op_{instruction.mnemonic}(vm{argument_values});"
yield f"return pc + {1 + instruction.arguments_size};"
def generate_execute_variable_width_instruction(instruction): def generate_execute_variable_width_instruction(instruction):
yield f"{instruction.mnemonic.upper()}_ARGS;" yield f"{instruction.mnemonic.upper()}_ARGS;"
yield f"vm->current_frame->next_pc = {instruction.mnemonic.upper()}_NEXT_PC;"
argument_values = ", ".join( argument_values = ", ".join(
argument argument
for argument in instruction.arguments for argument in instruction.arguments
@ -174,10 +175,9 @@ def generate_execute_variable_width_instruction(instruction):
if argument_values: if argument_values:
argument_values = ", " + argument_values argument_values = ", " + argument_values
yield f"op_{instruction.mnemonic}(vm{argument_values});" yield f"op_{instruction.mnemonic}(vm{argument_values});"
yield f"return {instruction.mnemonic.upper()}_NEXT_PC;"
def generate_execute_decoder(): def generate_execute_decoder():
yield "uint32_t decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc)" yield "void decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc)"
yield "{" yield "{"
yield "switch (code[pc]) {" yield "switch (code[pc]) {"
for instruction in opcode_table: for instruction in opcode_table:
@ -189,11 +189,12 @@ def generate_execute_decoder():
else: else:
yield from generate_execute_fixed_width_instruction(instruction) yield from generate_execute_fixed_width_instruction(instruction)
yield "break;"
yield "}" yield "}"
yield "default:" yield "default:"
yield "{" yield "{"
yield "assert(false);" yield "assert(false);"
yield "return pc;" yield "break;"
yield "}" yield "}"
yield "}" yield "}"
yield "}" yield "}"

View File

@ -3,6 +3,10 @@ package p;
import p.Data; import p.Data;
class DataTest { class DataTest {
static void main() {
test();
}
static int test() { static int test() {
return test2(6, 3) * 5; return test2(6, 3) * 5;
} }