diff options
Diffstat (limited to 'src/wasm-binary-reader-interpreter.c')
-rw-r--r-- | src/wasm-binary-reader-interpreter.c | 559 |
1 files changed, 420 insertions, 139 deletions
diff --git a/src/wasm-binary-reader-interpreter.c b/src/wasm-binary-reader-interpreter.c index 57d2fa23..62ac3ee1 100644 --- a/src/wasm-binary-reader-interpreter.c +++ b/src/wasm-binary-reader-interpreter.c @@ -17,6 +17,7 @@ #include "wasm-binary-reader-interpreter.h" #include <assert.h> +#include <inttypes.h> #include <stdarg.h> #include <stdio.h> @@ -51,7 +52,7 @@ #define CHECK_LOCAL(ctx, local_index) \ do { \ uint32_t max_local_index = \ - (ctx)->current_func->param_and_local_types.size; \ + (ctx)->current_func->defined.param_and_local_types.size; \ if ((local_index) >= max_local_index) { \ print_error((ctx), "invalid local_index: %d (max %d)", (local_index), \ max_local_index); \ @@ -61,7 +62,7 @@ #define CHECK_GLOBAL(ctx, global_index) \ do { \ - uint32_t max_global_index = (ctx)->module->globals.size; \ + uint32_t max_global_index = (ctx)->global_index_mapping.size; \ if ((global_index) >= max_global_index) { \ print_error((ctx), "invalid global_index: %d (max %d)", (global_index), \ max_global_index); \ @@ -110,6 +111,7 @@ typedef struct Context { WasmBinaryReader* reader; WasmBinaryErrorHandler* error_handler; WasmAllocator* memory_allocator; + WasmInterpreterEnvironment* env; WasmInterpreterModule* module; WasmInterpreterFunc* current_func; WasmTypeVector type_stack; @@ -119,9 +121,20 @@ typedef struct Context { uint32_t depth; WasmMemoryWriter istream_writer; uint32_t istream_offset; + /* mappings from module index space to env index space; this won't just be a + * translation, because imported values will be resolved as well */ + Uint32Vector sig_index_mapping; + Uint32Vector func_index_mapping; + Uint32Vector global_index_mapping; + + uint32_t num_func_imports; + + /* values cached in the Context so they can be shared between callbacks */ WasmInterpreterTypedValue init_expr_value; uint32_t table_offset; - uint32_t num_func_imports; + WasmBool is_host_import; + WasmInterpreterModule* host_import_module; + uint32_t import_index; } Context; static Label* get_label(Context* ctx, uint32_t depth) { @@ -140,50 +153,91 @@ static void handle_error(uint32_t offset, const char* message, Context* ctx) { } } -static void print_error(Context* ctx, const char* format, ...) { +static void WASM_PRINTF_FORMAT(2, 3) + print_error(Context* ctx, const char* format, ...) { WASM_SNPRINTF_ALLOCA(buffer, length, format); handle_error(WASM_INVALID_OFFSET, buffer, ctx); } -static WasmInterpreterFunc* get_func(Context* ctx, uint32_t func_index) { - assert(func_index < ctx->module->funcs.size); - return &ctx->module->funcs.data[func_index]; +static uint32_t translate_sig_index_to_env(Context* ctx, uint32_t sig_index) { + assert(sig_index < ctx->sig_index_mapping.size); + return ctx->sig_index_mapping.data[sig_index]; +} + +static WasmInterpreterFuncSignature* get_signature_by_env_index( + Context* ctx, + uint32_t sig_index) { + assert(sig_index < ctx->env->sigs.size); + return &ctx->env->sigs.data[sig_index]; +} + +static WasmInterpreterFuncSignature* get_signature_by_module_index( + Context* ctx, + uint32_t sig_index) { + return get_signature_by_env_index(ctx, + translate_sig_index_to_env(ctx, sig_index)); +} + +static uint32_t translate_func_index_to_env(Context* ctx, uint32_t func_index) { + assert(func_index < ctx->func_index_mapping.size); + return ctx->func_index_mapping.data[func_index]; } -static WasmInterpreterFunc* get_defined_func(Context* ctx, - uint32_t func_index) { +static uint32_t translate_defined_func_index_to_env(Context* ctx, + uint32_t func_index) { /* all function imports are first, so skip over those */ func_index += ctx->num_func_imports; - assert(func_index < ctx->module->funcs.size); - return &ctx->module->funcs.data[func_index]; + assert(func_index < ctx->func_index_mapping.size); + return ctx->func_index_mapping.data[func_index]; } -static WasmInterpreterFuncSignature* get_signature(Context* ctx, - uint32_t sig_index) { - assert(sig_index < ctx->module->sigs.size); - return &ctx->module->sigs.data[sig_index]; +static WasmInterpreterFunc* get_func_by_env_index(Context* ctx, + uint32_t func_index) { + assert(func_index < ctx->env->funcs.size); + return &ctx->env->funcs.data[func_index]; } -static WasmInterpreterFuncSignature* get_func_signature( - Context* ctx, - WasmInterpreterFunc* func) { - return get_signature(ctx, func->sig_index); +static WasmInterpreterFunc* get_func_by_module_index(Context* ctx, + uint32_t func_index) { + return get_func_by_env_index(ctx, + translate_func_index_to_env(ctx, func_index)); } -static WasmType get_local_type_by_index(WasmInterpreterFunc* func, - uint32_t local_index) { - assert(local_index < func->param_and_local_types.size); - return func->param_and_local_types.data[local_index]; +static WasmInterpreterFunc* get_func_by_defined_index(Context* ctx, + uint32_t func_index) { + return get_func_by_env_index( + ctx, translate_defined_func_index_to_env(ctx, func_index)); +} + +static uint32_t translate_global_index_to_env(Context* ctx, + uint32_t global_index) { + assert(global_index < ctx->global_index_mapping.size); + return ctx->global_index_mapping.data[global_index]; +} + +static WasmInterpreterGlobal* get_global_by_env_index(Context* ctx, + uint32_t global_index) { + assert(global_index < ctx->env->globals.size); + return &ctx->env->globals.data[global_index]; +} + +static WasmInterpreterGlobal* get_global_by_module_index( + Context* ctx, + uint32_t global_index) { + return get_global_by_env_index( + ctx, translate_global_index_to_env(ctx, global_index)); } -static WasmInterpreterGlobal* get_global_by_index(Context* ctx, - uint32_t global_index) { - assert(global_index < ctx->module->globals.size); - return &ctx->module->globals.data[global_index]; +static WasmType get_global_type_by_module_index(Context* ctx, + uint32_t global_index) { + return get_global_by_module_index(ctx, global_index)->typed_value.type; } -static WasmType get_global_type_by_index(Context* ctx, uint32_t global_index) { - return get_global_by_index(ctx, global_index)->typed_value.type; +static WasmType get_local_type_by_index(WasmInterpreterFunc* func, + uint32_t local_index) { + assert(!func->is_host); + assert(local_index < func->defined.param_and_local_types.size); + return func->defined.param_and_local_types.data[local_index]; } static uint32_t translate_local_index(Context* ctx, uint32_t local_index) { @@ -314,9 +368,9 @@ static WasmResult fixup_top_label(Context* ctx, uint32_t offset) { static WasmResult emit_func_offset(Context* ctx, WasmInterpreterFunc* func, uint32_t func_index) { - if (func->offset == WASM_INVALID_OFFSET) + if (func->defined.offset == WASM_INVALID_OFFSET) CHECK_RESULT(append_fixup(ctx, &ctx->func_fixups, func_index)); - CHECK_RESULT(emit_i32(ctx, func->offset)); + CHECK_RESULT(emit_i32(ctx, func->defined.offset)); return WASM_OK; } @@ -326,8 +380,12 @@ static void on_error(WasmBinaryReaderContext* ctx, const char* message) { static WasmResult on_signature_count(uint32_t count, void* user_data) { Context* ctx = user_data; - wasm_new_interpreter_func_signature_array(ctx->allocator, &ctx->module->sigs, - count); + wasm_resize_uint32_vector(ctx->allocator, &ctx->sig_index_mapping, count); + uint32_t i; + for (i = 0; i < count; ++i) + ctx->sig_index_mapping.data[i] = ctx->env->sigs.size + i; + wasm_resize_interpreter_func_signature_vector(ctx->allocator, &ctx->env->sigs, + ctx->env->sigs.size + count); return WASM_OK; } @@ -338,7 +396,7 @@ static WasmResult on_signature(uint32_t index, WasmType* result_types, void* user_data) { Context* ctx = user_data; - WasmInterpreterFuncSignature* sig = get_signature(ctx, index); + WasmInterpreterFuncSignature* sig = get_signature_by_module_index(ctx, index); wasm_reserve_types(ctx->allocator, &sig->param_types, param_count); sig->param_types.size = param_count; @@ -352,8 +410,8 @@ static WasmResult on_signature(uint32_t index, static WasmResult on_import_count(uint32_t count, void* user_data) { Context* ctx = user_data; - wasm_new_interpreter_import_array(ctx->allocator, &ctx->module->imports, - count); + wasm_new_interpreter_import_array(ctx->allocator, + &ctx->module->defined.imports, count); return WASM_OK; } @@ -362,63 +420,240 @@ static WasmResult on_import(uint32_t index, WasmStringSlice field_name, void* user_data) { Context* ctx = user_data; - assert(index < ctx->module->imports.size); - WasmInterpreterImport* import = &ctx->module->imports.data[index]; + assert(index < ctx->module->defined.imports.size); + WasmInterpreterImport* import = &ctx->module->defined.imports.data[index]; import->module_name = wasm_dup_string_slice(ctx->allocator, module_name); import->field_name = wasm_dup_string_slice(ctx->allocator, field_name); + int module_index = wasm_find_binding_index_by_name(&ctx->env->module_bindings, + &import->module_name); + if (module_index < 0) { + print_error(ctx, "unknown import module \"" PRIstringslice "\"", + WASM_PRINTF_STRING_SLICE_ARG(import->module_name)); + return WASM_ERROR; + } + + assert((size_t)module_index < ctx->env->modules.size); + WasmInterpreterModule* module = &ctx->env->modules.data[module_index]; + if (module->is_host) { + /* We don't yet know the kind of a host import module, so just assume it + * exists for now. We'll fail later (in on_import_* below) if it doesn't + * exist). */ + ctx->is_host_import = WASM_TRUE; + ctx->host_import_module = module; + } else { + WasmInterpreterExport* export = + wasm_get_interpreter_export_by_name(module, &import->field_name); + if (!export) { + print_error(ctx, "unknown module field \"" PRIstringslice "\"", + WASM_PRINTF_STRING_SLICE_ARG(import->field_name)); + return WASM_ERROR; + } + + import->kind = export->kind; + ctx->is_host_import = WASM_FALSE; + ctx->import_index = export->index; + } + return WASM_OK; +} + +static WasmResult check_import_kind(Context* ctx, + WasmInterpreterImport* import, + WasmExternalKind expected_kind) { + if (import->kind != expected_kind) { + print_error(ctx, "expected import \"" PRIstringslice "." PRIstringslice + "\" to have kind %s, not %s", + WASM_PRINTF_STRING_SLICE_ARG(import->module_name), + WASM_PRINTF_STRING_SLICE_ARG(import->field_name), + wasm_get_kind_name(expected_kind), + wasm_get_kind_name(import->kind)); + return WASM_ERROR; + } return WASM_OK; } +static void append_export(Context* ctx, + WasmInterpreterModule* module, + WasmExternalKind kind, + uint32_t item_index, + WasmStringSlice name) { + WasmInterpreterExport* export = + wasm_append_interpreter_export(ctx->allocator, &module->exports); + export->name = wasm_dup_string_slice(ctx->allocator, name); + export->kind = kind; + export->index = item_index; + + WasmBinding* binding = wasm_insert_binding( + ctx->allocator, &module->export_bindings, &export->name); + binding->index = module->exports.size - 1; +} + static WasmResult on_import_func(uint32_t index, uint32_t sig_index, void* user_data) { Context* ctx = user_data; - assert(index < ctx->module->imports.size); - WasmInterpreterImport* import = &ctx->module->imports.data[index]; - assert(sig_index < ctx->module->sigs.size); - import->kind = WASM_EXTERNAL_KIND_FUNC; - import->func.sig_index = sig_index; - - WasmInterpreterFunc* func = - wasm_append_interpreter_func(ctx->allocator, &ctx->module->funcs); - func->sig_index = sig_index; - func->offset = WASM_INVALID_OFFSET; - func->is_host = WASM_TRUE; - func->import_index = index; - + assert(index < ctx->module->defined.imports.size); + WasmInterpreterImport* import = &ctx->module->defined.imports.data[index]; + assert(sig_index < ctx->env->sigs.size); + import->func.sig_index = translate_sig_index_to_env(ctx, sig_index); + + uint32_t func_index; + if (ctx->is_host_import) { + WasmInterpreterFunc* func = + wasm_append_interpreter_func(ctx->allocator, &ctx->env->funcs); + func->is_host = WASM_TRUE; + func->sig_index = import->func.sig_index; + func->host.module_name = import->module_name; + func->host.field_name = import->field_name; + + WasmInterpreterHostImportDelegate* host_delegate = + &ctx->host_import_module->host.import_delegate; + WasmInterpreterFuncSignature* sig = &ctx->env->sigs.data[func->sig_index]; + CHECK_RESULT(host_delegate->import_func(import, func, sig, + host_delegate->user_data)); + assert(func->host.callback); + + func_index = ctx->env->funcs.size - 1; + append_export(ctx, ctx->host_import_module, WASM_EXTERNAL_KIND_FUNC, + func_index, import->field_name); + } else { + CHECK_RESULT(check_import_kind(ctx, import, WASM_EXTERNAL_KIND_FUNC)); + // TODO: check signature matches + func_index = ctx->import_index; + } + wasm_append_uint32_value(ctx->allocator, &ctx->func_index_mapping, + &func_index); ctx->num_func_imports++; return WASM_OK; } -/* TODO(binji): implement import_table, import_memory, import_global */ static WasmResult on_import_table(uint32_t index, uint32_t elem_type, const WasmLimits* elem_limits, void* user_data) { - /* TODO */ - return WASM_ERROR; + Context* ctx = user_data; + if (ctx->module->table_index != WASM_INVALID_INDEX) { + print_error(ctx, "only one table allowed"); + return WASM_ERROR; + } + + assert(index < ctx->module->defined.imports.size); + WasmInterpreterImport* import = &ctx->module->defined.imports.data[index]; + if (ctx->is_host_import) { + WasmInterpreterTable* table = + wasm_append_interpreter_table(ctx->allocator, &ctx->env->tables); + table->limits = *elem_limits; + wasm_new_uint32_array(ctx->allocator, &table->func_indexes, + table->limits.initial); + + WasmInterpreterHostImportDelegate* host_delegate = + &ctx->host_import_module->host.import_delegate; + CHECK_RESULT( + host_delegate->import_table(import, table, host_delegate->user_data)); + + uint32_t table_index = ctx->env->tables.size - 1; + append_export(ctx, ctx->host_import_module, WASM_EXTERNAL_KIND_TABLE, + table_index, import->field_name); + } else { + CHECK_RESULT(check_import_kind(ctx, import, WASM_EXTERNAL_KIND_TABLE)); + // TODO: check limits + import->table.limits = *elem_limits; + ctx->module->table_index = ctx->import_index; + } + return WASM_OK; +} + +static WasmInterpreterMemory* append_memory(Context* ctx, + const WasmLimits* page_limits) { + WasmInterpreterMemory* memory = + wasm_append_interpreter_memory(ctx->allocator, &ctx->env->memories); + memory->allocator = ctx->memory_allocator; + memory->page_size = page_limits->initial; + memory->byte_size = page_limits->initial * WASM_PAGE_SIZE; + memory->max_page_size = + page_limits->has_max ? page_limits->max : WASM_MAX_PAGES; + memory->data = wasm_alloc_zero(ctx->memory_allocator, memory->byte_size, + WASM_DEFAULT_ALIGN); + return memory; } static WasmResult on_import_memory(uint32_t index, const WasmLimits* page_limits, void* user_data) { - /* TODO */ - return WASM_ERROR; + Context* ctx = user_data; + if (ctx->module->memory_index != WASM_INVALID_INDEX) { + print_error(ctx, "only one memory allowed"); + return WASM_ERROR; + } + + assert(index < ctx->module->defined.imports.size); + WasmInterpreterImport* import = &ctx->module->defined.imports.data[index]; + + if (ctx->is_host_import) { + WasmInterpreterMemory* memory = append_memory(ctx, page_limits); + + WasmInterpreterHostImportDelegate* host_delegate = + &ctx->host_import_module->host.import_delegate; + CHECK_RESULT( + host_delegate->import_memory(import, memory, host_delegate->user_data)); + + uint32_t memory_index = ctx->env->memories.size - 1; + append_export(ctx, ctx->host_import_module, WASM_EXTERNAL_KIND_MEMORY, + memory_index, import->field_name); + } else { + CHECK_RESULT(check_import_kind(ctx, import, WASM_EXTERNAL_KIND_MEMORY)); + // TODO: check limits + import->memory.limits = *page_limits; + ctx->module->memory_index = ctx->import_index; + } + return WASM_OK; } static WasmResult on_import_global(uint32_t index, WasmType type, - WasmBool mutable_, + WasmBool mutable, void* user_data) { - /* TODO */ - return WASM_ERROR; + Context* ctx = user_data; + assert(index < ctx->module->defined.imports.size); + WasmInterpreterImport* import = &ctx->module->defined.imports.data[index]; + + uint32_t global_index = ctx->env->globals.size - 1; + if (ctx->is_host_import) { + WasmInterpreterGlobal* global = + wasm_append_interpreter_global(ctx->allocator, &ctx->env->globals); + global->typed_value.type = type; + global->mutable_ = mutable; + + WasmInterpreterHostImportDelegate* host_delegate = + &ctx->host_import_module->host.import_delegate; + CHECK_RESULT( + host_delegate->import_global(import, global, host_delegate->user_data)); + + global_index = ctx->env->globals.size - 1; + append_export(ctx, ctx->host_import_module, WASM_EXTERNAL_KIND_GLOBAL, + global_index, import->field_name); + } else { + CHECK_RESULT(check_import_kind(ctx, import, WASM_EXTERNAL_KIND_GLOBAL)); + // TODO: check type and mutability + import->global.type = type; + import->global.mutable_ = mutable; + global_index = ctx->import_index; + } + wasm_append_uint32_value(ctx->allocator, &ctx->global_index_mapping, + &global_index); + return WASM_OK; } static WasmResult on_function_signatures_count(uint32_t count, void* user_data) { Context* ctx = user_data; - wasm_resize_interpreter_func_vector(ctx->allocator, &ctx->module->funcs, - ctx->module->funcs.size + count); + wasm_resize_uint32_vector(ctx->allocator, &ctx->func_index_mapping, + ctx->func_index_mapping.size + count); + uint32_t i; + for (i = 0; i < count; ++i) + ctx->func_index_mapping.data[ctx->num_func_imports + i] = + ctx->env->funcs.size + i; + wasm_resize_interpreter_func_vector(ctx->allocator, &ctx->env->funcs, + ctx->env->funcs.size + count); wasm_resize_uint32_vector_vector(ctx->allocator, &ctx->func_fixups, count); return WASM_OK; } @@ -427,10 +662,9 @@ static WasmResult on_function_signature(uint32_t index, uint32_t sig_index, void* user_data) { Context* ctx = user_data; - assert(sig_index < ctx->module->sigs.size); - WasmInterpreterFunc* func = get_defined_func(ctx, index); - func->offset = WASM_INVALID_OFFSET; - func->sig_index = sig_index; + WasmInterpreterFunc* func = get_func_by_defined_index(ctx, index); + func->defined.offset = WASM_INVALID_OFFSET; + func->sig_index = translate_sig_index_to_env(ctx, sig_index); return WASM_OK; } @@ -439,8 +673,15 @@ static WasmResult on_table(uint32_t index, const WasmLimits* elem_limits, void* user_data) { Context* ctx = user_data; - wasm_new_uint32_array(ctx->allocator, &ctx->module->func_table, + if (ctx->module->table_index != WASM_INVALID_INDEX) { + print_error(ctx, "only one table allowed"); + return WASM_ERROR; + } + WasmInterpreterTable* table = + wasm_append_interpreter_table(ctx->allocator, &ctx->env->tables); + wasm_new_uint32_array(ctx->allocator, &table->func_indexes, elem_limits->initial); + ctx->module->table_index = ctx->env->tables.size - 1; return WASM_OK; } @@ -448,21 +689,23 @@ static WasmResult on_memory(uint32_t index, const WasmLimits* page_limits, void* user_data) { Context* ctx = user_data; - WasmInterpreterMemory* memory = &ctx->module->memory; - memory->allocator = ctx->memory_allocator; - memory->page_size = page_limits->initial; - memory->byte_size = page_limits->initial * WASM_PAGE_SIZE; - memory->max_page_size = - page_limits->has_max ? page_limits->max : WASM_MAX_PAGES; - memory->data = wasm_alloc_zero(ctx->memory_allocator, memory->byte_size, - WASM_DEFAULT_ALIGN); + if (ctx->module->memory_index != WASM_INVALID_INDEX) { + print_error(ctx, "only one memory allowed"); + return WASM_ERROR; + } + append_memory(ctx, page_limits); + ctx->module->memory_index = ctx->env->memories.size - 1; return WASM_OK; } static WasmResult on_global_count(uint32_t count, void* user_data) { Context* ctx = user_data; - wasm_new_interpreter_global_array(ctx->allocator, &ctx->module->globals, - count); + wasm_resize_uint32_vector(ctx->allocator, &ctx->global_index_mapping, count); + uint32_t i; + for (i = 0; i < count; ++i) + ctx->global_index_mapping.data[i] = ctx->env->globals.size + i; + wasm_resize_interpreter_global_vector(ctx->allocator, &ctx->env->globals, + ctx->env->globals.size + count); return WASM_OK; } @@ -471,8 +714,7 @@ static WasmResult begin_global(uint32_t index, WasmBool mutable_, void* user_data) { Context* ctx = user_data; - assert(index < ctx->module->globals.size); - WasmInterpreterGlobal* global = &ctx->module->globals.data[index]; + WasmInterpreterGlobal* global = get_global_by_module_index(ctx, index); global->typed_value.type = type; global->mutable_ = mutable_; return WASM_OK; @@ -480,8 +722,7 @@ static WasmResult begin_global(uint32_t index, static WasmResult end_global_init_expr(uint32_t index, void* user_data) { Context* ctx = user_data; - assert(index < ctx->module->globals.size); - WasmInterpreterGlobal* global = &ctx->module->globals.data[index]; + WasmInterpreterGlobal* global = get_global_by_module_index(ctx, index); global->typed_value = ctx->init_expr_value; return WASM_OK; } @@ -508,8 +749,8 @@ static WasmResult on_init_expr_get_global_expr(uint32_t index, uint32_t global_index, void* user_data) { Context* ctx = user_data; - assert(global_index < ctx->module->globals.size); - WasmInterpreterGlobal* ref_global = &ctx->module->globals.data[global_index]; + WasmInterpreterGlobal* ref_global = + get_global_by_module_index(ctx, global_index); ctx->init_expr_value = ref_global->typed_value; return WASM_OK; } @@ -532,30 +773,41 @@ static WasmResult on_init_expr_i64_const_expr(uint32_t index, return WASM_OK; } -static WasmResult on_export_count(uint32_t count, void* user_data) { - Context* ctx = user_data; - wasm_new_interpreter_export_array(ctx->allocator, &ctx->module->exports, - count); - return WASM_OK; -} - static WasmResult on_export(uint32_t index, WasmExternalKind kind, uint32_t item_index, WasmStringSlice name, void* user_data) { Context* ctx = user_data; - WasmInterpreterExport* export = &ctx->module->exports.data[index]; - export->name = wasm_dup_string_slice(ctx->allocator, name); - export->kind = kind; - export->index = item_index; + switch (kind) { + case WASM_EXTERNAL_KIND_FUNC: + item_index = translate_func_index_to_env(ctx, item_index); + break; + + case WASM_EXTERNAL_KIND_TABLE: + item_index = ctx->module->table_index; + break; + + case WASM_EXTERNAL_KIND_MEMORY: + item_index = ctx->module->memory_index; + break; + + case WASM_EXTERNAL_KIND_GLOBAL: + item_index = translate_global_index_to_env(ctx, item_index); + break; + + case WASM_NUM_EXTERNAL_KINDS: + assert(0); + break; + } + append_export(ctx, ctx->module, kind, item_index, name); return WASM_OK; } static WasmResult on_start_function(uint32_t func_index, void* user_data) { Context* ctx = user_data; - assert(func_index < ctx->module->funcs.size); - ctx->module->start_func_index = func_index; + ctx->module->defined.start_func_index = + translate_func_index_to_env(ctx, func_index); return WASM_OK; } @@ -570,10 +822,18 @@ static WasmResult on_elem_segment_function_index(uint32_t index, uint32_t func_index, void* user_data) { Context* ctx = user_data; - assert(ctx->table_offset < ctx->module->func_table.size); - assert(index < ctx->module->func_table.size); - uint32_t* entry = &ctx->module->func_table.data[ctx->table_offset++]; - *entry = func_index; + assert(ctx->module->table_index != WASM_INVALID_INDEX); + WasmInterpreterTable* table = + &ctx->env->tables.data[ctx->module->table_index]; + if (ctx->table_offset >= table->func_indexes.size) { + print_error(ctx, + "elem segment offset is out of bounds: %u >= max value %" PRIzd, + ctx->table_offset, table->func_indexes.size); + return WASM_ERROR; + } + + table->func_indexes.data[ctx->table_offset++] = + translate_func_index_to_env(ctx, func_index); return WASM_OK; } @@ -582,23 +842,23 @@ static WasmResult on_data_segment_data(uint32_t index, uint32_t size, void* user_data) { Context* ctx = user_data; - WasmInterpreterMemory* memory = &ctx->module->memory; + assert(ctx->module->memory_index != WASM_INVALID_INDEX); + WasmInterpreterMemory* memory = + &ctx->env->memories.data[ctx->module->memory_index]; assert(ctx->init_expr_value.type == WASM_TYPE_I32); uint32_t address = ctx->init_expr_value.value.i32; uint8_t* dst_data = memory->data; - if (size > 0 && (uint64_t)address + (uint64_t)size > memory->byte_size) + uint64_t end_address = (uint64_t)address + (uint64_t)size; + if (size > 0 && end_address > memory->byte_size) { + print_error(ctx, "data segment is out of bounds: [%u, %" PRIu64 + ") >= max value %u", + address, end_address, memory->byte_size); return WASM_ERROR; + } memcpy(&dst_data[address], src_data, size); return WASM_OK; } -static WasmResult on_function_bodies_count(uint32_t count, void* user_data) { - Context* ctx = user_data; - assert(ctx->num_func_imports + count == ctx->module->funcs.size); - WASM_USE(ctx); - return WASM_OK; -} - static uint32_t translate_depth(Context* ctx, uint32_t depth) { assert(depth < ctx->label_stack.size); return ctx->label_stack.size - 1 - depth; @@ -643,7 +903,8 @@ static WasmType top_type(Context* ctx) { } static WasmBool top_type_is_any(Context* ctx) { - if (ctx->type_stack.size > ctx->current_func->param_and_local_types.size) { + if (ctx->type_stack.size > + ctx->current_func->defined.param_and_local_types.size) { WasmType top_type = ctx->type_stack.data[ctx->type_stack.size - 1]; if (top_type == WASM_TYPE_ANY) return WASM_TRUE; @@ -810,12 +1071,14 @@ static WasmResult drop_types_for_return(Context* ctx, uint32_t arity) { static WasmResult begin_function_body(uint32_t index, void* user_data) { Context* ctx = user_data; - WasmInterpreterFunc* func = get_defined_func(ctx, index); - WasmInterpreterFuncSignature* sig = get_signature(ctx, func->sig_index); + WasmInterpreterFunc* func = get_func_by_defined_index(ctx, index); + WasmInterpreterFuncSignature* sig = + get_signature_by_env_index(ctx, func->sig_index); - func->offset = get_istream_offset(ctx); - func->local_decl_count = 0; - func->local_count = 0; + func->is_host = WASM_FALSE; + func->defined.offset = get_istream_offset(ctx); + func->defined.local_decl_count = 0; + func->defined.local_count = 0; ctx->current_func = func; ctx->depth_fixups.size = 0; @@ -827,12 +1090,13 @@ static WasmResult begin_function_body(uint32_t index, void* user_data) { uint32_t i; Uint32Vector* fixups = &ctx->func_fixups.data[index]; for (i = 0; i < fixups->size; ++i) - CHECK_RESULT(emit_i32_at(ctx, fixups->data[i], func->offset)); + CHECK_RESULT(emit_i32_at(ctx, fixups->data[i], func->defined.offset)); /* append param types */ for (i = 0; i < sig->param_types.size; ++i) { WasmType type = sig->param_types.data[i]; - wasm_append_type_value(ctx->allocator, &func->param_and_local_types, &type); + wasm_append_type_value(ctx->allocator, &func->defined.param_and_local_types, + &type); wasm_append_type_value(ctx->allocator, &ctx->type_stack, &type); } @@ -873,7 +1137,7 @@ static WasmResult end_function_body(uint32_t index, void* user_data) { static WasmResult on_local_decl_count(uint32_t count, void* user_data) { Context* ctx = user_data; WasmInterpreterFunc* func = ctx->current_func; - func->local_decl_count = count; + func->defined.local_decl_count = count; return WASM_OK; } @@ -884,22 +1148,23 @@ static WasmResult on_local_decl(uint32_t decl_index, Context* ctx = user_data; LOGF("%3" PRIzd ": alloca\n", ctx->type_stack.size); WasmInterpreterFunc* func = ctx->current_func; - func->local_count += count; + func->defined.local_count += count; uint32_t i; for (i = 0; i < count; ++i) { - wasm_append_type_value(ctx->allocator, &func->param_and_local_types, &type); + wasm_append_type_value(ctx->allocator, &func->defined.param_and_local_types, + &type); push_type(ctx, type); } - if (decl_index == func->local_decl_count - 1) { + if (decl_index == func->defined.local_decl_count - 1) { /* last local declaration, allocate space for all locals. */ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_ALLOCA)); - CHECK_RESULT(emit_i32(ctx, func->local_count)); + CHECK_RESULT(emit_i32(ctx, func->defined.local_count)); /* fixup the function label's type_stack_limit to include these values. */ Label* label = top_label(ctx); assert(label->label_type == LABEL_TYPE_FUNC); - label->type_stack_limit += func->local_count; + label->type_stack_limit += func->defined.local_count; } return WASM_OK; } @@ -1079,8 +1344,9 @@ static WasmResult on_br_table_expr(WasmBinaryReaderContext* context, static WasmResult on_call_expr(uint32_t func_index, void* user_data) { Context* ctx = user_data; - WasmInterpreterFunc* func = get_func(ctx, func_index); - WasmInterpreterFuncSignature* sig = get_signature(ctx, func->sig_index); + WasmInterpreterFunc* func = get_func_by_module_index(ctx, func_index); + WasmInterpreterFuncSignature* sig = + get_signature_by_env_index(ctx, func->sig_index); CHECK_RESULT(check_type_stack_limit(ctx, sig->param_types.size, "call")); uint32_t i; @@ -1091,7 +1357,7 @@ static WasmResult on_call_expr(uint32_t func_index, void* user_data) { if (func->is_host) { CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_HOST)); - CHECK_RESULT(emit_i32(ctx, func_index)); + CHECK_RESULT(emit_i32(ctx, translate_func_index_to_env(ctx, func_index))); } else { CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_FUNCTION)); CHECK_RESULT(emit_func_offset(ctx, func, func_index)); @@ -1103,7 +1369,8 @@ static WasmResult on_call_expr(uint32_t func_index, void* user_data) { static WasmResult on_call_indirect_expr(uint32_t sig_index, void* user_data) { Context* ctx = user_data; - WasmInterpreterFuncSignature* sig = get_signature(ctx, sig_index); + WasmInterpreterFuncSignature* sig = + get_signature_by_module_index(ctx, sig_index); CHECK_RESULT(pop_and_check_1_type(ctx, WASM_TYPE_I32, "call_indirect")); CHECK_RESULT( check_type_stack_limit(ctx, sig->param_types.size, "call_indirect")); @@ -1116,7 +1383,7 @@ static WasmResult on_call_indirect_expr(uint32_t sig_index, void* user_data) { } CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_INDIRECT)); - CHECK_RESULT(emit_i32(ctx, sig_index)); + CHECK_RESULT(emit_i32(ctx, translate_sig_index_to_env(ctx, sig_index))); push_types(ctx, &sig->result_types); return WASM_OK; } @@ -1164,7 +1431,7 @@ static WasmResult on_f64_const_expr(uint64_t value_bits, void* user_data) { static WasmResult on_get_global_expr(uint32_t global_index, void* user_data) { Context* ctx = user_data; CHECK_GLOBAL(ctx, global_index); - WasmType type = get_global_type_by_index(ctx, global_index); + WasmType type = get_global_type_by_module_index(ctx, global_index); CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GET_GLOBAL)); CHECK_RESULT(emit_i32(ctx, global_index)); push_type(ctx, type); @@ -1174,7 +1441,7 @@ static WasmResult on_get_global_expr(uint32_t global_index, void* user_data) { static WasmResult on_set_global_expr(uint32_t global_index, void* user_data) { Context* ctx = user_data; CHECK_GLOBAL(ctx, global_index); - WasmInterpreterGlobal* global = get_global_by_index(ctx, global_index); + WasmInterpreterGlobal* global = get_global_by_module_index(ctx, global_index); if (global->mutable_ != WASM_TRUE) { print_error(ctx, "can't set_global on immutable global at index %u.", global_index); @@ -1263,7 +1530,7 @@ static WasmResult on_nop_expr(void* user_data) { static WasmResult on_return_expr(void* user_data) { Context* ctx = user_data; WasmInterpreterFuncSignature* sig = - get_func_signature(ctx, ctx->current_func); + get_signature_by_env_index(ctx, ctx->current_func->sig_index); CHECK_RESULT(check_n_types(ctx, &sig->result_types, "return")); CHECK_RESULT(drop_types_for_return(ctx, sig->result_types.size)); CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_RETURN)); @@ -1317,12 +1584,10 @@ static WasmBinaryReader s_binary_reader = { .begin_global = begin_global, .end_global_init_expr = end_global_init_expr, - .on_export_count = on_export_count, .on_export = on_export, .on_start_function = on_start_function, - .on_function_bodies_count = on_function_bodies_count, .begin_function_body = begin_function_body, .on_local_decl_count = on_local_decl_count, .on_local_decl = on_local_decl, @@ -1379,28 +1644,42 @@ static void destroy_context(Context* ctx) { uint32_vector); WASM_DESTROY_VECTOR_AND_ELEMENTS(ctx->allocator, ctx->func_fixups, uint32_vector); + wasm_destroy_uint32_vector(ctx->allocator, &ctx->sig_index_mapping); + wasm_destroy_uint32_vector(ctx->allocator, &ctx->func_index_mapping); + wasm_destroy_uint32_vector(ctx->allocator, &ctx->global_index_mapping); } WasmResult wasm_read_binary_interpreter(WasmAllocator* allocator, WasmAllocator* memory_allocator, + WasmInterpreterEnvironment* env, const void* data, size_t size, const WasmReadBinaryOptions* options, WasmBinaryErrorHandler* error_handler, - WasmInterpreterModule* out_module) { + WasmInterpreterModule** out_module) { Context ctx; WasmBinaryReader reader; WASM_ZERO_MEMORY(ctx); WASM_ZERO_MEMORY(reader); + WasmInterpreterModule* module = + wasm_append_interpreter_module(allocator, &env->modules); + ctx.allocator = allocator; ctx.reader = &reader; ctx.error_handler = error_handler; ctx.memory_allocator = memory_allocator; - ctx.module = out_module; - ctx.module->start_func_index = WASM_INVALID_FUNC_INDEX; - CHECK_RESULT(wasm_init_mem_writer(allocator, &ctx.istream_writer)); + ctx.env = env; + ctx.module = module; + ctx.module->is_host = WASM_FALSE; + ctx.module->table_index = WASM_INVALID_INDEX; + ctx.module->memory_index = WASM_INVALID_INDEX; + ctx.module->defined.start_func_index = WASM_INVALID_INDEX; + ctx.module->defined.istream_start = env->istream.size; + ctx.istream_offset = env->istream.size; + CHECK_RESULT( + wasm_init_mem_writer_existing(&ctx.istream_writer, &env->istream)); reader = s_binary_reader; reader.user_data = &ctx; @@ -1409,11 +1688,13 @@ WasmResult wasm_read_binary_interpreter(WasmAllocator* allocator, WasmResult result = wasm_read_binary(allocator, data, size, &reader, num_function_passes, options); if (WASM_SUCCEEDED(result)) { - wasm_steal_mem_writer_output_buffer(&ctx.istream_writer, - &out_module->istream); - out_module->istream.size = ctx.istream_offset; + wasm_steal_mem_writer_output_buffer(&ctx.istream_writer, &env->istream); + env->istream.size = ctx.istream_offset; + ctx.module->defined.istream_end = env->istream.size; + *out_module = module; } else { wasm_close_mem_writer(&ctx.istream_writer); + *out_module = NULL; } destroy_context(&ctx); return result; |