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"
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)
{
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)
@ -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 value1 = operand_stack_pop_u32(vm->current_frame);
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 value1 = operand_stack_pop_u32(vm->current_frame);
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 value1 = operand_stack_pop_u32(vm->current_frame);
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 value1 = operand_stack_pop_u32(vm->current_frame);
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 value1 = operand_stack_pop_u32(vm->current_frame);
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 value1 = operand_stack_pop_u32(vm->current_frame);
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);
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);
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);
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);
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);
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);
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);
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);
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. */
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)
@ -1220,12 +1230,11 @@ void op_newarray(struct vm * vm, uint32_t atype)
void op_nop(struct vm * vm)
{
assert(!"op_nop");
}
void op_pop(struct vm * vm)
{
assert(!"op_pop");
operand_stack_pop_u32(vm->current_frame);
}
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)
{
assert(!"op_return");
vm_method_return(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)
{
assert(!"op_sipush");
assert(!"op_sipush2");
}
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);
if (index < lowbyte || index > highbyte) {
vm->current_thread.pc = vm->current_thread.pc + defaultbyte;
vm->current_frame->pc = vm->current_frame->pc + defaultbyte;
} else {
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;
assert(stack->ix >= 0);
struct frame * frame = &stack->frame[stack->ix];
struct frame * frame = &stack->frame[stack->ix - 1];
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);
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_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)
{
printf("execute:\n");
while (true) {
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");
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) {
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_thread.current_method;
decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc);
//if (vm->current_frame->pc >= vm->current_frame->code->code_length) {
if (vm->frame_stack.ix == 1) {
printf("terminate\n");
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,
string_length(main_class));
const char * method_name = "test";
const char * method_name = "main";
int method_name_length = string_length(method_name);
struct method_info * method_info = class_resolver_lookup_method(class_entry,
(const uint8_t *)method_name,
@ -197,6 +228,15 @@ int main(int argc, const char * argv[])
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->class_file, method_info);
vm_execute(&vm);
}

View File

@ -8,11 +8,13 @@ struct frame {
struct Code_attribute * code;
uint32_t * local_variable;
uint32_t * operand_stack;
uint32_t pc;
uint32_t next_pc;
uint16_t operand_stack_ix;
uint8_t return_type;
};
struct thread {
uint32_t pc;
struct class_file * current_class;
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_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)]
yield f"{c_type} {argument.name} = {conversion}(&code[pc + {offset}]);"
offset += argument.size
yield f"vm->current_frame->next_pc = pc + {1 + instruction.arguments_size};"
argument_values = ", ".join(
argument.name
for argument in instruction.arguments
@ -163,10 +164,10 @@ def generate_execute_fixed_width_instruction(instruction):
if argument_values:
argument_values = ", " + 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):
yield f"{instruction.mnemonic.upper()}_ARGS;"
yield f"vm->current_frame->next_pc = {instruction.mnemonic.upper()}_NEXT_PC;"
argument_values = ", ".join(
argument
for argument in instruction.arguments
@ -174,10 +175,9 @@ def generate_execute_variable_width_instruction(instruction):
if argument_values:
argument_values = ", " + argument_values
yield f"op_{instruction.mnemonic}(vm{argument_values});"
yield f"return {instruction.mnemonic.upper()}_NEXT_PC;"
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 "switch (code[pc]) {"
for instruction in opcode_table:
@ -189,11 +189,12 @@ def generate_execute_decoder():
else:
yield from generate_execute_fixed_width_instruction(instruction)
yield "break;"
yield "}"
yield "default:"
yield "{"
yield "assert(false);"
yield "return pc;"
yield "break;"
yield "}"
yield "}"
yield "}"

View File

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