Bug 1313024: Pass binary.wast; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 09 Nov 2016 18:39:14 +0100
changeset 436797 f0b9e37236b5fc5df582b72942916241f1ece3de
parent 436796 56f7c0be1ddaab2c5e3752814443c206c23f6e9c
child 436798 592187676a06cb47da66e56de1975ec9351c15a6
push id35189
push userbmo:jmaher@mozilla.com
push dateWed, 09 Nov 2016 18:58:07 +0000
reviewersluke
bugs1313024
milestone52.0a1
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);
 }