Bug 1301029: Hoist textToBinary and evalText in lib/wasm.js; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 07 Sep 2016 12:22:25 +0200
changeset 313028 7092faec0016abdaa7c0b06a75e80977ba9bda13
parent 313027 9b1425c4b569f20b3c9a50ac04e3afee4f13f61c
child 313029 77399867b2861839a93ef42dd17fad6e2652a049
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
bugs1301029
milestone51.0a1
Bug 1301029: Hoist textToBinary and evalText in lib/wasm.js; r=luke MozReview-Commit-ID: GkdlrEGQNZZ
js/src/jit-test/lib/wasm.js
js/src/jit-test/tests/wasm/globals.js
js/src/jit-test/tests/wasm/import-export.js
js/src/jit-test/tests/wasm/import-gc.js
js/src/jit-test/tests/wasm/jsapi.js
js/src/jit-test/tests/wasm/profiling.js
js/src/jit-test/tests/wasm/spec.js
js/src/jit-test/tests/wasm/start.js
js/src/jit-test/tests/wasm/table-gc.js
js/src/jit-test/tests/wasm/tables.js
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -1,13 +1,38 @@
 if (!wasmIsSupported())
     quit();
 
 load(libdir + "asserts.js");
 
+function textToBinary(str) {
+    // TODO when mass-switching to the new-format, just rename
+    // textToBinary to wasmTextToBinary and remove this function.
+    return wasmTextToBinary(str, 'new-format');
+}
+
+function evalText(str, imports) {
+    // TODO when mass-switching to the new-format, just rename
+    // evalText to wasmEvalText and remove the function wasmEvalText
+    // below.
+    let binary = wasmTextToBinary(str, 'new-format');
+    let valid = WebAssembly.validate(binary);
+
+    let m;
+    try {
+        m = new WebAssembly.Module(binary);
+        assertEq(valid, true);
+    } catch(e) {
+        assertEq(valid, false);
+        throw e;
+    }
+
+    return new WebAssembly.Instance(m, imports);
+}
+
 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/globals.js
+++ b/js/src/jit-test/tests/wasm/globals.js
@@ -1,13 +1,12 @@
 // |jit-test| test-also-wasm-baseline
 load(libdir + "wasm.js");
 
 const { Instance, Module } = WebAssembly;
-const evalText = (txt, imports = {}) => new Instance(new Module(wasmTextToBinary(txt, 'new-format')), imports).exports;
 
 // Locally-defined globals
 assertErrorMessage(() => evalText(`(module (global))`), SyntaxError, /parsing/);
 assertErrorMessage(() => evalText(`(module (global i32))`), SyntaxError, /parsing/);
 assertErrorMessage(() => evalText(`(module (global i32 immutable))`), SyntaxError, /parsing/);
 
 // Initializer expressions.
 assertErrorMessage(() => evalText(`(module (global i32 (f32.const 13.37)))`), TypeError, /type mismatch/);
@@ -28,17 +27,17 @@ function testInner(type, initialValue, n
         (func $set (param ${type}) (set_global 0 (get_local 0)))
 
         (func $get_cst (result ${type}) (get_global 1))
 
         (export "get" $get)
         (export "get_cst" $get_cst)
 
         (export "set" $set)
-    )`);
+    )`).exports;
 
     assertFunc(module.get(), coercion(initialValue));
     assertEq(module.set(coercion(nextValue)), undefined);
     assertFunc(module.get(), coercion(nextValue));
 
     assertFunc(module.get_cst(), coercion(initialValue));
 }
 
@@ -71,17 +70,17 @@ var module = evalText(`(module
     ${get_set(3, 'f64')}
     ${get_set(4, 'i32')}
 
     (export "get0" $get_0) (export "set0" $set_0)
     (export "get1" $get_1) (export "set1" $set_1)
     (export "get2" $get_2) (export "set2" $set_2)
     (export "get3" $get_3) (export "set3" $set_3)
     (export "get4" $get_4) (export "set4" $set_4)
-)`);
+)`).exports;
 
 let values = [42, 10, Math.fround(13.37), 13.37, -18];
 let nextValues = [13, 37, Math.fround(-17.89), 9.3, -13];
 for (let i = 0; i < 5; i++) {
     assertEq(module[`get${i}`](), values[i]);
     assertEq(module[`set${i}`](nextValues[i]), undefined);
     assertEq(module[`get${i}`](), nextValues[i]);
     for (let j = 0; j < 5; j++) {
@@ -102,41 +101,41 @@ module = evalText(`(module
     (elem (get_global 0) $f)
     (func $f)
     (export "f" $f)
     (export "tbl" table)
 )`, {
     globals: {
         a: 1
     }
-});
+}).exports;
 assertEq(module.f, module.tbl.get(1));
 
 // Import/export rules.
 assertErrorMessage(() => evalText(`(module (import "globals" "x" (global i32)))`), TypeError, /can't import.* mutable globals in the MVP/);
 assertErrorMessage(() => evalText(`(module (global i32 (i32.const 42)) (export "" global 0))`), TypeError, /can't .*export mutable globals in the MVP/);
 
 // Import/export semantics.
 module = evalText(`(module
  (import $g "globals" "x" (global i32 immutable))
  (func $get (result i32) (get_global $g))
  (export "getter" $get)
  (export "value" global 0)
-)`, { globals: {x: 42} });
+)`, { globals: {x: 42} }).exports;
 
 assertEq(module.getter(), 42);
 assertEq(module.value, 42);
 
 // Imported globals and locally defined globals use the same index space.
 module = evalText(`(module
  (import "globals" "x" (global i32 immutable))
  (global i32 immutable (i32.const 1337))
  (export "imported" global 0)
  (export "defined" global 1)
-)`, { globals: {x: 42} });
+)`, { globals: {x: 42} }).exports;
 
 assertEq(module.imported, 42);
 assertEq(module.defined, 1337);
 
 // Initializer expressions can reference an imported immutable global.
 assertErrorMessage(() => evalText(`(module (global f32 immutable (f32.const 13.37)) (global i32 (get_global 0)))`), TypeError, /must reference a global immutable import/);
 assertErrorMessage(() => evalText(`(module (global f32 (f32.const 13.37)) (global i32 (get_global 0)))`), TypeError, /must reference a global immutable import/);
 assertErrorMessage(() => evalText(`(module (global i32 (i32.const 0)) (global i32 (get_global 0)))`), TypeError, /must reference a global immutable import/);
@@ -161,17 +160,17 @@ function testInitExpr(type, initialValue
         (export "get1" $get1)
         (export "get_cst" $get_cst)
 
         (export "set1" $set1)
     )`, {
         globals: {
             a: coercion(initialValue)
         }
-    });
+    }).exports;
 
     assertFunc(module.get0(), coercion(initialValue));
     assertFunc(module.get1(), coercion(initialValue));
 
     assertEq(module.set1(coercion(nextValue)), undefined);
     assertFunc(module.get1(), coercion(nextValue));
     assertFunc(module.get0(), coercion(initialValue));
 
@@ -191,15 +190,15 @@ testInitExpr('f64', 13.37, 0.1989, x => 
     testInner('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
     testInitExpr('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
 
     module = evalText(`(module
      (import "globals" "x" (global i64 immutable))
      (global i64 immutable (i64.const 0xFAFADADABABA))
      (export "imported" global 0)
      (export "defined" global 1)
-    )`, { globals: {x: createI64('0x1234567887654321')} });
+    )`, { globals: {x: createI64('0x1234567887654321')} }).exports;
 
     assertEqI64(module.imported, createI64('0x1234567887654321'));
     assertEqI64(module.defined, createI64('0xFAFADADABABA'));
 
     setJitCompilerOption('wasm.test-mode', 0);
 }
--- a/js/src/jit-test/tests/wasm/import-export.js
+++ b/js/src/jit-test/tests/wasm/import-export.js
@@ -17,20 +17,16 @@ const mem3Page = new Memory({initial:3})
 const mem3PageMax3 = new Memory({initial:3, maximum: 3});
 const mem4Page = new Memory({initial:4});
 const mem4PageMax4 = new Memory({initial:4, maximum: 4});
 const tab1Elem = new Table({initial:1, element:"anyfunc"});
 const tab2Elem = new Table({initial:2, element:"anyfunc"});
 const tab3Elem = new Table({initial:3, element:"anyfunc"});
 const tab4Elem = new Table({initial:4, element:"anyfunc"});
 
-// Explicitly opt into the new binary format for imports and exports until it
-// is used by default everywhere.
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
-
 assertErrorMessage(() => new Memory({initial:2, maximum:1}), TypeError, /bad Memory maximum size/);
 
 const m1 = new Module(textToBinary('(module (import "foo" "bar") (import "baz" "quux"))'));
 assertErrorMessage(() => new Instance(m1), TypeError, /no import object given/);
 assertErrorMessage(() => new Instance(m1, {foo:null}), TypeError, /import object field is not an Object/);
 assertErrorMessage(() => new Instance(m1, {foo:{bar:{}}}), TypeError, /import object field is not a Function/);
 assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:null}), TypeError, /import object field is not an Object/);
 assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:{}}), TypeError, /import object field is not a Function/);
@@ -89,17 +85,17 @@ assertErrorMessage(() => new Instance(m7
 
 assertErrorMessage(() => new Module(textToBinary('(module (memory 2 1))')), TypeError, /maximum length less than initial length/);
 assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 2 1)))')), TypeError, /maximum length less than initial length/);
 assertErrorMessage(() => new Module(textToBinary('(module (table (resizable 2 1)))')), TypeError, /maximum length less than initial length/);
 assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (table 2 1)))')), TypeError, /maximum length less than initial length/);
 
 // Import wasm-wasm type mismatch
 
-var e = new Instance(new Module(textToBinary('(module (func $i2v (param i32)) (export "i2v" $i2v) (func $f2v (param f32)) (export "f2v" $f2v))'))).exports;
+var e = evalText('(module (func $i2v (param i32)) (export "i2v" $i2v) (func $f2v (param f32)) (export "f2v" $f2v))').exports;
 var i2vm = new Module(textToBinary('(module (import "a" "b" (param i32)))'));
 var f2vm = new Module(textToBinary('(module (import "a" "b" (param f32)))'));
 assertEq(new Instance(i2vm, {a:{b:e.i2v}}) instanceof Instance, true);
 assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function signature mismatch/);
 assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function signature mismatch/);
 assertEq(new Instance(f2vm, {a:{b:e.f2v}}) instanceof Instance, true);
 
 // Import order:
--- a/js/src/jit-test/tests/wasm/import-gc.js
+++ b/js/src/jit-test/tests/wasm/import-gc.js
@@ -3,20 +3,16 @@
 // adding spurious edges to the GC graph.
 
 load(libdir + 'wasm.js');
 load(libdir + 'asserts.js');
 
 const Module = WebAssembly.Module;
 const Instance = WebAssembly.Instance;
 
-// Explicitly opt into the new binary format for imports and exports until it
-// is used by default everywhere.
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
-
 const m1 = new Module(textToBinary(`(module (func $f) (export "f" $f))`));
 const m2 = new Module(textToBinary(`(module (import "a" "f") (func $f) (export "g" $f))`));
 
 // Imported instance objects should stay alive as long as any importer is alive.
 resetFinalizeCount();
 var i1 = new Instance(m1);
 var i2 = new Instance(m2, {a:i1.exports});
 var f = i1.exports.f;
--- a/js/src/jit-test/tests/wasm/jsapi.js
+++ b/js/src/jit-test/tests/wasm/jsapi.js
@@ -1,15 +1,11 @@
 load(libdir + 'wasm.js');
 load(libdir + 'asserts.js');
 
-// Explicitly opt into the new binary format for imports and exports until it
-// is used by default everywhere.
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
-
 const emptyModule = textToBinary('(module)');
 
 // 'WebAssembly' property on global object
 const wasmDesc = Object.getOwnPropertyDescriptor(this, 'WebAssembly');
 assertEq(typeof wasmDesc.value, "object");
 assertEq(wasmDesc.writable, true);
 assertEq(wasmDesc.enumerable, false);
 assertEq(wasmDesc.configurable, true);
--- a/js/src/jit-test/tests/wasm/profiling.js
+++ b/js/src/jit-test/tests/wasm/profiling.js
@@ -4,20 +4,16 @@ load(libdir + "asserts.js");
 // Single-step profiling currently only works in the ARM simulator
 if (!getBuildConfiguration()["arm-simulator"])
     quit();
 
 const Module = WebAssembly.Module;
 const Instance = WebAssembly.Instance;
 const Table = WebAssembly.Table;
 
-// Explicitly opt into the new binary format for imports and exports until it
-// is used by default everywhere.
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
-
 function normalize(stack)
 {
     var wasmFrameTypes = [
         {re:/^entry trampoline \(in asm.js\)$/,             sub:">"},
         {re:/^wasm-function\[(\d+)\] \(.*\)$/,              sub:"$1"},
         {re:/^(fast|slow) FFI trampoline \(in asm.js\)$/,   sub:"<"},
         {re:/ \(in asm.js\)$/,                              sub:""}
     ];
@@ -53,17 +49,17 @@ function assertEqStacks(got, expect)
         }
     }
 }
 
 function test(code, expect)
 {
     enableSPSProfiling();
 
-    var f = new Instance(new Module(textToBinary(code))).exports[""];
+    var f = evalText(code).exports[""];
     enableSingleStepProfiling();
     f();
     assertEqStacks(disableSingleStepProfiling(), expect);
 
     disableSPSProfiling();
 }
 
 test(
@@ -107,25 +103,25 @@ testError(
     (func $foo (call_indirect $bad (i32.const 0) (i32.const 1)))
     (func $bar (type $good))
     (table $bar)
     (export "" $foo)
 )`,
 Error);
 
 (function() {
-    var e = new Instance(new Module(textToBinary(`
+    var e = evalText(`
     (module
         (func $foo (result i32) (i32.const 42))
         (export "foo" $foo)
         (func $bar (result i32) (i32.const 13))
         (table (resizable 10))
         (elem (i32.const 0) $foo $bar)
         (export "tbl" table)
-    )`))).exports;
+    )`).exports;
     assertEq(e.foo(), 42);
     assertEq(e.tbl.get(0)(), 42);
     assertEq(e.tbl.get(1)(), 13);
 
     enableSPSProfiling();
     enableSingleStepProfiling();
     assertEq(e.tbl.get(0)(), 42);
     assertEqStacks(disableSingleStepProfiling(), ["", ">", "0,>", ">", ""]);
@@ -147,26 +143,25 @@ Error);
 
     enableSPSProfiling();
     enableSingleStepProfiling();
     assertEq(e.foo(), 42);
     assertEq(e.tbl.get(1)(), 13);
     assertEqStacks(disableSingleStepProfiling(), ["", ">", "0,>", ">", "", ">", "1,>", ">", ""]);
     disableSPSProfiling();
 
-    var e2 = new Instance(new Module(textToBinary(`
+    var e2 = evalText(`
     (module
         (type $v2i (func (result i32)))
         (import "a" "b" (table 10))
         (elem (i32.const 2) $bar)
         (func $bar (result i32) (i32.const 99))
         (func $baz (param $i i32) (result i32) (call_indirect $v2i (get_local $i)))
         (export "baz" $baz)
-    )`)),
-    {a:{b:e.tbl}}).exports;
+    )`, {a:{b:e.tbl}}).exports;
 
     enableSPSProfiling();
     enableSingleStepProfiling();
     assertEq(e2.baz(0), 42);
     assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
     disableSPSProfiling();
 
     enableSPSProfiling();
--- a/js/src/jit-test/tests/wasm/spec.js
+++ b/js/src/jit-test/tests/wasm/spec.js
@@ -210,18 +210,17 @@ function handleNonStandard(exprName, e)
 }
 
 // Recursively execute the expression.
 function exec(e) {
     var exprName = e.list[0].str;
 
     if (exprName === "module") {
         let moduleText = e.toString();
-        var m = new WebAssembly.Module(wasmTextToBinary(moduleText, 'new-format'));
-        module = new WebAssembly.Instance(m, imports).exports;
+        module = evalText(moduleText, imports).exports;
         return;
     }
 
     if (exprName === "invoke") {
         var name = e.list[1].str;
         var args = e.list.slice(2).map(exec);
         var fn = null;
 
@@ -270,28 +269,24 @@ function exec(e) {
 
     if (exprName === "assert_invalid") {
         let moduleText = e.list[1].toString();
         let errMsg = e.list[2];
         if (errMsg) {
             assert(errMsg.quoted, "assert_invalid second argument must be a string");
             errMsg.quoted = false;
         }
-        let caught = false;
+        // assert_invalid tests both the decoder *and* the parser itself.
         try {
-            new WebAssembly.Instance(
-                new WebAssembly.Module(
-                    wasmTextToBinary(moduleText, 'new-format')),
-                imports);
+            assertEq(WebAssembly.validate(textToBinary(moduleText)), false);
         } catch(e) {
-            if (errMsg && e.toString().indexOf(errMsg) === -1)
-                warn(`expected error message "${errMsg}", got "${e}"`);
-            caught = true;
+            if (/wasm text error/.test(e.toString()))
+                return;
+            throw e;
         }
-        assert(caught, "assert_invalid error");
         return;
     }
 
     if (exprName === 'assert_trap') {
         let caught = false;
         let errMsg = e.list[2];
         assert(errMsg.quoted, "assert_trap second argument must be a string");
         errMsg.quoted = false;
--- a/js/src/jit-test/tests/wasm/start.js
+++ b/js/src/jit-test/tests/wasm/start.js
@@ -23,17 +23,16 @@ exports = wasmEvalText(`(module (import 
 assertEq(count, 1);
 assertEq(typeof exports, 'function');
 assertEq(exports(), undefined);
 assertEq(count, 2);
 
 // New API.
 const Module = WebAssembly.Module;
 const Instance = WebAssembly.Instance;
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
 
 count = 0;
 const m = new Module(textToBinary('(module (import $imp "" "inc") (func) (func $start (call $imp)) (start $start) (export "" $start))'));
 assertEq(count, 0);
 
 assertErrorMessage(() => new Instance(m), TypeError, /no import object given/);
 assertEq(count, 0);
 
--- a/js/src/jit-test/tests/wasm/table-gc.js
+++ b/js/src/jit-test/tests/wasm/table-gc.js
@@ -4,21 +4,16 @@
 
 load(libdir + 'wasm.js');
 load(libdir + 'asserts.js');
 
 const Module = WebAssembly.Module;
 const Instance = WebAssembly.Instance;
 const Table = WebAssembly.Table;
 
-// Explicitly opt into the new binary format for imports and exports until it
-// is used by default everywhere.
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
-const evalText = (str, imports) => new Instance(new Module(textToBinary(str)), imports);
-
 var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect $v2i (get_local $i))) (export "call" $call)`
 var callee = i => `(func $f${i} (type $v2i) (result i32) (i32.const ${i}))`;
 
 // A table should not hold exported functions alive and exported functions
 // should not hold their originating table alive. Live exported functions should
 // hold instances alive and instances hold imported tables alive. Nothing
 // should hold the export object alive.
 resetFinalizeCount();
--- a/js/src/jit-test/tests/wasm/tables.js
+++ b/js/src/jit-test/tests/wasm/tables.js
@@ -2,22 +2,16 @@
 load(libdir + 'wasm.js');
 load(libdir + 'asserts.js');
 
 const Module = WebAssembly.Module;
 const Instance = WebAssembly.Instance;
 const Table = WebAssembly.Table;
 const Memory = WebAssembly.Memory;
 
-// Explicitly opt into the new binary format for imports and exports until it
-// is used by default everywhere.
-const textToBinary = str => wasmTextToBinary(str, 'new-format');
-
-const evalText = (str, imports) => new Instance(new Module(textToBinary(str)), imports);
-
 var callee = i => `(func $f${i} (result i32) (i32.const ${i}))`;
 
 assertErrorMessage(() => new Module(textToBinary(`(module (elem (i32.const 0) $f0) ${callee(0)})`)), TypeError, /table index out of range/);
 assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 0) 0))`)), TypeError, /table element out of range/);
 assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (func) (elem (i32.const 0) 0 1))`)), TypeError, /table element out of range/);
 assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (func) (elem (f32.const 0) 0) ${callee(0)})`)), TypeError, /type mismatch/);
 
 assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 10) $f0) ${callee(0)})`)), TypeError, /element segment does not fit/);