aboutsummaryrefslogtreecommitdiff
path: root/tools/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/translate.c')
-rw-r--r--tools/translate.c318
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))