diff options
Diffstat (limited to 'tools/translate.c')
-rw-r--r-- | tools/translate.c | 318 |
1 files changed, 290 insertions, 28 deletions
diff --git a/tools/translate.c b/tools/translate.c index 97d48f7..b3d2afd 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -2,20 +2,42 @@ #include "wasm.h" #include "stack_machine_instruction.h" +struct types { + struct types *prev; + char type; /* should be one of VALTYPE_* constants from wasm.h */ +}; + struct translation { FILE *handle; struct function *function; struct module *module; + struct types *types_stack; }; -/* All functions, that go into function pointer array, start with _ */ +void free_types_stack(struct types *top) +{ + struct types *tmp; + + while (top) { + tmp = top->prev; + free(top); + top = tmp; + } +} + +/* All functions, that go into one of function pointer arrays, start with _ */ + +/** DEFINE TRANSLATION FUNCTIONS **/ /* Translate complex - those routines have to be defined manually */ -#define TC(wasm_opcode, name) +#define TC(wasm_opcode, name, argtypes, restype) + +static int typecheck_call(struct translation *data, struct function *callee); static int _translate_call(struct translation *data) { uint32_t funcidx; + struct function *func; struct instruction **target; if (leb_u32(data->handle, &funcidx)) { @@ -28,15 +50,22 @@ static int _translate_call(struct translation *data) return -1; } - target = &data->module->functions[funcidx].translated_body; + func = data->module->functions + funcidx; + + if (typecheck_call(data, func)) + return -1; + + target = &func->translated_body; return i_call(ptr(target), &data->function->translated_body); } +static int typecheck_local_get(struct translation *data, uint32_t localidx); + static int _translate_local_get(struct translation *data) { uint32_t localidx; - uint32_t args_count = data->function->type->arguments_count; + uint32_t args_count = data->function->type->args.count; uint32_t locals_count = data->function->locals_count; uint32_t all_locals_count = args_count + locals_count; uint64_t offset_on_frame; @@ -52,14 +81,19 @@ static int _translate_local_get(struct translation *data) return -1; } + if (typecheck_local_get(data, localidx)) + return -1; + offset_on_frame = all_locals_count - localidx + 1; if (localidx >= args_count) offset_on_frame -= 1; - return - i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || - i_load_p(im(4 * offset_on_frame), expr); + if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || + i_load_p(im(4 * offset_on_frame), expr)) + return -1; + + return 0; } static int _translate_const(struct translation *data) @@ -75,7 +109,7 @@ static int _translate_const(struct translation *data) } /* Translate Simple */ -#define TS(wasm_opcode, sm_instr) \ +#define TS(wasm_opcode, sm_instr, argtypes, restype) \ static int _translate_##sm_instr(struct translation *data) \ { \ return i_##sm_instr(&data->function->translated_body); \ @@ -99,7 +133,7 @@ static int translate_load_store(struct translation *data, return instr_routine(im(offset), &data->function->translated_body); } -#define TLS(wasm_opcode, sm_instr) \ +#define TLS(wasm_opcode, sm_instr, argtypes, restype) \ static int _translate_##sm_instr(struct translation *data) \ { \ return translate_load_store(data, i_##sm_instr); \ @@ -112,14 +146,19 @@ static int translate_load_store(struct translation *data, #undef TLS #undef TC +/** DEFINE TRANSLATION FUNCTIONS POINTER ARRAY **/ + /* Translate complex */ -#define TC(wasm_opcode, name) [wasm_opcode] = _translate_##name, +#define TC(wasm_opcode, name, argtypes, restype) \ + [wasm_opcode] = _translate_##name, /* Translate Simple */ -#define TS(wasm_opcode, sm_instr) TC(wasm_opcode, sm_instr) +#define TS(wasm_opcode, sm_instr, argtypes, restype) \ + TC(wasm_opcode, sm_instr, dummy, dummy) /* Translate load/store */ -#define TLS(wasm_opcode, sm_instr) TC(wasm_opcode, sm_instr) +#define TLS(wasm_opcode, sm_instr, argtypes, restype) \ + TC(wasm_opcode, sm_instr, dummy, dummy) /* The actual array of function pointers is defined here */ static int (*translation_routines[256]) (struct translation *) = { @@ -130,42 +169,262 @@ static int (*translation_routines[256]) (struct translation *) = { #undef TLS #undef TC -static int translate_expr(struct translation *data, struct functype *exprtype) +/** DEFINE ARGUMENT TYPECHECK FUNCTIONS **/ + +static int _argcheck_empty(struct types **types_stack) +{ + return 0; +} + +static int argcheck_generic_noremove(struct types *types_stack, char expected) +{ + char *name; + + name = + expected == VALTYPE_F64 ? "f64" : + expected == VALTYPE_F32 ? "f32" : + expected == VALTYPE_I64 ? "i64" : + "i32"; + + if (!types_stack) { + PRERR("Expected %s on stack, got nothing\n", name); + return -1; + } + + if (types_stack->type != VALTYPE_I32) { + PRERR("Expected %s (0x%02hhx) on stack, got 0x%02hhx\n", + name, expected, types_stack->type); + return -1; + } + + return 0; +} + +static int argcheck_generic(struct types **types_stack, char expected) +{ + struct types *top_type; + + if (argcheck_generic_noremove(*types_stack, expected)) + return -1; + + top_type = *types_stack; + *types_stack = top_type->prev; + free(top_type); + + return 0; +} + +static int _argcheck_i32(struct types **types_stack) +{ + return argcheck_generic(types_stack, VALTYPE_I32); +} + +static int _argcheck_i32_i32(struct types **types_stack) +{ + int i; + + for (i = 0; i < 2; i++) { + if (argcheck_generic(types_stack, VALTYPE_I32)) + return -1; + } + + return 0; +} + +static int _argcheck_custom(struct types **types_stack) +{ + return 0; /* Translation function will handle argument checks */ +} + +/** DEFINE RESULT TYPECHECK FUNCTIONS **/ + +static int _rescheck_empty(struct types **types_stack) +{ + return 0; +} + +static int rescheck_generic(struct types **types_stack, char returned) +{ + struct types *top; + + top = malloc(sizeof(struct types)); + + if (!top) { + PRERR(MSG_ALLOC_FAIL(sizeof(struct types))); + return -1; + } + + *top = (struct types) {.prev = *types_stack, .type = returned}; + *types_stack = top; + + return 0; +} + +static int _rescheck_i32(struct types **types_stack) +{ + return rescheck_generic(types_stack, VALTYPE_I32); +} + +static int _rescheck_custom(struct types **types_stack) +{ + return 0; +} + +/** DEFINE TYPECHECK FUNCTION POINTER ARRAY **/ + +/* Translate complex */ +#define TC(wasm_opcode, name, argtypes, restype) \ + [wasm_opcode] = {.argcheck = _argcheck_##argtypes, \ + .rescheck = _rescheck_##restype}, + +/* Translate Simple */ +#define TS(wasm_opcode, sm_instr, argtypes, restype) \ + TC(wasm_opcode, dummy, argtypes, restype) + +/* Translate load/store */ +#define TLS(wasm_opcode, sm_instr, argtypes, restype) \ + TC(wasm_opcode, dummy, argtypes, restype) + +struct typecheck { + int (*argcheck) (struct types **), (*rescheck) (struct types **); +}; + +/*static*/ struct typecheck typecheck_routines[256] = { +#include "translate_xmacro.h" +}; + +#undef TS +#undef TLS +#undef TC + +/** DEFINE CUSTOM TYPECHECK FUNCTIONS **/ + +static int typecheck_call(struct translation *data, struct function *callee) +{ + uint32_t i; + + i = callee->type->args.count; + + while (i--) { + if (argcheck_generic(&data->types_stack, + callee->type->args.types[i])) + return -1; + } + + for (i = 0; i < callee->type->results.count; i++) { + if (rescheck_generic(&data->types_stack, + callee->type->results.types[i])) + return -1; + } + + return 0; +} + +static int typecheck_local_get(struct translation *data, uint32_t localidx) +{ + uint32_t args_count = data->function->type->args.count; + char type = localidx < args_count ? + data->function->type->args.types[localidx] : + data->function->locals[localidx - args_count]; + + if (rescheck_generic(&data->types_stack, type)) + return -1; + + return 0; +} + +/** REST OF THE CODE **/ + +static int translate_instr(struct translation *data, uint8_t wasm_opcode) { + struct typecheck *tc_routines; + + if (!translation_routines[wasm_opcode]) { + PRERR("Unknown Wasm opcode: 0x%02x\n", wasm_opcode); + return -1; + } + + tc_routines = typecheck_routines + wasm_opcode; + + if (tc_routines->argcheck(&data->types_stack) || + tc_routines->rescheck(&data->types_stack) || + translation_routines[wasm_opcode](data)) + return -1; + + return 0; +} + +static int translate_expr(struct translation *data, struct resulttype *args, + struct resulttype *results) +{ + struct types **tmp, *types_stack_rest; + uint32_t i; int wasm_opcode; + tmp = &data->types_stack; + i = args ? args->count : 0; + + while (i--) { + if (argcheck_generic_noremove(*tmp, args->types[i])) + return -1; + + tmp = &(*tmp)->prev; + } + + types_stack_rest = *tmp; + *tmp = NULL; + while (1) { wasm_opcode = fgetc(data->handle); if (wasm_opcode == EOF) { PRERR(MSG_EOF); - return -1; + goto fail; } - if (wasm_opcode == WASM_END) { - return 0; - } + if (wasm_opcode == WASM_END) + break; - if (!translation_routines[wasm_opcode]) { - PRERR("Unknown Wasm opcode: 0x%02x\n", wasm_opcode); - return -1; - } + if (translate_instr(data, wasm_opcode)) + goto fail; + } - if (translation_routines[wasm_opcode](data)) - return -1; + tmp = &data->types_stack; + i = results ? results->count : 0; + + while (i--) { + if (argcheck_generic_noremove(*tmp, results->types[i])) + goto fail; + + tmp = &(*tmp)->prev; } + + if (*tmp) { + PRERR("Expression produces too many result values\n"); + goto fail; + } + + *tmp = types_stack_rest; + return 0; + +fail: + free_types_stack(data->types_stack); + data->types_stack = types_stack_rest; + + return -1; } int translate(FILE *handle, struct function *function, struct module *module) { struct instruction **expr = &function->translated_body; - uint32_t args_count = function->type->arguments_count; + uint32_t args_count = function->type->args.count; uint32_t locals_count = function->locals_count; uint32_t all_locals_count = args_count + locals_count; size_t i; struct translation data = {.handle = handle, .function = function, - .module = module}; + .module = module, + .types_stack = NULL}; if (locals_count + (uint64_t) args_count > STACK_TOP_ADDR * 4) { PRERR("Too many locals in a function\n"); @@ -186,11 +445,11 @@ int translate(FILE *handle, struct function *function, struct module *module) goto fail; /* actual function body */ - if (translate_expr(&data, function->type)) + if (translate_expr(&data, NULL, &function->type->results)) goto fail; /* function epilogue */ - if (function->type->result) { + if (function->type->results.count) { if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || i_swap ( expr) || i_store_p(im(4 * (2 + all_locals_count - 1)), expr) || @@ -215,7 +474,10 @@ int translate(FILE *handle, struct function *function, struct module *module) } - i = locals_count + args_count + 2 + (function->type->result ? 0 : 1); + i = locals_count + args_count + 2; + + if (!function->type->results.count) + i++; while (i--) { if (i_drop(expr)) |