implement return/ireturn
This commit is contained in:
parent
932a7c82aa
commit
d09d712f1b
@ -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);
|
||||
|
619
c/decode.inc.c
619
c/decode.inc.c
File diff suppressed because it is too large
Load Diff
53
c/execute.c
53
c/execute.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
94
c/frame.c
94
c/frame.c
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 "}"
|
||||
|
@ -3,6 +3,10 @@ package p;
|
||||
import p.Data;
|
||||
|
||||
class DataTest {
|
||||
static void main() {
|
||||
test();
|
||||
}
|
||||
|
||||
static int test() {
|
||||
return test2(6, 3) * 5;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user