aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorWojciech Kosior <kwojtus@protonmail.com>2020-09-21 17:47:22 +0200
committerWojciech Kosior <kwojtus@protonmail.com>2020-09-21 17:47:22 +0200
commit155e9b30b135a99b42e0f42e9062c266f527df4b (patch)
tree1189f07c4e7eef8e97dff1cd94e0dd46df5a70db /tools
parentc75dcab5988f5c0b5e0629015f384e5aa1440690 (diff)
downloadAGH-engineering-thesis-155e9b30b135a99b42e0f42e9062c266f527df4b.tar.gz
AGH-engineering-thesis-155e9b30b135a99b42e0f42e9062c266f527df4b.zip
use function pointer array in Wasm opcode translation
Diffstat (limited to 'tools')
-rw-r--r--tools/parse_module.c1
-rw-r--r--tools/translate.c358
-rw-r--r--tools/translate_xmacro.h19
-rw-r--r--tools/wasm.h23
4 files changed, 225 insertions, 176 deletions
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