summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2025-05-22 05:50:35 +0200
committerOrangerot <purple@orangerot.dev>2025-05-22 05:50:35 +0200
commit9d0692a391cd492db3d393560d029e3d72840a77 (patch)
tree153d1fce2fe8b21226c32914c3ac30bd4a59fb76
parentd8c0b2bc2c7ef40fba75e271f29fdfc8f51c2417 (diff)
refactor: have instruction as macro to generate enum, functions and arrayHEADmain
-rw-r--r--wai.c173
1 files changed, 95 insertions, 78 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;
-
- 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);
+#define PARAMS(...) __VA_ARGS__
+
+// 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) {