From 9d0692a391cd492db3d393560d029e3d72840a77 Mon Sep 17 00:00:00 2001 From: Orangerot Date: Thu, 22 May 2025 05:50:35 +0200 Subject: [PATCH] refactor: have instruction as macro to generate enum, functions and array --- wai.c | 169 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 93 insertions(+), 76 deletions(-) diff --git a/wai.c b/wai.c index da42a55..73f5634 100644 --- a/wai.c +++ b/wai.c @@ -64,6 +64,27 @@ enum TYPE { TYPE_EXTERNREF = 0x6F }; +static const int TYPE_SIZE[] = { + [TYPE_I32] = 4, + [TYPE_I64] = 8, + [TYPE_F32] = 4, + [TYPE_F64] = 8, + [TYPE_V128] = 16, + [TYPE_FUNCREF] = 16, + [TYPE_EXTERNREF] = 16 +}; + +static const char *TYPE_NAME[] = { + [TYPE_I32] = "I32", + [TYPE_I64] = "I64", + [TYPE_F32] = "F32", + [TYPE_F64] = "F64", + [TYPE_V128] = "V128", + [TYPE_FUNCREF] = "FREF", + [TYPE_EXTERNREF] = "EXTR", + [TYPE_ANY] = "ANY", +}; + struct stack { u_char items[STACK_CAPACITY]; size_t bytes; @@ -112,39 +133,6 @@ struct module { size_t num_exports; }; -enum OP_CODES { - INSTR_CALL = 0x10, - INSTR_ELSE = 0x05, - INSTR_END = 0x0b, - INSTR_F64_CONST = 0x44, - INSTR_F64_LT = 0x63, - INSTR_F64_MUL = 0xa2, - INSTR_F64_SUB = 0xa1, - INSTR_IF = 0x04, - INSTR_LOCAL_GET = 0x20, -}; - -static const int TYPE_SIZE[] = { - [TYPE_I32] = 4, - [TYPE_I64] = 8, - [TYPE_F32] = 4, - [TYPE_F64] = 8, - [TYPE_V128] = 16, - [TYPE_FUNCREF] = 16, - [TYPE_EXTERNREF] = 16 -}; - -static const char *TYPE_NAME[] = { - [TYPE_I32] = "I32", - [TYPE_I64] = "I64", - [TYPE_F32] = "F32", - [TYPE_F64] = "F64", - [TYPE_V128] = "V128", - [TYPE_FUNCREF] = "FREF", - [TYPE_EXTERNREF] = "EXTR", - [TYPE_ANY] = "ANY", -}; - struct value_t { enum TYPE type; union { @@ -173,6 +161,7 @@ void print_value(struct value_t *value) { printf("%d", *(int32_t*)number); break; case TYPE_I64: + case TYPE_ANY: printf("%ld", *(int64_t*)number); break; case TYPE_F32: @@ -232,46 +221,72 @@ 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 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; +#define PARAMS(...) __VA_ARGS__ - 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); +// https://webassembly.github.io/spec/core/appendix/index-instructions.html +// OP(NAME, CODE, PARAM, NUM_RESULTS, LEN_IMMIDIATE, BODY) +#define DEFINE_OPERATIONS(OP) \ +OP(INSTR_F64_MUL, 0xa2, PARAMS(TYPE_F64, TYPE_F64), 1, 0, result->type = TYPE_F64; result->value.f64 = a->value.f64 * b->value.f64) \ +OP(INSTR_F64_SUB, 0xa1, PARAMS(TYPE_F64, TYPE_F64), 1, 0, result->type = TYPE_F64; result->value.f64 = b->value.f64 - a->value.f64) \ +OP(INSTR_F64_LT, 0x63, PARAMS(TYPE_F64, TYPE_F64), 1, 0, result->type = TYPE_F64; result->value.f64 = b->value.f64 < a->value.f64) \ +OP(INSTR_F64_CONST, 0x44, PARAMS(), 1, 8, result->type = TYPE_F64; result->value.f64 = *(double*)immidiate) \ +OP(INSTR_LOCAL_GET, 0x20, PARAMS(), 1, 1, \ + 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, 0x10, PARAMS(), 0, 1, parse_function(context.module, *(u_char*)immidiate, len)) \ +OP(INSTR_IF, 0x04, PARAMS(TYPE_ANY), 0, 1, \ + 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) { \ + 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; \ ) -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); - } +enum OP_CODES { +#define AS_ENUM(NAME, CODE, PARAM, NUM_RESULTS, LEN_IMMIDIATE, BODY) NAME = CODE, +DEFINE_OPERATIONS(AS_ENUM) + INSTR_END = 0x0B, + INSTR_ELSE = 0x05 +}; + + +#define AS_FUNCTION(NAME, CODE, PARAM, NUM_RESULTS, LEN_IMMIDIATE, BODY) \ + int exec_##NAME(struct context context, struct value_t *a, \ + struct value_t *b, void *immidiate, struct value_t *result, \ + u_char *binary, size_t len) { \ + (void) context; \ + (void) a; \ + (void) b; \ + (void) immidiate; \ + (void) result; \ + (void) binary; \ + (void) len; \ + BODY; \ + return 0; \ } - incr(i, len); - return i; -) +DEFINE_OPERATIONS(AS_FUNCTION) struct instruction { size_t num_param; @@ -282,13 +297,15 @@ struct instruction { }; 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}, +#define AS_INSTRUCTION(NAME, CODE, PARAM, NUM_RESULTS, LEN_IMMIDIATE, BODY) \ + [NAME] = { \ + .num_param = sizeof((enum TYPE[]) {PARAM}) / sizeof(enum TYPE), \ + .params = {PARAM}, \ + .num_results = NUM_RESULTS, \ + .len_immidiate = LEN_IMMIDIATE, \ + .exec = &exec_##NAME \ + }, +DEFINE_OPERATIONS(AS_INSTRUCTION) }; int parse_instruction(struct context context, u_char *binary, size_t len) {