Bug 1292723: Implement a basic WebAssembly.validate; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 07 Sep 2016 17:52:31 +0200
changeset 313055 5ad42aa79b3dbbfd54b54a4b2368d0677d01206d
parent 313054 77399867b2861839a93ef42dd17fad6e2652a049
child 313056 bfe117203e0cf267f180e0710b06e8425b99515f
push id30669
push userkwierso@gmail.com
push dateThu, 08 Sep 2016 00:56:12 +0000
treeherdermozilla-central@77940cbf0c2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1292723
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);
 }
-