From d8c0b2bc2c7ef40fba75e271f29fdfc8f51c2417 Mon Sep 17 00:00:00 2001 From: Orangerot Date: Tue, 20 May 2025 14:44:29 +0200 Subject: [PATCH] refactor: have instructions in array instead of switch-case --- wai.c | 192 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/wai.c b/wai.c index 8bf4cc2..da42a55 100644 --- a/wai.c +++ b/wai.c @@ -54,6 +54,7 @@ enum section { }; enum TYPE { + TYPE_ANY = 0, TYPE_I32 = 0x7F, TYPE_I64 = 0x7E, TYPE_F32 = 0x7D, @@ -111,7 +112,7 @@ struct module { size_t num_exports; }; -enum INSTRUCTION { +enum OP_CODES { INSTR_CALL = 0x10, INSTR_ELSE = 0x05, INSTR_END = 0x0b, @@ -140,7 +141,8 @@ static const char *TYPE_NAME[] = { [TYPE_F64] = "F64", [TYPE_V128] = "V128", [TYPE_FUNCREF] = "FREF", - [TYPE_EXTERNREF] = "EXTR" + [TYPE_EXTERNREF] = "EXTR", + [TYPE_ANY] = "ANY", }; struct value_t { @@ -156,6 +158,12 @@ struct value_t { } value; }; +struct context { + struct module *module; + size_t func_i; + size_t func_stack_begin; +}; + #define incr(i, len) i++; if (i >= len) {return 0;} void print_value(struct value_t *value) { @@ -222,107 +230,94 @@ void stack_pop(struct stack *s, struct value_t *value) { } int parse_function(struct module *module, size_t func_i, size_t len); -int parse_instruction(struct module *module, u_char *binary, size_t func_i, size_t func_stack_begin, size_t len) { +int parse_instruction(struct context context, u_char *binary, size_t len); + +#define OP(name, body) int name(struct context context, struct value_t *a, struct value_t *b, void *immidiate, struct value_t *result, u_char *binary, size_t len) { body; return 0;} +OP(instr_f64_mul_exec, result->type = TYPE_F64; result->value.f64 = a->value.f64 * b->value.f64) +OP(instr_f64_sub_exec, result->type = TYPE_F64; result->value.f64 = b->value.f64 - a->value.f64) +OP(instr_f64_lt_exec, result->type = TYPE_F64; result->value.f64 = b->value.f64 < a->value.f64) +OP(instr_f64_const_exec, result->type = TYPE_F64; result->value.f64 = *(double*)immidiate) +OP(instr_local_get_exec, + size_t func_type_i = context.module->func[context.func_i].func_type_index; + struct func_type_t *func_type = &context.module->func_types[func_type_i]; + int num_locals = func_type->num_params + context.module->func[context.func_i].num_local_vars; + + printf("num locals %d, %d\n", num_locals, num_locals - 1 - *(u_char*)immidiate); + stack_peak(&context.module->stack, result, num_locals - 1 - *(u_char*)immidiate, context.func_stack_begin); +) +OP(instr_call_exec, parse_function(context.module, *(u_char*)immidiate, len)) +OP(instr_if_exec, + size_t i = 0; + enum TYPE condition_type = *(u_char*) immidiate; + if (a->type != condition_type) + printf("Wrong types!\n"); + + while (binary[i] != INSTR_ELSE) { + // TODO test condition with correct type. + // This might not matter since all types are false with 0x0 + if (a->value.i64) { + i += parse_instruction(context, &binary[i], len); + } else { + incr(i, len); + } + } + incr(i, len); + while (binary[i] != INSTR_END) { + if (a->value.i64) { + incr(i, len); + } else { + i += parse_instruction(context, &binary[i], len); + } + } + incr(i, len); + return i; +) + +struct instruction { + size_t num_param; + enum TYPE params[2]; + size_t len_immidiate; + size_t num_results; + int (*exec) (struct context context, struct value_t *a, struct value_t *b, void *immidiate, struct value_t *result, u_char *binary, size_t len); +}; + +struct instruction INSTRUCTIONS[] = { + [INSTR_F64_MUL] = {.num_param = 2, .params = {TYPE_F64, TYPE_F64}, .num_results = 1, .len_immidiate = 0, .exec = &instr_f64_mul_exec}, + [INSTR_F64_SUB] = {.num_param = 2, .params = {TYPE_F64, TYPE_F64}, .num_results = 1, .len_immidiate = 0, .exec = &instr_f64_sub_exec}, + [INSTR_F64_LT] = {.num_param = 2, .params = {TYPE_F64, TYPE_F64}, .num_results = 1, .len_immidiate = 0, .exec = &instr_f64_lt_exec}, + [INSTR_F64_CONST] = {.num_param = 0, .params = {}, .num_results = 1, .len_immidiate = 8, .exec = &instr_f64_const_exec}, + [INSTR_LOCAL_GET] = {.num_param = 0, .params = {}, .num_results = 1, .len_immidiate = 1, .exec = &instr_local_get_exec}, + [INSTR_CALL] = {.num_param = 0, .params = {}, .num_results = 0, .len_immidiate = 1, .exec = &instr_call_exec}, + [INSTR_IF] = {.num_param = 1, .params = {TYPE_ANY}, .num_results = 0, .len_immidiate = 1, .exec = &instr_if_exec}, +}; + +int parse_instruction(struct context context, u_char *binary, size_t len) { size_t i = 0; - enum INSTRUCTION instr = binary[i]; + enum OP_CODES op_code = binary[i]; u_char *instr_addr = &binary[i]; - struct value_t a = {0}; - struct value_t b = {0}; struct value_t result = {0}; + struct value_t arguments[2]; incr(i, len); - switch (instr) { - case INSTR_CALL: { - int func_index = binary[i]; - incr(i, len); - // stack_pop(&module->stack, &a); - parse_function(module, func_index, len); - break; - } - case INSTR_ELSE: - printf("reached else instruction: impossible!\n"); - case INSTR_END: - break; - case INSTR_F64_CONST: - result.type = TYPE_F64; - result.value.f64 = *(double*)&binary[i]; - i += 8; - stack_push(&module->stack, &result); - break; - case INSTR_F64_LT: { - stack_pop(&module->stack, &a); - stack_pop(&module->stack, &b); - if (a.type != TYPE_F64 || b.type != TYPE_F64) - printf("Wrong types!\n"); - result.type = TYPE_F64; - result.value.f64 = b.value.f64 < a.value.f64; - stack_push(&module->stack, &result); - break; - } - case INSTR_F64_MUL: { - stack_pop(&module->stack, &a); - stack_pop(&module->stack, &b); - if (a.type != TYPE_F64 || b.type != TYPE_F64) - printf("Wrong types!\n"); - result.type = TYPE_F64; - result.value.f64 = a.value.f64 * b.value.f64; - stack_push(&module->stack, &result); - break; - } - case INSTR_F64_SUB: { - stack_pop(&module->stack, &a); - stack_pop(&module->stack, &b); - if (a.type != TYPE_F64 || b.type != TYPE_F64) - printf("Wrong types!\n"); - result.type = TYPE_F64; - result.value.f64 = b.value.f64 - a.value.f64; - stack_push(&module->stack, &result); - break; - } - case INSTR_IF: { - stack_pop(&module->stack, &a); - enum TYPE condition_type = binary[i]; - incr(i, len); - if (a.type != condition_type) - printf("Wrong types!\n"); + struct instruction *instr = &INSTRUCTIONS[op_code]; + if (instr->exec == NULL) { + printf("not implemented/illegal instruction %x at %lx\n", op_code, instr_addr - context.module->binary); + exit(1); + }; - while (binary[i] != INSTR_ELSE) { - // TODO test condition with correct type. - // This might not matter since all types are false with 0x0 - if (a.value.i64) { - i += parse_instruction(module, &binary[i], func_i, func_stack_begin, len); - } else { - incr(i, len); - } - } - incr(i, len); - while (binary[i] != INSTR_END) { - if (a.value.i64) { - incr(i, len); - } else { - i += parse_instruction(module, &binary[i], func_i, func_stack_begin, len); - } - } - incr(i, len); - break; - } - case INSTR_LOCAL_GET: { - int local_index = binary[i]; - size_t func_type_i = module->func[func_i].func_type_index; - struct func_type_t *func_type = &module->func_types[func_type_i]; - int num_locals = func_type->num_params + module->func[func_i].num_local_vars; - - printf("num locals %d, %d\n", num_locals, num_locals - 1 - local_index); - stack_peak(&module->stack, &result, num_locals - 1 - local_index, func_stack_begin); - incr(i, len); - stack_push(&module->stack, &result); - break; - } - default: - printf("unknown instruction! %x at %lx\n", instr, instr_addr - module->binary); - exit(1); + for (size_t param_i = 0; param_i < instr->num_param; param_i++) { + stack_pop(&context.module->stack, &arguments[param_i]); + if (instr->params[param_i] != TYPE_ANY && arguments[param_i].type != instr->params[param_i]) { + printf("wrong type! %x\n", op_code); + } } + i += instr->exec(context, &arguments[0], &arguments[1], &binary[i], &result, &binary[i + instr->len_immidiate], len); + i += instr->len_immidiate; + if (instr->num_results) { + stack_push(&context.module->stack, &result); + } + return i; } @@ -336,6 +331,11 @@ int parse_function(struct module *module, size_t func_i, size_t len) { size_t func_stack_begin = module->stack.bytes; size_t func_stack_end; struct value_t result = {0}; + struct context context = { + .module = module, + .func_i = func_i, + .func_stack_begin = func_stack_begin + }; incr(i, len); func->num_local_vars = binary[i]; @@ -345,7 +345,7 @@ int parse_function(struct module *module, size_t func_i, size_t len) { incr(i, len); } while (binary[i] != INSTR_END) { - i += parse_instruction(module, &binary[i], func_i, func_stack_begin, len); + i += parse_instruction(context, &binary[i], len); } incr(i, len);