summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--src/tools/wasm-interp.c236
-rw-r--r--src/wasm-ast.c171
-rw-r--r--src/wasm-ast.h25
-rw-r--r--src/wasm-binary-reader-interpreter.c559
-rw-r--r--src/wasm-binary-reader-interpreter.h4
-rw-r--r--src/wasm-binary-reader.c2
-rw-r--r--src/wasm-binding-hash.c175
-rw-r--r--src/wasm-binding-hash.h54
-rw-r--r--src/wasm-common.c7
-rw-r--r--src/wasm-common.h17
-rw-r--r--src/wasm-interpreter.c358
-rw-r--r--src/wasm-interpreter.h175
-rw-r--r--src/wasm-writer.c23
-rw-r--r--src/wasm-writer.h6
-rw-r--r--test/binary/bad-data-size.txt1
-rw-r--r--test/interp/callimport-zero-args.txt4
-rw-r--r--test/interp/import.txt8
18 files changed, 1146 insertions, 682 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f416911a..a160ec6e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -205,9 +205,10 @@ add_library(libwasm STATIC
src/wasm-binary-writer.c
src/wasm-binary-writer-spec.c
src/wasm-binary-reader-ast.c
+ src/wasm-binding-hash.c
src/wasm-ast-writer.c
- src/wasm-binary-reader-interpreter.c
src/wasm-interpreter.c
+ src/wasm-binary-reader-interpreter.c
src/wasm-apply-names.c
src/wasm-generate-names.c
diff --git a/src/tools/wasm-interp.c b/src/tools/wasm-interp.c
index 85abc7e4..5e99a345 100644
--- a/src/tools/wasm-interp.c
+++ b/src/tools/wasm-interp.c
@@ -231,41 +231,7 @@ static void print_typed_value(WasmInterpreterTypedValue* tv) {
}
}
-static void print_typed_values(WasmInterpreterTypedValue* values,
- size_t num_values) {
- uint32_t i;
- for (i = 0; i < num_values; ++i) {
- print_typed_value(&values[i]);
- if (i != num_values - 1)
- printf(", ");
- }
-}
-
-static WasmResult default_host_callback(const WasmInterpreterFuncSignature* sig,
- const WasmStringSlice* module_name,
- const WasmStringSlice* field_name,
- uint32_t num_args,
- WasmInterpreterTypedValue* args,
- uint32_t num_results,
- WasmInterpreterTypedValue* out_results,
- void* user_data) {
- memset(out_results, 0, sizeof(WasmInterpreterTypedValue) * num_results);
- uint32_t i;
- for (i = 0; i < num_results; ++i)
- out_results[i].type = sig->result_types.data[i];
-
- printf("called host " PRIstringslice "." PRIstringslice "(",
- WASM_PRINTF_STRING_SLICE_ARG(*module_name),
- WASM_PRINTF_STRING_SLICE_ARG(*field_name));
- print_typed_values(args, num_args);
- printf(") => (");
- print_typed_values(out_results, num_results);
- printf(")\n");
- return WASM_OK;
-}
-
-static WasmInterpreterResult run_defined_function(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
+static WasmInterpreterResult run_defined_function(WasmInterpreterThread* thread,
uint32_t offset) {
thread->pc = offset;
WasmInterpreterResult iresult = WASM_INTERPRETER_OK;
@@ -273,9 +239,8 @@ static WasmInterpreterResult run_defined_function(WasmInterpreterModule* module,
uint32_t* call_stack_return_top = thread->call_stack_top;
while (iresult == WASM_INTERPRETER_OK) {
if (s_trace)
- wasm_trace_pc(module, thread, s_stdout_stream);
- iresult =
- wasm_run_interpreter(module, thread, quantum, call_stack_return_top);
+ wasm_trace_pc(thread, s_stdout_stream);
+ iresult = wasm_run_interpreter(thread, quantum, call_stack_return_top);
}
if (iresult != WASM_INTERPRETER_RETURNED) {
if (s_trace)
@@ -286,27 +251,23 @@ static WasmInterpreterResult run_defined_function(WasmInterpreterModule* module,
return WASM_INTERPRETER_OK;
}
-static WasmInterpreterResult run_function(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
+static WasmInterpreterResult run_function(WasmInterpreterThread* thread,
uint32_t func_index) {
- assert(func_index < module->funcs.size);
- WasmInterpreterFunc* func = &module->funcs.data[func_index];
- if (func->is_host) {
- WasmInterpreterImport* import = &module->imports.data[func->import_index];
- return wasm_call_host(module, thread, import);
- } else {
- return run_defined_function(module, thread, func->offset);
- }
+ assert(func_index < thread->env->funcs.size);
+ WasmInterpreterFunc* func = &thread->env->funcs.data[func_index];
+ if (func->is_host)
+ return wasm_call_host(thread, func);
+ else
+ return run_defined_function(thread, func->defined.offset);
}
-static WasmResult run_start_function(WasmInterpreterModule* module,
- WasmInterpreterThread* thread) {
+static WasmResult run_start_function(WasmInterpreterThread* thread) {
WasmResult result = WASM_OK;
- if (module->start_func_index != WASM_INVALID_FUNC_INDEX) {
+ if (thread->module->defined.start_func_index != WASM_INVALID_INDEX) {
if (s_trace)
printf(">>> running start function:\n");
WasmInterpreterResult iresult =
- run_function(module, thread, module->start_func_index);
+ run_function(thread, thread->module->defined.start_func_index);
if (iresult != WASM_INTERPRETER_OK) {
/* trap */
fprintf(stderr, "error: %s\n", s_trap_strings[iresult]);
@@ -317,22 +278,22 @@ static WasmResult run_start_function(WasmInterpreterModule* module,
}
static WasmInterpreterFuncSignature* get_export_signature(
- WasmInterpreterModule* module,
+ WasmInterpreterEnvironment* env,
WasmInterpreterExport* export) {
+ assert(export->kind == WASM_EXTERNAL_KIND_FUNC);
uint32_t func_index = export->index;
- uint32_t sig_index = module->funcs.data[func_index].sig_index;
- assert(sig_index < module->sigs.size);
- return &module->sigs.data[sig_index];
+ uint32_t sig_index = env->funcs.data[func_index].sig_index;
+ assert(sig_index < env->sigs.size);
+ return &env->sigs.data[sig_index];
}
static WasmInterpreterResult run_export(
WasmAllocator* allocator,
- WasmInterpreterModule* module,
WasmInterpreterThread* thread,
WasmInterpreterExport* export,
- WasmInterpreterFuncSignature* sig,
WasmInterpreterTypedValueVector* out_results) {
assert(export->kind == WASM_EXTERNAL_KIND_FUNC);
+ WasmInterpreterFuncSignature* sig = get_export_signature(thread->env, export);
/* push all 0 values as arguments */
assert(sig->param_types.size < thread->value_stack.size);
@@ -340,7 +301,7 @@ static WasmInterpreterResult run_export(
thread->value_stack_top = &thread->value_stack.data[num_args];
memset(thread->value_stack.data, 0, num_args * sizeof(WasmInterpreterValue));
- WasmInterpreterResult result = run_function(module, thread, export->index);
+ WasmInterpreterResult result = run_function(thread, export->index);
if (result == WASM_INTERPRETER_OK) {
size_t expected_results = sig->result_types.size;
@@ -374,7 +335,6 @@ static WasmInterpreterResult run_export(
static WasmInterpreterResult run_export_wrapper(
WasmAllocator* allocator,
- WasmInterpreterModule* module,
WasmInterpreterThread* thread,
WasmInterpreterExport* export,
WasmInterpreterTypedValueVector* out_results,
@@ -384,11 +344,12 @@ static WasmInterpreterResult run_export_wrapper(
WASM_PRINTF_STRING_SLICE_ARG(export->name));
}
- WasmInterpreterFuncSignature* sig = get_export_signature(module, export);
WasmInterpreterResult result =
- run_export(allocator, module, thread, export, sig, out_results);
+ run_export(allocator, thread, export, out_results);
if (verbose) {
+ WasmInterpreterFuncSignature* sig =
+ get_export_signature(thread->env, export);
printf(PRIstringslice "(", WASM_PRINTF_STRING_SLICE_ARG(export->name));
size_t i;
for (i = 0; i < sig->param_types.size; ++i) {
@@ -416,19 +377,18 @@ static WasmInterpreterResult run_export_wrapper(
static WasmResult run_export_by_name(
WasmAllocator* allocator,
- WasmInterpreterModule* module,
WasmInterpreterThread* thread,
WasmStringSlice* name,
WasmInterpreterResult* out_iresult,
WasmInterpreterTypedValueVector* out_results,
RunVerbosity verbose) {
WasmInterpreterExport* export =
- wasm_get_interpreter_export_by_name(module, name);
+ wasm_get_interpreter_export_by_name(thread->module, name);
if (!export)
return WASM_ERROR;
- *out_iresult = run_export_wrapper(allocator, module, thread, export,
- out_results, verbose);
+ *out_iresult =
+ run_export_wrapper(allocator, thread, export, out_results, verbose);
return WASM_OK;
}
@@ -441,86 +401,148 @@ static void run_all_exports(WasmAllocator* allocator,
uint32_t i;
for (i = 0; i < module->exports.size; ++i) {
WasmInterpreterExport* export = &module->exports.data[i];
- run_export_wrapper(allocator, module, thread, export, &results, verbose);
+ run_export_wrapper(allocator, thread, export, &results, verbose);
}
wasm_destroy_interpreter_typed_value_vector(allocator, &results);
}
static WasmResult read_module(WasmAllocator* allocator,
const char* module_filename,
- WasmInterpreterModule* out_module,
+ WasmInterpreterEnvironment* env,
+ WasmInterpreterModule** out_module,
WasmInterpreterThread* out_thread) {
WasmResult result;
void* data;
size_t size;
- WASM_ZERO_MEMORY(*out_module);
WASM_ZERO_MEMORY(*out_thread);
result = wasm_read_file(allocator, module_filename, &data, &size);
if (WASM_SUCCEEDED(result)) {
WasmAllocator* memory_allocator = &g_wasm_libc_allocator;
- result = wasm_read_binary_interpreter(allocator, memory_allocator, data,
- size, &s_read_binary_options,
+ result = wasm_read_binary_interpreter(allocator, memory_allocator, env,
+ data, size, &s_read_binary_options,
&s_error_handler, out_module);
if (WASM_SUCCEEDED(result)) {
- if (s_verbose) {
- wasm_disassemble_module(out_module, s_stdout_stream, 0,
- out_module->istream.size);
- }
+ if (s_verbose)
+ wasm_disassemble_module(env, s_stdout_stream, *out_module);
- result = wasm_init_interpreter_thread(allocator, out_module, out_thread,
- &s_thread_options);
- out_thread->host_func.callback = default_host_callback;
- out_thread->host_func.user_data = NULL;
+ result = wasm_init_interpreter_thread(allocator, env, *out_module,
+ out_thread, &s_thread_options);
}
wasm_free(allocator, data);
}
return result;
}
-static void destroy_module_and_thread(WasmAllocator* allocator,
- WasmInterpreterModule* module,
- WasmInterpreterThread* thread) {
- wasm_destroy_interpreter_thread(allocator, thread);
- wasm_destroy_interpreter_module(allocator, module);
+static void print_typed_values(WasmInterpreterTypedValue* values,
+ size_t num_values) {
+ uint32_t i;
+ for (i = 0; i < num_values; ++i) {
+ print_typed_value(&values[i]);
+ if (i != num_values - 1)
+ printf(", ");
+ }
+}
+
+static WasmResult default_host_callback(const WasmInterpreterFunc* func,
+ const WasmInterpreterFuncSignature* sig,
+ uint32_t num_args,
+ WasmInterpreterTypedValue* args,
+ uint32_t num_results,
+ WasmInterpreterTypedValue* out_results,
+ void* user_data) {
+ memset(out_results, 0, sizeof(WasmInterpreterTypedValue) * num_results);
+ uint32_t i;
+ for (i = 0; i < num_results; ++i)
+ out_results[i].type = sig->result_types.data[i];
+
+ printf("called host " PRIstringslice "." PRIstringslice "(",
+ WASM_PRINTF_STRING_SLICE_ARG(func->host.module_name),
+ WASM_PRINTF_STRING_SLICE_ARG(func->host.field_name));
+ print_typed_values(args, num_args);
+ printf(") => (");
+ print_typed_values(out_results, num_results);
+ printf(")\n");
+ return WASM_OK;
+}
+
+static WasmResult spectest_import_func(WasmInterpreterImport* import,
+ WasmInterpreterFunc* func,
+ WasmInterpreterFuncSignature* sig,
+ void* user_data) {
+ func->host.callback = default_host_callback;
+ return WASM_OK;
+}
+
+static WasmResult spectest_import_table(WasmInterpreterImport* import,
+ WasmInterpreterTable* table,
+ void* user_data) {
+ return WASM_ERROR;
+}
+
+static WasmResult spectest_import_memory(WasmInterpreterImport* import,
+ WasmInterpreterMemory* memory,
+ void* user_data) {
+ return WASM_ERROR;
+}
+
+static WasmResult spectest_import_global(WasmInterpreterImport* import,
+ WasmInterpreterGlobal* global,
+ void* user_data) {
+ return WASM_ERROR;
+}
+
+static void init_environment(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env) {
+ wasm_init_interpreter_environment(allocator, env);
+ WasmInterpreterModule* host_module = wasm_append_host_module(
+ allocator, env, wasm_string_slice_from_cstr("spectest"));
+ host_module->host.import_delegate.import_func = spectest_import_func;
+ host_module->host.import_delegate.import_table = spectest_import_table;
+ host_module->host.import_delegate.import_memory = spectest_import_memory;
+ host_module->host.import_delegate.import_global = spectest_import_global;
}
static WasmResult read_and_run_module(WasmAllocator* allocator,
const char* module_filename) {
WasmResult result;
- WasmInterpreterModule module;
+ WasmInterpreterEnvironment env;
+ WasmInterpreterModule* module = NULL;
WasmInterpreterThread thread;
- result = read_module(allocator, module_filename, &module, &thread);
- if (WASM_SUCCEEDED(result))
- result = run_start_function(&module, &thread);
- if (WASM_SUCCEEDED(result) && s_run_all_exports)
- run_all_exports(allocator, &module, &thread, RUN_VERBOSE);
- destroy_module_and_thread(allocator, &module, &thread);
+ init_environment(allocator, &env);
+ result = read_module(allocator, module_filename, &env, &module, &thread);
+ if (WASM_SUCCEEDED(result)) {
+ result = run_start_function(&thread);
+ if (s_run_all_exports)
+ run_all_exports(allocator, module, &thread, RUN_VERBOSE);
+ }
+ wasm_destroy_interpreter_thread(allocator, &thread);
+ wasm_destroy_interpreter_environment(allocator, &env);
return result;
}
static WasmResult read_and_run_spec_json(WasmAllocator* allocator,
const char* spec_json_filename) {
WasmResult result = WASM_OK;
- WasmInterpreterModule module;
+ WasmInterpreterEnvironment env;
+ WasmInterpreterModule* module = NULL;
WasmInterpreterThread thread;
WasmStringSlice command_file;
WasmStringSlice command_name;
- WasmAllocatorMark module_mark;
WasmInterpreterTypedValueVector result_values;
uint32_t command_line_no;
- WasmBool has_module = WASM_FALSE;
+ WasmBool has_thread = WASM_FALSE;
uint32_t passed = 0;
uint32_t failed = 0;
- WASM_ZERO_MEMORY(module);
WASM_ZERO_MEMORY(thread);
WASM_ZERO_MEMORY(command_file);
WASM_ZERO_MEMORY(command_name);
- WASM_ZERO_MEMORY(module_mark);
WASM_ZERO_MEMORY(result_values);
+ init_environment(allocator, &env);
+
void* data;
size_t size;
result = wasm_read_file(allocator, spec_json_filename, &data, &size);
@@ -653,9 +675,9 @@ static WasmResult read_and_run_spec_json(WasmAllocator* allocator,
case END_MODULE_OBJECT:
EXPECT('}');
MAYBE_CONTINUE(MODULES_ARRAY);
- destroy_module_and_thread(allocator, &module, &thread);
- wasm_reset_to_mark(allocator, module_mark);
- has_module = WASM_FALSE;
+ assert(has_thread);
+ wasm_destroy_interpreter_thread(allocator, &thread);
+ has_thread = WASM_FALSE;
break;
case MODULE_FILENAME: {
@@ -673,14 +695,13 @@ static WasmResult read_and_run_spec_json(WasmAllocator* allocator,
WASM_PRINTF_STRING_SLICE_ARG(module_filename));
}
- module_mark = wasm_mark(allocator);
- result = read_module(allocator, path, &module, &thread);
+ result = read_module(allocator, path, &env, &module, &thread);
if (WASM_FAILED(result))
goto fail;
- has_module = WASM_TRUE;
+ has_thread = WASM_TRUE;
- result = run_start_function(&module, &thread);
+ result = run_start_function(&thread);
if (WASM_FAILED(result))
goto fail;
@@ -727,8 +748,8 @@ static WasmResult read_and_run_spec_json(WasmAllocator* allocator,
WasmInterpreterResult iresult;
EXPECT('}');
RunVerbosity verbose = command_type == ACTION ? RUN_VERBOSE : RUN_QUIET;
- result = run_export_by_name(allocator, &module, &thread, &command_name,
- &iresult, &result_values, verbose);
+ result = run_export_by_name(allocator, &thread, &command_name, &iresult,
+ &result_values, verbose);
if (WASM_FAILED(result)) {
FAILED("unknown export");
failed++;
@@ -837,8 +858,9 @@ fail:
result = WASM_ERROR;
done:
- if (has_module)
- destroy_module_and_thread(allocator, &module, &thread);
+ if (has_thread)
+ wasm_destroy_interpreter_thread(allocator, &thread);
+ wasm_destroy_interpreter_environment(allocator, &env);
wasm_destroy_interpreter_typed_value_vector(allocator, &result_values);
wasm_free(allocator, data);
return result;
diff --git a/src/wasm-ast.c b/src/wasm-ast.c
index a6c4fe8a..780f595f 100644
--- a/src/wasm-ast.c
+++ b/src/wasm-ast.c
@@ -21,158 +21,15 @@
#include "wasm-allocator.h"
-#define INITIAL_HASH_CAPACITY 8
-
-static size_t hash_name(const WasmStringSlice* name) {
- // FNV-1a hash
- const uint32_t fnv_prime = 0x01000193;
- const uint8_t* bp = (const uint8_t*)name->start;
- const uint8_t* be = bp + name->length;
- uint32_t hval = 0x811c9dc5;
- while (bp < be) {
- hval ^= (uint32_t)*bp++;
- hval *= fnv_prime;
- }
- return hval;
-}
-
-static WasmBindingHashEntry* hash_main_entry(const WasmBindingHash* hash,
- const WasmStringSlice* name) {
- return &hash->entries.data[hash_name(name) % hash->entries.capacity];
-}
-
-WasmBool wasm_hash_entry_is_free(const WasmBindingHashEntry* entry) {
- return !entry->binding.name.start;
-}
-
-static WasmBindingHashEntry* hash_new_entry(WasmBindingHash* hash,
- const WasmStringSlice* name) {
- WasmBindingHashEntry* entry = hash_main_entry(hash, name);
- if (!wasm_hash_entry_is_free(entry)) {
- assert(hash->free_head);
- WasmBindingHashEntry* free_entry = hash->free_head;
- hash->free_head = free_entry->next;
- if (free_entry->next)
- free_entry->next->prev = NULL;
-
- /* our main position is already claimed. Check to see if the entry in that
- * position is in its main position */
- WasmBindingHashEntry* other_entry =
- hash_main_entry(hash, &entry->binding.name);
- if (other_entry == entry) {
- /* yes, so add this new entry to the chain, even if it is already there */
- /* add as the second entry in the chain */
- free_entry->next = entry->next;
- entry->next = free_entry;
- entry = free_entry;
- } else {
- /* no, move the entry to the free entry */
- assert(!wasm_hash_entry_is_free(other_entry));
- while (other_entry->next != entry)
- other_entry = other_entry->next;
-
- other_entry->next = free_entry;
- *free_entry = *entry;
- entry->next = NULL;
- }
- } else {
- /* remove from the free list */
- if (entry->next)
- entry->next->prev = entry->prev;
- if (entry->prev)
- entry->prev->next = entry->next;
- else
- hash->free_head = entry->next;
- entry->next = NULL;
- }
-
- WASM_ZERO_MEMORY(entry->binding);
- entry->binding.name = *name;
- entry->prev = NULL;
- /* entry->next is set above */
- return entry;
-}
-
-static void hash_resize(WasmAllocator* allocator,
- WasmBindingHash* hash,
- size_t desired_capacity) {
- WasmBindingHash new_hash;
- WASM_ZERO_MEMORY(new_hash);
- /* TODO(binji): better plural */
- wasm_reserve_binding_hash_entrys(allocator, &new_hash.entries,
- desired_capacity);
-
- /* update the free list */
- size_t i;
- for (i = 0; i < new_hash.entries.capacity; ++i) {
- WasmBindingHashEntry* entry = &new_hash.entries.data[i];
- if (new_hash.free_head)
- new_hash.free_head->prev = entry;
-
- WASM_ZERO_MEMORY(entry->binding.name);
- entry->next = new_hash.free_head;
- new_hash.free_head = entry;
- }
- new_hash.free_head->prev = NULL;
-
- /* copy from the old hash to the new hash */
- for (i = 0; i < hash->entries.capacity; ++i) {
- WasmBindingHashEntry* old_entry = &hash->entries.data[i];
- if (wasm_hash_entry_is_free(old_entry))
- continue;
-
- WasmStringSlice* name = &old_entry->binding.name;
- WasmBindingHashEntry* new_entry = hash_new_entry(&new_hash, name);
- new_entry->binding = old_entry->binding;
- }
-
- /* we are sharing the WasmStringSlices, so we only need to destroy the old
- * binding vector */
- wasm_destroy_binding_hash_entry_vector(allocator, &hash->entries);
- *hash = new_hash;
-}
-
-WasmBinding* wasm_insert_binding(WasmAllocator* allocator,
- WasmBindingHash* hash,
- const WasmStringSlice* name) {
- if (hash->entries.size == 0)
- hash_resize(allocator, hash, INITIAL_HASH_CAPACITY);
-
- if (!hash->free_head) {
- /* no more free space, allocate more */
- hash_resize(allocator, hash, hash->entries.capacity * 2);
- }
-
- WasmBindingHashEntry* entry = hash_new_entry(hash, name);
- assert(entry);
- hash->entries.size++;
- return &entry->binding;
-}
-
-static int find_binding_index_by_name(const WasmBindingHash* hash,
- const WasmStringSlice* name) {
- if (hash->entries.capacity == 0)
- return -1;
-
- WasmBindingHashEntry* entry = hash_main_entry(hash, name);
- do {
- if (wasm_string_slices_are_equal(&entry->binding.name, name))
- return entry->binding.index;
-
- entry = entry->next;
- } while (entry && !wasm_hash_entry_is_free(entry));
- return -1;
-}
-
int wasm_get_index_from_var(const WasmBindingHash* hash, const WasmVar* var) {
if (var->type == WASM_VAR_TYPE_NAME)
- return find_binding_index_by_name(hash, &var->name);
+ return wasm_find_binding_index_by_name(hash, &var->name);
return (int)var->index;
}
WasmExportPtr wasm_get_export_by_name(const WasmModule* module,
const WasmStringSlice* name) {
- int index = find_binding_index_by_name(&module->export_bindings, name);
+ int index = wasm_find_binding_index_by_name(&module->export_bindings, name);
if (index == -1)
return NULL;
return module->exports.data[index];
@@ -203,11 +60,12 @@ int wasm_get_local_index_by_var(const WasmFunc* func, const WasmVar* var) {
if (var->type == WASM_VAR_TYPE_INDEX)
return (int)var->index;
- int result = find_binding_index_by_name(&func->param_bindings, &var->name);
+ int result =
+ wasm_find_binding_index_by_name(&func->param_bindings, &var->name);
if (result != -1)
return result;
- result = find_binding_index_by_name(&func->local_bindings, &var->name);
+ result = wasm_find_binding_index_by_name(&func->local_bindings, &var->name);
if (result == -1)
return result;
@@ -393,21 +251,6 @@ WasmExpr* wasm_new_empty_expr(struct WasmAllocator* allocator,
return result;
}
-static void destroy_binding_hash_entry(WasmAllocator* allocator,
- WasmBindingHashEntry* entry) {
- wasm_destroy_string_slice(allocator, &entry->binding.name);
-}
-
-static void destroy_binding_hash(WasmAllocator* allocator,
- WasmBindingHash* hash) {
- /* Can't use WASM_DESTROY_VECTOR_AND_ELEMENTS, because it loops over size, not
- * capacity. */
- size_t i;
- for (i = 0; i < hash->entries.capacity; ++i)
- destroy_binding_hash_entry(allocator, &hash->entries.data[i]);
- wasm_destroy_binding_hash_entry_vector(allocator, &hash->entries);
-}
-
void wasm_destroy_var(WasmAllocator* allocator, WasmVar* var) {
if (var->type == WASM_VAR_TYPE_NAME)
wasm_destroy_string_slice(allocator, &var->name);
@@ -513,8 +356,8 @@ void wasm_destroy_func(WasmAllocator* allocator, WasmFunc* func) {
wasm_destroy_string_slice(allocator, &func->name);
wasm_destroy_func_declaration(allocator, &func->decl);
wasm_destroy_type_vector(allocator, &func->local_types);
- destroy_binding_hash(allocator, &func->param_bindings);
- destroy_binding_hash(allocator, &func->local_bindings);
+ wasm_destroy_binding_hash(allocator, &func->param_bindings);
+ wasm_destroy_binding_hash(allocator, &func->local_bindings);
wasm_destroy_expr_list(allocator, func->first_expr);
}
diff --git a/src/wasm-ast.h b/src/wasm-ast.h
index 244a1cb7..5d6b6f2d 100644
--- a/src/wasm-ast.h
+++ b/src/wasm-ast.h
@@ -21,6 +21,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "wasm-binding-hash.h"
#include "wasm-common.h"
#include "wasm-type-vector.h"
#include "wasm-vector.h"
@@ -85,24 +86,6 @@ typedef enum WasmExprType {
WASM_EXPR_TYPE_UNREACHABLE,
} WasmExprType;
-typedef struct WasmBinding {
- WasmLocation loc;
- WasmStringSlice name;
- int index;
-} WasmBinding;
-
-typedef struct WasmBindingHashEntry {
- WasmBinding binding;
- struct WasmBindingHashEntry* next;
- struct WasmBindingHashEntry* prev; /* only valid when this entry is unused */
-} WasmBindingHashEntry;
-WASM_DEFINE_VECTOR(binding_hash_entry, WasmBindingHashEntry);
-
-typedef struct WasmBindingHash {
- WasmBindingHashEntryVector entries;
- WasmBindingHashEntry* free_head;
-} WasmBindingHash;
-
typedef WasmTypeVector WasmBlockSignature;
typedef struct WasmBlock {
@@ -411,12 +394,6 @@ typedef struct WasmExprVisitor {
} WasmExprVisitor;
WASM_EXTERN_C_BEGIN
-WasmBinding* wasm_insert_binding(struct WasmAllocator*,
- WasmBindingHash*,
- const WasmStringSlice*);
-
-WasmBool wasm_hash_entry_is_free(const WasmBindingHashEntry*);
-
WasmModuleField* wasm_append_module_field(struct WasmAllocator*, WasmModule*);
/* ownership of the function signature is passed to the module */
WasmFuncType* wasm_append_implicit_func_type(struct WasmAllocator*,
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;
diff --git a/src/wasm-binary-reader-interpreter.h b/src/wasm-binary-reader-interpreter.h
index bd701b92..2cb26652 100644
--- a/src/wasm-binary-reader-interpreter.h
+++ b/src/wasm-binary-reader-interpreter.h
@@ -20,6 +20,7 @@
#include "wasm-common.h"
struct WasmAllocator;
+struct WasmInterpreterEnvironment;
struct WasmInterpreterModule;
struct WasmReadBinaryOptions;
@@ -27,11 +28,12 @@ WASM_EXTERN_C_BEGIN
WasmResult wasm_read_binary_interpreter(
struct WasmAllocator* allocator,
struct WasmAllocator* memory_allocator,
+ struct WasmInterpreterEnvironment* env,
const void* data,
size_t size,
const struct WasmReadBinaryOptions* options,
WasmBinaryErrorHandler*,
- struct WasmInterpreterModule* out_module);
+ struct WasmInterpreterModule** out_module);
WASM_EXTERN_C_END
#endif /* WASM_BINARY_READER_INTERPRETER_H_ */
diff --git a/src/wasm-binary-reader.c b/src/wasm-binary-reader.c
index 378f5927..d30473d5 100644
--- a/src/wasm-binary-reader.c
+++ b/src/wasm-binary-reader.c
@@ -2015,7 +2015,7 @@ WasmResult wasm_read_binary(WasmAllocator* allocator,
CALLBACK_CTX0(end_data_section);
}
- CALLBACK_CTX0(end_module);
+ CALLBACK0(end_module);
destroy_context(allocator, ctx);
return WASM_OK;
}
diff --git a/src/wasm-binding-hash.c b/src/wasm-binding-hash.c
new file mode 100644
index 00000000..68b80eb7
--- /dev/null
+++ b/src/wasm-binding-hash.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm-binding-hash.h"
+
+#define INITIAL_HASH_CAPACITY 8
+
+static size_t hash_name(const WasmStringSlice* name) {
+ // FNV-1a hash
+ const uint32_t fnv_prime = 0x01000193;
+ const uint8_t* bp = (const uint8_t*)name->start;
+ const uint8_t* be = bp + name->length;
+ uint32_t hval = 0x811c9dc5;
+ while (bp < be) {
+ hval ^= (uint32_t)*bp++;
+ hval *= fnv_prime;
+ }
+ return hval;
+}
+
+static WasmBindingHashEntry* hash_main_entry(const WasmBindingHash* hash,
+ const WasmStringSlice* name) {
+ return &hash->entries.data[hash_name(name) % hash->entries.capacity];
+}
+
+WasmBool wasm_hash_entry_is_free(const WasmBindingHashEntry* entry) {
+ return !entry->binding.name.start;
+}
+
+static WasmBindingHashEntry* hash_new_entry(WasmBindingHash* hash,
+ const WasmStringSlice* name) {
+ WasmBindingHashEntry* entry = hash_main_entry(hash, name);
+ if (!wasm_hash_entry_is_free(entry)) {
+ assert(hash->free_head);
+ WasmBindingHashEntry* free_entry = hash->free_head;
+ hash->free_head = free_entry->next;
+ if (free_entry->next)
+ free_entry->next->prev = NULL;
+
+ /* our main position is already claimed. Check to see if the entry in that
+ * position is in its main position */
+ WasmBindingHashEntry* other_entry =
+ hash_main_entry(hash, &entry->binding.name);
+ if (other_entry == entry) {
+ /* yes, so add this new entry to the chain, even if it is already there */
+ /* add as the second entry in the chain */
+ free_entry->next = entry->next;
+ entry->next = free_entry;
+ entry = free_entry;
+ } else {
+ /* no, move the entry to the free entry */
+ assert(!wasm_hash_entry_is_free(other_entry));
+ while (other_entry->next != entry)
+ other_entry = other_entry->next;
+
+ other_entry->next = free_entry;
+ *free_entry = *entry;
+ entry->next = NULL;
+ }
+ } else {
+ /* remove from the free list */
+ if (entry->next)
+ entry->next->prev = entry->prev;
+ if (entry->prev)
+ entry->prev->next = entry->next;
+ else
+ hash->free_head = entry->next;
+ entry->next = NULL;
+ }
+
+ WASM_ZERO_MEMORY(entry->binding);
+ entry->binding.name = *name;
+ entry->prev = NULL;
+ /* entry->next is set above */
+ return entry;
+}
+
+static void hash_resize(WasmAllocator* allocator,
+ WasmBindingHash* hash,
+ size_t desired_capacity) {
+ WasmBindingHash new_hash;
+ WASM_ZERO_MEMORY(new_hash);
+ /* TODO(binji): better plural */
+ wasm_reserve_binding_hash_entrys(allocator, &new_hash.entries,
+ desired_capacity);
+
+ /* update the free list */
+ size_t i;
+ for (i = 0; i < new_hash.entries.capacity; ++i) {
+ WasmBindingHashEntry* entry = &new_hash.entries.data[i];
+ if (new_hash.free_head)
+ new_hash.free_head->prev = entry;
+
+ WASM_ZERO_MEMORY(entry->binding.name);
+ entry->next = new_hash.free_head;
+ new_hash.free_head = entry;
+ }
+ new_hash.free_head->prev = NULL;
+
+ /* copy from the old hash to the new hash */
+ for (i = 0; i < hash->entries.capacity; ++i) {
+ WasmBindingHashEntry* old_entry = &hash->entries.data[i];
+ if (wasm_hash_entry_is_free(old_entry))
+ continue;
+
+ WasmStringSlice* name = &old_entry->binding.name;
+ WasmBindingHashEntry* new_entry = hash_new_entry(&new_hash, name);
+ new_entry->binding = old_entry->binding;
+ }
+
+ /* we are sharing the WasmStringSlices, so we only need to destroy the old
+ * binding vector */
+ wasm_destroy_binding_hash_entry_vector(allocator, &hash->entries);
+ *hash = new_hash;
+}
+
+WasmBinding* wasm_insert_binding(WasmAllocator* allocator,
+ WasmBindingHash* hash,
+ const WasmStringSlice* name) {
+ if (hash->entries.size == 0)
+ hash_resize(allocator, hash, INITIAL_HASH_CAPACITY);
+
+ if (!hash->free_head) {
+ /* no more free space, allocate more */
+ hash_resize(allocator, hash, hash->entries.capacity * 2);
+ }
+
+ WasmBindingHashEntry* entry = hash_new_entry(hash, name);
+ assert(entry);
+ hash->entries.size++;
+ return &entry->binding;
+}
+
+int wasm_find_binding_index_by_name(const WasmBindingHash* hash,
+ const WasmStringSlice* name) {
+ if (hash->entries.capacity == 0)
+ return -1;
+
+ WasmBindingHashEntry* entry = hash_main_entry(hash, name);
+ do {
+ if (wasm_string_slices_are_equal(&entry->binding.name, name))
+ return entry->binding.index;
+
+ entry = entry->next;
+ } while (entry && !wasm_hash_entry_is_free(entry));
+ return -1;
+}
+
+static void destroy_binding_hash_entry(WasmAllocator* allocator,
+ WasmBindingHashEntry* entry) {
+ wasm_destroy_string_slice(allocator, &entry->binding.name);
+}
+
+void wasm_destroy_binding_hash(WasmAllocator* allocator,
+ WasmBindingHash* hash) {
+ /* Can't use WASM_DESTROY_VECTOR_AND_ELEMENTS, because it loops over size, not
+ * capacity. */
+ size_t i;
+ for (i = 0; i < hash->entries.capacity; ++i)
+ destroy_binding_hash_entry(allocator, &hash->entries.data[i]);
+ wasm_destroy_binding_hash_entry_vector(allocator, &hash->entries);
+}
diff --git a/src/wasm-binding-hash.h b/src/wasm-binding-hash.h
new file mode 100644
index 00000000..2897e44a
--- /dev/null
+++ b/src/wasm-binding-hash.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WASM_BINDING_HASH_H_
+#define WASM_BINDING_HASH_H_
+
+#include "wasm-common.h"
+#include "wasm-vector.h"
+
+struct WasmAllocator;
+
+typedef struct WasmBinding {
+ WasmLocation loc;
+ WasmStringSlice name;
+ int index;
+} WasmBinding;
+
+typedef struct WasmBindingHashEntry {
+ WasmBinding binding;
+ struct WasmBindingHashEntry* next;
+ struct WasmBindingHashEntry* prev; /* only valid when this entry is unused */
+} WasmBindingHashEntry;
+WASM_DEFINE_VECTOR(binding_hash_entry, WasmBindingHashEntry);
+
+typedef struct WasmBindingHash {
+ WasmBindingHashEntryVector entries;
+ WasmBindingHashEntry* free_head;
+} WasmBindingHash;
+
+WASM_EXTERN_C_BEGIN
+WasmBinding* wasm_insert_binding(struct WasmAllocator*,
+ WasmBindingHash*,
+ const WasmStringSlice*);
+WasmBool wasm_hash_entry_is_free(const WasmBindingHashEntry*);
+/* returns -1 if the name is not in the hash */
+int wasm_find_binding_index_by_name(const WasmBindingHash*,
+ const WasmStringSlice* name);
+void wasm_destroy_binding_hash(struct WasmAllocator*, WasmBindingHash*);
+WASM_EXTERN_C_END
+
+#endif /* WASM_BINDING_HASH_H_ */
diff --git a/src/wasm-common.c b/src/wasm-common.c
index 1df2e335..f439c01d 100644
--- a/src/wasm-common.c
+++ b/src/wasm-common.c
@@ -56,6 +56,13 @@ WasmStringSlice wasm_empty_string_slice(void) {
return result;
}
+WasmStringSlice wasm_string_slice_from_cstr(const char* string) {
+ WasmStringSlice result;
+ result.start = string;
+ result.length = strlen(string);
+ return result;
+}
+
WasmBool wasm_string_slices_are_equal(const WasmStringSlice* a,
const WasmStringSlice* b) {
return a->start && b->start && a->length == b->length &&
diff --git a/src/wasm-common.h b/src/wasm-common.h
index 365572da..4f257872 100644
--- a/src/wasm-common.h
+++ b/src/wasm-common.h
@@ -151,13 +151,6 @@ typedef enum WasmExternalKind {
WASM_NUM_EXTERNAL_KINDS,
} WasmExternalKind;
-extern const char* g_wasm_kind_name[];
-
-static WASM_INLINE const char* wasm_get_kind_name(WasmExternalKind kind) {
- assert(kind < WASM_NUM_EXTERNAL_KINDS);
- return g_wasm_kind_name[kind];
-}
-
typedef struct WasmLimits {
uint64_t initial;
uint64_t max;
@@ -390,6 +383,7 @@ WasmBool wasm_is_naturally_aligned(WasmOpcode opcode, uint32_t alignment);
uint32_t wasm_get_opcode_alignment(WasmOpcode opcode, uint32_t alignment);
WasmStringSlice wasm_empty_string_slice(void);
+WasmStringSlice wasm_string_slice_from_cstr(const char* string);
WasmBool wasm_string_slices_are_equal(const WasmStringSlice*,
const WasmStringSlice*);
void wasm_destroy_string_slice(struct WasmAllocator*, WasmStringSlice*);
@@ -452,6 +446,15 @@ static WASM_INLINE int wasm_get_opcode_memory_size(WasmOpcode opcode) {
return g_wasm_opcode_info[opcode].memory_size;
}
+/* external kind */
+
+extern const char* g_wasm_kind_name[];
+
+static WASM_INLINE const char* wasm_get_kind_name(WasmExternalKind kind) {
+ assert(kind < WASM_NUM_EXTERNAL_KINDS);
+ return g_wasm_kind_name[kind];
+}
+
WASM_EXTERN_C_END
#endif /* WASM_COMMON_H_ */
diff --git a/src/wasm-interpreter.c b/src/wasm-interpreter.c
index 66d3042e..c004ce80 100644
--- a/src/wasm-interpreter.c
+++ b/src/wasm-interpreter.c
@@ -22,6 +22,8 @@
#include "wasm-stream.h"
+#define INITIAL_ISTREAM_CAPACITY (64 * 1024)
+
#define V(rtype, type1, type2, mem_size, code, NAME, text) [code] = text,
static const char* s_interpreter_opcode_name[] = {
WASM_FOREACH_OPCODE(V)
@@ -44,47 +46,127 @@ static const char* wasm_get_interpreter_opcode_name(uint8_t opcode) {
return s_interpreter_opcode_name[opcode];
}
-static WasmResult trapping_host_func_callback(
- const WasmInterpreterFuncSignature* sig,
- const WasmStringSlice* module_name,
- const WasmStringSlice* field_name,
- uint32_t num_args,
- WasmInterpreterTypedValue* args,
- uint32_t num_results,
- WasmInterpreterTypedValue* out_results,
- void* user_data) {
- return WASM_ERROR;
+void wasm_init_interpreter_environment(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env) {
+ WASM_ZERO_MEMORY(*env);
+ wasm_init_output_buffer(allocator, &env->istream, INITIAL_ISTREAM_CAPACITY);
+}
+
+static void wasm_destroy_interpreter_func_signature(
+ WasmAllocator* allocator,
+ WasmInterpreterFuncSignature* sig) {
+ wasm_destroy_type_vector(allocator, &sig->param_types);
+ wasm_destroy_type_vector(allocator, &sig->result_types);
+}
+
+static void wasm_destroy_interpreter_func(
+ WasmAllocator* allocator,
+ WasmInterpreterFunc* func) {
+ if (!func->is_host)
+ wasm_destroy_type_vector(allocator, &func->defined.param_and_local_types);
+}
+
+static void wasm_destroy_interpreter_memory(WasmAllocator* unused,
+ WasmInterpreterMemory* memory) {
+ if (memory->allocator) {
+ wasm_free(memory->allocator, memory->data);
+ } else {
+ assert(memory->data == NULL);
+ }
+}
+
+static void wasm_destroy_interpreter_table(WasmAllocator* allocator,
+ WasmInterpreterTable* table) {
+ wasm_destroy_uint32_array(allocator, &table->func_indexes);
+}
+
+static void wasm_destroy_interpreter_import(WasmAllocator* allocator,
+ WasmInterpreterImport* import) {
+ wasm_destroy_string_slice(allocator, &import->module_name);
+ wasm_destroy_string_slice(allocator, &import->field_name);
+}
+
+static void wasm_destroy_interpreter_module(WasmAllocator* allocator,
+ WasmInterpreterModule* module) {
+ wasm_destroy_interpreter_export_vector(allocator, &module->exports);
+ wasm_destroy_binding_hash(allocator, &module->export_bindings);
+ if (!module->is_host) {
+ WASM_DESTROY_ARRAY_AND_ELEMENTS(allocator, module->defined.imports,
+ interpreter_import);
+ }
+}
+
+void wasm_destroy_interpreter_environment(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env) {
+ WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, env->modules,
+ interpreter_module);
+ WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, env->sigs,
+ interpreter_func_signature);
+ WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, env->funcs, interpreter_func);
+ WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, env->memories,
+ interpreter_memory);
+ WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, env->tables, interpreter_table);
+ wasm_destroy_interpreter_global_vector(allocator, &env->globals);
+ wasm_destroy_output_buffer(&env->istream);
+ wasm_destroy_binding_hash(allocator, &env->module_bindings);
+}
+
+WasmInterpreterModule* wasm_append_host_module(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env,
+ WasmStringSlice name) {
+ WasmInterpreterModule* module =
+ wasm_append_interpreter_module(allocator, &env->modules);
+ module->name = wasm_dup_string_slice(allocator, name);
+ module->memory_index = WASM_INVALID_INDEX;
+ module->table_index = WASM_INVALID_INDEX;
+ module->is_host = WASM_TRUE;
+
+ WasmBinding* binding =
+ wasm_insert_binding(allocator, &env->module_bindings, &module->name);
+ binding->index = env->modules.size - 1;
+ return module;
}
WasmResult wasm_init_interpreter_thread(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env,
WasmInterpreterModule* module,
WasmInterpreterThread* thread,
WasmInterpreterThreadOptions* options) {
+ assert(!module->is_host);
+ WASM_ZERO_MEMORY(*thread);
wasm_new_interpreter_value_array(allocator, &thread->value_stack,
options->value_stack_size);
wasm_new_uint32_array(allocator, &thread->call_stack,
options->call_stack_size);
+ thread->env = env;
+ thread->module = module;
thread->value_stack_top = thread->value_stack.data;
thread->value_stack_end = thread->value_stack.data + thread->value_stack.size;
thread->call_stack_top = thread->call_stack.data;
thread->call_stack_end = thread->call_stack.data + thread->call_stack.size;
thread->pc = options->pc;
- thread->host_func.callback = trapping_host_func_callback;
+ /* cache this module's memory and table, for convenience */
+ if (module->memory_index != WASM_INVALID_INDEX)
+ thread->memory = &env->memories.data[module->memory_index];
+ if (module->table_index != WASM_INVALID_INDEX)
+ thread->table = &env->tables.data[module->table_index];
- /* allocate import_args based on the signature with the most params */
+ /* allocate host_args based on the signature with the most params */
/* TODO(binji): move this elsewhere? */
uint32_t i;
- uint32_t max_import_params = 0;
- for (i = 0; i < module->funcs.size; ++i) {
- WasmInterpreterFunc* func = &module->funcs.data[i];
- assert(func->sig_index < module->sigs.size);
- WasmInterpreterFuncSignature* sig = &module->sigs.data[func->sig_index];
- if (sig->param_types.size > max_import_params)
- max_import_params = sig->param_types.size;
+ uint32_t max_host_params = 0;
+ for (i = 0; i < env->funcs.size; ++i) {
+ WasmInterpreterFunc* func = &env->funcs.data[i];
+ if (!func->is_host)
+ continue;
+ assert(func->sig_index < env->sigs.size);
+ WasmInterpreterFuncSignature* sig = &env->sigs.data[func->sig_index];
+ if (sig->param_types.size > max_host_params)
+ max_host_params = sig->param_types.size;
}
- wasm_new_interpreter_typed_value_array(allocator, &thread->import_args,
- max_import_params);
+ wasm_new_interpreter_typed_value_array(allocator, &thread->host_args,
+ max_host_params);
return WASM_OK;
}
@@ -99,35 +181,19 @@ WasmInterpreterResult wasm_push_thread_value(WasmInterpreterThread* thread,
WasmInterpreterExport* wasm_get_interpreter_export_by_name(
WasmInterpreterModule* module,
WasmStringSlice* name) {
- uint32_t i;
- for (i = 0; i < module->exports.size; ++i) {
- WasmInterpreterExport* export = &module->exports.data[i];
- if (wasm_string_slices_are_equal(name, &export->name))
- return export;
- }
- return NULL;
-}
-
-WasmInterpreterImport* wasm_get_interpreter_import_by_name(
- WasmInterpreterModule* module,
- WasmStringSlice* module_name,
- WasmStringSlice* func_name) {
- uint32_t i;
- for (i = 0; i < module->imports.size; ++i) {
- WasmInterpreterImport* import = &module->imports.data[i];
- if (wasm_string_slices_are_equal(module_name, &import->module_name) &&
- wasm_string_slices_are_equal(func_name, &import->field_name)) {
- return import;
- }
- }
- return NULL;
+ int field_index =
+ wasm_find_binding_index_by_name(&module->export_bindings, name);
+ if (field_index < 0)
+ return NULL;
+ assert((size_t)field_index < module->exports.size);
+ return &module->exports.data[field_index];
}
void wasm_destroy_interpreter_thread(WasmAllocator* allocator,
WasmInterpreterThread* thread) {
wasm_destroy_interpreter_value_array(allocator, &thread->value_stack);
wasm_destroy_uint32_array(allocator, &thread->call_stack);
- wasm_destroy_interpreter_typed_value_array(allocator, &thread->import_args);
+ wasm_destroy_interpreter_typed_value_array(allocator, &thread->host_args);
}
/* 3 32222222 222...00
@@ -421,26 +487,26 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double)
#define POP_CALL() (*--thread->call_stack_top)
-#define LOAD(type, mem_type) \
- do { \
- uint64_t offset = (uint64_t)POP_I32() + read_u32(&pc); \
- MEM_TYPE_##mem_type value; \
- TRAP_IF(offset + sizeof(value) > module->memory.byte_size, \
- MEMORY_ACCESS_OUT_OF_BOUNDS); \
- void* src = (void*)((intptr_t)module->memory.data + (uint32_t)offset); \
- memcpy(&value, src, sizeof(MEM_TYPE_##mem_type)); \
- PUSH_##type((MEM_TYPE_EXTEND_##type##_##mem_type)value); \
+#define LOAD(type, mem_type) \
+ do { \
+ uint64_t offset = (uint64_t)POP_I32() + read_u32(&pc); \
+ MEM_TYPE_##mem_type value; \
+ TRAP_IF(offset + sizeof(value) > thread->memory->byte_size, \
+ MEMORY_ACCESS_OUT_OF_BOUNDS); \
+ void* src = (void*)((intptr_t)thread->memory->data + (uint32_t)offset); \
+ memcpy(&value, src, sizeof(MEM_TYPE_##mem_type)); \
+ PUSH_##type((MEM_TYPE_EXTEND_##type##_##mem_type)value); \
} while (0)
-#define STORE(type, mem_type) \
- do { \
- VALUE_TYPE_##type value = POP_##type(); \
- uint64_t offset = (uint64_t)POP_I32() + read_u32(&pc); \
- MEM_TYPE_##mem_type src = (MEM_TYPE_##mem_type)value; \
- TRAP_IF(offset + sizeof(src) > module->memory.byte_size, \
- MEMORY_ACCESS_OUT_OF_BOUNDS); \
- void* dst = (void*)((intptr_t)module->memory.data + (uint32_t)offset); \
- memcpy(dst, &src, sizeof(MEM_TYPE_##mem_type)); \
+#define STORE(type, mem_type) \
+ do { \
+ VALUE_TYPE_##type value = POP_##type(); \
+ uint64_t offset = (uint64_t)POP_I32() + read_u32(&pc); \
+ MEM_TYPE_##mem_type src = (MEM_TYPE_##mem_type)value; \
+ TRAP_IF(offset + sizeof(src) > thread->memory->byte_size, \
+ MEMORY_ACCESS_OUT_OF_BOUNDS); \
+ void* dst = (void*)((intptr_t)thread->memory->data + (uint32_t)offset); \
+ memcpy(dst, &src, sizeof(MEM_TYPE_##mem_type)); \
} while (0)
#define BINOP(rtype, type, op) \
@@ -625,32 +691,31 @@ static WASM_INLINE void read_table_entry_at(const uint8_t* pc,
*out_keep = *(pc + WASM_TABLE_ENTRY_KEEP_OFFSET);
}
-static WasmBool signatures_are_equal(WasmInterpreterModule* module,
+static WasmBool signatures_are_equal(WasmInterpreterEnvironment* env,
uint32_t sig_index_0,
uint32_t sig_index_1) {
if (sig_index_0 == sig_index_1)
return WASM_TRUE;
- WasmInterpreterFuncSignature* sig_0 = &module->sigs.data[sig_index_0];
- WasmInterpreterFuncSignature* sig_1 = &module->sigs.data[sig_index_1];
+ WasmInterpreterFuncSignature* sig_0 = &env->sigs.data[sig_index_0];
+ WasmInterpreterFuncSignature* sig_1 = &env->sigs.data[sig_index_1];
return wasm_type_vectors_are_equal(&sig_0->param_types,
&sig_1->param_types) &&
wasm_type_vectors_are_equal(&sig_0->result_types,
&sig_1->result_types);
}
-WasmInterpreterResult wasm_call_host(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
- WasmInterpreterImport* import) {
- uint32_t sig_index = import->func.sig_index;
- assert(sig_index < module->sigs.size);
- WasmInterpreterFuncSignature* sig = &module->sigs.data[sig_index];
+WasmInterpreterResult wasm_call_host(WasmInterpreterThread* thread,
+ WasmInterpreterFunc* func) {
+ assert(func->is_host);
+ assert(func->sig_index < thread->env->sigs.size);
+ WasmInterpreterFuncSignature* sig = &thread->env->sigs.data[func->sig_index];
uint32_t num_args = sig->param_types.size;
uint32_t i;
- assert(num_args <= thread->import_args.size);
+ assert(num_args <= thread->host_args.size);
for (i = num_args; i > 0; --i) {
WasmInterpreterValue value = POP();
- WasmInterpreterTypedValue* arg = &thread->import_args.data[i - 1];
+ WasmInterpreterTypedValue* arg = &thread->host_args.data[i - 1];
arg->type = sig->param_types.data[i - 1];
arg->value = value;
}
@@ -659,11 +724,9 @@ WasmInterpreterResult wasm_call_host(WasmInterpreterModule* module,
WasmInterpreterTypedValue* call_result_values =
alloca(sizeof(WasmInterpreterTypedValue) * num_results);
- assert(thread->host_func.callback);
- WasmResult call_result = thread->host_func.callback(
- sig, &import->module_name, &import->field_name, num_args,
- thread->import_args.data, num_results, call_result_values,
- thread->host_func.user_data);
+ WasmResult call_result = func->host.callback(
+ func, sig, num_args, thread->host_args.data, num_results,
+ call_result_values, func->host.user_data);
TRAP_IF(call_result != WASM_OK, HOST_TRAPPED);
for (i = 0; i < num_results; ++i) {
@@ -675,14 +738,16 @@ WasmInterpreterResult wasm_call_host(WasmInterpreterModule* module,
return WASM_INTERPRETER_OK;
}
-WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
+WasmInterpreterResult wasm_run_interpreter(WasmInterpreterThread* thread,
uint32_t num_instructions,
uint32_t* call_stack_return_top) {
WasmInterpreterResult result = WASM_INTERPRETER_OK;
assert(call_stack_return_top < thread->call_stack_end);
- const uint8_t* istream = module->istream.start;
+ WasmInterpreterEnvironment* env = thread->env;
+ WasmInterpreterModule* module = thread->module;
+
+ const uint8_t* istream = env->istream.start;
const uint8_t* pc = &istream[thread->pc];
uint32_t i;
for (i = 0; i < num_instructions; ++i) {
@@ -753,15 +818,15 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
case WASM_OPCODE_GET_GLOBAL: {
uint32_t index = read_u32(&pc);
- assert(index < module->globals.size);
- PUSH(module->globals.data[index].typed_value.value);
+ assert(index < env->globals.size);
+ PUSH(env->globals.data[index].typed_value.value);
break;
}
case WASM_OPCODE_SET_GLOBAL: {
uint32_t index = read_u32(&pc);
- assert(index < module->globals.size);
- module->globals.data[index].typed_value.value = POP();
+ assert(index < env->globals.size);
+ env->globals.data[index].typed_value.value = POP();
break;
}
@@ -789,36 +854,29 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
}
case WASM_OPCODE_CALL_INDIRECT: {
+ WasmInterpreterTable* table = &env->tables.data[module->table_index];
uint32_t sig_index = read_u32(&pc);
- assert(sig_index < module->sigs.size);
+ assert(sig_index < env->sigs.size);
VALUE_TYPE_I32 entry_index = POP_I32();
- TRAP_IF(entry_index >= module->func_table.size, UNDEFINED_TABLE_INDEX);
- uint32_t func_index = module->func_table.data[entry_index];
- WasmInterpreterFunc* func = &module->funcs.data[func_index];
+ TRAP_IF(entry_index >= table->func_indexes.size, UNDEFINED_TABLE_INDEX);
+ uint32_t func_index = table->func_indexes.data[entry_index];
+ WasmInterpreterFunc* func = &env->funcs.data[func_index];
+ TRAP_UNLESS(signatures_are_equal(env, func->sig_index, sig_index),
+ INDIRECT_CALL_SIGNATURE_MISMATCH);
if (func->is_host) {
- TRAP_UNLESS(signatures_are_equal(module, func->sig_index, sig_index),
- INDIRECT_CALL_SIGNATURE_MISMATCH);
- uint32_t import_index = func->import_index;
- assert(import_index < module->imports.size);
- WasmInterpreterImport* import = &module->imports.data[import_index];
- wasm_call_host(module, thread, import);
+ wasm_call_host(thread, func);
} else {
- TRAP_UNLESS(signatures_are_equal(module, func->sig_index, sig_index),
- INDIRECT_CALL_SIGNATURE_MISMATCH);
PUSH_CALL();
- GOTO(func->offset);
+ GOTO(func->defined.offset);
}
break;
}
case WASM_OPCODE_CALL_HOST: {
uint32_t func_index = read_u32(&pc);
- assert(func_index < module->funcs.size);
- WasmInterpreterFunc* func = &module->funcs.data[func_index];
- uint32_t import_index = func->import_index;
- assert(import_index < module->imports.size);
- WasmInterpreterImport* import = &module->imports.data[import_index];
- wasm_call_host(module, thread, import);
+ assert(func_index < env->funcs.size);
+ WasmInterpreterFunc* func = &env->funcs.data[func_index];
+ wasm_call_host(thread, func);
break;
}
@@ -915,27 +973,27 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
break;
case WASM_OPCODE_CURRENT_MEMORY:
- PUSH_I32(module->memory.page_size);
+ PUSH_I32(thread->memory->page_size);
break;
case WASM_OPCODE_GROW_MEMORY: {
- uint32_t old_page_size = module->memory.page_size;
- uint32_t old_byte_size = module->memory.byte_size;
+ uint32_t old_page_size = thread->memory->page_size;
+ uint32_t old_byte_size = thread->memory->byte_size;
VALUE_TYPE_I32 grow_pages = POP_I32();
uint32_t new_page_size = old_page_size + grow_pages;
- PUSH_NEG_1_AND_BREAK_IF(new_page_size > module->memory.max_page_size);
+ PUSH_NEG_1_AND_BREAK_IF(new_page_size > thread->memory->max_page_size);
PUSH_NEG_1_AND_BREAK_IF((uint64_t)new_page_size * WASM_PAGE_SIZE >
UINT32_MAX);
uint32_t new_byte_size = new_page_size * WASM_PAGE_SIZE;
- WasmAllocator* allocator = module->memory.allocator;
- void* new_data = wasm_realloc(allocator, module->memory.data,
+ WasmAllocator* allocator = thread->memory->allocator;
+ void* new_data = wasm_realloc(allocator, thread->memory->data,
new_byte_size, WASM_DEFAULT_ALIGN);
PUSH_NEG_1_AND_BREAK_IF(new_data == NULL);
memset((void*)((intptr_t)new_data + old_byte_size), 0,
new_byte_size - old_byte_size);
- module->memory.data = new_data;
- module->memory.page_size = new_page_size;
- module->memory.byte_size = new_byte_size;
+ thread->memory->data = new_data;
+ thread->memory->page_size = new_page_size;
+ thread->memory->byte_size = new_byte_size;
PUSH_I32(old_page_size);
break;
}
@@ -1581,16 +1639,14 @@ exit_loop:
return result;
}
-void wasm_trace_pc(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
- WasmStream* stream) {
- const uint8_t* istream = module->istream.start;
+void wasm_trace_pc(WasmInterpreterThread* thread, WasmStream* stream) {
+ const uint8_t* istream = thread->env->istream.start;
const uint8_t* pc = &istream[thread->pc];
size_t value_stack_depth = thread->value_stack_top - thread->value_stack.data;
size_t call_stack_depth = thread->call_stack_top - thread->call_stack.data;
wasm_writef(stream, "#%" PRIzd ". %4" PRIzd ": V:%-3" PRIzd "| ",
- call_stack_depth, pc - (uint8_t*)module->istream.start,
+ call_stack_depth, pc - (uint8_t*)thread->env->istream.start,
value_stack_depth);
uint8_t opcode = *pc++;
@@ -1934,17 +1990,17 @@ void wasm_trace_pc(WasmInterpreterModule* module,
}
}
-void wasm_disassemble_module(WasmInterpreterModule* module,
- WasmStream* stream,
- uint32_t from,
- uint32_t to) {
+void wasm_disassemble(WasmInterpreterEnvironment* env,
+ WasmStream* stream,
+ uint32_t from,
+ uint32_t to) {
/* TODO(binji): mark function entries */
/* TODO(binji): track value stack size */
- if (from >= module->istream.size)
+ if (from >= env->istream.size)
return;
- if (to > module->istream.size)
- to = module->istream.size;
- const uint8_t* istream = module->istream.start;
+ if (to > env->istream.size)
+ to = env->istream.size;
+ const uint8_t* istream = env->istream.start;
const uint8_t* pc = &istream[from];
while ((uint32_t)(pc - istream) < to) {
@@ -2247,49 +2303,11 @@ void wasm_disassemble_module(WasmInterpreterModule* module,
}
}
-static void wasm_destroy_memory(WasmInterpreterMemory* memory) {
- if (memory->allocator) {
- wasm_free(memory->allocator, memory->data);
- } else {
- assert(memory->data == NULL);
- }
-}
-
-static void wasm_destroy_interpreter_func_signature(
- WasmAllocator* allocator,
- WasmInterpreterFuncSignature* sig) {
- wasm_destroy_type_vector(allocator, &sig->param_types);
- wasm_destroy_type_vector(allocator, &sig->result_types);
-}
-
-static void wasm_destroy_interpreter_func(
- WasmAllocator* allocator,
- WasmInterpreterFunc* func) {
- wasm_destroy_type_vector(allocator, &func->param_and_local_types);
-}
-
-static void wasm_destroy_interpreter_import(WasmAllocator* allocator,
- WasmInterpreterImport* import) {
- wasm_destroy_string_slice(allocator, &import->module_name);
- wasm_destroy_string_slice(allocator, &import->field_name);
-}
-
-static void wasm_destroy_interpreter_export(WasmAllocator* allocator,
- WasmInterpreterExport* export) {
- wasm_destroy_string_slice(allocator, &export->name);
+void wasm_disassemble_module(WasmInterpreterEnvironment* env,
+ WasmStream* stream,
+ WasmInterpreterModule* module) {
+ assert(!module->is_host);
+ wasm_disassemble(env, stream, module->defined.istream_start,
+ module->defined.istream_end);
}
-void wasm_destroy_interpreter_module(WasmAllocator* allocator,
- WasmInterpreterModule* module) {
- wasm_destroy_memory(&module->memory);
- WASM_DESTROY_ARRAY_AND_ELEMENTS(allocator, module->sigs,
- interpreter_func_signature);
- WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, module->funcs, interpreter_func);
- wasm_destroy_uint32_array(allocator, &module->func_table);
- WASM_DESTROY_ARRAY_AND_ELEMENTS(allocator, module->imports,
- interpreter_import);
- WASM_DESTROY_ARRAY_AND_ELEMENTS(allocator, module->exports,
- interpreter_export);
- wasm_destroy_interpreter_global_array(allocator, &module->globals);
- wasm_destroy_output_buffer(&module->istream);
-}
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index b172e5ca..2b470348 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include "wasm-array.h"
+#include "wasm-binding-hash.h"
#include "wasm-type-vector.h"
#include "wasm-vector.h"
#include "wasm-writer.h"
@@ -60,7 +61,7 @@ typedef enum WasmInterpreterResult {
#undef V
} WasmInterpreterResult;
-#define WASM_INVALID_FUNC_INDEX ((uint32_t)~0)
+#define WASM_INVALID_INDEX ((uint32_t)~0)
#define WASM_INVALID_OFFSET ((uint32_t)~0)
#define WASM_TABLE_ENTRY_SIZE (sizeof(uint32_t) * 2 + sizeof(uint8_t))
#define WASM_TABLE_ENTRY_OFFSET_OFFSET 0
@@ -78,12 +79,21 @@ enum {
};
WASM_STATIC_ASSERT(WASM_NUM_INTERPRETER_OPCODES <= 256);
+typedef uint32_t WasmUint32;
+WASM_DEFINE_ARRAY(uint32, WasmUint32);
+
/* TODO(binji): identical to WasmFuncSignature. Share? */
typedef struct WasmInterpreterFuncSignature {
WasmTypeVector param_types;
WasmTypeVector result_types;
} WasmInterpreterFuncSignature;
-WASM_DEFINE_ARRAY(interpreter_func_signature, WasmInterpreterFuncSignature);
+WASM_DEFINE_VECTOR(interpreter_func_signature, WasmInterpreterFuncSignature);
+
+typedef struct WasmInterpreterTable {
+ WasmLimits limits;
+ WasmUint32Array func_indexes;
+} WasmInterpreterTable;
+WASM_DEFINE_VECTOR(interpreter_table, WasmInterpreterTable);
typedef struct WasmInterpreterMemory {
WasmAllocator* allocator;
@@ -92,12 +102,7 @@ typedef struct WasmInterpreterMemory {
uint32_t byte_size;
uint32_t max_page_size;
} WasmInterpreterMemory;
-
-typedef struct WasmInterpreterFuncTableEntry {
- uint32_t sig_index;
- uint32_t func_index;
-} WasmInterpreterFuncTableEntry;
-WASM_DEFINE_ARRAY(interpreter_func_table_entry, WasmInterpreterFuncTableEntry);
+WASM_DEFINE_VECTOR(interpreter_memory, WasmInterpreterMemory);
typedef union WasmInterpreterValue {
uint32_t i32;
@@ -117,8 +122,9 @@ WASM_DEFINE_VECTOR(interpreter_typed_value, WasmInterpreterTypedValue);
typedef struct WasmInterpreterGlobal {
WasmInterpreterTypedValue typed_value;
WasmBool mutable_;
+ uint32_t import_index; /* or INVALID_INDEX if not imported */
} WasmInterpreterGlobal;
-WASM_DEFINE_ARRAY(interpreter_global, WasmInterpreterGlobal);
+WASM_DEFINE_VECTOR(interpreter_global, WasmInterpreterGlobal);
typedef struct WasmInterpreterImport {
WasmStringSlice module_name;
@@ -128,56 +134,109 @@ typedef struct WasmInterpreterImport {
struct {
uint32_t sig_index;
} func;
+ struct {
+ WasmLimits limits;
+ } table, memory;
+ struct {
+ WasmType type;
+ WasmBool mutable_;
+ } global;
};
} WasmInterpreterImport;
-typedef WasmInterpreterImport* WasmInterpreterImportPtr;
WASM_DEFINE_ARRAY(interpreter_import, WasmInterpreterImport);
-WASM_DEFINE_ARRAY(interpreter_import_ptr, WasmInterpreterImportPtr);
+
+struct WasmInterpreterFunc;
+
+typedef WasmResult (*WasmInterpreterHostFuncCallback)(
+ const struct WasmInterpreterFunc* func,
+ const WasmInterpreterFuncSignature* sig,
+ uint32_t num_args,
+ WasmInterpreterTypedValue* args,
+ uint32_t num_results,
+ WasmInterpreterTypedValue* out_results,
+ void* user_data);
typedef struct WasmInterpreterFunc {
uint32_t sig_index;
- uint32_t offset;
- uint32_t local_decl_count;
- uint32_t local_count;
- WasmTypeVector param_and_local_types;
WasmBool is_host;
- uint32_t import_index; /* or INVALID_FUNC_INDEX if not imported */
+ union {
+ struct {
+ uint32_t offset;
+ uint32_t local_decl_count;
+ uint32_t local_count;
+ WasmTypeVector param_and_local_types;
+ } defined;
+ struct {
+ WasmStringSlice module_name;
+ WasmStringSlice field_name;
+ WasmInterpreterHostFuncCallback callback;
+ void* user_data;
+ } host;
+ };
} WasmInterpreterFunc;
WASM_DEFINE_VECTOR(interpreter_func, WasmInterpreterFunc);
typedef struct WasmInterpreterExport {
- WasmStringSlice name;
+ WasmStringSlice name; /* Owned by the export_bindings hash */
WasmExternalKind kind;
uint32_t index;
} WasmInterpreterExport;
-WASM_DEFINE_ARRAY(interpreter_export, WasmInterpreterExport);
+WASM_DEFINE_VECTOR(interpreter_export, WasmInterpreterExport);
-typedef uint32_t WasmUint32;
-WASM_DEFINE_ARRAY(uint32, WasmUint32);
+typedef struct WasmInterpreterHostImportDelegate {
+ void *user_data;
+ WasmResult (*import_func)(WasmInterpreterImport*,
+ WasmInterpreterFunc*,
+ WasmInterpreterFuncSignature*,
+ void* user_data);
+ WasmResult (*import_table)(WasmInterpreterImport*,
+ WasmInterpreterTable*,
+ void* user_data);
+ WasmResult (*import_memory)(WasmInterpreterImport*,
+ WasmInterpreterMemory*,
+ void* user_data);
+ WasmResult (*import_global)(WasmInterpreterImport*,
+ WasmInterpreterGlobal*,
+ void* user_data);
+} WasmInterpreterHostImportDelegate;
typedef struct WasmInterpreterModule {
- WasmInterpreterMemory memory;
- WasmInterpreterFuncSignatureArray sigs;
- WasmInterpreterFuncVector funcs;
- WasmUint32Array func_table;
- WasmInterpreterImportArray imports;
- WasmInterpreterExportArray exports;
- WasmInterpreterGlobalArray globals;
- WasmOutputBuffer istream;
- uint32_t start_func_index; /* == INVALID_FUNC_INDEX if not defined */
+ WasmStringSlice name;
+ WasmInterpreterExportVector exports;
+ WasmBindingHash export_bindings;
+ uint32_t memory_index; /* INVALID_INDEX if not defined */
+ uint32_t table_index; /* INVALID_INDEX if not defined */
+ WasmBool is_host;
+ union {
+ struct {
+ WasmInterpreterImportArray imports;
+ uint32_t start_func_index; /* INVALID_INDEX if not defined */
+ size_t istream_start;
+ size_t istream_end;
+ } defined;
+ struct {
+ WasmInterpreterHostImportDelegate import_delegate;
+ } host;
+ };
} WasmInterpreterModule;
+WASM_DEFINE_VECTOR(interpreter_module, WasmInterpreterModule);
-typedef WasmResult (*WasmInterpreterHostFuncCallback)(
- const WasmInterpreterFuncSignature* sig,
- const WasmStringSlice* module_name,
- const WasmStringSlice* field_name,
- uint32_t num_args,
- WasmInterpreterTypedValue* args,
- uint32_t num_results,
- WasmInterpreterTypedValue* out_results,
- void* user_data);
+typedef struct WasmInterpreterEnvironment {
+ WasmInterpreterModuleVector modules;
+ WasmInterpreterFuncSignatureVector sigs;
+ WasmInterpreterFuncVector funcs;
+ WasmInterpreterMemoryVector memories;
+ WasmInterpreterTableVector tables;
+ WasmInterpreterGlobalVector globals;
+ WasmOutputBuffer istream;
+ WasmBindingHash module_bindings;
+} WasmInterpreterEnvironment;
typedef struct WasmInterpreterThread {
+ WasmInterpreterEnvironment* env;
+ WasmInterpreterModule* module;
+ WasmInterpreterTable* table;
+ WasmInterpreterMemory* memory;
WasmInterpreterValueArray value_stack;
WasmUint32Array call_stack;
WasmInterpreterValue* value_stack_top;
@@ -186,13 +245,8 @@ typedef struct WasmInterpreterThread {
uint32_t* call_stack_end;
uint32_t pc;
- struct {
- WasmInterpreterHostFuncCallback callback;
- void* user_data;
- } host_func;
-
- /* a temporary buffer that is for passing args to import functions */
- WasmInterpreterTypedValueArray import_args;
+ /* a temporary buffer that is for passing args to host functions */
+ WasmInterpreterTypedValueArray host_args;
} WasmInterpreterThread;
#define WASM_INTERPRETER_THREAD_OPTIONS_DEFAULT \
@@ -205,7 +259,15 @@ typedef struct WasmInterpreterThreadOptions {
} WasmInterpreterThreadOptions;
WASM_EXTERN_C_BEGIN
+void wasm_init_interpreter_environment(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env);
+void wasm_destroy_interpreter_environment(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env);
+WasmInterpreterModule* wasm_append_host_module(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env,
+ WasmStringSlice name);
WasmResult wasm_init_interpreter_thread(WasmAllocator* allocator,
+ WasmInterpreterEnvironment* env,
WasmInterpreterModule* module,
WasmInterpreterThread* thread,
WasmInterpreterThreadOptions* options);
@@ -213,22 +275,19 @@ WasmInterpreterResult wasm_push_thread_value(WasmInterpreterThread* thread,
WasmInterpreterValue value);
void wasm_destroy_interpreter_thread(WasmAllocator* allocator,
WasmInterpreterThread* thread);
-WasmInterpreterResult wasm_call_host(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
- WasmInterpreterImport* import);
-WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
+WasmInterpreterResult wasm_call_host(WasmInterpreterThread* thread,
+ WasmInterpreterFunc* func);
+WasmInterpreterResult wasm_run_interpreter(WasmInterpreterThread* thread,
uint32_t num_instructions,
uint32_t* call_stack_return_top);
-void wasm_trace_pc(WasmInterpreterModule* module,
- WasmInterpreterThread* thread,
- struct WasmStream* stream);
-void wasm_disassemble_module(WasmInterpreterModule* module,
+void wasm_trace_pc(WasmInterpreterThread* thread, struct WasmStream* stream);
+void wasm_disassemble(WasmInterpreterEnvironment* env,
+ struct WasmStream* stream,
+ uint32_t from,
+ uint32_t to);
+void wasm_disassemble_module(WasmInterpreterEnvironment* env,
struct WasmStream* stream,
- uint32_t from,
- uint32_t to);
-void wasm_destroy_interpreter_module(WasmAllocator* allocator,
- WasmInterpreterModule* module);
+ WasmInterpreterModule* module);
WasmInterpreterExport* wasm_get_interpreter_export_by_name(
WasmInterpreterModule* module,
diff --git a/src/wasm-writer.c b/src/wasm-writer.c
index 1805078e..bef915b0 100644
--- a/src/wasm-writer.c
+++ b/src/wasm-writer.c
@@ -85,9 +85,10 @@ void wasm_close_file_writer(WasmFileWriter* writer) {
fclose(writer->file);
}
-static void init_output_buffer(WasmAllocator* allocator,
- WasmOutputBuffer* buf,
- size_t initial_capacity) {
+void wasm_init_output_buffer(WasmAllocator* allocator,
+ WasmOutputBuffer* buf,
+ size_t initial_capacity) {
+ assert(initial_capacity != 0);
buf->allocator = allocator;
buf->start = wasm_alloc(allocator, initial_capacity, WASM_DEFAULT_ALIGN);
buf->size = 0;
@@ -97,6 +98,7 @@ static void init_output_buffer(WasmAllocator* allocator,
static void ensure_output_buffer_capacity(WasmOutputBuffer* buf,
size_t ensure_capacity) {
if (ensure_capacity > buf->capacity) {
+ assert(buf->capacity != 0);
size_t new_capacity = buf->capacity * 2;
while (new_capacity < ensure_capacity)
new_capacity *= 2;
@@ -142,7 +144,20 @@ WasmResult wasm_init_mem_writer(WasmAllocator* allocator,
writer->base.user_data = writer;
writer->base.write_data = write_data_to_output_buffer;
writer->base.move_data = move_data_in_output_buffer;
- init_output_buffer(allocator, &writer->buf, INITIAL_OUTPUT_BUFFER_CAPACITY);
+ wasm_init_output_buffer(allocator, &writer->buf,
+ INITIAL_OUTPUT_BUFFER_CAPACITY);
+ return WASM_OK;
+}
+
+WasmResult wasm_init_mem_writer_existing(WasmMemoryWriter* writer,
+ WasmOutputBuffer* buf) {
+ WASM_ZERO_MEMORY(*writer);
+ writer->base.user_data = writer;
+ writer->base.write_data = write_data_to_output_buffer;
+ writer->base.move_data = move_data_in_output_buffer;
+ writer->buf = *buf;
+ /* Clear buffer, since ownership has passed to the writer. */
+ WASM_ZERO_MEMORY(*buf);
return WASM_OK;
}
diff --git a/src/wasm-writer.h b/src/wasm-writer.h
index 11382a18..ad6046fd 100644
--- a/src/wasm-writer.h
+++ b/src/wasm-writer.h
@@ -62,11 +62,17 @@ void wasm_close_file_writer(WasmFileWriter* writer);
/* WasmMemoryWriter */
WasmResult wasm_init_mem_writer(WasmAllocator* allocator,
WasmMemoryWriter* writer);
+/* Passes ownership of the buffer to writer */
+WasmResult wasm_init_mem_writer_existing(WasmMemoryWriter* writer,
+ WasmOutputBuffer* buf);
void wasm_steal_mem_writer_output_buffer(WasmMemoryWriter* writer,
WasmOutputBuffer* out_buf);
void wasm_close_mem_writer(WasmMemoryWriter* writer);
/* WasmOutputBuffer */
+void wasm_init_output_buffer(WasmAllocator* allocator,
+ WasmOutputBuffer* buf,
+ size_t initial_capacity);
WasmResult wasm_write_output_buffer_to_file(WasmOutputBuffer* buf,
const char* filename);
void wasm_destroy_output_buffer(WasmOutputBuffer* buf);
diff --git a/test/binary/bad-data-size.txt b/test/binary/bad-data-size.txt
index 9ae34b53..3d60af8e 100644
--- a/test/binary/bad-data-size.txt
+++ b/test/binary/bad-data-size.txt
@@ -15,6 +15,7 @@ section(DATA) {
}
(;; STDERR ;;;
Error running "wasm-interp":
+error: data segment is out of bounds: [0, 8) >= max value 0
error: @0x0000001d: on_data_segment_data callback failed
;;; STDERR ;;)
diff --git a/test/interp/callimport-zero-args.txt b/test/interp/callimport-zero-args.txt
index 4ef162c7..68c86b18 100644
--- a/test/interp/callimport-zero-args.txt
+++ b/test/interp/callimport-zero-args.txt
@@ -1,12 +1,12 @@
;;; TOOL: run-interp
(module
- (import "foo" "bar" (func $imported (result i32)))
+ (import "spectest" "print" (func $imported (result i32)))
(func (export "f") (result i32)
(i32.add
(i32.const 13)
(call $imported))))
(;; STDOUT ;;;
-called host foo.bar() => (i32:0)
+called host spectest.print() => (i32:0)
f() => i32:13
;;; STDOUT ;;)
diff --git a/test/interp/import.txt b/test/interp/import.txt
index fc02b0d4..90899592 100644
--- a/test/interp/import.txt
+++ b/test/interp/import.txt
@@ -1,14 +1,14 @@
;;; TOOL: run-interp
(module
- (import "stdio" "print" (func $print_i32 (param i32)))
- (import "stdio" "print" (func $print_i32_i32 (param i32 i32)))
+ (import "spectest" "print" (func $print_i32 (param i32)))
+ (import "spectest" "print" (func $print_i32_i32 (param i32 i32)))
(func (export "test") (result i32)
(call $print_i32 (i32.const 100))
(call $print_i32_i32 (i32.const 200) (i32.const 300))
(return (i32.const 1)))
)
(;; STDOUT ;;;
-called host stdio.print(i32:100) => ()
-called host stdio.print(i32:200, i32:300) => ()
+called host spectest.print(i32:100) => ()
+called host spectest.print(i32:200, i32:300) => ()
test() => i32:1
;;; STDOUT ;;)