summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast-checker.c308
-rw-r--r--src/ast-checker.h17
-rw-r--r--src/ast.c12
-rw-r--r--src/ast.h1
-rw-r--r--src/binary-reader-interpreter.c2
-rw-r--r--src/binary-writer.c100
-rw-r--r--src/resolve-names.c444
-rw-r--r--src/resolve-names.h40
-rw-r--r--src/tools/wast2wasm.c13
9 files changed, 609 insertions, 328 deletions
diff --git a/src/ast-checker.c b/src/ast-checker.c
index a12b28b4..ea9835da 100644
--- a/src/ast-checker.c
+++ b/src/ast-checker.c
@@ -27,11 +27,7 @@
#include "ast-parser-lexer-shared.h"
#include "binary-reader-ast.h"
#include "binary-reader.h"
-
-typedef enum CheckStyle {
- CHECK_STYLE_NAME,
- CHECK_STYLE_FULL,
-} CheckStyle;
+#include "resolve-names.h"
typedef enum LabelType {
LABEL_TYPE_FUNC,
@@ -42,7 +38,6 @@ typedef enum LabelType {
typedef struct LabelNode {
LabelType label_type;
- const WasmLabel* label;
const WasmTypeVector* sig;
struct LabelNode* next;
size_t type_stack_limit;
@@ -63,7 +58,6 @@ typedef struct ActionResult {
} ActionResult;
typedef struct Context {
- CheckStyle check_style;
WasmSourceErrorHandler* error_handler;
WasmAllocator* allocator;
WasmAstLexer* lexer;
@@ -79,18 +73,13 @@ typedef struct Context {
WasmResult result;
} Context;
-static void WASM_PRINTF_FORMAT(4, 5) print_error(Context* ctx,
- CheckStyle check_style,
- const WasmLocation* loc,
- const char* fmt,
- ...) {
- if (check_style <= ctx->check_style) {
- ctx->result = WASM_ERROR;
- va_list args;
- va_start(args, fmt);
- wasm_ast_format_error(ctx->error_handler, loc, ctx->lexer, fmt, args);
- va_end(args);
- }
+static void WASM_PRINTF_FORMAT(3, 4)
+ print_error(Context* ctx, const WasmLocation* loc, const char* fmt, ...) {
+ ctx->result = WASM_ERROR;
+ va_list args;
+ va_start(args, fmt);
+ wasm_ast_format_error(ctx->error_handler, loc, ctx->lexer, fmt, args);
+ va_end(args);
}
static WasmBool is_power_of_two(uint32_t x) {
@@ -103,57 +92,19 @@ static uint32_t get_opcode_natural_alignment(WasmOpcode opcode) {
return memory_size;
}
-static void check_duplicate_bindings(Context* ctx,
- const WasmBindingHash* bindings,
- const char* desc) {
- size_t i;
- for (i = 0; i < bindings->entries.capacity; ++i) {
- WasmBindingHashEntry* entry = &bindings->entries.data[i];
- if (wasm_hash_entry_is_free(entry))
- continue;
-
- /* only follow the chain if this is the first entry in the chain */
- if (entry->prev != NULL)
- continue;
-
- WasmBindingHashEntry* a = entry;
- for (; a; a = a->next) {
- WasmBindingHashEntry* b = a->next;
- for (; b; b = b->next) {
- if (wasm_string_slices_are_equal(&a->binding.name, &b->binding.name)) {
- /* choose the location that is later in the file */
- WasmLocation* a_loc = &a->binding.loc;
- WasmLocation* b_loc = &b->binding.loc;
- WasmLocation* loc = a_loc->line > b_loc->line ? a_loc : b_loc;
- print_error(ctx, CHECK_STYLE_NAME, loc,
- "redefinition of %s \"" PRIstringslice "\"", desc,
- WASM_PRINTF_STRING_SLICE_ARG(a->binding.name));
- }
- }
- }
- }
-}
-
static WasmResult check_var(Context* ctx,
- const WasmBindingHash* bindings,
int max_index,
const WasmVar* var,
const char* desc,
int* out_index) {
- int index = wasm_get_index_from_var(bindings, var);
- if (index >= 0 && index < max_index) {
+ assert(var->type == WASM_VAR_TYPE_INDEX);
+ if (var->index >= 0 && var->index < max_index) {
if (out_index)
- *out_index = index;
+ *out_index = var->index;
return WASM_OK;
}
- if (var->type == WASM_VAR_TYPE_NAME) {
- print_error(ctx, CHECK_STYLE_NAME, &var->loc,
- "undefined %s variable \"" PRIstringslice "\"", desc,
- WASM_PRINTF_STRING_SLICE_ARG(var->name));
- } else {
- print_error(ctx, CHECK_STYLE_NAME, &var->loc,
- "%s variable out of range (max %d)", desc, max_index);
- }
+ print_error(ctx, &var->loc, "%s variable out of range (max %d)", desc,
+ max_index);
return WASM_ERROR;
}
@@ -161,9 +112,8 @@ static WasmResult check_func_var(Context* ctx,
const WasmVar* var,
const WasmFunc** out_func) {
int index;
- if (WASM_FAILED(check_var(ctx, &ctx->current_module->func_bindings,
- ctx->current_module->funcs.size, var, "function",
- &index))) {
+ if (WASM_FAILED(check_var(ctx, ctx->current_module->funcs.size, var,
+ "function", &index))) {
return WASM_ERROR;
}
@@ -177,9 +127,8 @@ static WasmResult check_global_var(Context* ctx,
const WasmGlobal** out_global,
int* out_global_index) {
int index;
- if (WASM_FAILED(check_var(ctx, &ctx->current_module->global_bindings,
- ctx->current_module->globals.size, var, "global",
- &index))) {
+ if (WASM_FAILED(check_var(ctx, ctx->current_module->globals.size, var,
+ "global", &index))) {
return WASM_ERROR;
}
@@ -194,8 +143,7 @@ static WasmResult check_func_type_var(Context* ctx,
const WasmVar* var,
const WasmFuncType** out_func_type) {
int index;
- if (WASM_FAILED(check_var(ctx, &ctx->current_module->func_type_bindings,
- ctx->current_module->func_types.size, var,
+ if (WASM_FAILED(check_var(ctx, ctx->current_module->func_types.size, var,
"function type", &index))) {
return WASM_ERROR;
}
@@ -209,8 +157,7 @@ static WasmResult check_table_var(Context* ctx,
const WasmVar* var,
const WasmTable** out_table) {
int index;
- if (WASM_FAILED(check_var(ctx, &ctx->current_module->table_bindings,
- ctx->current_module->tables.size, var, "table",
+ if (WASM_FAILED(check_var(ctx, ctx->current_module->tables.size, var, "table",
&index))) {
return WASM_ERROR;
}
@@ -224,9 +171,8 @@ static WasmResult check_memory_var(Context* ctx,
const WasmVar* var,
const WasmMemory** out_memory) {
int index;
- if (WASM_FAILED(check_var(ctx, &ctx->current_module->memory_bindings,
- ctx->current_module->memories.size, var, "memory",
- &index))) {
+ if (WASM_FAILED(check_var(ctx, ctx->current_module->memories.size, var,
+ "memory", &index))) {
return WASM_ERROR;
}
@@ -254,12 +200,12 @@ static WasmResult check_local_var(Context* ctx,
}
if (var->type == WASM_VAR_TYPE_NAME) {
- print_error(ctx, CHECK_STYLE_NAME, &var->loc,
+ print_error(ctx, &var->loc,
"undefined local variable \"" PRIstringslice "\"",
WASM_PRINTF_STRING_SLICE_ARG(var->name));
} else {
- print_error(ctx, CHECK_STYLE_NAME, &var->loc,
- "local variable out of range (max %d)", max_index);
+ print_error(ctx, &var->loc, "local variable out of range (max %d)",
+ max_index);
}
return WASM_ERROR;
}
@@ -270,9 +216,9 @@ static void check_align(Context* ctx,
uint32_t natural_alignment) {
if (alignment != WASM_USE_NATURAL_ALIGNMENT) {
if (!is_power_of_two(alignment))
- print_error(ctx, CHECK_STYLE_FULL, loc, "alignment must be power-of-two");
+ print_error(ctx, loc, "alignment must be power-of-two");
if (alignment > natural_alignment) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
+ print_error(ctx, loc,
"alignment must not be larger than natural alignment (%u)",
natural_alignment);
}
@@ -283,26 +229,12 @@ static void check_offset(Context* ctx,
const WasmLocation* loc,
uint64_t offset) {
if (offset > UINT32_MAX) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "offset must be less than or equal to 0xffffffff");
- }
-}
-
-static LabelNode* find_label_by_name(LabelNode* top_label,
- const WasmStringSlice* name) {
- LabelNode* node = top_label;
- while (node) {
- if (wasm_string_slices_are_equal(node->label, name))
- return node;
- node = node->next;
+ print_error(ctx, loc, "offset must be less than or equal to 0xffffffff");
}
- return NULL;
}
static LabelNode* find_label_by_var(LabelNode* top_label, const WasmVar* var) {
- if (var->type == WASM_VAR_TYPE_NAME)
- return find_label_by_name(top_label, &var->name);
-
+ assert(var->type == WASM_VAR_TYPE_INDEX);
LabelNode* node = top_label;
int i = 0;
while (node && i != var->index) {
@@ -323,15 +255,8 @@ static WasmResult check_label_var(Context* ctx,
return WASM_OK;
}
- if (var->type == WASM_VAR_TYPE_NAME) {
- print_error(ctx, CHECK_STYLE_NAME, &var->loc,
- "undefined label variable \"" PRIstringslice "\"",
- WASM_PRINTF_STRING_SLICE_ARG(var->name));
- } else {
- print_error(ctx, CHECK_STYLE_NAME, &var->loc,
- "label variable out of range (max %d)", ctx->max_depth);
- }
-
+ print_error(ctx, &var->loc, "label variable out of range (max %d)",
+ ctx->max_depth);
return WASM_ERROR;
}
@@ -339,10 +264,8 @@ static void push_label(Context* ctx,
const WasmLocation* loc,
LabelNode* node,
LabelType label_type,
- const WasmLabel* label,
const WasmTypeVector* sig) {
node->label_type = label_type;
- node->label = label;
node->next = ctx->top_label;
node->sig = sig;
node->type_stack_limit = ctx->type_stack.size;
@@ -367,9 +290,8 @@ static WasmResult check_type_stack_limit(Context* ctx,
size_t limit = type_stack_limit(ctx);
size_t avail = ctx->type_stack.size - limit;
if (expected > avail) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "type stack size too small at %s. got %" PRIzd
- ", expected at least %" PRIzd,
+ print_error(ctx, loc, "type stack size too small at %s. got %" PRIzd
+ ", expected at least %" PRIzd,
desc, avail, expected);
return WASM_ERROR;
}
@@ -383,7 +305,7 @@ static WasmResult check_type_stack_limit_exact(Context* ctx,
size_t limit = type_stack_limit(ctx);
size_t avail = ctx->type_stack.size - limit;
if (expected != avail) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
+ print_error(ctx, loc,
"type stack at end of %s is %" PRIzd ". expected %" PRIzd, desc,
avail, expected);
return WASM_ERROR;
@@ -437,10 +359,8 @@ static void check_type(Context* ctx,
WasmType expected,
const char* desc) {
if (actual != expected) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "type mismatch at %s. got %s, expected %s", desc,
- wasm_get_type_name(actual),
- wasm_get_type_name(expected));
+ print_error(ctx, loc, "type mismatch at %s. got %s, expected %s", desc,
+ wasm_get_type_name(actual), wasm_get_type_name(expected));
}
}
@@ -452,8 +372,7 @@ static void check_type_index(Context* ctx,
int index,
const char* index_kind) {
if (actual != expected) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "type mismatch for %s %d of %s. got %s, expected %s",
+ print_error(ctx, loc, "type mismatch for %s %d of %s. got %s, expected %s",
index_kind, index, desc, wasm_get_type_name(actual),
wasm_get_type_name(expected));
}
@@ -472,9 +391,8 @@ static void check_types(Context* ctx,
index_kind);
}
} else {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "expected %" PRIzd " %ss, got %" PRIzd, expected->size,
- index_kind, actual->size);
+ print_error(ctx, loc, "expected %" PRIzd " %ss, got %" PRIzd,
+ expected->size, index_kind, actual->size);
}
}
@@ -490,9 +408,8 @@ static void check_const_types(Context* ctx,
i, "result");
}
} else {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "expected %" PRIzd " results, got %" PRIzd, expected->size,
- actual->size);
+ print_error(ctx, loc, "expected %" PRIzd " results, got %" PRIzd,
+ expected->size, actual->size);
}
}
@@ -571,9 +488,8 @@ static void check_assert_return_nan_type(Context* ctx,
/* when using assert_return_nan, the result can be either a f32 or f64 type
* so we special case it here. */
if (actual != WASM_TYPE_F32 && actual != WASM_TYPE_F64) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "type mismatch at %s. got %s, expected f32 or f64", desc,
- wasm_get_type_name(actual));
+ print_error(ctx, loc, "type mismatch at %s. got %s, expected f32 or f64",
+ desc, wasm_get_type_name(actual));
}
}
@@ -613,9 +529,8 @@ static void check_call(Context* ctx,
}
ctx->type_stack.size -= expected_args;
} else {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "type stack size too small at %s. got %" PRIzd
- ", expected at least %" PRIzd,
+ print_error(ctx, loc, "type stack size too small at %s. got %" PRIzd
+ ", expected at least %" PRIzd,
desc, avail, expected_args);
ctx->type_stack.size = limit;
}
@@ -657,8 +572,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) {
case WASM_EXPR_TYPE_BLOCK: {
LabelNode node;
- push_label(ctx, &expr->loc, &node, LABEL_TYPE_BLOCK, &expr->block.label,
- &expr->block.sig);
+ push_label(ctx, &expr->loc, &node, LABEL_TYPE_BLOCK, &expr->block.sig);
check_block(ctx, &expr->loc, expr->block.first, "block");
pop_label(ctx);
push_types(ctx, &expr->block.sig);
@@ -702,7 +616,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) {
case WASM_EXPR_TYPE_CALL_INDIRECT: {
const WasmFuncType* func_type;
if (ctx->current_module->tables.size == 0) {
- print_error(ctx, CHECK_STYLE_FULL, &expr->loc,
+ print_error(ctx, &expr->loc,
"found call_indirect operator, but no table");
}
if (WASM_SUCCEEDED(
@@ -754,8 +668,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) {
case WASM_EXPR_TYPE_IF: {
LabelNode node;
pop_and_check_1_type(ctx, &expr->loc, WASM_TYPE_I32, "if condition");
- push_label(ctx, &expr->loc, &node, LABEL_TYPE_IF, &expr->if_.true_.label,
- &expr->if_.true_.sig);
+ push_label(ctx, &expr->loc, &node, LABEL_TYPE_IF, &expr->if_.true_.sig);
check_block(ctx, &expr->loc, expr->if_.true_.first, "if true branch");
check_block(ctx, &expr->loc, expr->if_.false_, "if false branch");
pop_label(ctx);
@@ -772,8 +685,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) {
case WASM_EXPR_TYPE_LOOP: {
LabelNode node;
- push_label(ctx, &expr->loc, &node, LABEL_TYPE_LOOP, &expr->loop.label,
- &expr->loop.sig);
+ push_label(ctx, &expr->loc, &node, LABEL_TYPE_LOOP, &expr->loop.sig);
check_block(ctx, &expr->loc, expr->loop.first, "loop");
pop_label(ctx);
push_types(ctx, &expr->block.sig);
@@ -867,8 +779,7 @@ static void check_func(Context* ctx,
const WasmFunc* func) {
ctx->current_func = func;
if (wasm_get_num_results(func) > 1) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "multiple result values not currently supported.");
+ print_error(ctx, loc, "multiple result values not currently supported.");
/* don't run any other checks, the won't test the result_type properly */
return;
}
@@ -881,14 +792,10 @@ static void check_func(Context* ctx,
}
}
- check_duplicate_bindings(ctx, &func->param_bindings, "parameter");
- check_duplicate_bindings(ctx, &func->local_bindings, "local");
/* The function has an implicit label; branching to it is equivalent to the
* returning from the function. */
LabelNode node;
- WasmLabel label = wasm_empty_string_slice();
- push_label(ctx, loc, &node, LABEL_TYPE_FUNC, &label,
- &func->decl.sig.result_types);
+ push_label(ctx, loc, &node, LABEL_TYPE_FUNC, &func->decl.sig.result_types);
check_block(ctx, loc, func->first_expr, "function");
pop_label(ctx);
ctx->current_func = NULL;
@@ -897,7 +804,7 @@ static void check_func(Context* ctx,
static void print_const_expr_error(Context* ctx,
const WasmLocation* loc,
const char* desc) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
+ print_error(ctx, loc,
"invalid %s, must be a constant expression; either *.const or "
"get_global.",
desc);
@@ -932,14 +839,14 @@ static void check_const_init_expr(Context* ctx,
/* globals can only reference previously defined globals */
if (ref_global_index >= ctx->current_global_index) {
print_error(
- ctx, CHECK_STYLE_FULL, loc,
+ ctx, loc,
"initializer expression can only be reference a previously "
"defined global");
}
if (ref_global->mutable_) {
print_error(
- ctx, CHECK_STYLE_FULL, loc,
+ ctx, loc,
"initializer expression cannot reference a mutable global");
}
break;
@@ -967,20 +874,18 @@ static void check_limits(Context* ctx,
uint64_t absolute_max,
const char* desc) {
if (limits->initial > absolute_max) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "initial %s (%" PRIu64 ") must be <= (%" PRIu64 ")", desc,
- limits->initial, absolute_max);
+ print_error(ctx, loc, "initial %s (%" PRIu64 ") must be <= (%" PRIu64 ")",
+ desc, limits->initial, absolute_max);
}
if (limits->has_max) {
if (limits->max > absolute_max) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "max %s (%" PRIu64 ") must be <= (%" PRIu64 ")", desc,
- limits->max, absolute_max);
+ print_error(ctx, loc, "max %s (%" PRIu64 ") must be <= (%" PRIu64 ")",
+ desc, limits->max, absolute_max);
}
if (limits->max < limits->initial) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
+ print_error(ctx, loc,
"max %s (%" PRIu64 ") must be >= initial %s (%" PRIu64 ")",
desc, limits->max, desc, limits->initial);
}
@@ -991,7 +896,7 @@ static void check_table(Context* ctx,
const WasmLocation* loc,
const WasmTable* table) {
if (ctx->current_table_index == 1)
- print_error(ctx, CHECK_STYLE_FULL, loc, "only one table allowed");
+ print_error(ctx, loc, "only one table allowed");
check_limits(ctx, loc, &table->elem_limits, UINT32_MAX, "elems");
}
@@ -1016,7 +921,7 @@ static void check_memory(Context* ctx,
const WasmLocation* loc,
const WasmMemory* memory) {
if (ctx->current_memory_index == 1)
- print_error(ctx, CHECK_STYLE_FULL, loc, "only one memory block allowed");
+ print_error(ctx, loc, "only one memory block allowed");
check_limits(ctx, loc, &memory->page_limits, WASM_MAX_PAGES, "pages");
}
@@ -1055,8 +960,7 @@ static void check_import(Context* ctx,
break;
case WASM_EXTERNAL_KIND_GLOBAL:
if (import->global.mutable_) {
- print_error(ctx, CHECK_STYLE_FULL, loc,
- "mutable globals cannot be imported");
+ print_error(ctx, loc, "mutable globals cannot be imported");
}
ctx->current_global_index++;
break;
@@ -1081,7 +985,7 @@ static void check_export(Context* ctx, const WasmExport* export_) {
const WasmGlobal* global;
if (WASM_SUCCEEDED(check_global_var(ctx, &export_->var, &global, NULL))) {
if (global->mutable_) {
- print_error(ctx, CHECK_STYLE_FULL, &export_->var.loc,
+ print_error(ctx, &export_->var.loc,
"mutable globals cannot be exported");
}
}
@@ -1144,20 +1048,18 @@ static void check_module(Context* ctx, const WasmModule* module) {
case WASM_MODULE_FIELD_TYPE_START: {
if (seen_start) {
- print_error(ctx, CHECK_STYLE_FULL, &field->loc,
- "only one start function allowed");
+ print_error(ctx, &field->loc, "only one start function allowed");
}
const WasmFunc* start_func = NULL;
check_func_var(ctx, &field->start, &start_func);
if (start_func) {
if (wasm_get_num_params(start_func) != 0) {
- print_error(ctx, CHECK_STYLE_FULL, &field->loc,
- "start function must be nullary");
+ print_error(ctx, &field->loc, "start function must be nullary");
}
if (wasm_get_num_results(start_func) != 0) {
- print_error(ctx, CHECK_STYLE_FULL, &field->loc,
+ print_error(ctx, &field->loc,
"start function must not return anything");
}
}
@@ -1169,13 +1071,6 @@ static void check_module(Context* ctx, const WasmModule* module) {
check_elem_segments(ctx, module);
check_data_segments(ctx, module);
-
- check_duplicate_bindings(ctx, &module->func_bindings, "function");
- check_duplicate_bindings(ctx, &module->global_bindings, "global");
- check_duplicate_bindings(ctx, &module->export_bindings, "export");
- check_duplicate_bindings(ctx, &module->func_type_bindings, "function type");
- check_duplicate_bindings(ctx, &module->table_bindings, "table");
- check_duplicate_bindings(ctx, &module->memory_bindings, "memory");
}
typedef struct BinaryErrorCallbackData {
@@ -1188,11 +1083,10 @@ static void on_read_binary_error(uint32_t offset,
void* user_data) {
BinaryErrorCallbackData* data = user_data;
if (offset == WASM_UNKNOWN_OFFSET) {
- print_error(data->ctx, CHECK_STYLE_FULL, data->loc,
- "error in binary module: %s", error);
+ print_error(data->ctx, data->loc, "error in binary module: %s", error);
} else {
- print_error(data->ctx, CHECK_STYLE_FULL, data->loc,
- "error in binary module: @0x%08x: %s", offset, error);
+ print_error(data->ctx, data->loc, "error in binary module: @0x%08x: %s",
+ offset, error);
}
}
@@ -1233,8 +1127,13 @@ static WasmResult read_raw_module(Context* ctx,
static void check_raw_module(Context* ctx, WasmRawModule* raw) {
ReadModule read_module;
- if (WASM_SUCCEEDED(read_raw_module(ctx, raw, &read_module)))
- check_module(ctx, &read_module.module);
+ if (WASM_SUCCEEDED(read_raw_module(ctx, raw, &read_module))) {
+ WasmModule* module = &read_module.module;
+ ctx->result = wasm_resolve_names_module(ctx->allocator, ctx->lexer, module,
+ ctx->error_handler);
+ if (WASM_SUCCEEDED(ctx->result))
+ check_module(ctx, module);
+ }
destroy_read_module(ctx->allocator, &read_module);
}
@@ -1247,13 +1146,13 @@ static const WasmTypeVector* check_invoke(Context* ctx,
const WasmModule* module =
wasm_get_module_by_var(ctx->script, &action->module_var);
if (!module) {
- print_error(ctx, CHECK_STYLE_FULL, &action->loc, "unknown module");
+ print_error(ctx, &action->loc, "unknown module");
return NULL;
}
WasmExport* export = wasm_get_export_by_name(module, &invoke->name);
if (!export) {
- print_error(ctx, CHECK_STYLE_NAME, &action->loc,
+ print_error(ctx, &action->loc,
"unknown function export \"" PRIstringslice "\"",
WASM_PRINTF_STRING_SLICE_ARG(invoke->name));
return NULL;
@@ -1268,9 +1167,8 @@ static const WasmTypeVector* check_invoke(Context* ctx,
size_t actual_args = invoke->args.size;
size_t expected_args = wasm_get_num_params(func);
if (expected_args != actual_args) {
- print_error(ctx, CHECK_STYLE_FULL, &action->loc,
- "too %s parameters to function. got %" PRIzd
- ", expected %" PRIzd,
+ print_error(ctx, &action->loc, "too %s parameters to function. got %" PRIzd
+ ", expected %" PRIzd,
actual_args > expected_args ? "many" : "few", actual_args,
expected_args);
return NULL;
@@ -1292,13 +1190,13 @@ static WasmResult check_get(Context* ctx,
const WasmModule* module =
wasm_get_module_by_var(ctx->script, &action->module_var);
if (!module) {
- print_error(ctx, CHECK_STYLE_FULL, &action->loc, "unknown module");
+ print_error(ctx, &action->loc, "unknown module");
return WASM_ERROR;
}
WasmExport* export = wasm_get_export_by_name(module, &get->name);
if (!export) {
- print_error(ctx, CHECK_STYLE_NAME, &action->loc,
+ print_error(ctx, &action->loc,
"unknown global export \"" PRIstringslice "\"",
WASM_PRINTF_STRING_SLICE_ARG(get->name));
return WASM_ERROR;
@@ -1389,8 +1287,8 @@ static void check_command(Context* ctx, const WasmCommand* command) {
result.kind = ACTION_RESULT_KIND_TYPE;
result.type = result.types->data[0];
} else {
- print_error(ctx, CHECK_STYLE_FULL, &action->loc,
- "expected 1 result, got %" PRIzd, result.types->size);
+ print_error(ctx, &action->loc, "expected 1 result, got %" PRIzd,
+ result.types->size);
result.type = WASM_TYPE_ANY;
}
}
@@ -1416,32 +1314,12 @@ static void wasm_destroy_context(Context* ctx) {
wasm_destroy_type_vector(ctx->allocator, &ctx->type_stack);
}
-WasmResult wasm_check_names(WasmAllocator* allocator,
- WasmAstLexer* lexer,
- const struct WasmScript* script,
- WasmSourceErrorHandler* error_handler) {
+WasmResult wasm_check_script(WasmAllocator* allocator,
+ WasmAstLexer* lexer,
+ const struct WasmScript* script,
+ WasmSourceErrorHandler* error_handler) {
Context ctx;
WASM_ZERO_MEMORY(ctx);
- ctx.check_style = CHECK_STYLE_NAME;
- ctx.allocator = allocator;
- ctx.lexer = lexer;
- ctx.error_handler = error_handler;
- ctx.result = WASM_OK;
- ctx.script = script;
- size_t i;
- for (i = 0; i < script->commands.size; ++i)
- check_command(&ctx, &script->commands.data[i]);
- wasm_destroy_context(&ctx);
- return ctx.result;
-}
-
-WasmResult wasm_check_ast(WasmAllocator* allocator,
- WasmAstLexer* lexer,
- const struct WasmScript* script,
- WasmSourceErrorHandler* error_handler) {
- Context ctx;
- WASM_ZERO_MEMORY(ctx);
- ctx.check_style = CHECK_STYLE_FULL;
ctx.allocator = allocator;
ctx.lexer = lexer;
ctx.error_handler = error_handler;
@@ -1463,7 +1341,6 @@ WasmResult wasm_check_assert_invalid_and_malformed(
WasmSourceErrorHandler* error_handler) {
Context ctx;
WASM_ZERO_MEMORY(ctx);
- ctx.check_style = CHECK_STYLE_FULL;
ctx.allocator = allocator;
ctx.lexer = lexer;
ctx.error_handler = error_handler;
@@ -1480,7 +1357,6 @@ WasmResult wasm_check_assert_invalid_and_malformed(
Context ctx2;
WASM_ZERO_MEMORY(ctx2);
- ctx2.check_style = CHECK_STYLE_FULL;
ctx2.allocator = allocator;
ctx2.lexer = lexer;
ctx2.result = WASM_OK;
@@ -1492,8 +1368,7 @@ WasmResult wasm_check_assert_invalid_and_malformed(
wasm_destroy_context(&ctx2);
if (WASM_SUCCEEDED(ctx2.result)) {
print_error(
- &ctx, CHECK_STYLE_FULL,
- wasm_get_raw_module_location(&command->assert_invalid.module),
+ &ctx, wasm_get_raw_module_location(&command->assert_invalid.module),
"expected module to be invalid");
}
} else if (command->type == WASM_COMMAND_TYPE_ASSERT_MALFORMED) {
@@ -1503,10 +1378,9 @@ WasmResult wasm_check_assert_invalid_and_malformed(
destroy_read_module(ctx.allocator, &read_module);
wasm_destroy_context(&ctx2);
if (WASM_SUCCEEDED(ctx2.result)) {
- print_error(
- &ctx, CHECK_STYLE_FULL,
- wasm_get_raw_module_location(&command->assert_malformed.module),
- "expected module to be malformed");
+ print_error(&ctx, wasm_get_raw_module_location(
+ &command->assert_malformed.module),
+ "expected module to be malformed");
}
}
}
diff --git a/src/ast-checker.h b/src/ast-checker.h
index 6f0ec22e..c73386b2 100644
--- a/src/ast-checker.h
+++ b/src/ast-checker.h
@@ -25,24 +25,17 @@ struct WasmModule;
struct WasmScript;
WASM_EXTERN_C_BEGIN
-/* Only check that names are valid; this is useful if you want to generate
- * invalid binaries (so they can be validated by the consumer). */
-WasmResult wasm_check_names(struct WasmAllocator*,
- WasmAstLexer*,
- const struct WasmScript*,
- WasmSourceErrorHandler*);
-
/* perform all checks on the AST; the module is valid if and only if this
* function succeeds. */
-WasmResult wasm_check_ast(struct WasmAllocator*,
- WasmAstLexer*,
- const struct WasmScript*,
- WasmSourceErrorHandler*);
+WasmResult wasm_check_script(struct WasmAllocator*,
+ WasmAstLexer*,
+ const struct WasmScript*,
+ WasmSourceErrorHandler*);
/* Run the assert_invalid and assert_malformed spec tests. A module is
* "malformed" if it cannot be read from the binary format. A module is
* "invalid" if either it is malformed, or if it does not pass the standard
- * checks (as done by wasm_check_ast). This function succeeds if and only if
+ * checks (as done by wasm_check_script). This function succeeds if and only if
* all assert_invalid and assert_malformed tests pass. */
WasmResult wasm_check_assert_invalid_and_malformed(
struct WasmAllocator*,
diff --git a/src/ast.c b/src/ast.c
index e8ba5449..34192040 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -600,7 +600,7 @@ void wasm_destroy_script(WasmScript* script) {
static WasmResult visit_expr(WasmExpr* expr, WasmExprVisitor* visitor);
-static WasmResult visit_expr_list(WasmExpr* first, WasmExprVisitor* visitor) {
+WasmResult wasm_visit_expr_list(WasmExpr* first, WasmExprVisitor* visitor) {
WasmExpr* expr;
for (expr = first; expr; expr = expr->next)
CHECK_RESULT(visit_expr(expr, visitor));
@@ -615,7 +615,7 @@ static WasmResult visit_expr(WasmExpr* expr, WasmExprVisitor* visitor) {
case WASM_EXPR_TYPE_BLOCK:
CALLBACK(begin_block_expr);
- CHECK_RESULT(visit_expr_list(expr->block.first, visitor));
+ CHECK_RESULT(wasm_visit_expr_list(expr->block.first, visitor));
CALLBACK(end_block_expr);
break;
@@ -673,9 +673,9 @@ static WasmResult visit_expr(WasmExpr* expr, WasmExprVisitor* visitor) {
case WASM_EXPR_TYPE_IF:
CALLBACK(begin_if_expr);
- CHECK_RESULT(visit_expr_list(expr->if_.true_.first, visitor));
+ CHECK_RESULT(wasm_visit_expr_list(expr->if_.true_.first, visitor));
CALLBACK(after_if_true_expr);
- CHECK_RESULT(visit_expr_list(expr->if_.false_, visitor));
+ CHECK_RESULT(wasm_visit_expr_list(expr->if_.false_, visitor));
CALLBACK(end_if_expr);
break;
@@ -685,7 +685,7 @@ static WasmResult visit_expr(WasmExpr* expr, WasmExprVisitor* visitor) {
case WASM_EXPR_TYPE_LOOP:
CALLBACK(begin_loop_expr);
- CHECK_RESULT(visit_expr_list(expr->loop.first, visitor));
+ CHECK_RESULT(wasm_visit_expr_list(expr->loop.first, visitor));
CALLBACK(end_loop_expr);
break;
@@ -731,5 +731,5 @@ static WasmResult visit_expr(WasmExpr* expr, WasmExprVisitor* visitor) {
/* TODO(binji): make the visitor non-recursive */
WasmResult wasm_visit_func(WasmFunc* func, WasmExprVisitor* visitor) {
- return visit_expr_list(func->first_expr, visitor);
+ return wasm_visit_expr_list(func->first_expr, visitor);
}
diff --git a/src/ast.h b/src/ast.h
index 1e01ebf3..a002fa76 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -462,6 +462,7 @@ void wasm_destroy_var(struct WasmAllocator*, WasmVar*);
/* traversal functions */
WasmResult wasm_visit_func(WasmFunc* func, WasmExprVisitor*);
+WasmResult wasm_visit_expr_list(WasmExpr* expr, WasmExprVisitor*);
/* convenience functions for looking through the AST */
int wasm_get_index_from_var(const WasmBindingHash* bindings,
diff --git a/src/binary-reader-interpreter.c b/src/binary-reader-interpreter.c
index 32fcc6a3..bfbb9cc5 100644
--- a/src/binary-reader-interpreter.c
+++ b/src/binary-reader-interpreter.c
@@ -217,7 +217,7 @@ static uint32_t translate_global_index_to_env(Context* ctx,
static uint32_t translate_defined_global_index_to_env(Context* ctx,
uint32_t global_index) {
- /* all globaltion imports are first, so skip over those */
+ /* all global imports are first, so skip over those */
global_index += ctx->num_global_imports;
assert(global_index < ctx->global_index_mapping.size);
return ctx->global_index_mapping.data[global_index];
diff --git a/src/binary-writer.c b/src/binary-writer.c
index 11a1c89b..b9d9f27f 100644
--- a/src/binary-writer.c
+++ b/src/binary-writer.c
@@ -40,19 +40,11 @@
static const char* s_section_name[] = {WASM_FOREACH_BINARY_SECTION(V)};
#undef V
-typedef struct WasmLabelNode {
- const WasmLabel* label;
- int depth;
- struct WasmLabelNode* next;
-} WasmLabelNode;
-
typedef struct Context {
WasmAllocator* allocator;
WasmStream stream;
WasmStream* log_stream;
const WasmWriteBinaryOptions* options;
- WasmLabelNode* top_label;
- int max_depth;
size_t last_section_offset;
size_t last_section_leb_size_guess;
@@ -267,46 +259,9 @@ static void end_section(Context* ctx) {
ctx->last_section_leb_size_guess = 0;
}
-static WasmLabelNode* find_label_by_name(WasmLabelNode* top_label,
- const WasmStringSlice* name) {
- WasmLabelNode* node = top_label;
- while (node) {
- if (node->label && wasm_string_slices_are_equal(node->label, name))
- return node;
- node = node->next;
- }
- return NULL;
-}
-
-static WasmLabelNode* find_label_by_var(WasmLabelNode* top_label,
- const WasmVar* var) {
- if (var->type == WASM_VAR_TYPE_NAME)
- return find_label_by_name(top_label, &var->name);
-
- WasmLabelNode* node = top_label;
- int i = 0;
- while (node && i != var->index) {
- node = node->next;
- i++;
- }
- return node;
-}
-
-static void push_label(Context* ctx,
- WasmLabelNode* node,
- const WasmLabel* label) {
- assert(label);
- node->label = label;
- node->next = ctx->top_label;
- node->depth = ctx->max_depth;
- ctx->top_label = node;
- ctx->max_depth++;
-}
-
-static void pop_label(Context* ctx, const WasmLabel* label) {
- ctx->max_depth--;
- if (ctx->top_label && ctx->top_label->label == label)
- ctx->top_label = ctx->top_label->next;
+static uint32_t get_label_var_depth(Context* ctx, const WasmVar* var) {
+ assert(var->type == WASM_VAR_TYPE_INDEX);
+ return var->index;
}
static void write_expr_list(Context* ctx,
@@ -322,47 +277,34 @@ static void write_expr(Context* ctx,
case WASM_EXPR_TYPE_BINARY:
write_opcode(&ctx->stream, expr->binary.opcode);
break;
- case WASM_EXPR_TYPE_BLOCK: {
- WasmLabelNode node;
- push_label(ctx, &node, &expr->block.label);
+ case WASM_EXPR_TYPE_BLOCK:
write_opcode(&ctx->stream, WASM_OPCODE_BLOCK);
write_inline_signature_type(&ctx->stream, &expr->block.sig);
write_expr_list(ctx, module, func, expr->block.first);
write_opcode(&ctx->stream, WASM_OPCODE_END);
- pop_label(ctx, &expr->block.label);
break;
- }
- case WASM_EXPR_TYPE_BR: {
- WasmLabelNode* node = find_label_by_var(ctx->top_label, &expr->br.var);
- assert(node);
+ case WASM_EXPR_TYPE_BR:
write_opcode(&ctx->stream, WASM_OPCODE_BR);
- write_u32_leb128(&ctx->stream, ctx->max_depth - node->depth - 1,
+ write_u32_leb128(&ctx->stream, get_label_var_depth(ctx, &expr->br.var),
"break depth");
break;
- }
- case WASM_EXPR_TYPE_BR_IF: {
- WasmLabelNode* node = find_label_by_var(ctx->top_label, &expr->br_if.var);
- assert(node);
+ case WASM_EXPR_TYPE_BR_IF:
write_opcode(&ctx->stream, WASM_OPCODE_BR_IF);
- write_u32_leb128(&ctx->stream, ctx->max_depth - node->depth - 1,
+ write_u32_leb128(&ctx->stream, get_label_var_depth(ctx, &expr->br_if.var),
"break depth");
break;
- }
case WASM_EXPR_TYPE_BR_TABLE: {
write_opcode(&ctx->stream, WASM_OPCODE_BR_TABLE);
write_u32_leb128(&ctx->stream, expr->br_table.targets.size,
"num targets");
size_t i;
- WasmLabelNode* node;
+ uint32_t depth;
for (i = 0; i < expr->br_table.targets.size; ++i) {
- const WasmVar* var = &expr->br_table.targets.data[i];
- node = find_label_by_var(ctx->top_label, var);
- write_u32_leb128(&ctx->stream, ctx->max_depth - node->depth - 1,
- "break depth");
+ depth = get_label_var_depth(ctx, &expr->br_table.targets.data[i]);
+ write_u32_leb128(&ctx->stream, depth, "break depth");
}
- node = find_label_by_var(ctx->top_label, &expr->br_table.default_target);
- write_u32_leb128(&ctx->stream, ctx->max_depth - node->depth - 1,
- "break depth for default");
+ depth = get_label_var_depth(ctx, &expr->br_table.default_target);
+ write_u32_leb128(&ctx->stream, depth, "break depth for default");
break;
}
case WASM_EXPR_TYPE_CALL: {
@@ -435,20 +377,16 @@ static void write_expr(Context* ctx,
write_opcode(&ctx->stream, WASM_OPCODE_GROW_MEMORY);
write_u32_leb128(&ctx->stream, 0, "grow_memory reserved");
break;
- case WASM_EXPR_TYPE_IF: {
- WasmLabelNode node;
+ case WASM_EXPR_TYPE_IF:
write_opcode(&ctx->stream, WASM_OPCODE_IF);
write_inline_signature_type(&ctx->stream, &expr->if_.true_.sig);
- push_label(ctx, &node, &expr->if_.true_.label);
write_expr_list(ctx, module, func, expr->if_.true_.first);
if (expr->if_.false_) {
write_opcode(&ctx->stream, WASM_OPCODE_ELSE);
write_expr_list(ctx, module, func, expr->if_.false_);
}
- pop_label(ctx, &expr->if_.true_.label);
write_opcode(&ctx->stream, WASM_OPCODE_END);
break;
- }
case WASM_EXPR_TYPE_LOAD: {
write_opcode(&ctx->stream, expr->load.opcode);
uint32_t align =
@@ -458,16 +396,12 @@ static void write_expr(Context* ctx,
"load offset");
break;
}
- case WASM_EXPR_TYPE_LOOP: {
- WasmLabelNode node;
- push_label(ctx, &node, &expr->loop.label);
+ case WASM_EXPR_TYPE_LOOP:
write_opcode(&ctx->stream, WASM_OPCODE_LOOP);
write_inline_signature_type(&ctx->stream, &expr->loop.sig);
write_expr_list(ctx, module, func, expr->loop.first);
write_opcode(&ctx->stream, WASM_OPCODE_END);
- pop_label(ctx, &expr->loop.label);
break;
- }
case WASM_EXPR_TYPE_NOP:
write_opcode(&ctx->stream, WASM_OPCODE_NOP);
break;
@@ -578,13 +512,9 @@ static void write_func_locals(Context* ctx,
static void write_func(Context* ctx,
const WasmModule* module,
const WasmFunc* func) {
- WasmLabelNode node;
- WasmLabel label = wasm_empty_string_slice();
write_func_locals(ctx, module, func, &func->local_types);
- push_label(ctx, &node, &label);
write_expr_list(ctx, module, func, func->first_expr);
write_opcode(&ctx->stream, WASM_OPCODE_END);
- pop_label(ctx, &label);
}
static void write_table(Context* ctx, const WasmTable* table) {
diff --git a/src/resolve-names.c b/src/resolve-names.c
new file mode 100644
index 00000000..ea73ed2a
--- /dev/null
+++ b/src/resolve-names.c
@@ -0,0 +1,444 @@
+/*
+ * 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 "resolve-names.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "allocator.h"
+#include "ast.h"
+#include "ast-parser-lexer-shared.h"
+
+typedef WasmLabel* LabelPtr;
+WASM_DEFINE_VECTOR(label_ptr, LabelPtr);
+
+typedef struct Context {
+ WasmAllocator* allocator;
+ WasmSourceErrorHandler* error_handler;
+ WasmAstLexer* lexer;
+ WasmScript* script;
+ WasmModule* current_module;
+ WasmFunc* current_func;
+ WasmExprVisitor visitor;
+ LabelPtrVector labels;
+ WasmResult result;
+} Context;
+
+static void WASM_PRINTF_FORMAT(3, 4)
+ print_error(Context* ctx, const WasmLocation* loc, const char* fmt, ...) {
+ ctx->result = WASM_ERROR;
+ va_list args;
+ va_start(args, fmt);
+ wasm_ast_format_error(ctx->error_handler, loc, ctx->lexer, fmt, args);
+ va_end(args);
+}
+
+static void push_label(Context* ctx, WasmLabel* label) {
+ wasm_append_label_ptr_value(ctx->allocator, &ctx->labels, &label);
+}
+
+static void pop_label(Context* ctx) {
+ assert(ctx->labels.size > 0);
+ ctx->labels.size--;
+}
+
+static void check_duplicate_bindings(Context* ctx,
+ const WasmBindingHash* bindings,
+ const char* desc) {
+ size_t i;
+ for (i = 0; i < bindings->entries.capacity; ++i) {
+ WasmBindingHashEntry* entry = &bindings->entries.data[i];
+ if (wasm_hash_entry_is_free(entry))
+ continue;
+
+ /* only follow the chain if this is the first entry in the chain */
+ if (entry->prev != NULL)
+ continue;
+
+ WasmBindingHashEntry* a = entry;
+ for (; a; a = a->next) {
+ WasmBindingHashEntry* b = a->next;
+ for (; b; b = b->next) {
+ if (wasm_string_slices_are_equal(&a->binding.name, &b->binding.name)) {
+ /* choose the location that is later in the file */
+ WasmLocation* a_loc = &a->binding.loc;
+ WasmLocation* b_loc = &b->binding.loc;
+ WasmLocation* loc = a_loc->line > b_loc->line ? a_loc : b_loc;
+ print_error(ctx, loc, "redefinition of %s \"" PRIstringslice "\"",
+ desc, WASM_PRINTF_STRING_SLICE_ARG(a->binding.name));
+ }
+ }
+ }
+ }
+}
+
+static void resolve_label_var(Context* ctx, WasmVar* var) {
+ if (var->type == WASM_VAR_TYPE_NAME) {
+ int i;
+ for (i = ctx->labels.size - 1; i >= 0; --i) {
+ WasmLabel* label = ctx->labels.data[i];
+ if (wasm_string_slices_are_equal(label, &var->name)) {
+ wasm_destroy_string_slice(ctx->allocator, &var->name);
+ var->type = WASM_VAR_TYPE_INDEX;
+ var->index = ctx->labels.size - i - 1;
+ return;
+ }
+ }
+ print_error(ctx, &var->loc,
+ "undefined label variable \"" PRIstringslice "\"",
+ WASM_PRINTF_STRING_SLICE_ARG(var->name));
+ }
+}
+
+static void resolve_var(Context* ctx,
+ const WasmBindingHash* bindings,
+ WasmVar* var,
+ const char* desc) {
+ if (var->type == WASM_VAR_TYPE_NAME) {
+ int index = wasm_get_index_from_var(bindings, var);
+ if (index == -1) {
+ print_error(ctx, &var->loc,
+ "undefined %s variable \"" PRIstringslice "\"", desc,
+ WASM_PRINTF_STRING_SLICE_ARG(var->name));
+ return;
+ }
+
+ wasm_destroy_string_slice(ctx->allocator, &var->name);
+ var->index = index;
+ var->type = WASM_VAR_TYPE_INDEX;
+ }
+}
+
+static void resolve_func_var(Context* ctx, WasmVar* var) {
+ resolve_var(ctx, &ctx->current_module->func_bindings, var, "function");
+}
+
+static void resolve_global_var(Context* ctx, WasmVar* var) {
+ resolve_var(ctx, &ctx->current_module->global_bindings, var, "global");
+}
+
+static void resolve_func_type_var(Context* ctx, WasmVar* var) {
+ resolve_var(ctx, &ctx->current_module->func_type_bindings, var,
+ "function type");
+}
+
+static void resolve_table_var(Context* ctx, WasmVar* var) {
+ resolve_var(ctx, &ctx->current_module->table_bindings, var, "table");
+}
+
+static void resolve_memory_var(Context* ctx, WasmVar* var) {
+ resolve_var(ctx, &ctx->current_module->memory_bindings, var, "memory");
+}
+
+static void resolve_local_var(Context* ctx, WasmVar* var) {
+ if (var->type == WASM_VAR_TYPE_NAME) {
+ int index = wasm_get_local_index_by_var(ctx->current_func, var);
+ if (index == -1) {
+ print_error(ctx, &var->loc,
+ "undefined local variable \"" PRIstringslice "\"",
+ WASM_PRINTF_STRING_SLICE_ARG(var->name));
+ return;
+ }
+
+ wasm_destroy_string_slice(ctx->allocator, &var->name);
+ var->index = index;
+ var->type = WASM_VAR_TYPE_INDEX;
+ }
+}
+
+static WasmResult begin_block_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ push_label(ctx, &expr->block.label);
+ return WASM_OK;
+}
+
+static WasmResult end_block_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ pop_label(ctx);
+ return WASM_OK;
+}
+
+static WasmResult begin_loop_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ push_label(ctx, &expr->loop.label);
+ return WASM_OK;
+}
+
+static WasmResult end_loop_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ pop_label(ctx);
+ return WASM_OK;
+}
+
+static WasmResult on_br_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_label_var(ctx, &expr->br.var);
+ return WASM_OK;
+}
+
+static WasmResult on_br_if_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_label_var(ctx, &expr->br_if.var);
+ return WASM_OK;
+}
+
+static WasmResult on_br_table_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ size_t i;
+ WasmVarVector* targets = &expr->br_table.targets;
+ for (i = 0; i < targets->size; ++i) {
+ WasmVar* target = &targets->data[i];
+ resolve_label_var(ctx, target);
+ }
+
+ resolve_label_var(ctx, &expr->br_table.default_target);
+ return WASM_OK;
+}
+
+static WasmResult on_call_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_func_var(ctx, &expr->call.var);
+ return WASM_OK;
+}
+
+static WasmResult on_call_indirect_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_func_type_var(ctx, &expr->call_indirect.var);
+ return WASM_OK;
+}
+
+static WasmResult on_get_global_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_global_var(ctx, &expr->get_global.var);
+ return WASM_OK;
+}
+
+static WasmResult on_get_local_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_local_var(ctx, &expr->get_local.var);
+ return WASM_OK;
+}
+
+static WasmResult begin_if_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ push_label(ctx, &expr->if_.true_.label);
+ return WASM_OK;
+}
+
+static WasmResult end_if_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ pop_label(ctx);
+ return WASM_OK;
+}
+
+static WasmResult on_set_global_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_global_var(ctx, &expr->set_global.var);
+ return WASM_OK;
+}
+
+static WasmResult on_set_local_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_local_var(ctx, &expr->set_local.var);
+ return WASM_OK;
+}
+
+static WasmResult on_tee_local_expr(WasmExpr* expr, void* user_data) {
+ Context* ctx = user_data;
+ resolve_local_var(ctx, &expr->tee_local.var);
+ return WASM_OK;
+}
+
+static void visit_func(Context* ctx, WasmFunc* func) {
+ ctx->current_func = func;
+ if (wasm_decl_has_func_type(&func->decl))
+ resolve_func_type_var(ctx, &func->decl.type_var);
+
+ check_duplicate_bindings(ctx, &func->param_bindings, "parameter");
+ check_duplicate_bindings(ctx, &func->local_bindings, "local");
+
+ wasm_visit_func(func, &ctx->visitor);
+ ctx->current_func = NULL;
+}
+
+static void visit_export(Context* ctx, WasmExport* export) {
+ switch (export->kind) {
+ case WASM_EXTERNAL_KIND_FUNC:
+ resolve_func_var(ctx, &export->var);
+ break;
+
+ case WASM_EXTERNAL_KIND_TABLE:
+ resolve_table_var(ctx, &export->var);
+ break;
+
+ case WASM_EXTERNAL_KIND_MEMORY:
+ resolve_memory_var(ctx, &export->var);
+ break;
+
+ case WASM_EXTERNAL_KIND_GLOBAL:
+ resolve_global_var(ctx, &export->var);
+ break;
+
+ case WASM_NUM_EXTERNAL_KINDS:
+ assert(0);
+ break;
+ }
+}
+
+static void visit_global(Context* ctx, WasmGlobal* global) {
+ wasm_visit_expr_list(global->init_expr, &ctx->visitor);
+}
+
+static void visit_elem_segment(Context* ctx, WasmElemSegment* segment) {
+ size_t i;
+ resolve_table_var(ctx, &segment->table_var);
+ wasm_visit_expr_list(segment->offset, &ctx->visitor);
+ for (i = 0; i < segment->vars.size; ++i)
+ resolve_func_var(ctx, &segment->vars.data[i]);
+}
+
+static void visit_data_segment(Context* ctx, WasmDataSegment* segment) {
+ resolve_memory_var(ctx, &segment->memory_var);
+ wasm_visit_expr_list(segment->offset, &ctx->visitor);
+}
+
+static void visit_module(Context* ctx, WasmModule* module) {
+ ctx->current_module = module;
+ check_duplicate_bindings(ctx, &module->func_bindings, "function");
+ check_duplicate_bindings(ctx, &module->global_bindings, "global");
+ check_duplicate_bindings(ctx, &module->export_bindings, "export");
+ check_duplicate_bindings(ctx, &module->func_type_bindings, "function type");
+ check_duplicate_bindings(ctx, &module->table_bindings, "table");
+ check_duplicate_bindings(ctx, &module->memory_bindings, "memory");
+
+ size_t i;
+ for (i = 0; i < module->funcs.size; ++i)
+ visit_func(ctx, module->funcs.data[i]);
+ for (i = 0; i < module->exports.size; ++i)
+ visit_export(ctx, module->exports.data[i]);
+ for (i = 0; i < module->globals.size; ++i)
+ visit_global(ctx, module->globals.data[i]);
+ for (i = 0; i < module->elem_segments.size; ++i)
+ visit_elem_segment(ctx, module->elem_segments.data[i]);
+ for (i = 0; i < module->data_segments.size; ++i)
+ visit_data_segment(ctx, module->data_segments.data[i]);
+ if (module->start)
+ resolve_func_var(ctx, module->start);
+ ctx->current_module = NULL;
+}
+
+static void visit_raw_module(Context* ctx, WasmRawModule* raw_module) {
+ if (raw_module->type == WASM_RAW_MODULE_TYPE_TEXT)
+ visit_module(ctx, raw_module->text);
+}
+
+static void visit_command(Context* ctx, WasmCommand* command) {
+ switch (command->type) {
+ case WASM_COMMAND_TYPE_MODULE:
+ visit_module(ctx, &command->module);
+ break;
+
+ case WASM_COMMAND_TYPE_ACTION:
+ case WASM_COMMAND_TYPE_ASSERT_RETURN:
+ case WASM_COMMAND_TYPE_ASSERT_RETURN_NAN:
+ case WASM_COMMAND_TYPE_ASSERT_TRAP:
+ case WASM_COMMAND_TYPE_REGISTER:
+ /* Don't resolve a module_var, since it doesn't really behave like other
+ * vars. You can't reference a module by index. */
+ break;
+
+ case WASM_COMMAND_TYPE_ASSERT_MALFORMED:
+ /* Malformed modules should not be text; the whole point of this
+ * assertion is to test for malformed binary modules. */
+ break;
+
+ case WASM_COMMAND_TYPE_ASSERT_INVALID:
+ /* The module may be invalid because the names cannot be resolved (or are
+ * duplicates). In either case, don't resolve. */
+ break;
+
+ case WASM_COMMAND_TYPE_ASSERT_UNLINKABLE:
+ visit_raw_module(ctx, &command->assert_unlinkable.module);
+ break;
+
+ case WASM_COMMAND_TYPE_ASSERT_UNINSTANTIABLE:
+ visit_raw_module(ctx, &command->assert_uninstantiable.module);
+ break;
+
+ case WASM_NUM_COMMAND_TYPES:
+ assert(0);
+ break;
+ }
+}
+
+static void visit_script(Context* ctx, WasmScript* script) {
+ size_t i;
+ for (i = 0; i < script->commands.size; ++i)
+ visit_command(ctx, &script->commands.data[i]);
+}
+
+static void init_context(Context* ctx,
+ WasmAllocator* allocator,
+ WasmAstLexer* lexer,
+ WasmScript* script,
+ WasmSourceErrorHandler* error_handler) {
+ WASM_ZERO_MEMORY(*ctx);
+ ctx->allocator = allocator;
+ ctx->lexer = lexer;
+ ctx->error_handler = error_handler;
+ ctx->result = WASM_OK;
+ ctx->script = script;
+ ctx->visitor.user_data = ctx;
+ ctx->visitor.begin_block_expr = begin_block_expr;
+ ctx->visitor.end_block_expr = end_block_expr;
+ ctx->visitor.begin_loop_expr = begin_loop_expr;
+ ctx->visitor.end_loop_expr = end_loop_expr;
+ ctx->visitor.on_br_expr = on_br_expr;
+ ctx->visitor.on_br_if_expr = on_br_if_expr;
+ ctx->visitor.on_br_table_expr = on_br_table_expr;
+ ctx->visitor.on_call_expr = on_call_expr;
+ ctx->visitor.on_call_indirect_expr = on_call_indirect_expr;
+ ctx->visitor.on_get_global_expr = on_get_global_expr;
+ ctx->visitor.on_get_local_expr = on_get_local_expr;
+ ctx->visitor.begin_if_expr = begin_if_expr;
+ ctx->visitor.end_if_expr = end_if_expr;
+ ctx->visitor.on_set_global_expr = on_set_global_expr;
+ ctx->visitor.on_set_local_expr = on_set_local_expr;
+ ctx->visitor.on_tee_local_expr = on_tee_local_expr;
+}
+
+WasmResult wasm_resolve_names_module(WasmAllocator* allocator,
+ WasmAstLexer* lexer,
+ WasmModule* module,
+ WasmSourceErrorHandler* error_handler) {
+ Context ctx;
+ init_context(&ctx, allocator, lexer, NULL, error_handler);
+ visit_module(&ctx, module);
+ wasm_destroy_label_ptr_vector(allocator, &ctx.labels);
+ return ctx.result;
+}
+
+WasmResult wasm_resolve_names_script(WasmAllocator* allocator,
+ WasmAstLexer* lexer,
+ WasmScript* script,
+ WasmSourceErrorHandler* error_handler) {
+ Context ctx;
+ init_context(&ctx, allocator, lexer, script, error_handler);
+ visit_script(&ctx, script);
+ wasm_destroy_label_ptr_vector(allocator, &ctx.labels);
+ return ctx.result;
+}
diff --git a/src/resolve-names.h b/src/resolve-names.h
new file mode 100644
index 00000000..f248792d
--- /dev/null
+++ b/src/resolve-names.h
@@ -0,0 +1,40 @@
+/*
+ * 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_RESOLVE_NAMES_H_
+#define WASM_RESOLVE_NAMES_H_
+
+#include "common.h"
+
+struct WasmAllocator;
+struct WasmAstLexer;
+struct WasmModule;
+struct WasmScript;
+struct WasmSourceErrorHandler;
+
+WASM_EXTERN_C_BEGIN
+WasmResult wasm_resolve_names_module(struct WasmAllocator*,
+ struct WasmAstLexer*,
+ struct WasmModule*,
+ struct WasmSourceErrorHandler*);
+
+WasmResult wasm_resolve_names_script(struct WasmAllocator*,
+ struct WasmAstLexer*,
+ struct WasmScript*,
+ struct WasmSourceErrorHandler*);
+WASM_EXTERN_C_END
+
+#endif /* WASM_RESOLVE_NAMES_H_ */
diff --git a/src/tools/wast2wasm.c b/src/tools/wast2wasm.c
index 064806b7..6017d77f 100644
--- a/src/tools/wast2wasm.c
+++ b/src/tools/wast2wasm.c
@@ -28,6 +28,7 @@
#include "binary-writer-spec.h"
#include "common.h"
#include "option-parser.h"
+#include "resolve-names.h"
#include "stack-allocator.h"
#include "stream.h"
#include "writer.h"
@@ -238,13 +239,11 @@ int main(int argc, char** argv) {
WasmResult result = wasm_parse_ast(lexer, &script, &s_error_handler);
if (WASM_SUCCEEDED(result)) {
- if (s_check) {
- /* full validation of the module */
- result = wasm_check_ast(allocator, lexer, &script, &s_error_handler);
- } else {
- /* minimal checks necessary to ensure we can generate a binary */
- result = wasm_check_names(allocator, lexer, &script, &s_error_handler);
- }
+ result =
+ wasm_resolve_names_script(allocator, lexer, &script, &s_error_handler);
+
+ if (WASM_SUCCEEDED(result) && s_check)
+ result = wasm_check_script(allocator, lexer, &script, &s_error_handler);
if (WASM_SUCCEEDED(result) && s_check_assert_invalid_and_malformed) {
WasmDefaultErrorHandlerInfo assert_invalid_info;