diff options
Diffstat (limited to 'tools/translate.c')
-rw-r--r-- | tools/translate.c | 246 |
1 files changed, 231 insertions, 15 deletions
diff --git a/tools/translate.c b/tools/translate.c index b3d2afd..3a4496d 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -2,9 +2,15 @@ #include "wasm.h" #include "stack_machine_instruction.h" +struct target { + struct instruction *instr; + struct target *prev; +}; + struct types { struct types *prev; char type; /* should be one of VALTYPE_* constants from wasm.h */ + int refs; }; struct translation { @@ -14,7 +20,40 @@ struct translation { struct types *types_stack; }; -void free_types_stack(struct types *top) +struct end_markers { + int count; + const uint8_t *codes; +}; + +void free_targets(struct target *top) +{ + struct target *tmp; + + while (top) { + tmp = top->prev; + free(top); + top = tmp; + } +} + +inline static void get_type(struct types *type) +{ + if (type) + type->refs++; +} + +static void put_type(struct types *type) +{ + struct types *tmp; + + while (type && !--type->refs) { + tmp = type->prev; + free(type); + type = tmp; + } +} + +static void free_types_stack(struct types *top) { struct types *tmp; @@ -25,13 +64,163 @@ void free_types_stack(struct types *top) } } +static int translate_expr(struct translation *data, struct resulttype *args, + struct resulttype *results, + const struct end_markers *end_markers, + char *marker_found); + /* All functions, that go into one of function pointer arrays, start with _ */ -/** DEFINE TRANSLATION FUNCTIONS **/ +/** DEFINE INSTRUCTION TRANSLATION FUNCTIONS **/ /* Translate complex - those routines have to be defined manually */ #define TC(wasm_opcode, name, argtypes, restype) +static int parse_blocktype(FILE *handle, struct resulttype *args, + struct resulttype *results, char *storage, + struct module *module) +{ + int readval; + uint32_t typeidx; + + readval = fgetc(handle); + + if (readval == EOF) { + PRERR(MSG_EOF); + return -1; + } + + if (readval == 0x40) { + /* Blocktype is empty (no arguments, no result values) */ + *args = (struct resulttype) {.count = 0, .types = NULL}; + *results = *args; + return 0; + } + + /* + * A nonnegative array index encoded as signed number in LEB + * shall have 0 as the second (most significant) bit of the first byte. + * Otherwise, it can't be array index, but might be a simple value type. + */ + if (readval & (1 << 6)) { + if (!is_valid_valtype(readval)) + goto fail; + + *args = (struct resulttype) {.count = 0, .types = NULL}; + *storage = readval; + *results = (struct resulttype) {.count = 1, .types = storage}; + return 0; + } + + /* + * We know for sure it's a nonnegative number, we can just use leb_u32 + * decoding function (encoding as signed or unsigned is the same in this + * particular case). + */ + ungetc(readval, handle); + + if (leb_u32(handle, &typeidx)) { + PRERR(MSG_BAD_NUM); + goto fail; + } + + if (typeidx <= module->functypes_count) { + PRERR(MSG_BAD_IDX("type index")); + goto fail; + } + + *args = module->functypes[typeidx].args; + *results = module->functypes[typeidx].results; + return 0; + +fail: + PRERR("Couldn't parse blocktype\n"); + return -1; +} + +static struct target *add_target(struct module *module) +{ + struct target *tgt; + + tgt = malloc(sizeof(struct target)); + + if (!tgt) { + PRERR(MSG_ALLOC_FAIL(sizeof(struct target))); + return NULL; + } + + tgt->instr = NULL; + tgt->prev = module->targets; + module->targets = tgt; + return tgt; +} + +static int _translate_if(struct translation *data) +{ + struct types *backed_stack; + struct resulttype block_args, block_results; + char type_storage; + struct target *if_end, *else_end; + struct instruction **expr = &data->function->translated_body; + static const uint8_t if_end_markers_codes[2] = {WASM_ELSE, WASM_END}; + static const struct end_markers if_end_markers = { + .count = 2, + .codes = if_end_markers_codes + }; + static const struct end_markers else_end_markers = { + .count = 1, + .codes = if_end_markers_codes + 1 + }; + char marker_found; + int retval; + + if (parse_blocktype(data->handle, &block_args, &block_results, + &type_storage, data->module)) + goto fail; + + if_end = add_target(data->module); + else_end = add_target(data->module); + + if (!if_end || !else_end) + goto fail; + + if (i_cond_jump_n(ptr_after(&if_end->instr), expr)) + goto fail; + + backed_stack = data->types_stack; + get_type(backed_stack); + + retval = translate_expr(data, &block_args, &block_results, + &if_end_markers, &marker_found); + + put_type(data->types_stack); + data->types_stack = backed_stack; + + if (retval) + goto fail; + + if (i_jump(ptr_after(&else_end->instr), expr)) + goto fail; + + if_end->instr = data->function->translated_body->prev; + + if (marker_found == WASM_END) + ungetc(WASM_END, data->handle); + + if (translate_expr(data, &block_args, &block_results, + &else_end_markers, NULL)) + goto fail; + + else_end->instr = data->function->translated_body->prev; + + return 0; + +fail: + PRERR("Couldn't translate if-else instruction\n"); + + return -1; +} + static int typecheck_call(struct translation *data, struct function *callee); static int _translate_call(struct translation *data) @@ -98,9 +287,9 @@ static int _translate_local_get(struct translation *data) static int _translate_const(struct translation *data) { - uint32_t constant; + int32_t constant; - if (leb_u32(data->handle, &constant)) { + if (leb_s32(data->handle, &constant)) { PRERR(MSG_BAD_NUM); return -1; } @@ -209,7 +398,11 @@ static int argcheck_generic(struct types **types_stack, char expected) top_type = *types_stack; *types_stack = top_type->prev; - free(top_type); + + if (*types_stack) + get_type(*types_stack); + + put_type(top_type); return 0; } @@ -254,7 +447,7 @@ static int rescheck_generic(struct types **types_stack, char returned) return -1; } - *top = (struct types) {.prev = *types_stack, .type = returned}; + *top = (struct types) {.prev = *types_stack, .type = returned, .refs = 1}; *types_stack = top; return 0; @@ -289,7 +482,7 @@ struct typecheck { int (*argcheck) (struct types **), (*rescheck) (struct types **); }; -/*static*/ struct typecheck typecheck_routines[256] = { +static struct typecheck typecheck_routines[256] = { #include "translate_xmacro.h" }; @@ -355,7 +548,9 @@ static int translate_instr(struct translation *data, uint8_t wasm_opcode) } static int translate_expr(struct translation *data, struct resulttype *args, - struct resulttype *results) + struct resulttype *results, + const struct end_markers *end_markers, + char *marker_found) { struct types **tmp, *types_stack_rest; uint32_t i; @@ -382,13 +577,23 @@ static int translate_expr(struct translation *data, struct resulttype *args, goto fail; } - if (wasm_opcode == WASM_END) - break; + i = end_markers->count; + + while (i--) { + if (wasm_opcode == end_markers->codes[i]) { + if (marker_found) + *marker_found = wasm_opcode; + + goto block_end; + } + } if (translate_instr(data, wasm_opcode)) goto fail; } +block_end: + tmp = &data->types_stack; i = results ? results->count : 0; @@ -408,7 +613,7 @@ static int translate_expr(struct translation *data, struct resulttype *args, return 0; fail: - free_types_stack(data->types_stack); + put_type(data->types_stack); data->types_stack = types_stack_rest; return -1; @@ -421,10 +626,16 @@ int translate(FILE *handle, struct function *function, struct module *module) uint32_t locals_count = function->locals_count; uint32_t all_locals_count = args_count + locals_count; size_t i; + static const uint8_t function_end_marker_code = WASM_END; + static const struct end_markers function_end_markers = { + .count = 1, + .codes = &function_end_marker_code + }; struct translation data = {.handle = handle, .function = function, .module = module, .types_stack = NULL}; + int retval = -1; if (locals_count + (uint64_t) args_count > STACK_TOP_ADDR * 4) { PRERR("Too many locals in a function\n"); @@ -445,7 +656,8 @@ int translate(FILE *handle, struct function *function, struct module *module) goto fail; /* actual function body */ - if (translate_expr(&data, NULL, &function->type->results)) + if (translate_expr(&data, NULL, &function->type->results, + &function_end_markers, NULL)) goto fail; /* function epilogue */ @@ -471,7 +683,6 @@ int translate(FILE *handle, struct function *function, struct module *module) i_load_p (im(0), expr) || i_store (im(STACK_FRAME_BACKUP_ADDR), expr)) goto fail; - } i = locals_count + args_count + 2; @@ -487,13 +698,18 @@ int translate(FILE *handle, struct function *function, struct module *module) if (i_ret(expr)) goto fail; - return 0; + retval = 0; fail: + free_types_stack(data.types_stack); + + if (!retval) + return retval; + PRERR("Couldn't translate function to stack machine\n"); free_expr(*expr); function->translated_body = NULL; - return -1; + return retval; } |