From 155e9b30b135a99b42e0f42e9062c266f527df4b Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Mon, 21 Sep 2020 17:47:22 +0200 Subject: use function pointer array in Wasm opcode translation --- tools/parse_module.c | 1 + tools/translate.c | 358 ++++++++++++++++++++++++----------------------- tools/translate_xmacro.h | 19 +++ tools/wasm.h | 23 +++ 4 files changed, 225 insertions(+), 176 deletions(-) create mode 100644 tools/translate_xmacro.h (limited to 'tools') diff --git a/tools/parse_module.c b/tools/parse_module.c index c9a5b12..7c54144 100644 --- a/tools/parse_module.c +++ b/tools/parse_module.c @@ -273,6 +273,7 @@ int parse_function_section(FILE *handle, struct module *module) } funcs[i].type = module->functypes + i; + funcs[i].translated_body = NULL; } module->functions_count = funcs_count; diff --git a/tools/translate.c b/tools/translate.c index bf13bd1..97d48f7 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -1,39 +1,171 @@ #include "wasm_compile.h" +#include "wasm.h" #include "stack_machine_instruction.h" -/* WebAssembly opcodes */ -#define WASM_END 0x0B -#define WASM_CALL 0x10 +struct translation { + FILE *handle; + struct function *function; + struct module *module; +}; -#define WASM_LOCAL_GET 0x20 +/* All functions, that go into function pointer array, start with _ */ -#define WASM_I32_LOAD 0x28 -#define WASM_I32_LOAD8_S 0x2C -#define WASM_I32_LOAD8_U 0x2D -#define WASM_I32_LOAD16_S 0x2E -#define WASM_I32_LOAD16_U 0x2F -#define WASM_I32_STORE 0x36 -#define WASM_I32_STORE8 0x3A -#define WASM_I32_STORE16 0x3B -#define WASM_I64_STORE32 0x3E +/* Translate complex - those routines have to be defined manually */ +#define TC(wasm_opcode, name) -#define WASM_I32_CONST 0x41 +static int _translate_call(struct translation *data) +{ + uint32_t funcidx; + struct instruction **target; + + if (leb_u32(data->handle, &funcidx)) { + PRERR(MSG_BAD_NUM); + return -1; + } + + if (funcidx >= data->module->functions_count) { + PRERR(MSG_BAD_IDX("funcidx")); + return -1; + } + + target = &data->module->functions[funcidx].translated_body; + + return i_call(ptr(target), &data->function->translated_body); +} + +static int _translate_local_get(struct translation *data) +{ + uint32_t localidx; + uint32_t args_count = data->function->type->arguments_count; + uint32_t locals_count = data->function->locals_count; + uint32_t all_locals_count = args_count + locals_count; + uint64_t offset_on_frame; + struct instruction **expr = &data->function->translated_body; + + if (leb_u32(data->handle, &localidx)) { + PRERR(MSG_BAD_NUM); + return -1; + } + + if (localidx >= all_locals_count) { + PRERR(MSG_BAD_IDX("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); +} + +static int _translate_const(struct translation *data) +{ + uint32_t constant; + + if (leb_u32(data->handle, &constant)) { + PRERR(MSG_BAD_NUM); + return -1; + } + + return i_const(im(constant), &data->function->translated_body); +} + +/* Translate Simple */ +#define TS(wasm_opcode, sm_instr) \ + static int _translate_##sm_instr(struct translation *data) \ + { \ + return i_##sm_instr(&data->function->translated_body); \ + } + +/* Translate load/store */ +static int translate_load_store(struct translation *data, + int (*instr_routine) (struct instruction_data, + struct instruction **)) +{ + uint32_t align, offset; + + if (leb_u32(data->handle, &align) || + leb_u32(data->handle, &offset)) { + PRERR(MSG_BAD_NUM); + return -1; + } + + offset += MEMORY_BOTTOM_ADDR; + + return instr_routine(im(offset), &data->function->translated_body); +} + +#define TLS(wasm_opcode, sm_instr) \ + static int _translate_##sm_instr(struct translation *data) \ + { \ + return translate_load_store(data, i_##sm_instr); \ + } + +/* This inclusion defines functions using macros above */ +#include "translate_xmacro.h" -#define WASM_I32_ADD 0x6A -#define WASM_I32_SUB 0x6B -#define WASM_I32_MUL 0x6C -#define WASM_I32_DIV_U 0x6E +#undef TS +#undef TLS +#undef TC +/* Translate complex */ +#define TC(wasm_opcode, name) [wasm_opcode] = _translate_##name, + +/* Translate Simple */ +#define TS(wasm_opcode, sm_instr) TC(wasm_opcode, sm_instr) + +/* Translate load/store */ +#define TLS(wasm_opcode, sm_instr) TC(wasm_opcode, sm_instr) + +/* The actual array of function pointers is defined here */ +static int (*translation_routines[256]) (struct translation *) = { +#include "translate_xmacro.h" +}; + +#undef TS +#undef TLS +#undef TC + +static int translate_expr(struct translation *data, struct functype *exprtype) +{ + int wasm_opcode; + + while (1) { + wasm_opcode = fgetc(data->handle); + + if (wasm_opcode == EOF) { + PRERR(MSG_EOF); + return -1; + } + + if (wasm_opcode == WASM_END) { + return 0; + } + + if (!translation_routines[wasm_opcode]) { + PRERR("Unknown Wasm opcode: 0x%02x\n", wasm_opcode); + return -1; + } + + if (translation_routines[wasm_opcode](data)) + return -1; + } +} int translate(FILE *handle, struct function *function, struct module *module) { - struct instruction *expr = NULL; + struct instruction **expr = &function->translated_body; uint32_t args_count = function->type->arguments_count; uint32_t locals_count = function->locals_count; uint32_t all_locals_count = args_count + locals_count; size_t i; - int wasm_opcode; - int matched; + struct translation data = {.handle = handle, + .function = function, + .module = module}; if (locals_count + (uint64_t) args_count > STACK_TOP_ADDR * 4) { PRERR("Too many locals in a function\n"); @@ -41,169 +173,44 @@ int translate(FILE *handle, struct function *function, struct module *module) } for (i = locals_count + 3; i; i--) { - if (i_const(im(0), &expr)) + if (i_const(im(0), expr)) goto fail; } /* function prologue */ - if (i_get_frame( &expr) || - i_tee ( &expr) || - i_load (im(STACK_FRAME_BACKUP_ADDR), &expr) || - i_store_p (im(0x0), &expr) || - i_store (im(STACK_FRAME_BACKUP_ADDR), &expr)) + if (i_get_frame( expr) || + i_tee ( expr) || + i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || + i_store_p (im(0x0), expr) || + i_store (im(STACK_FRAME_BACKUP_ADDR), expr)) goto fail; /* actual function body */ - i = 0; - while (1) { - matched = 0; - - wasm_opcode = fgetc(handle); - - if (wasm_opcode == EOF) { - PRERR(MSG_EOF); - goto fail; - } - - // TODO: make a function for each instruction type, - // call them through some table... - if (wasm_opcode == WASM_I32_ADD) { - if (i_add(&expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode == WASM_I32_SUB) { - if (i_sub(&expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode == WASM_I32_MUL) { - if (i_mul(&expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode == WASM_I32_DIV_U) { - if (i_div(&expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode == WASM_CALL) { - uint32_t funcidx; - struct instruction **target; - - if (leb_u32(handle, &funcidx)) { - PRERR(MSG_BAD_NUM); - goto fail; - } - - if (funcidx >= module->functions_count) { - PRERR(MSG_BAD_IDX("funcidx")); - goto fail; - } - - target = &module->functions[funcidx].translated_body; - - if (i_call(ptr(target), &expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode <= WASM_I64_STORE32 && - wasm_opcode >= WASM_I32_LOAD) { - uint32_t align, offset; - - if (leb_u32(handle, &align) || - leb_u32(handle, &offset)) { - PRERR(MSG_BAD_NUM); - goto fail; - } - - offset += MEMORY_BOTTOM_ADDR; - - // TODO: rewrite it some cleaner way -#define TRY(opcode, instr) \ - if (wasm_opcode == opcode) { \ - matched = 1; \ - \ - if (i_##instr(im(offset), &expr)) \ - goto fail; \ - } - - TRY(WASM_I32_LOAD, load_p); - TRY(WASM_I32_LOAD8_S, loadbsx_p); - TRY(WASM_I32_LOAD8_U, loadbzx_p); - TRY(WASM_I32_LOAD16_S, loadwsx_p); - TRY(WASM_I32_LOAD16_U, loadwzx_p); - TRY(WASM_I32_STORE, store_p); - TRY(WASM_I32_STORE8, storeb_p); - TRY(WASM_I32_STORE16, storew_p); - } else if (wasm_opcode == WASM_LOCAL_GET) { - uint32_t localidx; - uint64_t offset_on_frame; - - if (leb_u32(handle, &localidx)) { - PRERR(MSG_BAD_NUM); - goto fail; - } - - if (localidx >= all_locals_count) { - PRERR(MSG_BAD_IDX("localidx")); - goto fail; - } - - offset_on_frame = all_locals_count - localidx + 1; - - if (localidx >= args_count) - offset_on_frame -= 1; - - if (i_load (im(STACK_FRAME_BACKUP_ADDR), &expr) || - i_load_p(im(4 * offset_on_frame), &expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode == WASM_I32_CONST) { - uint32_t constant; - - if (leb_u32(handle, &constant)) { - PRERR(MSG_BAD_NUM); - goto fail; - } - - if (i_const(im(constant), &expr)) - goto fail; - - matched = 1; - } else if (wasm_opcode == WASM_END) { - break; - } - - if (!matched) { - PRERR("Unknown Wasm opcode: %02x\n", wasm_opcode); - goto fail; - } - } + if (translate_expr(&data, function->type)) + goto fail; /* function epilogue */ if (function->type->result) { - if (i_load (im(STACK_FRAME_BACKUP_ADDR), &expr) || - i_swap ( &expr) || - i_store_p(im(4 * (2 + all_locals_count - 1)), &expr) || - i_load (im(STACK_FRAME_BACKUP_ADDR), &expr) || - i_tee ( &expr) || - i_tee ( &expr) || - i_load_p (im(4 * (1 + locals_count)), &expr) || - i_store_p(im(4 * (2 + all_locals_count - 2)), &expr) || - i_load_p (im(0), &expr) || - i_store (im(STACK_FRAME_BACKUP_ADDR), &expr)) + if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || + i_swap ( expr) || + i_store_p(im(4 * (2 + all_locals_count - 1)), expr) || + i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || + i_tee ( expr) || + i_tee ( expr) || + i_load_p (im(4 * (1 + locals_count)), expr) || + i_store_p(im(4 * (2 + all_locals_count - 2)), expr) || + i_load_p (im(0), expr) || + i_store (im(STACK_FRAME_BACKUP_ADDR), expr)) goto fail; } else { /* It's a bit shorter if we don't return anything */ - if (i_load (im(STACK_FRAME_BACKUP_ADDR), &expr) || - i_tee ( &expr) || - i_tee ( &expr) || - i_load_p (im(4 * (1 + locals_count)), &expr) || - i_store_p(im(4 * (2 + all_locals_count - 1)), &expr) || - i_load_p (im(0), &expr) || - i_store (im(STACK_FRAME_BACKUP_ADDR), &expr)) + if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || + i_tee ( expr) || + i_tee ( expr) || + i_load_p (im(4 * (1 + locals_count)), expr) || + i_store_p(im(4 * (2 + all_locals_count - 1)), expr) || + i_load_p (im(0), expr) || + i_store (im(STACK_FRAME_BACKUP_ADDR), expr)) goto fail; } @@ -211,21 +218,20 @@ int translate(FILE *handle, struct function *function, struct module *module) i = locals_count + args_count + 2 + (function->type->result ? 0 : 1); while (i--) { - if (i_drop(&expr)) + if (i_drop(expr)) goto fail; } - if (i_ret(&expr)) + if (i_ret(expr)) goto fail; - function->translated_body = expr; - return 0; fail: PRERR("Couldn't translate function to stack machine\n"); - free_expr(expr); + free_expr(*expr); + function->translated_body = NULL; return -1; } diff --git a/tools/translate_xmacro.h b/tools/translate_xmacro.h new file mode 100644 index 0000000..2fc4558 --- /dev/null +++ b/tools/translate_xmacro.h @@ -0,0 +1,19 @@ +/* X-macro-like definition of translation routines for each webasm opcode */ + +TS(WASM_I32_ADD, add) +TS(WASM_I32_SUB, sub) +TS(WASM_I32_DIV_U, div) +TS(WASM_I32_MUL, mul) + +TLS(WASM_I32_LOAD, load_p) +TLS(WASM_I32_LOAD8_S, loadbsx_p) +TLS(WASM_I32_LOAD8_U, loadbzx_p) +TLS(WASM_I32_LOAD16_S, loadwsx_p) +TLS(WASM_I32_LOAD16_U, loadwzx_p) +TLS(WASM_I32_STORE, store_p) +TLS(WASM_I32_STORE8, storeb_p) +TLS(WASM_I32_STORE16, storew_p) + +TC(WASM_CALL, call) +TC(WASM_LOCAL_GET, local_get) +TC(WASM_I32_CONST, const) diff --git a/tools/wasm.h b/tools/wasm.h index fc6a910..07252fc 100644 --- a/tools/wasm.h +++ b/tools/wasm.h @@ -20,3 +20,26 @@ #define EXPORT_TABLEIDX 0x01 #define EXPORT_MEMIDX 0x02 #define EXPORT_GLOBALIDX 0x03 + +/* WebAssembly opcodes */ +#define WASM_END 0x0B +#define WASM_CALL 0x10 + +#define WASM_LOCAL_GET 0x20 + +#define WASM_I32_LOAD 0x28 +#define WASM_I32_LOAD8_S 0x2C +#define WASM_I32_LOAD8_U 0x2D +#define WASM_I32_LOAD16_S 0x2E +#define WASM_I32_LOAD16_U 0x2F +#define WASM_I32_STORE 0x36 +#define WASM_I32_STORE8 0x3A +#define WASM_I32_STORE16 0x3B +#define WASM_I64_STORE32 0x3E + +#define WASM_I32_CONST 0x41 + +#define WASM_I32_ADD 0x6A +#define WASM_I32_SUB 0x6B +#define WASM_I32_MUL 0x6C +#define WASM_I32_DIV_U 0x6E -- cgit v1.2.3