Bug 1313024: Allow data sections to be displayed on several lines; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 26 Oct 2016 16:44:47 +0200
changeset 320009 58c6affba442284f0ca3b02f14b1f10ea1907109
parent 320008 ef0ab8f78fe9911e3b0dfcf30fbc315f95b4d665
child 320010 fb3cd4dc8aef5f2e33a274c21e5e0acc7cce230a
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1313024
milestone52.0a1
Bug 1313024: Allow data sections to be displayed on several lines; r=luke MozReview-Commit-ID: 2gBp7UAM4fF
js/src/asmjs/WasmAST.h
js/src/asmjs/WasmBinaryToAST.cpp
js/src/asmjs/WasmBinaryToExperimentalText.cpp
js/src/asmjs/WasmBinaryToText.cpp
js/src/asmjs/WasmTextToBinary.cpp
js/src/jit-test/tests/wasm/full-cycle.js
js/src/jit-test/tests/wasm/spec/float_exprs.wast.js
--- a/js/src/asmjs/WasmAST.h
+++ b/js/src/asmjs/WasmAST.h
@@ -696,25 +696,25 @@ class AstExport : public AstNode
     AstName name() const { return name_; }
     DefinitionKind kind() const { return kind_; }
     AstRef& ref() { return ref_; }
 };
 
 class AstDataSegment : public AstNode
 {
     AstExpr* offset_;
-    AstName text_;
+    AstNameVector fragments_;
 
   public:
-    AstDataSegment(AstExpr* offset, AstName text)
-      : offset_(offset), text_(text)
+    AstDataSegment(AstExpr* offset, AstNameVector&& fragments)
+      : offset_(offset), fragments_(Move(fragments))
     {}
 
     AstExpr* offset() const { return offset_; }
-    AstName text() const { return text_; }
+    const AstNameVector& fragments() const { return fragments_; }
 };
 
 typedef AstVector<AstDataSegment*> AstDataSegmentVector;
 
 class AstElemSegment : public AstNode
 {
     AstExpr* offset_;
     AstRefVector elems_;
--- a/js/src/asmjs/WasmBinaryToAST.cpp
+++ b/js/src/asmjs/WasmBinaryToAST.cpp
@@ -2022,16 +2022,19 @@ AstDecodeCodeSection(AstDecodeContext &c
     }
 
     if (!c.d.finishSection(sectionStart, sectionSize, "code"))
         return false;
 
     return true;
 }
 
+// Number of bytes to display in a single fragment of a data section (per line).
+static const size_t WRAP_DATA_BYTES = 30;
+
 static bool
 AstDecodeDataSection(AstDecodeContext &c)
 {
     DataSegmentVector segments;
     bool hasMemory = c.module().hasMemory();
 
     MOZ_ASSERT(c.module().memories().length() <= 1, "at most one memory in MVP");
     uint32_t memByteLength = hasMemory ? c.module().memories()[0].limits.initial : 0;
@@ -2044,18 +2047,24 @@ AstDecodeDataSection(AstDecodeContext &c
         char16_t* buffer = static_cast<char16_t*>(c.lifo.alloc(s.length * sizeof(char16_t)));
         for (size_t i = 0; i < s.length; i++)
             buffer[i] = src[i];
 
         AstExpr* offset = ToAstExpr(c, s.offset);
         if (!offset)
             return false;
 
-        AstName name(buffer, s.length);
-        AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, name);
+        AstNameVector fragments(c.lifo);
+        for (size_t start = 0; start < s.length; start += WRAP_DATA_BYTES) {
+            AstName name(buffer + start, Min(WRAP_DATA_BYTES, s.length - start));
+            if (!fragments.append(name))
+                return false;
+        }
+
+        AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, Move(fragments));
         if (!segment || !c.module().append(segment))
             return false;
     }
 
     return true;
 }
 
 static bool
--- a/js/src/asmjs/WasmBinaryToExperimentalText.cpp
+++ b/js/src/asmjs/WasmBinaryToExperimentalText.cpp
@@ -1768,53 +1768,65 @@ PrintDataSection(WasmPrintContext& c, co
     if (!PrintIndent(c))
         return false;
     if (!c.buffer.append("memory "))
         return false;
 
     const Limits& memory = module.memories()[0].limits;
     MOZ_ASSERT(memory.initial % PageSize == 0);
     if (!PrintInt32(c, memory.initial / PageSize))
-       return false;
+        return false;
 
     if (memory.maximum) {
         MOZ_ASSERT(*memory.maximum % PageSize == 0);
         if (!c.buffer.append(", "))
             return false;
         if (!PrintInt32(c, *memory.maximum / PageSize))
             return false;
     }
 
     c.indent++;
 
     uint32_t numSegments = module.dataSegments().length();
     if (!numSegments) {
-      if (!c.buffer.append(" {}\n\n"))
-          return false;
-      return true;
+        if (!c.buffer.append(" {}\n\n"))
+            return false;
+        return true;
     }
     if (!c.buffer.append(" {\n"))
         return false;
 
     for (uint32_t i = 0; i < numSegments; i++) {
         const AstDataSegment* segment = module.dataSegments()[i];
-
         if (!PrintIndent(c))
             return false;
         if (!c.buffer.append("segment "))
-           return false;
+            return false;
         if (!PrintInt32(c, segment->offset()->as<AstConst>().val().i32()))
-           return false;
-        if (!c.buffer.append(" \""))
-           return false;
+            return false;
+        if (!c.buffer.append("\n"))
+            return false;
 
-        PrintEscapedString(c, segment->text());
+        c.indent++;
+        for (const AstName& fragment : segment->fragments()) {
+            if (!PrintIndent(c))
+                return false;
+            if (!c.buffer.append("\""))
+                return false;
+            if (!PrintEscapedString(c, fragment))
+                return false;
+            if (!c.buffer.append("\"\n"))
+                return false;
+        }
+        c.indent--;
 
-        if (!c.buffer.append("\";\n"))
-           return false;
+        if (!PrintIndent(c))
+            return false;
+        if (!c.buffer.append(";\n"))
+            return false;
     }
 
     c.indent--;
     if (!c.buffer.append("}\n\n"))
         return false;
 
     return true;
 }
--- a/js/src/asmjs/WasmBinaryToText.cpp
+++ b/js/src/asmjs/WasmBinaryToText.cpp
@@ -1625,21 +1625,35 @@ RenderDataSection(WasmRenderContext& c, 
 
     for (const AstDataSegment* seg : module.dataSegments()) {
         if (!RenderIndent(c))
             return false;
         if (!c.buffer.append("(data "))
             return false;
         if (!RenderInlineExpr(c, *seg->offset()))
             return false;
-        if (!c.buffer.append(" \""))
+        if (!c.buffer.append("\n"))
             return false;
-        if (!RenderEscapedString(c, seg->text()))
+
+        c.indent++;
+        for (const AstName& fragment : seg->fragments()) {
+            if (!RenderIndent(c))
+                return false;
+            if (!c.buffer.append("\""))
+                return false;
+            if (!RenderEscapedString(c, fragment))
+                return false;
+            if (!c.buffer.append("\"\n"))
+                return false;
+        }
+        c.indent--;
+
+        if (!RenderIndent(c))
             return false;
-        if (!c.buffer.append("\")\n"))
+        if (!c.buffer.append(")\n"))
             return false;
     }
 
     return true;
 }
 
 static bool
 RenderStartSection(WasmRenderContext& c, AstModule& module)
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -2733,21 +2733,25 @@ ParseDataSegment(WasmParseContext& c)
 {
     if (!MaybeParseOwnerIndex(c))
         return nullptr;
 
     AstExpr* offset = ParseInitializerExpression(c);
     if (!offset)
         return nullptr;
 
+    AstNameVector fragments(c.lifo);
+
     WasmToken text;
-    if (!c.ts.getIf(WasmToken::Text, &text))
-        return new(c.lifo) AstDataSegment(offset, AstName());
-
-    return new(c.lifo) AstDataSegment(offset, text.text());
+    while (c.ts.getIf(WasmToken::Text, &text)) {
+        if (!fragments.append(text.text()))
+            return nullptr;
+    }
+
+    return new(c.lifo) AstDataSegment(offset, Move(fragments));
 }
 
 static bool
 ParseLimits(WasmParseContext& c, Limits* limits)
 {
     WasmToken initial;
     if (!c.ts.match(WasmToken::Index, &initial, c.error))
         return false;
@@ -2795,28 +2799,37 @@ ParseMemory(WasmParseContext& c, WasmTok
             c.ts.unget(openParen);
         }
     }
 
     if (c.ts.getIf(WasmToken::OpenParen)) {
         if (!c.ts.match(WasmToken::Data, c.error))
             return false;
 
-        WasmToken text;
+        AstNameVector fragments(c.lifo);
+
+        WasmToken data;
         size_t pages = 0;
-        if (c.ts.getIf(WasmToken::Text, &text)) {
+        size_t totalLength = 0;
+        while (c.ts.getIf(WasmToken::Text, &data)) {
+            if (!fragments.append(data.text()))
+                return false;
+            totalLength += data.text().length();
+        }
+
+        if (fragments.length()) {
             AstExpr* offset = new(c.lifo) AstConst(Val(uint32_t(0)));
             if (!offset)
                 return false;
 
-            AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, text.text());
+            AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, Move(fragments));
             if (!segment || !module->append(segment))
                 return false;
 
-            pages = AlignBytes<size_t>(segment->text().length(), PageSize) / PageSize;
+            pages = AlignBytes<size_t>(totalLength, PageSize) / PageSize;
             if (pages != uint32_t(pages))
                 return false;
         }
 
         Limits memory = { uint32_t(pages), Some(uint32_t(pages)) };
         if (!module->addMemory(name, memory))
             return false;
 
@@ -4616,28 +4629,32 @@ EncodeDataSegment(Encoder& e, AstDataSeg
     if (!e.writeVarU32(0))  // linear memory index
         return false;
 
     if (!EncodeExpr(e, *segment.offset()))
         return false;
     if (!e.writeExpr(Expr::End))
         return false;
 
-    AstName text = segment.text();
+    size_t totalLength = 0;
+    for (const AstName& fragment : segment.fragments())
+        totalLength += fragment.length();
 
     Vector<uint8_t, 0, SystemAllocPolicy> bytes;
-    if (!bytes.reserve(text.length()))
+    if (!bytes.reserve(totalLength))
         return false;
 
-    const char16_t* cur = text.begin();
-    const char16_t* end = text.end();
-    while (cur != end) {
-        uint8_t byte;
-        MOZ_ALWAYS_TRUE(ConsumeTextByte(&cur, end, &byte));
-        bytes.infallibleAppend(byte);
+    for (const AstName& fragment : segment.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));
+            bytes.infallibleAppend(byte);
+        }
     }
 
     if (!e.writeBytes(bytes.begin(), bytes.length()))
         return false;
 
     return true;
 }
 
--- a/js/src/jit-test/tests/wasm/full-cycle.js
+++ b/js/src/jit-test/tests/wasm/full-cycle.js
@@ -40,22 +40,23 @@ wasmFullPass(`(module
   i32.add
  )
  (export "run" $get)
 )`, 13 + 42 + 37 + 42, { globals: {x: 42} });
 
 // Memory.
 wasmFullPass(`(module
     (memory (export "memory") 1 2)
-    (data (i32.const 0) "\\00\\01\\02\\03\\04\\05")
+    (data (i32.const 0) "\\00\\01\\02" "\\03\\04\\05")
+    (data (i32.const 6) "\\06")
     (func (export "run") (result i32)
         i32.const 1
         i32.load offset=2
     )
-)`, 0x050403);
+)`, 0x06050403);
 
 let memory = new WebAssembly.Memory({ initial: 1, maximum: 2 });
 
 wasmFullPass(`(module
     (memory (import "" "memory") 1 2)
     (data (i32.const 0) "\\00\\01\\02\\03\\04\\05")
     (func (export "run") (result i32)
         i32.const 1
--- a/js/src/jit-test/tests/wasm/spec/float_exprs.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/float_exprs.wast.js
@@ -1,4 +1,2 @@
 // |jit-test| test-also-wasm-baseline
-// TODO parse error (memory data on several lines)
-quit();
 var importedArgs = ['float_exprs.wast']; load(scriptdir + '../spec.js');