refactor: have instruction as macro to generate enum, functions and array
This commit is contained in:
parent
d8c0b2bc2c
commit
9d0692a391
169
wai.c
169
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) {
|
||||
|
|
Loading…
Reference in a new issue