diff --git a/wai.c b/wai.c index aac65ca..48f897f 100644 --- a/wai.c +++ b/wai.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -48,8 +49,8 @@ enum section { #define STACK_CAPACITY 1024 struct stack { - double items[STACK_CAPACITY]; - size_t count; + u_char items[STACK_CAPACITY]; + size_t bytes; }; #define MAX_FUNCTIONS 128 @@ -87,7 +88,6 @@ enum INSTRUCTION { INSTR_CALL = 0x10, INSTR_ELSE = 0x05, INSTR_END = 0x0b, - INSTR_F64 = 0x7C, INSTR_F64_CONST = 0x44, INSTR_F64_LT = 0x63, INSTR_F64_MUL = 0xa2, @@ -106,26 +106,81 @@ 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 +}; + +struct value_t { + enum TYPE type; + union { + int32_t i32; + int64_t i64; + float f32; + double f64; + __int128 v128; + int64_t funcref; + int64_t extref; + } value; +}; + #define incr(i, len) i++; if (i >= len) {return -1;} -void stack_push(struct stack *s, double a) { - s->items[s->count++] = a; +void stack_push(struct stack *s, const struct value_t *value) { + size_t type_size = TYPE_SIZE[value->type]; + memcpy(&(s->items[s->bytes]), &value->value, type_size); + s->items[s->bytes + type_size] = value->type; + s->bytes += type_size + 1; + printf("stack: "); - for (int i = 0; i < s->count; i++) { - printf("%f, ", s->items[i]); + for (int i = s->bytes - 1; i > 0; i -= TYPE_SIZE[s->items[i]] + 1) { + enum TYPE t = s->items[i]; + size_t type_size = TYPE_SIZE[t]; + void *value = &s->items[i - type_size]; + + switch (t) { + case TYPE_I32: + printf("%d (I32)", *(int32_t*)value); + break; + case TYPE_I64: + printf("%ld (I32)", *(int64_t*)value); + break; + case TYPE_F32: + printf("%f (F32)", *(float*)value); + break; + case TYPE_F64: + printf("%f (F64)", *(double*)value); + break; + case TYPE_V128: + printf("%ld (V128)", *(__int128*)value); + break; + case TYPE_FUNCREF: + printf("%ld (EREF)", *(int64_t*)value); + break; + case TYPE_EXTERNREF: + printf("%ld (EREF)", *(int64_t*)value); + break; + } + printf(", "); } printf("\n"); } -double stack_pop(struct stack *s) { - s->count--; - return s->items[s->count]; -} - -double stack_top(struct stack *s) { - return s->items[s->count-1]; +void stack_top(struct stack *s, struct value_t *value) { + value->type = s->items[s->bytes-1]; + memcpy(&value->value, &(s->items[s->bytes - 1 - TYPE_SIZE[value->type]]), TYPE_SIZE[value->type]); } +void stack_pop(struct stack *s, struct value_t *value) { + stack_top(s, value); + s->bytes -= TYPE_SIZE[value->type] + 1; +} + int parse_type(u_char *binary, int len) { int i = 0; enum TYPE param = binary[i]; @@ -151,47 +206,71 @@ int parse_instruction(struct module *module, u_char *binary, double param, int l int i = 0; enum INSTRUCTION instr = (u_char) binary[i]; u_char *instr_addr = &binary[i]; + struct value_t a = {0}; + struct value_t b = {0}; + struct value_t result = {0}; + incr(i, len); switch (instr) { - case INSTR_CALL: - int a = binary[i]; + case INSTR_CALL: { + int func_index = binary[i]; incr(i, len); - parse_function(module, module->funcs[a], stack_pop(&module->stack), len); + stack_pop(&module->stack, &a); + parse_function(module, module->funcs[func_index], a.value.f64, len); break; + } case INSTR_ELSE: printf("reached else instruction: impossible!\n"); case INSTR_END: break; - case INSTR_F64: - break; case INSTR_F64_CONST: - double k = *(double*)&binary[i]; - stack_push(&module->stack, k); + result.type = TYPE_F64; + result.value.f64 = *(double*)&binary[i]; i += 8; + stack_push(&module->stack, &result); break; case INSTR_F64_LT: { - double b = stack_pop(&module->stack); - double a = stack_pop(&module->stack); - stack_push(&module->stack, a < b); + 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: { - double b = stack_pop(&module->stack); - double a = stack_pop(&module->stack); - stack_push(&module->stack, a * b); + 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: { - double b = stack_pop(&module->stack); - double a = stack_pop(&module->stack); - stack_push(&module->stack, a - b); + 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: { - double a = stack_pop(&module->stack); + 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) { - if (a) { + // 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], param, len); } else { incr(i, len); @@ -199,7 +278,7 @@ int parse_instruction(struct module *module, u_char *binary, double param, int l } incr(i, len); while (binary[i] != INSTR_END) { - if (a) { + if (a.value.i64) { incr(i, len); } else { i += parse_instruction(module, &binary[i], param, len); @@ -208,11 +287,12 @@ int parse_instruction(struct module *module, u_char *binary, double param, int l incr(i, len); break; } - case INSTR_LOCAL_GET: + case INSTR_LOCAL_GET: { int local_index = binary[i]; incr(i, len); - stack_push(&module->stack, param); + stack_push(&module->stack, &(struct value_t) {.value.f64 = param, .type = TYPE_F64}); break; + } default: printf("unknown instruction! %x at %lx\n", instr, instr_addr - module->binary); exit(1); @@ -322,7 +402,7 @@ int parse_section(struct module *module, u_char *binary, int len) { module->funcs[function_i] = &binary[i]; i += parse_function(module, &binary[i], 4, len); } - printf("result: %f\n", module->stack.items[0]); + // printf("result: %f\n", module->stack.items[0]); break; case Section_Data: break; @@ -339,9 +419,9 @@ int parse_section(struct module *module, u_char *binary, int len) { int parse_module(u_char *binary, size_t len) { int i = 0; - u_char *magic = "\0asm"; + char *magic = "\0asm"; while (i < 4) { - if (binary[i] != magic[i]) { + if ((char) binary[i] != magic[i]) { fprintf(stderr, "no wasm magic\n"); return 0; } @@ -377,7 +457,7 @@ int main(int argc, char **argv) { stat(argv[1], &st); printf("size: %ld\n", st.st_size); - unsigned char *binary = malloc(st.st_size); + u_char *binary = malloc(st.st_size); fread(binary, st.st_size, 1, file); if (parse_module(binary, st.st_size) == -1) {