Bug 1310949: Factor out DecodeDataSection; r=luke
authorBenjamin Bouvier <benj@benj.me>
Thu, 20 Oct 2016 12:48:44 +0200
changeset 319219 743986b85b599eab0581b08172b8805ce3a44abc
parent 319218 bd4555428a116a2819715116dd34a13fa8203308
child 319220 0511d6630bdb62c34a689a5371e2b78930f37d1e
push id33488
push usercbook@mozilla.com
push dateTue, 25 Oct 2016 08:49:50 +0000
treeherderautoland@2bcd92f4caa0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1310949
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 1310949: Factor out DecodeDataSection; r=luke MozReview-Commit-ID: 2M84eKv8sIj
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmBinaryFormat.cpp
js/src/asmjs/WasmBinaryFormat.h
js/src/asmjs/WasmBinaryToAST.cpp
js/src/asmjs/WasmCompile.cpp
js/src/asmjs/WasmGenerator.cpp
js/src/asmjs/WasmGenerator.h
js/src/asmjs/WasmModule.h
js/src/asmjs/WasmTypes.h
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -797,16 +797,19 @@ class Decoder
         return size_t(end_ - cur_);
     }
     const uint8_t* currentPosition() const {
         return cur_;
     }
     size_t currentOffset() const {
         return cur_ - beg_;
     }
+    const uint8_t* begin() const {
+        return beg_;
+    }
 
     // Fixed-size encoding operations simply copy the literal bytes (without
     // attempting to align).
 
     MOZ_MUST_USE bool readFixedU8(uint8_t* i) {
         return read<uint8_t>(i);
     }
     MOZ_MUST_USE bool readFixedU32(uint32_t* u) {
--- a/js/src/asmjs/WasmBinaryFormat.cpp
+++ b/js/src/asmjs/WasmBinaryFormat.cpp
@@ -206,16 +206,72 @@ wasm::DecodeLimits(Decoder& d, Limits* l
 
         limits->maximum.emplace(maximum);
     }
 
     return true;
 }
 
 bool
+wasm::DecodeDataSection(Decoder& d, bool usesMemory, uint32_t minMemoryByteLength,
+                        const GlobalDescVector& globals, DataSegmentVector* segments)
+{
+    uint32_t sectionStart, sectionSize;
+    if (!d.startSection(SectionId::Data, &sectionStart, &sectionSize, "data"))
+        return false;
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    if (!usesMemory)
+        return d.fail("data section requires a memory section");
+
+    uint32_t numSegments;
+    if (!d.readVarU32(&numSegments))
+        return d.fail("failed to read number of data segments");
+
+    if (numSegments > MaxDataSegments)
+        return d.fail("too many data segments");
+
+    for (uint32_t i = 0; i < numSegments; i++) {
+        uint32_t linearMemoryIndex;
+        if (!d.readVarU32(&linearMemoryIndex))
+            return d.fail("expected linear memory index");
+
+        if (linearMemoryIndex != 0)
+            return d.fail("linear memory index must currently be 0");
+
+        DataSegment seg;
+        if (!DecodeInitializerExpression(d, globals, ValType::I32, &seg.offset))
+            return false;
+
+        if (!d.readVarU32(&seg.length))
+            return d.fail("expected segment size");
+
+        if (seg.offset.isVal()) {
+            uint32_t off = seg.offset.val().i32();
+            if (off > minMemoryByteLength || minMemoryByteLength - off < seg.length)
+                return d.fail("data segment does not fit");
+        }
+
+        seg.bytecodeOffset = d.currentOffset();
+
+        if (!d.readBytes(seg.length))
+            return d.fail("data segment shorter than declared");
+
+        if (!segments->append(seg))
+            return false;
+    }
+
+    if (!d.finishSection(sectionStart, sectionSize, "data"))
+        return false;
+
+    return true;
+}
+
+bool
 wasm::DecodeUnknownSections(Decoder& d)
 {
     while (!d.done()) {
         if (!d.skipUserDefinedSection())
             return false;
     }
 
     return true;
--- a/js/src/asmjs/WasmBinaryFormat.h
+++ b/js/src/asmjs/WasmBinaryFormat.h
@@ -46,12 +46,16 @@ DecodeInitializerExpression(Decoder& d, 
                             InitExpr* init);
 
 MOZ_MUST_USE bool
 DecodeLimits(Decoder& d, Limits* limits);
 
 MOZ_MUST_USE bool
 DecodeUnknownSections(Decoder& d);
 
+MOZ_MUST_USE bool
+DecodeDataSection(Decoder& d, bool usesMemory, uint32_t minMemoryByteLength,
+                  const GlobalDescVector& globals, DataSegmentVector* segments);
+
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_binary_format_h
--- a/js/src/asmjs/WasmBinaryToAST.cpp
+++ b/js/src/asmjs/WasmBinaryToAST.cpp
@@ -1780,37 +1780,41 @@ AstDecodeMemorySection(AstDecodeContext&
 
     if (!c.d.finishSection(sectionStart, sectionSize, "memory"))
         return false;
 
     c.module().setMemory(memory);
     return true;
 }
 
+static AstExpr*
+ToAstExpr(AstDecodeContext& c, const InitExpr& initExpr)
+{
+    switch (initExpr.kind()) {
+      case InitExpr::Kind::Constant: {
+        return new(c.lifo) AstConst(Val(initExpr.val()));
+      }
+      case InitExpr::Kind::GetGlobal: {
+        AstRef globalRef;
+        if (!AstDecodeGenerateRef(c, AstName(u"global"), initExpr.globalIndex(), &globalRef))
+            return nullptr;
+        return new(c.lifo) AstGetGlobal(globalRef);
+      }
+    }
+    return nullptr;
+}
+
 static bool
 AstDecodeInitializerExpression(AstDecodeContext& c, ValType type, AstExpr** init)
 {
     InitExpr initExpr;
     if (!DecodeInitializerExpression(c.d, c.globalDescs(), type, &initExpr))
         return false;
 
-    switch (initExpr.kind()) {
-      case InitExpr::Kind::Constant: {
-        *init = new(c.lifo) AstConst(Val(initExpr.val()));
-        break;
-      }
-      case InitExpr::Kind::GetGlobal: {
-        AstRef globalRef;
-        if (!AstDecodeGenerateRef(c, AstName(u"global"), initExpr.globalIndex(), &globalRef))
-            return false;
-        *init = new(c.lifo) AstGetGlobal(globalRef);
-        break;
-      }
-    }
-
+    *init = ToAstExpr(c, initExpr);
     return !!*init;
 }
 
 static bool
 AstDecodeGlobal(AstDecodeContext& c, uint32_t i, AstGlobal* global)
 {
     AstName name;
     if (!AstDecodeGenerateName(c, AstName(u"global"), i, &name))
@@ -2043,65 +2047,41 @@ AstDecodeCodeSection(AstDecodeContext &c
         return false;
 
     return true;
 }
 
 static bool
 AstDecodeDataSection(AstDecodeContext &c)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!c.d.startSection(SectionId::Data, &sectionStart, &sectionSize, "data"))
+    DataSegmentVector segments;
+    bool hasMemory = c.module().hasMemory();
+    uint32_t memByteLength = hasMemory ? c.module().memory().initial * PageSize : 0;
+    if (!DecodeDataSection(c.d, hasMemory, memByteLength, c.globalDescs(), &segments))
         return false;
-    if (sectionStart == Decoder::NotStarted)
-        return true;
-
-    uint32_t numSegments;
-    if (!c.d.readVarU32(&numSegments))
-        return c.d.fail("failed to read number of data segments");
-
-    const uint32_t heapLength = c.module().hasMemory() ? c.module().memory().initial : 0;
 
-    for (uint32_t i = 0; i < numSegments; i++) {
-        uint32_t dstOffset;
-        if (!c.d.readVarU32(&dstOffset))
-            return c.d.fail("expected segment destination offset");
-
-        uint32_t numBytes;
-        if (!c.d.readVarU32(&numBytes))
-            return c.d.fail("expected segment size");
-
-        if (dstOffset > heapLength || heapLength - dstOffset < numBytes)
-            return c.d.fail("data segment does not fit in memory");
-
-        const uint8_t* src;
-        if (!c.d.readBytes(numBytes, &src))
-            return c.d.fail("data segment shorter than declared");
-
-        char16_t *buffer = static_cast<char16_t *>(c.lifo.alloc(numBytes * sizeof(char16_t)));
-        for (size_t i = 0; i < numBytes; i++)
+    for (DataSegment& s : segments) {
+        const uint8_t* src = c.d.begin() + s.bytecodeOffset;
+        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 = new(c.lifo) AstConst(Val(dstOffset));
+        AstExpr* offset = ToAstExpr(c, s.offset);
         if (!offset)
             return false;
 
-        AstName name(buffer, numBytes);
+        AstName name(buffer, s.length);
         AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, name);
         if (!segment || !c.module().append(segment))
             return false;
     }
 
-    if (!c.d.finishSection(sectionStart, sectionSize, "data"))
-        return false;
-
     return true;
 }
 
-
 static bool
 AstDecodeElemSection(AstDecodeContext &c)
 {
     uint32_t sectionStart, sectionSize;
     if (!c.d.startSection(SectionId::Elem, &sectionStart, &sectionSize, "elem"))
         return false;
     if (sectionStart == Decoder::NotStarted)
         return true;
--- a/js/src/asmjs/WasmCompile.cpp
+++ b/js/src/asmjs/WasmCompile.cpp
@@ -1134,72 +1134,16 @@ DecodeElemSection(Decoder& d, Uint32Vect
     }
 
     if (!d.finishSection(sectionStart, sectionSize, "elem"))
         return false;
 
     return true;
 }
 
-static bool
-DecodeDataSection(Decoder& d, ModuleGenerator& mg)
-{
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Data, &sectionStart, &sectionSize, "data"))
-        return false;
-    if (sectionStart == Decoder::NotStarted)
-        return true;
-
-    if (!mg.usesMemory())
-        return d.fail("data section requires a memory section");
-
-    uint32_t numSegments;
-    if (!d.readVarU32(&numSegments))
-        return d.fail("failed to read number of data segments");
-
-    if (numSegments > MaxDataSegments)
-        return d.fail("too many data segments");
-
-    uint32_t max = mg.minMemoryLength();
-    for (uint32_t i = 0; i < numSegments; i++) {
-        uint32_t linearMemoryIndex;
-        if (!d.readVarU32(&linearMemoryIndex))
-            return d.fail("expected linear memory index");
-
-        if (linearMemoryIndex != 0)
-            return d.fail("linear memory index must currently be 0");
-
-        DataSegment seg;
-        if (!DecodeInitializerExpression(d, mg.globals(), ValType::I32, &seg.offset))
-            return false;
-
-        if (!d.readVarU32(&seg.length))
-            return d.fail("expected segment size");
-
-        if (seg.offset.isVal()) {
-            uint32_t off = seg.offset.val().i32();
-            if (off > max || max - off < seg.length)
-                return d.fail("data segment does not fit");
-        }
-
-        seg.bytecodeOffset = d.currentOffset();
-
-        if (!d.readBytes(seg.length))
-            return d.fail("data segment shorter than declared");
-
-        if (!mg.addDataSegment(seg))
-            return false;
-    }
-
-    if (!d.finishSection(sectionStart, sectionSize, "data"))
-        return false;
-
-    return true;
-}
-
 static void
 MaybeDecodeNameSectionBody(Decoder& d, ModuleGenerator& mg)
 {
     // For simplicity, ignore all failures, even OOM. Failure will simply result
     // in the names section not being included for this module.
 
     uint32_t numFuncNames;
     if (!d.readVarU32(&numFuncNames))
@@ -1237,16 +1181,27 @@ MaybeDecodeNameSectionBody(Decoder& d, M
                 return;
         }
     }
 
     mg.setFuncNames(Move(funcNames));
 }
 
 static bool
+DecodeDataSection(Decoder& d, ModuleGenerator& mg)
+{
+    DataSegmentVector dataSegments;
+    if (!DecodeDataSection(d, mg.usesMemory(), mg.minMemoryLength(), mg.globals(), &dataSegments))
+        return false;
+
+    mg.setDataSegments(Move(dataSegments));
+    return true;
+}
+
+static bool
 DecodeNameSection(Decoder& d, ModuleGenerator& mg)
 {
     uint32_t sectionStart, sectionSize;
     if (!d.startUserDefinedSection(NameSectionName, &sectionStart, &sectionSize))
         return false;
     if (sectionStart == Decoder::NotStarted)
         return true;
 
@@ -1312,17 +1267,17 @@ wasm::Compile(const ShareableBytes& byte
         return nullptr;
 
     if (!DecodeElemSection(d, Move(oldElems), mg))
         return nullptr;
 
     if (!DecodeCodeSection(d, mg))
         return nullptr;
 
-    if (!DecodeDataSection(d, mg))
+    if (!::DecodeDataSection(d, mg))
         return nullptr;
 
     if (!DecodeNameSection(d, mg))
         return nullptr;
 
     if (!DecodeUnknownSections(d))
         return nullptr;
 
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -855,16 +855,23 @@ ModuleGenerator::addElemSegment(InitExpr
             shared_->tables[0].external = true;
             break;
         }
     }
 
     return elemSegments_.emplaceBack(0, offset, Move(elemFuncIndices));
 }
 
+void
+ModuleGenerator::setDataSegments(DataSegmentVector&& segments)
+{
+    MOZ_ASSERT(dataSegments_.empty());
+    dataSegments_ = Move(segments);
+}
+
 bool
 ModuleGenerator::startFuncDefs()
 {
     MOZ_ASSERT(!startedFuncDefs_);
     MOZ_ASSERT(!finishedFuncDefs_);
 
     // Now that it is known whether tables are internal or external, mark the
     // elements of any external table as exported since they may be called from
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -187,17 +187,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     MOZ_MUST_USE bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDef(uint32_t funcDefIndex, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDefs();
 
     // Start function:
     bool setStartFunction(uint32_t funcIndex);
 
     // Segments:
-    MOZ_MUST_USE bool addDataSegment(DataSegment s) { return dataSegments_.append(s); }
+    void setDataSegments(DataSegmentVector&& segments);
     MOZ_MUST_USE bool addElemSegment(InitExpr offset, Uint32Vector&& elemFuncIndices);
 
     // Function names:
     void setFuncNames(NameInBytecodeVector&& funcNames);
 
     // asm.js lazy initialization:
     void initSig(uint32_t sigIndex, Sig&& sig);
     void initFuncDefSig(uint32_t funcIndex, uint32_t sigIndex);
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -126,28 +126,16 @@ class Export
     uint32_t funcIndex() const;
     uint32_t globalIndex() const;
 
     WASM_DECLARE_SERIALIZABLE(Export)
 };
 
 typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
 
-// DataSegment describes the offset of a data segment in the bytecode that is
-// to be copied at a given offset into linear memory upon instantiation.
-
-struct DataSegment
-{
-    InitExpr offset;
-    uint32_t bytecodeOffset;
-    uint32_t length;
-};
-
-typedef Vector<DataSegment, 0, SystemAllocPolicy> DataSegmentVector;
-
 // ElemSegment represents an element segment in the module where each element
 // describes both its function index and its code range.
 
 struct ElemSegment
 {
     uint32_t tableIndex;
     InitExpr offset;
     Uint32Vector elemFuncIndices;
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -569,16 +569,28 @@ class GlobalDesc
           case GlobalKind::Constant: return u.cst_.type();
         }
         MOZ_CRASH("unexpected global kind");
     }
 };
 
 typedef Vector<GlobalDesc, 0, SystemAllocPolicy> GlobalDescVector;
 
+// DataSegment describes the offset of a data segment in the bytecode that is
+// to be copied at a given offset into linear memory upon instantiation.
+
+struct DataSegment
+{
+    InitExpr offset;
+    uint32_t bytecodeOffset;
+    uint32_t length;
+};
+
+typedef Vector<DataSegment, 0, SystemAllocPolicy> DataSegmentVector;
+
 // SigIdDesc describes a signature id that can be used by call_indirect and
 // table-entry prologues to structurally compare whether the caller and callee's
 // signatures *structurally* match. To handle the general case, a Sig is
 // allocated and stored in a process-wide hash table, so that pointer equality
 // implies structural equality. As an optimization for the 99% case where the
 // Sig has a small number of parameters, the Sig is bit-packed into a uint32
 // immediate value so that integer equality implies structural equality. Both
 // cases can be handled with a single comparison by always setting the LSB for