summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2025-05-20 14:44:29 +0200
committerOrangerot <purple@orangerot.dev>2025-05-20 14:44:29 +0200
commitd8c0b2bc2c7ef40fba75e271f29fdfc8f51c2417 (patch)
tree0617f09ded3aeec84b678f0202ed753397038bb2
parent311010f4e6ca8f6ef0b7b615344dc8be75beee04 (diff)
refactor: have instructions in array instead of switch-case
-rw-r--r--wai.c194
1 files changed, 97 insertions, 97 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");
-
- 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);
+ 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);
+ };
+
+ 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);