Bug 1313024: Pass binary.wast; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 09 Nov 2016 18:39:14 +0100
changeset 321858 f0b9e37236b5fc5df582b72942916241f1ece3de
parent 321857 56f7c0be1ddaab2c5e3752814443c206c23f6e9c
child 321859 592187676a06cb47da66e56de1975ec9351c15a6
push id83690
push userbbouvier@mozilla.com
push dateWed, 09 Nov 2016 17:55:21 +0000
treeherdermozilla-inbound@f0b9e37236b5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1313024
milestone52.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 1313024: Pass binary.wast; r=luke MozReview-Commit-ID: AdgZ3Jm5Pbg
js/src/jit-test/tests/wasm/spec.js
js/src/jit-test/tests/wasm/spec/binary.wast.js
js/src/wasm/WasmTextToBinary.cpp
--- a/js/src/jit-test/tests/wasm/spec.js
+++ b/js/src/jit-test/tests/wasm/spec.js
@@ -392,31 +392,43 @@ function exec(e) {
 
             i32[0] = res.nan_low;
             i32[1] = res.nan_high;
             assert(Number.isNaN(f64[0]) || Number.isNaN(f32[0]), "assert_return_nan test failed.");
         }
         return;
     }
 
-    if (exprName === "assert_invalid") {
+    if (exprName === "assert_invalid" || exprName === "assert_malformed") {
         let moduleText = e.list[1].toString();
         let errMsg = e.list[2];
         if (errMsg) {
-            assert(errMsg.quoted, "assert_invalid second argument must be a string");
+            assert(errMsg.quoted, "assert_invalid/malformed second argument must be a string");
             errMsg.quoted = false;
         }
+
         // assert_invalid tests both the decoder *and* the parser itself.
+        let text;
         try {
-            assertEq(WebAssembly.validate(wasmTextToBinary(moduleText)), false, "assert_invalid failed");
+            text = wasmTextToBinary(moduleText);
         } catch(e) {
             if (/wasm text error/.test(e.toString()))
                 return;
-            throw e;
         }
+
+        assertEq(WebAssembly.validate(text), false, "assert_invalid failed");
+
+        let caught = false;
+        try {
+            new WebAssembly.Module(text)
+        } catch (e) {
+            caught = true;
+            debug("Caught", e.toString(), ", expected:", errMsg);
+        }
+        assertEq(caught, true);
         return;
     }
 
     if (exprName === "assert_soft_invalid") {
         let moduleText = e.list[1].toString();
         let errMsg = e.list[2];
         if (errMsg) {
             assert(errMsg.quoted, "assert_soft_invalid second argument must be a string");
--- a/js/src/jit-test/tests/wasm/spec/binary.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/binary.wast.js
@@ -1,3 +1,1 @@
-// TODO: binary text format.
-quit();
 var importedArgs = ['binary.wast']; load(scriptdir + '../spec.js');
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -461,17 +461,17 @@ LexDecFloatLiteral(const char16_t* begin
             cur++;
     }
 
     *curp = cur;
     return WasmToken(WasmToken::DecNumber, begin, cur);
 }
 
 static bool
-ConsumeTextByte(const char16_t** curp, const char16_t* end, uint8_t *byte = nullptr)
+ConsumeTextByte(const char16_t** curp, const char16_t* end, uint8_t* byte = nullptr)
 {
     const char16_t*& cur = *curp;
     MOZ_ASSERT(cur != end);
 
     if (*cur != '\\') {
         if (byte)
             *byte = *cur;
         cur++;
@@ -3208,29 +3208,56 @@ ParseGlobal(WasmParseContext& c, AstModu
     if (!init)
         return false;
 
     auto* glob = new(c.lifo) AstGlobal(name, typeToken.valueType(), isMutable, Some(init));
     return glob && module->append(glob);
 }
 
 static AstModule*
-ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
+ParseBinaryModule(WasmParseContext& c, AstModule* module)
+{
+    // By convention with EncodeBinaryModule, a binary module only contains a
+    // data section containing the raw bytes contained in the module.
+    AstNameVector fragments(c.lifo);
+
+    WasmToken text;
+    while (c.ts.getIf(WasmToken::Text, &text)) {
+        if (!fragments.append(text.text()))
+            return nullptr;
+    }
+
+    auto* data = new(c.lifo) AstDataSegment(nullptr, Move(fragments));
+    if (!data || !module->append(data))
+        return nullptr;
+
+    return module;
+}
+
+static AstModule*
+ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error, bool* binary)
 {
     WasmParseContext c(text, lifo, error);
 
+    *binary = false;
+
     if (!c.ts.match(WasmToken::OpenParen, c.error))
         return nullptr;
     if (!c.ts.match(WasmToken::Module, c.error))
         return nullptr;
 
     auto* module = new(c.lifo) AstModule(c.lifo);
     if (!module || !module->init())
         return nullptr;
 
+    if (c.ts.peek().kind() == WasmToken::Text) {
+        *binary = true;
+        return ParseBinaryModule(c, module);
+    }
+
     while (c.ts.getIf(WasmToken::OpenParen)) {
         WasmToken section = c.ts.get();
 
         switch (section.kind()) {
           case WasmToken::Type: {
             AstSig* sig = ParseTypeDef(c);
             if (!sig || !module->append(sig))
                 return nullptr;
@@ -4623,17 +4650,17 @@ EncodeCodeSection(Encoder& e, AstModule&
             return false;
     }
 
     e.finishSection(offset);
     return true;
 }
 
 static bool
-EncodeDataSegment(Encoder& e, AstDataSegment& segment)
+EncodeDataSegment(Encoder& e, const AstDataSegment& segment)
 {
     if (!e.writeVarU32(0))  // linear memory index
         return false;
 
     if (!EncodeExpr(e, *segment.offset()))
         return false;
     if (!e.writeExpr(Expr::End))
         return false;
@@ -4651,20 +4678,17 @@ EncodeDataSegment(Encoder& e, AstDataSeg
         const char16_t* end = fragment.end();
         while (cur != end) {
             uint8_t byte;
             MOZ_ALWAYS_TRUE(ConsumeTextByte(&cur, end, &byte));
             bytes.infallibleAppend(byte);
         }
     }
 
-    if (!e.writeBytes(bytes.begin(), bytes.length()))
-        return false;
-
-    return true;
+    return e.writeBytes(bytes.begin(), bytes.length());
 }
 
 static bool
 EncodeDataSection(Encoder& e, AstModule& module)
 {
     if (module.dataSegments().empty())
         return true;
 
@@ -4770,23 +4794,50 @@ EncodeModule(AstModule& module, Bytes* b
         return false;
 
     if (!EncodeDataSection(e, module))
         return false;
 
     return true;
 }
 
+static bool
+EncodeBinaryModule(const AstModule& module, Bytes* bytes)
+{
+    Encoder e(*bytes);
+
+    const AstDataSegmentVector& dataSegments = module.dataSegments();
+    MOZ_ASSERT(dataSegments.length() == 1);
+
+    for (const AstName& fragment : dataSegments[0]->fragments()) {
+        const char16_t* cur = fragment.begin();
+        const char16_t* end = fragment.end();
+        while (cur != end) {
+            uint8_t byte;
+            MOZ_ALWAYS_TRUE(ConsumeTextByte(&cur, end, &byte));
+            if (!e.writeFixedU8(byte))
+                return false;
+        }
+    }
+
+    return true;
+}
+
 /*****************************************************************************/
 
 bool
 wasm::TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error)
 {
     LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
-    AstModule* module = ParseModule(text, lifo, error);
+
+    bool binary = false;
+    AstModule* module = ParseModule(text, lifo, error, &binary);
     if (!module)
         return false;
 
+    if (binary)
+        return EncodeBinaryModule(*module, bytes);
+
     if (!ResolveModule(lifo, module, error))
         return false;
 
     return EncodeModule(*module, bytes);
 }