Bug 1292723: Implement a basic WebAssembly.validate; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 07 Sep 2016 17:52:31 +0200
changeset 313030 5ad42aa79b3dbbfd54b54a4b2368d0677d01206d
parent 313029 77399867b2861839a93ef42dd17fad6e2652a049
child 313031 bfe117203e0cf267f180e0710b06e8425b99515f
push id20479
push userkwierso@gmail.com
push dateThu, 08 Sep 2016 01:08:46 +0000
treeherderfx-team@fb7c6b034329 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1292723
milestone51.0a1
Bug 1292723: Implement a basic WebAssembly.validate; r=luke MozReview-Commit-ID: FRNy8jS0v3e
js/src/asmjs/WasmJS.cpp
js/src/jit-test/lib/asm.js
js/src/jit-test/lib/wasm.js
js/src/jit-test/tests/wasm/basic.js
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -1281,24 +1281,55 @@ WebAssembly_compile(JSContext* cx, unsig
         task->finishPromise(cx, promise);
     }
 
     callArgs.rval().setObject(*promise);
     return true;
 }
 #endif
 
+static bool
+WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs callArgs = CallArgsFromVp(argc, vp);
+
+    MutableBytes bytecode;
+    CompileArgs compileArgs;
+    if (!GetCompileArgs(cx, callArgs, "WebAssembly.validate", &bytecode, &compileArgs))
+        return false;
+
+    UniqueChars error;
+    bool validated = !!Compile(*bytecode, compileArgs, &error);
+
+    // If the reason for validation failure was OOM (signalled by null error
+    // message), report out-of-memory so that validate's return is always
+    // correct.
+    if (!validated && !error) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+
+    if (error) {
+        JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
+                                     JSMSG_WASM_DECODE_FAIL, "?", error.get());
+    }
+
+    callArgs.rval().setBoolean(validated);
+    return true;
+}
+
 static const JSFunctionSpec WebAssembly_static_methods[] =
 {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str, WebAssembly_toSource, 0, 0),
 #endif
 #ifdef SPIDERMONKEY_PROMISE
     JS_FN("compile", WebAssembly_compile, 1, 0),
 #endif
+    JS_FN("validate", WebAssembly_validate, 1, 0),
     JS_FS_END
 };
 
 const Class js::WebAssemblyClass =
 {
     js_WebAssembly_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_WebAssembly)
 };
--- a/js/src/jit-test/lib/asm.js
+++ b/js/src/jit-test/lib/asm.js
@@ -1,13 +1,12 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const ASM_OK_STRING = "successfully compiled asm.js code";
 const ASM_TYPE_FAIL_STRING = "asm.js type error:";
 const ASM_DIRECTIVE_FAIL_STRING = "\"use asm\" is only meaningful in the Directive Prologue of a function body";
 
 const USE_ASM = '"use asm";';
 const HEAP_IMPORTS = "const i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);"+
                      "const i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);"+
                      "const i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);"+
                      "const f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -23,16 +23,26 @@ function evalText(str, imports) {
     } catch(e) {
         assertEq(valid, false);
         throw e;
     }
 
     return new WebAssembly.Instance(m, imports);
 }
 
+function wasmValidateText(str) {
+    assertEq(WebAssembly.validate(wasmTextToBinary(str, 'new-format')), true);
+}
+
+function wasmFailValidateText(str, errorType, pattern) {
+    let binary = wasmTextToBinary(str, 'new-format');
+    assertEq(WebAssembly.validate(binary), false);
+    assertErrorMessage(() => new WebAssembly.Module(binary), errorType, pattern);
+}
+
 function wasmEvalText(str, imports) {
     var exports = Wasm.instantiateModule(wasmTextToBinary(str), imports).exports;
     if (Object.keys(exports).length == 1 && exports[""])
         return exports[""];
     return exports;
 }
 
 function mismatchError(actual, expect) {
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -19,23 +19,23 @@ assertEq(typeof desc.value, "function");
 assertEq(desc.value.name, "wasm-function[0]");
 assertEq(desc.value.length, 0);
 assertEq(desc.value(), undefined);
 assertEq(desc.writable, true);
 assertEq(desc.enumerable, true);
 assertEq(desc.configurable, true);
 assertEq(desc.value(), undefined);
 
-wasmEvalText('(module (func) (func) (export "a" 0))');
-wasmEvalText('(module (func) (func) (export "a" 1))');
-wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
-wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
+wasmValidateText('(module (func) (func) (export "a" 0))');
+wasmValidateText('(module (func) (func) (export "a" 1))');
+wasmValidateText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
+wasmValidateText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
 
-assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /exported function index out of bounds/);
-assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), TypeError, /exported function index out of bounds/);
+wasmFailValidateText('(module (func) (export "a" 1))', TypeError, /exported function index out of bounds/);
+wasmFailValidateText('(module (func) (func) (export "a" 2))', TypeError, /exported function index out of bounds/);
 
 var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))');
 assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
 assertEq(o.a.name, "wasm-function[0]");
 assertEq(o.b.name, "wasm-function[0]");
 assertEq(o.a === o.b, true);
 
 var o = wasmEvalText('(module (func) (func) (export "a" 0) (export "b" 1))');
@@ -52,35 +52,36 @@ assertEq(o.a(), 2);
 assertEq(o.b(), 1);
 
 assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 0) (export "a" 0))'), TypeError, /duplicate export/);
 assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 0) (export "a" 1))'), TypeError, /duplicate export/);
 
 // ----------------------------------------------------------------------------
 // signatures
 
-assertErrorMessage(() => wasmEvalText('(module (func (result i32)))'), TypeError, mismatchError("void", "i32"));
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (nop)))'), TypeError, mismatchError("void", "i32"));
-wasmEvalText('(module (func (nop)))');
-wasmEvalText('(module (func (result i32) (i32.const 42)))');
-wasmEvalText('(module (func (param i32)))');
-wasmEvalText('(module (func (param i32) (result i32) (i32.const 42)))');
-wasmEvalText('(module (func (result i32) (param i32) (i32.const 42)))');
-wasmEvalText('(module (func (param f32)))');
-wasmEvalText('(module (func (param f64)))');
+wasmFailValidateText('(module (func (result i32)))', TypeError, mismatchError("void", "i32"));
+wasmFailValidateText('(module (func (result i32) (nop)))', TypeError, mismatchError("void", "i32"));
+
+wasmValidateText('(module (func (nop)))');
+wasmValidateText('(module (func (result i32) (i32.const 42)))');
+wasmValidateText('(module (func (param i32)))');
+wasmValidateText('(module (func (param i32) (result i32) (i32.const 42)))');
+wasmValidateText('(module (func (result i32) (param i32) (i32.const 42)))');
+wasmValidateText('(module (func (param f32)))');
+wasmValidateText('(module (func (param f64)))');
 
 var f = wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))');
-assertErrorMessage(() => f(), TypeError, /i64/);
+assertErrorMessage(f, TypeError, /i64/);
 var f = wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))');
-assertErrorMessage(() => f(), TypeError, /i64/);
+assertErrorMessage(f, TypeError, /i64/);
 
 var f = wasmEvalText('(module (import $imp "a" "b" (param i64) (result i32)) (func $f (call_import $imp (i64.const 0))) (export "" $f))', {a:{b:()=>{}}});
-assertErrorMessage(() => f(), TypeError, /i64/);
+assertErrorMessage(f, TypeError, /i64/);
 var f = wasmEvalText('(module (import $imp "a" "b" (result i64)) (func $f (call_import $imp)) (export "" $f))', {a:{b:()=>{}}});
-assertErrorMessage(() => f(), TypeError, /i64/);
+assertErrorMessage(f, TypeError, /i64/);
 
 setJitCompilerOption('wasm.test-mode', 1);
 assertEqI64(wasmEvalText('(module (func (result i64) (i64.const 123)) (export "" 0))')(), {low: 123, high: 0});
 assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (get_local 0)) (export "" 0))')({ low: 0x7fffffff, high: 0x12340000}),
             {low: 0x7fffffff, high: 0x12340000});
 assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (i64.add (get_local 0) (i64.const 1))) (export "" 0))')({ low: 0xffffffff, high: 0x12340000}), {low: 0x0, high: 0x12340001});
 setJitCompilerOption('wasm.test-mode', 0);
 
@@ -118,19 +119,19 @@ wasmEvalText(code, {a:{"":()=>{}}, b:{c:
 wasmEvalText('(module (import "a" "" (result i32)))', {a:{"":()=>{}}});
 wasmEvalText('(module (import "a" "" (result f32)))', {a:{"":()=>{}}});
 wasmEvalText('(module (import "a" "" (result f64)))', {a:{"":()=>{}}});
 wasmEvalText('(module (import $foo "a" "" (result f64)))', {a:{"":()=>{}}});
 
 // ----------------------------------------------------------------------------
 // memory
 
-wasmEvalText('(module (memory 0))');
-wasmEvalText('(module (memory 1))');
-assertErrorMessage(() => wasmEvalText('(module (memory 65536))'), TypeError, /initial memory size too big/);
+wasmValidateText('(module (memory 0))');
+wasmValidateText('(module (memory 1))');
+wasmFailValidateText('(module (memory 65536))', TypeError, /initial memory size too big/);
 
 // May OOM, but must not crash:
 try {
     wasmEvalText('(module (memory 65535))');
 } catch (e) {
     assertEq(String(e).indexOf("out of memory") != -1, true);
 }
 
@@ -159,110 +160,113 @@ var buf = wasmEvalText('(module (memory 
 assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
 assertEq(new Uint8Array(buf)[1], 0);
 assertEq(new Uint8Array(buf)[2], 'b'.charCodeAt(0));
 
 var buf = wasmEvalText('(module (memory 1 (segment 65535 "c")) (export "memory" memory))').memory;
 assertEq(new Uint8Array(buf)[0], 0);
 assertEq(new Uint8Array(buf)[65535], 'c'.charCodeAt(0));
 
-assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65536 "a")) (export "memory" memory))'), TypeError, /data segment does not fit/);
-assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65535 "ab")) (export "memory" memory))'), TypeError, /data segment does not fit/);
+wasmFailValidateText('(module (memory 1 (segment 65536 "a")) (export "memory" memory))', TypeError, /data segment does not fit/);
+wasmFailValidateText('(module (memory 1 (segment 65535 "ab")) (export "memory" memory))', TypeError, /data segment does not fit/);
 
 // ----------------------------------------------------------------------------
 // locals
 
 assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))')(42), 42);
 assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 0)) (export "" 0))')(42, 43), 42);
 assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 1)) (export "" 0))')(42, 43), 43);
 
-assertErrorMessage(() => wasmEvalText('(module (func (get_local 0)))'), TypeError, /get_local index out of range/);
-wasmEvalText('(module (func (local i32)))');
-wasmEvalText('(module (func (local i32) (local f32)))');
+wasmFailValidateText('(module (func (get_local 0)))', TypeError, /get_local index out of range/);
+wasmValidateText('(module (func (local i32)))');
+wasmValidateText('(module (func (local i32) (local f32)))');
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (get_local 0)) (export "" 0))')(), 0);
-assertErrorMessage(() => wasmEvalText('(module (func (result f32) (local i32) (get_local 0)))'), TypeError, mismatchError("i32", "f32"));
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (local f32) (get_local 0)))'), TypeError, mismatchError("f32", "i32"));
+wasmFailValidateText('(module (func (result f32) (local i32) (get_local 0)))', TypeError, mismatchError("i32", "f32"));
+wasmFailValidateText('(module (func (result i32) (local f32) (get_local 0)))', TypeError, mismatchError("f32", "i32"));
 assertEq(wasmEvalText('(module (func (result i32) (param i32) (local f32) (get_local 0)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (result f32) (param i32) (local f32) (get_local 1)) (export "" 0))')(), 0);
-assertErrorMessage(() => wasmEvalText('(module (func (result f32) (param i32) (local f32) (get_local 0)))'), TypeError, mismatchError("i32", "f32"));
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (param i32) (local f32) (get_local 1)))'), TypeError, mismatchError("f32", "i32"));
+wasmFailValidateText('(module (func (result f32) (param i32) (local f32) (get_local 0)))', TypeError, mismatchError("i32", "f32"));
+wasmFailValidateText('(module (func (result i32) (param i32) (local f32) (get_local 1)))', TypeError, mismatchError("f32", "i32"));
 
-assertErrorMessage(() => wasmEvalText('(module (func (set_local 0 (i32.const 0))))'), TypeError, /set_local index out of range/);
-wasmEvalText('(module (func (local i32) (set_local 0 (i32.const 0))))');
-assertErrorMessage(() => wasmEvalText('(module (func (local f32) (set_local 0 (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
-assertErrorMessage(() => wasmEvalText('(module (func (local f32) (set_local 0 (nop))))'), TypeError, mismatchError("void", "f32"));
-assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))'), TypeError, mismatchError("f32", "i32"));
-assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))'), TypeError, mismatchError("i32", "f32"));
-wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 0))))');
-wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 1))))');
+wasmFailValidateText('(module (func (set_local 0 (i32.const 0))))', TypeError, /set_local index out of range/);
+wasmValidateText('(module (func (local i32) (set_local 0 (i32.const 0))))');
+wasmFailValidateText('(module (func (local f32) (set_local 0 (i32.const 0))))', TypeError, mismatchError("i32", "f32"));
+wasmFailValidateText('(module (func (local f32) (set_local 0 (nop))))', TypeError, mismatchError("void", "f32"));
+wasmFailValidateText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))', TypeError, mismatchError("f32", "i32"));
+wasmFailValidateText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))', TypeError, mismatchError("i32", "f32"));
+wasmValidateText('(module (func (local i32) (local f32) (set_local 0 (get_local 0))))');
+wasmValidateText('(module (func (local i32) (local f32) (set_local 1 (get_local 1))))');
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (i32.const 42))) (export "" 0))')(), 42);
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (get_local 0))) (export "" 0))')(), 0);
 
 assertEq(wasmEvalText('(module (func (param $a i32) (result i32) (get_local $a)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (param $a i32) (local $b i32) (result i32) (block (set_local $b (get_local $a)) (get_local $b))) (export "" 0))')(42), 42);
 
-wasmEvalText('(module (func (local i32) (local $a f32) (set_local 0 (i32.const 1)) (set_local $a (f32.const nan))))');
+wasmValidateText('(module (func (local i32) (local $a f32) (set_local 0 (i32.const 1)) (set_local $a (f32.const nan))))');
 
 // ----------------------------------------------------------------------------
 // blocks
 
 assertEq(wasmEvalText('(module (func (block)) (export "" 0))')(), undefined);
 
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block)))'), TypeError, mismatchError("void", "i32"));
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (block))))'), TypeError, mismatchError("void", "i32"));
-assertErrorMessage(() => wasmEvalText('(module (func (local i32) (set_local 0 (block))))'), TypeError, mismatchError("void", "i32"));
+wasmFailValidateText('(module (func (result i32) (block)))', TypeError, mismatchError("void", "i32"));
+wasmFailValidateText('(module (func (result i32) (block (block))))', TypeError, mismatchError("void", "i32"));
+wasmFailValidateText('(module (func (local i32) (set_local 0 (block))))', TypeError, mismatchError("void", "i32"));
 
 assertEq(wasmEvalText('(module (func (block (block))) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func (result i32) (block (i32.const 42))) (export "" 0))')(), 42);
 assertEq(wasmEvalText('(module (func (result i32) (block (block (i32.const 42)))) (export "" 0))')(), 42);
-assertErrorMessage(() => wasmEvalText('(module (func (result f32) (block (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
+wasmFailValidateText('(module (func (result f32) (block (i32.const 0))))', TypeError, mismatchError("i32", "f32"));
 
 assertEq(wasmEvalText('(module (func (result i32) (block (i32.const 13) (block (i32.const 42)))) (export "" 0))')(), 42);
-assertErrorMessage(() => wasmEvalText('(module (func (result f32) (param f32) (block (get_local 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
+wasmFailValidateText('(module (func (result f32) (param f32) (block (get_local 0) (i32.const 0))))', TypeError, mismatchError("i32", "f32"));
 
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (i32.const 42)) (get_local 0)) (export "" 0))')(), 42);
 
 // ----------------------------------------------------------------------------
 // calls
 
-assertThrowsInstanceOf(() => wasmEvalText('(module (func (nop)) (func (call 0 (i32.const 0))))'), TypeError);
+wasmFailValidateText('(module (func (nop)) (func (call 0 (i32.const 0))))', TypeError, /call arity out of range/);
 
-assertThrowsInstanceOf(() => wasmEvalText('(module (func (param i32) (nop)) (func (call 0)))'), TypeError);
-assertThrowsInstanceOf(() => wasmEvalText('(module (func (param f32) (nop)) (func (call 0 (i32.const 0))))'), TypeError);
-assertErrorMessage(() => wasmEvalText('(module (func (nop)) (func (call 3)))'), TypeError, /callee index out of range/);
-wasmEvalText('(module (func (nop)) (func (call 0)))');
-wasmEvalText('(module (func (param i32) (nop)) (func (call 0 (i32.const 0))))');
+wasmFailValidateText('(module (func (param i32) (nop)) (func (call 0)))', TypeError, /call arity out of range/);
+wasmFailValidateText('(module (func (param f32) (nop)) (func (call 0 (i32.const 0))))', TypeError, mismatchError("i32", "f32"));
+wasmFailValidateText('(module (func (nop)) (func (call 3)))', TypeError, /callee index out of range/);
+
+wasmValidateText('(module (func (nop)) (func (call 0)))');
+wasmValidateText('(module (func (param i32) (nop)) (func (call 0 (i32.const 0))))');
+
 assertEq(wasmEvalText('(module (func (result i32) (i32.const 42)) (func (result i32) (call 0)) (export "" 1))')(), 42);
 assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 0)) (export "" 0))')(), InternalError);
 assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 1)) (func (call 0)) (export "" 0))')(), InternalError);
-wasmEvalText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (f32.const nan))))');
-assertErrorMessage(() => wasmEvalText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
+
+wasmValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (f32.const nan))))');
+wasmFailValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (i32.const 0))))', TypeError, mismatchError("i32", "f32"));
 
-assertThrowsInstanceOf(() => wasmEvalText('(module (import "a" "") (func (call_import 0 (i32.const 0))))', {a:()=>{}}), TypeError);
+wasmFailValidateText('(module (import "a" "") (func (call_import 0 (i32.const 0))))', TypeError, /call arity out of range/);
+wasmFailValidateText('(module (import "a" "" (param i32)) (func (call_import 0)))', TypeError, /call arity out of range/);
+wasmFailValidateText('(module (import "a" "" (param f32)) (func (call_import 0 (i32.const 0))))', TypeError, mismatchError("i32", "f32"));
 
-assertThrowsInstanceOf(() => wasmEvalText('(module (import "a" "" (param i32)) (func (call_import 0)))', {a:()=>{}}), TypeError);
-assertThrowsInstanceOf(() => wasmEvalText('(module (import "a" "" (param f32)) (func (call_import 0 (i32.const 0))))', {a:()=>{}}), TypeError);
 assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call_import 1)))'), TypeError, /import index out of range/);
 wasmEvalText('(module (import "" "a") (func (call_import 0)))', {"":{a:()=>{}}});
 wasmEvalText('(module (import "" "a" (param i32)) (func (call_import 0 (i32.const 0))))', {"":{a:()=>{}}});
 
 function checkF32CallImport(v) {
     assertEq(wasmEvalText('(module (import "" "a" (result f32)) (func (result f32) (call_import 0)) (export "" 0))', {"":{a:()=>{ return v; }}})(), Math.fround(v));
     wasmEvalText('(module (import "" "a" (param f32)) (func (param f32) (call_import 0 (get_local 0))) (export "" 0))', {"":{a:x=>{ assertEq(Math.fround(v), x); }}})(v);
 }
 checkF32CallImport(13.37);
 checkF32CallImport(NaN);
 checkF32CallImport(-Infinity);
 checkF32CallImport(-0);
 checkF32CallImport(Math.pow(2, 32) - 1);
 
+var counter = 0;
 var f = wasmEvalText('(module (import "" "inc") (func (call_import 0)) (export "" 0))', {"":{inc:()=>counter++}});
 var g = wasmEvalText('(module (import "" "f") (func (block (call_import 0) (call_import 0))) (export "" 0))', {"":{f}});
-var counter = 0;
 f();
 assertEq(counter, 1);
 g();
 assertEq(counter, 3);
 
 var f = wasmEvalText('(module (import "" "callf") (func (call_import 0)) (export "" 0))', {"":{callf:()=>f()}});
 assertThrowsInstanceOf(() => f(), InternalError);
 
@@ -337,17 +341,17 @@ if (typeof evaluate === 'function')
          )
          (get_local 1)
         )
     (export "" 0))`, imp)(), { low: 1337, high: 0x12345678 });
 
     setJitCompilerOption('wasm.test-mode', 0);
 }
 
-assertErrorMessage(() => wasmEvalText(`(module (type $t (func)) (func (call_indirect $t (i32.const 0))))`), TypeError, /can't call_indirect without a table/);
+wasmFailValidateText(`(module (type $t (func)) (func (call_indirect $t (i32.const 0))))`, TypeError, /can't call_indirect without a table/);
 
 var {v2i, i2i, i2v} = wasmEvalText(`(module
     (type (func (result i32)))
     (type (func (param i32) (result i32)))
     (type (func (param i32)))
     (func (type 0) (i32.const 13))
     (func (type 0) (i32.const 42))
     (func (type 1) (i32.add (get_local 0) (i32.const 1)))
@@ -413,25 +417,24 @@ assertErrorMessage(() => i2v(5), Error, 
 }
 
 for (bad of [6, 7, 100, Math.pow(2,31)-1, Math.pow(2,31), Math.pow(2,31)+1, Math.pow(2,32)-2, Math.pow(2,32)-1]) {
     assertThrowsInstanceOf(() => v2i(bad), RangeError);
     assertThrowsInstanceOf(() => i2i(bad, 0), RangeError);
     assertThrowsInstanceOf(() => i2v(bad, 0), RangeError);
 }
 
-wasmEvalText('(module (func $foo (nop)) (func (call $foo)))');
-wasmEvalText('(module (func (call $foo)) (func $foo (nop)))');
-wasmEvalText('(module (import $bar "" "a") (func (call_import $bar)) (func $foo (nop)))', {"":{a:()=>{}}});
-
+wasmValidateText('(module (func $foo (nop)) (func (call $foo)))');
+wasmValidateText('(module (func (call $foo)) (func $foo (nop)))');
+wasmValidateText('(module (import $bar "" "a") (func (call_import $bar)) (func $foo (nop)))');
 
 // ----------------------------------------------------------------------------
 // select
 
-assertErrorMessage(() => wasmEvalText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "i32"));
+wasmFailValidateText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))', TypeError, mismatchError("f32", "i32"));
 
 assertEq(wasmEvalText('(module (func (select (i32.const 0) (f32.const 0) (i32.const 0))) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func (select (block) (i32.const 0) (i32.const 0))) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func (i32.add (i32.const 0) (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func (select (if (i32.const 1) (i32.const 0) (f32.const 0)) (i32.const 0) (i32.const 0))) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func) (func (select (call 0) (call 0) (i32.const 0))) (export "" 0))')(), undefined);
 
@@ -574,9 +577,8 @@ testSelect('f64', 'nan', Math.pow(2, -31
     )`, imports);
 
     assertEqI64(f(0),  { low: 0xdeadc0de, high: 0x12345678});
     assertEqI64(f(1),  { low: 0x8badf00d, high: 0xc0010ff0});
     assertEqI64(f(-1), { low: 0x8badf00d, high: 0xc0010ff0});
 
     setJitCompilerOption('wasm.test-mode', 0);
 }
-