Bug 1250551 - Make it possible to run wasm ml-proto spec tests directly. r=bbouvier
authorMichael Bebenita <mbebenita@gmail.com>
Tue, 23 Feb 2016 21:16:27 -0800
changeset 322713 eacf24b301ac0207e1dd1283f11133904cacbfb8
parent 322712 b1766ac255d5df660ac56b0421a82dc3a5fcd977
child 322714 b1af09a2c2d1f01ec45e34b3b0ae5b4f3b533f50
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1250551
milestone47.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 1250551 - Make it possible to run wasm ml-proto spec tests directly. r=bbouvier
js/src/jit-test/tests/wasm/spec.js
js/src/jit-test/tests/wasm/spec/list.js
js/src/jit-test/tests/wasm/spec/names.wast
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec.js
@@ -0,0 +1,182 @@
+load(libdir + "wasm.js");
+load(scriptdir + "spec/list.js");
+
+if (typeof assert === 'undefined') {
+    var assert = function assert(c, msg) {
+        if (!c) {
+            throw new Error("Assertion failed: " + msg);
+        }
+    };
+}
+
+// Element list or string.
+function Element(str, dollared, quoted) {
+    this.list = [];
+    this.str = str === undefined ? null : str;
+    this.dollared = !!dollared;
+    this.quoted = !!quoted;
+}
+Element.prototype.toString = function() {
+    if (this.str !== null) {
+        if (this.dollared) {
+            return "$" + this.str;
+        } else if (this.quoted) {
+            return `"${this.str}"`;
+        }
+        return this.str;
+    }
+    return `(${this.list.map(x => x.toString()).join(" ")})`;
+};
+
+// Creates a tree of s-expressions. Ported from Binaryen's SExpressionParser.
+function parseSExpression(text) {
+    var input = 0;
+    function parseInnerList() {
+        if (text[input] === ';') {
+            // Parse comment.
+            input++;
+            if (text[input] === ';') {
+                while (text[input] != '\n') input++;
+                return null;
+            }
+            input = text.substring(";)", input);
+            assert(input >= 0);
+            return null;
+        }
+        var ret = new Element();
+        while (true) {
+            var curr = parse();
+            if (!curr) return ret;
+            ret.list.push(curr);
+        }
+    }
+    function isSpace(c) {
+        switch (c) {
+            case ' ':
+            case '\n':
+            case '\r':
+            case '\t':
+            case '\v':
+            case '\f':
+                return true;
+            default:
+                return false;
+        }
+    }
+    function skipWhitespace() {
+        while (true) {
+            while (isSpace(text[input])) input++;
+            if (text[input] === ';' && text[input + 1] === ';') {
+                while (text.length > input && text[input] != '\n') input++;
+            } else if (text[input] === '(' && text[input + 1] === ';') {
+                input = text.substring(";)", input) + 2;
+            } else {
+                return;
+            }
+        }
+    }
+    function parseString() {
+        var dollared = false;
+        var quoted = false;
+        if (text[input] === '$') {
+            input++;
+            dollared = true;
+        }
+        var start = input;
+        if (text[input] === '"') {
+            quoted = true;
+            // Parse escaping \", but leave code escaped - we'll handle escaping in memory segments specifically.
+            input++;
+            var str = "";
+            while (true) {
+                if (text[input] === '"') break;
+                if (text[input] === '\\') {
+                    str += text[input];
+                    str += text[input + 1];
+                    input += 2;
+                    continue;
+                }
+                str += text[input];
+                input++;
+            }
+            input++;
+            return new Element(str, dollared, quoted);
+        }
+        while (text.length > input && !isSpace(text[input]) && text[input] != ')' && text[input] != '(') input++;
+        return new Element(text.substring(start, input), dollared);
+    }
+    function parse() {
+        skipWhitespace();
+        if (text.length === input || text[input] === ')') return null;
+        if (text[input] === '(') {
+            input++;
+            var ret = parseInnerList();
+            skipWhitespace();
+            assert(text[input] === ')');
+            input++;
+            return ret;
+        }
+        return parseString();
+    }
+    var root = null;
+    while (!root) { // Keep parsing until we pass an initial comment.
+        root = parseInnerList();
+    }
+    return root;
+}
+
+var imports = {
+    spectest: {
+        print: function (x) {
+            print(x);
+        }
+    }
+};
+var module;
+var moduleText;
+
+// Recursively execute the expression.
+function exec(e) {
+    var exprName = e.list[0].str;
+    if (exprName === "module") {
+        moduleText = e.toString();
+        try {
+            module = wasmEvalText(moduleText, imports);
+        } catch (x) {
+            assert(false, x.toString());
+        }
+    } else if (exprName === "invoke") {
+        var name = e.list[1].str;
+        var args = e.list.slice(2).map(exec);
+        var fn = null;
+        assert(module !== null);
+        if (typeof module[name] === "function") {
+            fn = module[name];
+        } else if (name === "") {
+            fn = module;
+            assert(typeof fn === "function", "Default exported function not found: " + e);
+        } else {
+            assert(false, "Exported function not found: " + e);
+        }
+        return fn.apply(null, args);
+    } else if (exprName.indexOf(".const") > 0) {
+        // Eval the expression using a wasm module.
+        var type = exprName.substring(0, exprName.indexOf(".const"));
+        return wasmEvalText('(module (func (result ' + type + ') ' + e + ') (export "" 0))')()
+    } else if (exprName === "assert_return") {
+        assertEq(exec(e.list[1]), exec(e.list[2]));
+    } else if (exprName === "assert_return_nan") {
+        assertEq(exec(e.list[1]), NaN);
+    } else {
+        assert(false, "NYI: " + e);
+    }
+}
+
+for (var test of specTests) {
+    module = null;
+    moduleText = null;
+    var root = new parseSExpression(read(scriptdir + "spec/" + test));
+    for (var e of root.list) {
+        exec(e);
+    }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/list.js
@@ -0,0 +1,7 @@
+// Included by ../spec.js.
+
+var specTests = [];
+
+specTests.push("names.wast");
+
+// Add more tests here.
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/names.wast
@@ -0,0 +1,91 @@
+;; Test files can define multiple modules. Test that implementations treat
+;; each module independently from the other.
+
+(module
+  (func $foo (result i32) (i32.const 0))
+  (export "foo" $foo)
+)
+
+(assert_return (invoke "foo") (i32.const 0))
+
+;; Another module, same function name, different contents.
+
+(module
+  (func $foo (result i32) (i32.const 1))
+  (export "foo" $foo)
+)
+
+(assert_return (invoke "foo") (i32.const 1))
+
+
+(module
+  ;; Test that we can use the empty string as a symbol.
+  (func (result f32) (f32.const 0x1.91p+2))
+  (export "" 0)
+
+  ;; Test that we can use common libc names without conflict.
+  (func $malloc (result f32) (f32.const 0x1.92p+2))
+  (export "malloc" $malloc)
+
+  ;; Test that we can use some libc hidden names without conflict.
+  (func $_malloc (result f32) (f32.const 0x1.93p+2))
+  (func $__malloc (result f32) (f32.const 0x1.94p+2))
+  (func (result f32) (f32.const 0x1.95p+2))
+  (export "_malloc" $_malloc)
+  (export "__malloc" $__malloc)
+
+  ;; Test that we can use non-alphanumeric names.
+  (func (result f32) (f32.const 0x1.96p+2))
+  (export "~!@#$%^&*()_+`-={}|[]\\:\";'<>?,./ " 5)
+
+  ;; Test that we can use names beginning with a digit.
+  (func (result f32) (f32.const 0x1.97p+2))
+  (export "0" 6)
+
+  ;; Test that we can use names beginning with an underscore.
+  (func $_ (result f32) (f32.const 0x1.98p+2))
+  (export "_" $_)
+
+  ;; Test that we can use names beginning with a dollar sign.
+  (func (result f32) (f32.const 0x1.99p+2))
+  (export "$" 8)
+
+  ;; Test that we can use names beginning with an at sign.
+  (func (result f32) (f32.const 0x2.00p+2))
+  (export "@" 9)
+
+  ;; Test that we can use names that have special meaning in JS.
+  (func $NaN (result f32) (f32.const 0x2.01p+2))
+  (func $Infinity (result f32) (f32.const 0x2.02p+2))
+  (func $if (result f32) (f32.const 0x2.03p+2))
+  (export "NaN" $NaN)
+  (export "Infinity" $Infinity)
+  (export "if" $if)
+)
+
+(assert_return (invoke "") (f32.const 0x1.91p+2))
+(assert_return (invoke "malloc") (f32.const 0x1.92p+2))
+(assert_return (invoke "_malloc") (f32.const 0x1.93p+2))
+(assert_return (invoke "__malloc") (f32.const 0x1.94p+2))
+(assert_return (invoke "~!@#$%^&*()_+`-={}|[]\\:\";'<>?,./ ") (f32.const 0x1.96p+2))
+(assert_return (invoke "0") (f32.const 0x1.97p+2))
+(assert_return (invoke "_") (f32.const 0x1.98p+2))
+(assert_return (invoke "$") (f32.const 0x1.99p+2))
+(assert_return (invoke "@") (f32.const 0x2.00p+2))
+(assert_return (invoke "NaN") (f32.const 0x2.01p+2))
+(assert_return (invoke "Infinity") (f32.const 0x2.02p+2))
+(assert_return (invoke "if") (f32.const 0x2.03p+2))
+
+(module
+  ;; Test that we can use indices instead of names to reference imports, 
+  ;; functions and parameters.
+  (import "spectest" "print" (param i32))
+  (import "spectest" "print" (param i32))
+  (func (param i32) (param i32)
+    (call_import 0 (get_local 0))
+    (call_import 1 (get_local 1))
+  )
+  (export "print32" 0)
+)
+
+(invoke "print32" (i32.const 42) (i32.const 123))
\ No newline at end of file