Bug 1317319: Factor out Elem section decoding; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 16 Nov 2016 16:21:31 +0100
changeset 323053 04f447c49c4695eaed0da6e65c1fc22e6386353d
parent 323052 bcaa68d34a94c6b7b2614e2e0eaaeb8cfa04d4a4
child 323054 954af429f89cf4e21398fdb30f3062c393baa84c
push id30967
push userphilringnalda@gmail.com
push dateFri, 18 Nov 2016 03:21:38 +0000
treeherdermozilla-central@8e476f8bd52d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1317319
milestone53.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 1317319: Factor out Elem section decoding; r=luke MozReview-Commit-ID: BAYTHtquTNB
js/src/wasm/WasmBinaryFormat.cpp
js/src/wasm/WasmBinaryFormat.h
js/src/wasm/WasmBinaryToAST.cpp
js/src/wasm/WasmCompile.cpp
js/src/wasm/WasmGenerator.cpp
js/src/wasm/WasmGenerator.h
js/src/wasm/WasmModule.cpp
js/src/wasm/WasmModule.h
js/src/wasm/WasmTypes.cpp
js/src/wasm/WasmTypes.h
--- a/js/src/wasm/WasmBinaryFormat.cpp
+++ b/js/src/wasm/WasmBinaryFormat.cpp
@@ -462,16 +462,79 @@ wasm::DecodeMemorySection(Decoder& d, bo
         return false;
 
     if (!d.finishSection(sectionStart, sectionSize, "memory"))
         return false;
 
     return true;
 }
 
+static bool
+DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected,
+                            InitExpr* init)
+{
+    uint16_t op;
+    if (!d.readOp(&op))
+        return d.fail("failed to read initializer type");
+
+    switch (op) {
+      case uint16_t(Op::I32Const): {
+        int32_t i32;
+        if (!d.readVarS32(&i32))
+            return d.fail("failed to read initializer i32 expression");
+        *init = InitExpr(Val(uint32_t(i32)));
+        break;
+      }
+      case uint16_t(Op::I64Const): {
+        int64_t i64;
+        if (!d.readVarS64(&i64))
+            return d.fail("failed to read initializer i64 expression");
+        *init = InitExpr(Val(uint64_t(i64)));
+        break;
+      }
+      case uint16_t(Op::F32Const): {
+        RawF32 f32;
+        if (!d.readFixedF32(&f32))
+            return d.fail("failed to read initializer f32 expression");
+        *init = InitExpr(Val(f32));
+        break;
+      }
+      case uint16_t(Op::F64Const): {
+        RawF64 f64;
+        if (!d.readFixedF64(&f64))
+            return d.fail("failed to read initializer f64 expression");
+        *init = InitExpr(Val(f64));
+        break;
+      }
+      case uint16_t(Op::GetGlobal): {
+        uint32_t i;
+        if (!d.readVarU32(&i))
+            return d.fail("failed to read get_global index in initializer expression");
+        if (i >= globals.length())
+            return d.fail("global index out of range in initializer expression");
+        if (!globals[i].isImport() || globals[i].isMutable())
+            return d.fail("initializer expression must reference a global immutable import");
+        *init = InitExpr(i, globals[i].type());
+        break;
+      }
+      default: {
+        return d.fail("unexpected initializer expression");
+      }
+    }
+
+    if (expected != init->type())
+        return d.fail("type mismatch: initializer type and expected type don't match");
+
+    uint16_t end;
+    if (!d.readOp(&end) || end != uint16_t(Op::End))
+        return d.fail("failed to read end of initializer expression");
+
+    return true;
+}
+
 bool
 wasm::DecodeGlobalSection(Decoder& d, GlobalDescVector* globals)
 {
     uint32_t sectionStart, sectionSize;
     if (!d.startSection(SectionId::Global, &sectionStart, &sectionSize, "global"))
         return false;
     if (sectionStart == Decoder::NotStarted)
         return true;
@@ -650,16 +713,71 @@ wasm::DecodeStartSection(Decoder& d, con
 
     if (!d.finishSection(sectionStart, sectionSize, "start"))
         return false;
 
     return true;
 }
 
 bool
+wasm::DecodeElemSection(Decoder& d, const TableDescVector& tables, const GlobalDescVector& globals,
+                        size_t numFuncs, ElemSegmentVector* elemSegments)
+{
+    uint32_t sectionStart, sectionSize;
+    if (!d.startSection(SectionId::Elem, &sectionStart, &sectionSize, "elem"))
+        return false;
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numSegments;
+    if (!d.readVarU32(&numSegments))
+        return d.fail("failed to read number of elem segments");
+
+    if (numSegments > MaxElemSegments)
+        return d.fail("too many elem segments");
+
+    for (uint32_t i = 0; i < numSegments; i++) {
+        uint32_t tableIndex;
+        if (!d.readVarU32(&tableIndex))
+            return d.fail("expected table index");
+
+        MOZ_ASSERT(tables.length() <= 1);
+        if (tableIndex >= tables.length())
+            return d.fail("table index out of range");
+
+        InitExpr offset;
+        if (!DecodeInitializerExpression(d, globals, ValType::I32, &offset))
+            return false;
+
+        uint32_t numElems;
+        if (!d.readVarU32(&numElems))
+            return d.fail("expected segment size");
+
+        Uint32Vector elemFuncIndices;
+        if (!elemFuncIndices.resize(numElems))
+            return false;
+
+        for (uint32_t i = 0; i < numElems; i++) {
+            if (!d.readVarU32(&elemFuncIndices[i]))
+                return d.fail("failed to read element function index");
+            if (elemFuncIndices[i] >= numFuncs)
+                return d.fail("table element out of range");
+        }
+
+        if (!elemSegments->emplaceBack(0, offset, Move(elemFuncIndices)))
+            return false;
+    }
+
+    if (!d.finishSection(sectionStart, sectionSize, "elem"))
+        return false;
+
+    return true;
+}
+
+bool
 wasm::EncodeLocalEntries(Encoder& e, const ValTypeVector& locals)
 {
     uint32_t numLocalEntries = 0;
     ValType prev = ValType(TypeCode::Limit);
     for (ValType t : locals) {
         if (t != prev) {
             numLocalEntries++;
             prev = t;
@@ -713,79 +831,16 @@ wasm::DecodeLocalEntries(Decoder& d, Mod
         if (!locals->appendN(type, count))
             return false;
     }
 
     return true;
 }
 
 bool
-wasm::DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected,
-                                  InitExpr* init)
-{
-    uint16_t op;
-    if (!d.readOp(&op))
-        return d.fail("failed to read initializer type");
-
-    switch (op) {
-      case uint16_t(Op::I32Const): {
-        int32_t i32;
-        if (!d.readVarS32(&i32))
-            return d.fail("failed to read initializer i32 expression");
-        *init = InitExpr(Val(uint32_t(i32)));
-        break;
-      }
-      case uint16_t(Op::I64Const): {
-        int64_t i64;
-        if (!d.readVarS64(&i64))
-            return d.fail("failed to read initializer i64 expression");
-        *init = InitExpr(Val(uint64_t(i64)));
-        break;
-      }
-      case uint16_t(Op::F32Const): {
-        RawF32 f32;
-        if (!d.readFixedF32(&f32))
-            return d.fail("failed to read initializer f32 expression");
-        *init = InitExpr(Val(f32));
-        break;
-      }
-      case uint16_t(Op::F64Const): {
-        RawF64 f64;
-        if (!d.readFixedF64(&f64))
-            return d.fail("failed to read initializer f64 expression");
-        *init = InitExpr(Val(f64));
-        break;
-      }
-      case uint16_t(Op::GetGlobal): {
-        uint32_t i;
-        if (!d.readVarU32(&i))
-            return d.fail("failed to read get_global index in initializer expression");
-        if (i >= globals.length())
-            return d.fail("global index out of range in initializer expression");
-        if (!globals[i].isImport() || globals[i].isMutable())
-            return d.fail("initializer expression must reference a global immutable import");
-        *init = InitExpr(i, globals[i].type());
-        break;
-      }
-      default: {
-        return d.fail("unexpected initializer expression");
-      }
-    }
-
-    if (expected != init->type())
-        return d.fail("type mismatch: initializer type and expected type don't match");
-
-    uint16_t end;
-    if (!d.readOp(&end) || end != uint16_t(Op::End))
-        return d.fail("failed to read end of initializer expression");
-
-    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;
--- a/js/src/wasm/WasmBinaryFormat.h
+++ b/js/src/wasm/WasmBinaryFormat.h
@@ -625,20 +625,16 @@ class Decoder
 // Misc helpers.
 
 MOZ_MUST_USE bool
 EncodeLocalEntries(Encoder& d, const ValTypeVector& locals);
 
 MOZ_MUST_USE bool
 DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals);
 
-MOZ_MUST_USE bool
-DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected,
-                            InitExpr* init);
-
 // Section macros.
 
 MOZ_MUST_USE bool
 DecodePreamble(Decoder& d);
 
 MOZ_MUST_USE bool
 DecodeTypeSection(Decoder& d, SigWithIdVector* sigs);
 
@@ -663,16 +659,20 @@ MOZ_MUST_USE bool
 DecodeExportSection(Decoder& d, size_t numFuncs, size_t numTables, bool usesMemory,
                     const GlobalDescVector& globals, ExportVector* exports);
 
 MOZ_MUST_USE bool
 DecodeStartSection(Decoder& d, const SigWithIdPtrVector& funcSigs,
                    Maybe<uint32_t>* startFunctionIndex);
 
 MOZ_MUST_USE bool
+DecodeElemSection(Decoder& d, const TableDescVector& tables, const GlobalDescVector& globals,
+                  size_t numFuncs, ElemSegmentVector* elemSegments);
+
+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
--- a/js/src/wasm/WasmBinaryToAST.cpp
+++ b/js/src/wasm/WasmBinaryToAST.cpp
@@ -1601,27 +1601,16 @@ ToAstExpr(AstDecodeContext& c, const Ini
             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;
-
-    *init = ToAstExpr(c, initExpr);
-    return !!*init;
-}
-
-static bool
 AstDecodeGlobalSection(AstDecodeContext& c)
 {
     size_t numImported = c.globalDescs().length();
     if (!DecodeGlobalSection(c.d, &c.globalDescs()))
         return false;
 
     for (uint32_t i = numImported; i < c.globalDescs().length(); i++) {
         AstName name;
@@ -1766,16 +1755,43 @@ AstDecodeFunctionBody(AstDecodeContext &
     if (!*func)
         return false;
     (*func)->setOffset(offset);
 
     return true;
 }
 
 static bool
+AstDecodeElemSection(AstDecodeContext &c)
+{
+    ElemSegmentVector elems;
+    if (!DecodeElemSection(c.d, c.tables(), c.globalDescs(), c.numFuncs(), &elems))
+        return false;
+
+    for (const ElemSegment& seg : elems) {
+        AstRefVector elems(c.lifo);
+        if (!elems.reserve(seg.elemFuncIndices.length()))
+            return false;
+
+        for (uint32_t i : seg.elemFuncIndices)
+            elems.infallibleAppend(AstRef(i));
+
+        AstExpr* offset = ToAstExpr(c, seg.offset);
+        if (!offset)
+            return false;
+
+        AstElemSegment* segment = new(c.lifo) AstElemSegment(offset, Move(elems));
+        if (!segment || !c.module().append(segment))
+            return false;
+    }
+
+    return true;
+}
+
+static bool
 AstDecodeCodeSection(AstDecodeContext &c)
 {
     uint32_t sectionStart, sectionSize;
     if (!c.d.startSection(SectionId::Code, &sectionStart, &sectionSize, "code"))
         return false;
 
     if (sectionStart == Decoder::NotStarted) {
         if (c.numFuncDefs() != 0)
@@ -1841,68 +1857,16 @@ AstDecodeDataSection(AstDecodeContext &c
         if (!segment || !c.module().append(segment))
             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;
-
-    uint32_t numElems;
-    if (!c.d.readVarU32(&numElems))
-        return c.d.fail("failed to read number of table elements");
-
-    for (uint32_t i = 0; i < numElems; i++) {
-        uint32_t tableIndex;
-        if (!c.d.readVarU32(&tableIndex))
-            return c.d.fail("expected table index for element");
-
-        if (tableIndex != 0)
-            return c.d.fail("non-zero table index for element");
-
-        AstExpr* offset;
-        if (!AstDecodeInitializerExpression(c, ValType::I32, &offset))
-            return false;
-
-        uint32_t count;
-        if (!c.d.readVarU32(&count))
-            return c.d.fail("expected element count");
-
-        AstRefVector elems(c.lifo);
-        if (!elems.resize(count))
-            return false;
-
-        for (uint32_t i = 0; i < count; i++) {
-            uint32_t index;
-            if (!c.d.readVarU32(&index))
-                return c.d.fail("expected element index");
-
-            elems[i] = AstRef(index);
-        }
-
-        AstElemSegment* segment = new(c.lifo) AstElemSegment(offset, Move(elems));
-        if (!segment || !c.module().append(segment))
-            return false;
-    }
-
-    if (!c.d.finishSection(sectionStart, sectionSize, "elem"))
-        return false;
-
-    return true;
-}
-
-static bool
 AstDecodeStartSection(AstDecodeContext &c)
 {
     Maybe<uint32_t> startFuncIndex;
     if (!DecodeStartSection(c.d, c.funcSigs(), &startFuncIndex))
         return false;
 
     if (!startFuncIndex)
         return true;
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -465,16 +465,27 @@ DecodeStartSection(Decoder& d, ModuleGen
     Maybe<uint32_t> startFuncIndex;
     if (!DecodeStartSection(d, mg.funcSigs(), &startFuncIndex))
         return false;
 
     return !startFuncIndex || mg.setStartFunction(*startFuncIndex);
 }
 
 static bool
+DecodeElemSection(Decoder& d, ModuleGenerator& mg)
+{
+    ElemSegmentVector elems;
+    if (!DecodeElemSection(d, mg.tables(), mg.globals(), mg.numFuncs(), &elems))
+        return false;
+
+    mg.setElemSegments(Move(elems));
+    return true;
+}
+
+static bool
 DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex)
 {
     uint32_t bodySize;
     if (!d.readVarU32(&bodySize))
         return d.fail("expected number of function body bytes");
 
     if (d.bytesRemain() < bodySize)
         return d.fail("function body length too big");
@@ -546,70 +557,16 @@ DecodeCodeSection(Decoder& d, ModuleGene
     }
 
     if (!d.finishSection(sectionStart, sectionSize, "code"))
         return false;
 
     return mg.finishFuncDefs();
 }
 
-static bool
-DecodeElemSection(Decoder& d, ModuleGenerator& mg)
-{
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Elem, &sectionStart, &sectionSize, "elem"))
-        return false;
-    if (sectionStart == Decoder::NotStarted)
-        return true;
-
-    uint32_t numSegments;
-    if (!d.readVarU32(&numSegments))
-        return d.fail("failed to read number of elem segments");
-
-    if (numSegments > MaxElemSegments)
-        return d.fail("too many elem segments");
-
-    for (uint32_t i = 0; i < numSegments; i++) {
-        uint32_t tableIndex;
-        if (!d.readVarU32(&tableIndex))
-            return d.fail("expected table index");
-
-        MOZ_ASSERT(mg.tables().length() <= 1);
-        if (tableIndex >= mg.tables().length())
-            return d.fail("table index out of range");
-
-        InitExpr offset;
-        if (!DecodeInitializerExpression(d, mg.globals(), ValType::I32, &offset))
-            return false;
-
-        uint32_t numElems;
-        if (!d.readVarU32(&numElems))
-            return d.fail("expected segment size");
-
-        Uint32Vector elemFuncIndices;
-        if (!elemFuncIndices.resize(numElems))
-            return false;
-
-        for (uint32_t i = 0; i < numElems; i++) {
-            if (!d.readVarU32(&elemFuncIndices[i]))
-                return d.fail("failed to read element function index");
-            if (elemFuncIndices[i] >= mg.numFuncs())
-                return d.fail("table element out of range");
-        }
-
-        if (!mg.addElemSegment(offset, Move(elemFuncIndices)))
-            return false;
-    }
-
-    if (!d.finishSection(sectionStart, sectionSize, "elem"))
-        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))
@@ -725,17 +682,17 @@ wasm::Compile(const ShareableBytes& byte
         return nullptr;
 
     if (!::DecodeExportSection(d, mg))
         return nullptr;
 
     if (!::DecodeStartSection(d, mg))
         return nullptr;
 
-    if (!DecodeElemSection(d, mg))
+    if (!::DecodeElemSection(d, mg))
         return nullptr;
 
     if (!DecodeCodeSection(d, mg))
         return nullptr;
 
     if (!::DecodeDataSection(d, mg))
         return nullptr;
 
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -828,31 +828,34 @@ ModuleGenerator::setExports(ExportVector
 
 bool
 ModuleGenerator::setStartFunction(uint32_t funcIndex)
 {
     metadata_->startFuncIndex.emplace(funcIndex);
     return exportedFuncs_.put(funcIndex);
 }
 
-bool
-ModuleGenerator::addElemSegment(InitExpr offset, Uint32Vector&& elemFuncIndices)
+void
+ModuleGenerator::setElemSegments(ElemSegmentVector&& segments)
 {
     MOZ_ASSERT(!isAsmJS());
     MOZ_ASSERT(!startedFuncDefs_);
-    MOZ_ASSERT(shared_->tables.length() == 1);
+
+    elemSegments_ = Move(segments);
 
-    for (uint32_t funcIndex : elemFuncIndices) {
-        if (funcIndex < numFuncImports()) {
-            shared_->tables[0].external = true;
-            break;
+    for (const ElemSegment& seg : elemSegments_) {
+        if (shared_->tables[seg.tableIndex].external)
+            continue;
+        for (uint32_t funcIndex : seg.elemFuncIndices) {
+            if (funcIndex < numFuncImports()) {
+                shared_->tables[seg.tableIndex].external = true;
+                break;
+            }
         }
     }
-
-    return elemSegments_.emplaceBack(0, offset, Move(elemFuncIndices));
 }
 
 void
 ModuleGenerator::setDataSegments(DataSegmentVector&& segments)
 {
     MOZ_ASSERT(dataSegments_.empty());
     dataSegments_ = Move(segments);
 }
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -169,17 +169,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     MOZ_MUST_USE bool finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDefs();
 
     // Start function:
     bool setStartFunction(uint32_t funcIndex);
 
     // Segments:
     void setDataSegments(DataSegmentVector&& segments);
-    MOZ_MUST_USE bool addElemSegment(InitExpr offset, Uint32Vector&& elemFuncIndices);
+    void setElemSegments(ElemSegmentVector&& segments);
 
     // Function names:
     void setFuncNames(NameInBytecodeVector&& funcNames);
 
     // asm.js lazy initialization:
     void initSig(uint32_t sigIndex, Sig&& sig);
     void initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
     MOZ_MUST_USE bool initImport(uint32_t funcIndex, uint32_t sigIndex);
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -162,52 +162,16 @@ Import::deserialize(const uint8_t* curso
 
 size_t
 Import::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return module.sizeOfExcludingThis(mallocSizeOf) +
            field.sizeOfExcludingThis(mallocSizeOf);
 }
 
-size_t
-ElemSegment::serializedSize() const
-{
-    return sizeof(tableIndex) +
-           sizeof(offset) +
-           SerializedPodVectorSize(elemFuncIndices) +
-           SerializedPodVectorSize(elemCodeRangeIndices);
-}
-
-uint8_t*
-ElemSegment::serialize(uint8_t* cursor) const
-{
-    cursor = WriteBytes(cursor, &tableIndex, sizeof(tableIndex));
-    cursor = WriteBytes(cursor, &offset, sizeof(offset));
-    cursor = SerializePodVector(cursor, elemFuncIndices);
-    cursor = SerializePodVector(cursor, elemCodeRangeIndices);
-    return cursor;
-}
-
-const uint8_t*
-ElemSegment::deserialize(const uint8_t* cursor)
-{
-    (cursor = ReadBytes(cursor, &tableIndex, sizeof(tableIndex))) &&
-    (cursor = ReadBytes(cursor, &offset, sizeof(offset))) &&
-    (cursor = DeserializePodVector(cursor, &elemFuncIndices)) &&
-    (cursor = DeserializePodVector(cursor, &elemCodeRangeIndices));
-    return cursor;
-}
-
-size_t
-ElemSegment::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
-{
-    return elemFuncIndices.sizeOfExcludingThis(mallocSizeOf) +
-           elemCodeRangeIndices.sizeOfExcludingThis(mallocSizeOf);
-}
-
 /* virtual */ void
 Module::serializedSize(size_t* bytecodeSize, size_t* compiledSize) const
 {
     *bytecodeSize = SerializedPodVectorSize(bytecode_->bytes);
 
     *compiledSize = assumptions_.serializedSize() +
                     SerializedPodVectorSize(code_) +
                     linkData_.serializedSize() +
--- a/js/src/wasm/WasmModule.h
+++ b/js/src/wasm/WasmModule.h
@@ -72,36 +72,16 @@ struct LinkData : LinkDataCacheablePod
     SymbolicLinkArray   symbolicLinks;
 
     WASM_DECLARE_SERIALIZABLE(LinkData)
 };
 
 typedef UniquePtr<LinkData> UniqueLinkData;
 typedef UniquePtr<const LinkData> UniqueConstLinkData;
 
-// 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;
-    Uint32Vector elemCodeRangeIndices;
-
-    ElemSegment() = default;
-    ElemSegment(uint32_t tableIndex, InitExpr offset, Uint32Vector&& elemFuncIndices)
-      : tableIndex(tableIndex), offset(offset), elemFuncIndices(Move(elemFuncIndices))
-    {}
-
-    WASM_DECLARE_SERIALIZABLE(ElemSegment)
-};
-
-typedef Vector<ElemSegment, 0, SystemAllocPolicy> ElemSegmentVector;
-
 // Module represents a compiled wasm module and primarily provides two
 // operations: instantiation and serialization. A Module can be instantiated any
 // number of times to produce new Instance objects. A Module can be serialized
 // any number of times such that the serialized bytes can be deserialized later
 // to produce a new, equivalent Module.
 //
 // Since fully linked-and-instantiated code (represented by CodeSegment) cannot
 // be shared between instances, Module stores an unlinked, uninstantiated copy
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -619,16 +619,52 @@ Export::deserialize(const uint8_t* curso
 }
 
 size_t
 Export::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return fieldName_.sizeOfExcludingThis(mallocSizeOf);
 }
 
+size_t
+ElemSegment::serializedSize() const
+{
+    return sizeof(tableIndex) +
+           sizeof(offset) +
+           SerializedPodVectorSize(elemFuncIndices) +
+           SerializedPodVectorSize(elemCodeRangeIndices);
+}
+
+uint8_t*
+ElemSegment::serialize(uint8_t* cursor) const
+{
+    cursor = WriteBytes(cursor, &tableIndex, sizeof(tableIndex));
+    cursor = WriteBytes(cursor, &offset, sizeof(offset));
+    cursor = SerializePodVector(cursor, elemFuncIndices);
+    cursor = SerializePodVector(cursor, elemCodeRangeIndices);
+    return cursor;
+}
+
+const uint8_t*
+ElemSegment::deserialize(const uint8_t* cursor)
+{
+    (cursor = ReadBytes(cursor, &tableIndex, sizeof(tableIndex))) &&
+    (cursor = ReadBytes(cursor, &offset, sizeof(offset))) &&
+    (cursor = DeserializePodVector(cursor, &elemFuncIndices)) &&
+    (cursor = DeserializePodVector(cursor, &elemCodeRangeIndices));
+    return cursor;
+}
+
+size_t
+ElemSegment::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+{
+    return elemFuncIndices.sizeOfExcludingThis(mallocSizeOf) +
+           elemCodeRangeIndices.sizeOfExcludingThis(mallocSizeOf);
+}
+
 Assumptions::Assumptions(JS::BuildIdCharVector&& buildId)
   : cpuId(GetCPUID()),
     buildId(Move(buildId))
 {}
 
 Assumptions::Assumptions()
   : cpuId(GetCPUID()),
     buildId()
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -701,16 +701,36 @@ class GlobalDesc
           case GlobalKind::Constant: return u.cst_.type();
         }
         MOZ_CRASH("unexpected global kind");
     }
 };
 
 typedef Vector<GlobalDesc, 0, SystemAllocPolicy> GlobalDescVector;
 
+// 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;
+    Uint32Vector elemCodeRangeIndices;
+
+    ElemSegment() = default;
+    ElemSegment(uint32_t tableIndex, InitExpr offset, Uint32Vector&& elemFuncIndices)
+      : tableIndex(tableIndex), offset(offset), elemFuncIndices(Move(elemFuncIndices))
+    {}
+
+    WASM_DECLARE_SERIALIZABLE(ElemSegment)
+};
+
+typedef Vector<ElemSegment, 0, SystemAllocPolicy> ElemSegmentVector;
+
 // 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;