Bug 1405661 - Baldr: stidy Decoder::startSection (r=lth)
authorLuke Wagner <luke@mozilla.com>
Thu, 05 Oct 2017 08:44:02 -0500
changeset 384690 62fc2f51d566974bf2de7b93cf4588a2c2e81c4d
parent 384689 0b50187d11f9299a66c2ea797943dcbb2a1ab2aa
child 384691 13b556ec5a8e1adaabab213f987c437736f740b8
push id95824
push userlwagner@mozilla.com
push dateThu, 05 Oct 2017 13:47:17 +0000
treeherdermozilla-inbound@13b556ec5a8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1405661
milestone58.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 1405661 - Baldr: stidy Decoder::startSection (r=lth) MozReview-Commit-ID: 8oc7V0h8YpF
js/src/wasm/WasmBinaryToAST.cpp
js/src/wasm/WasmCompile.cpp
js/src/wasm/WasmValidate.cpp
js/src/wasm/WasmValidate.h
--- a/js/src/wasm/WasmBinaryToAST.cpp
+++ b/js/src/wasm/WasmBinaryToAST.cpp
@@ -1794,21 +1794,20 @@ AstDecodeEnvironment(AstDecodeContext& c
         return false;
 
     return true;
 }
 
 static bool
 AstDecodeCodeSection(AstDecodeContext& c)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!c.d.startSection(SectionId::Code, &c.env(), &sectionStart, &sectionSize, "code"))
+    MaybeSectionRange range;
+    if (!c.d.startSection(SectionId::Code, &c.env(), &range, "code"))
         return false;
-
-    if (sectionStart == Decoder::NotStarted) {
+    if (!range) {
         if (c.env().numFuncDefs() != 0)
             return c.d.fail("expected function bodies");
         return true;
     }
 
     uint32_t numFuncBodies;
     if (!c.d.readVarU32(&numFuncBodies))
         return c.d.fail("expected function body count");
@@ -1819,17 +1818,17 @@ AstDecodeCodeSection(AstDecodeContext& c
     for (uint32_t funcDefIndex = 0; funcDefIndex < numFuncBodies; funcDefIndex++) {
         AstFunc* func;
         if (!AstDecodeFunctionBody(c, c.module().numFuncImports() + funcDefIndex, &func))
             return false;
         if (!c.module().append(func))
             return false;
     }
 
-    return c.d.finishSection(sectionStart, sectionSize, "code");
+    return c.d.finishSection(*range, "code");
 }
 
 // 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
 AstDecodeModuleTail(AstDecodeContext& c)
 {
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -49,24 +49,24 @@ DecodeFunctionBody(Decoder& d, ModuleGen
         return d.fail("function body length too big");
 
     return mg.compileFuncDef(funcIndex, offsetInModule, bodyBegin, bodyBegin + bodySize);
 }
 
 static bool
 DecodeCodeSection(Decoder& d, ModuleGenerator& mg, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Code, env, &sectionStart, &sectionSize, "code"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Code, env, &range, "code"))
         return false;
 
     if (!mg.startFuncDefs())
         return false;
 
-    if (sectionStart == Decoder::NotStarted) {
+    if (!range) {
         if (env->numFuncDefs() != 0)
             return d.fail("expected function bodies");
 
         return mg.finishFuncDefs();
     }
 
     uint32_t numFuncDefs;
     if (!d.readVarU32(&numFuncDefs))
@@ -75,17 +75,17 @@ DecodeCodeSection(Decoder& d, ModuleGene
     if (numFuncDefs != env->numFuncDefs())
         return d.fail("function body count does not match function signature count");
 
     for (uint32_t funcDefIndex = 0; funcDefIndex < numFuncDefs; funcDefIndex++) {
         if (!DecodeFunctionBody(d, mg, env->numFuncImports() + funcDefIndex))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "code"))
+    if (!d.finishSection(*range, "code"))
         return false;
 
     return mg.finishFuncDefs();
 }
 
 bool
 CompileArgs::initFromContext(JSContext* cx, ScriptedCaller&& scriptedCaller)
 {
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -54,19 +54,21 @@ Decoder::fail(size_t errorOffset, const 
     if (!strWithOffset)
         return false;
 
     *error_ = Move(strWithOffset);
     return false;
 }
 
 bool
-Decoder::startSection(SectionId id, ModuleEnvironment* env, uint32_t* sectionStart,
-                      uint32_t* sectionSize, const char* sectionName, bool peeking)
+Decoder::startSection(SectionId id, ModuleEnvironment* env, MaybeSectionRange* range,
+                      const char* sectionName, bool peeking)
 {
+    MOZ_ASSERT(!*range);
+
     // Record state at beginning of section to allow rewinding to this point
     // if, after skipping through several custom sections, we don't find the
     // section 'id'.
     const uint8_t* const initialCur = cur_;
     const size_t initialCustomSectionsLength = env->customSections.length();
 
     // Maintain a pointer to the current section that gets updated as custom
     // sections are skipped.
@@ -95,85 +97,87 @@ Decoder::startSection(SectionId id, Modu
         // section.
         currentSectionStart = cur_;
         if (!readFixedU8(&idValue))
             goto rewind;
     }
 
     // Found it, now start the section.
 
-    if (!readVarU32(sectionSize) || bytesRemain() < *sectionSize) {
+    uint32_t size;
+    if (!readVarU32(&size) || bytesRemain() < size) {
         if (peeking)
             goto rewind;
         goto fail;
     }
 
-    *sectionStart = cur_ - beg_;
+    range->emplace();
+    (*range)->start = cur_ - beg_;
+    (*range)->size = size;
     if (peeking)
-        goto rewind_peeking;
+        goto rewind;
     return true;
 
   rewind:
-    peeking = false;
-  rewind_peeking:
     cur_ = initialCur;
     env->customSections.shrinkTo(initialCustomSectionsLength);
-    if (!peeking)
-        *sectionStart = NotStarted;
     return true;
 
   fail:
     return failf("failed to start %s section", sectionName);
 }
 
 bool
 Decoder::peekSectionSize(SectionId id, ModuleEnvironment* env, const char* sectionName, uint32_t* sectionSize)
 {
-    uint32_t sectionStart;
-    if (!startSection(id, env, &sectionStart, sectionSize, sectionName, /*peeking=*/true))
+    MaybeSectionRange range;
+    if (!startSection(id, env, &range, sectionName, /* peeking = */ true))
         return false;
-    return sectionStart != NotStarted;
+    if (!range)
+        return false;
+    *sectionSize = range->size;
+    return true;
 }
 
 bool
-Decoder::finishSection(uint32_t sectionStart, uint32_t sectionSize, const char* sectionName)
+Decoder::finishSection(const SectionRange& range, const char* sectionName)
 {
     if (resilientMode_)
         return true;
-    if (sectionSize != (cur_ - beg_) - sectionStart)
+    if (range.size != (cur_ - beg_) - range.start)
         return failf("byte size mismatch in %s section", sectionName);
     return true;
 }
 
 bool
 Decoder::startCustomSection(const char* expected, size_t expectedLength, ModuleEnvironment* env,
-                            uint32_t* sectionStart, uint32_t* sectionSize)
+                            MaybeSectionRange* range)
 {
     // Record state at beginning of section to allow rewinding to this point
     // if, after skipping through several custom sections, we don't find the
     // section 'id'.
     const uint8_t* const initialCur = cur_;
     const size_t initialCustomSectionsLength = env->customSections.length();
 
     while (true) {
         // Try to start a custom section. If we can't, rewind to the beginning
         // since we may have skipped several custom sections already looking for
         // 'expected'.
-        if (!startSection(SectionId::Custom, env, sectionStart, sectionSize, "custom"))
+        if (!startSection(SectionId::Custom, env, range, "custom"))
             return false;
-        if (*sectionStart == NotStarted)
+        if (!*range)
             goto rewind;
 
         NameInBytecode name;
         if (!readVarU32(&name.length) || name.length > bytesRemain())
             goto fail;
 
         name.offset = currentOffset();
         uint32_t payloadOffset = name.offset + name.length;
-        uint32_t payloadEnd = *sectionStart + *sectionSize;
+        uint32_t payloadEnd = (*range)->start + (*range)->size;
         if (payloadOffset > payloadEnd)
             goto fail;
 
         // Now that we have a valid custom section, record its offsets in the
         // metadata which can be queried by the user via Module.customSections.
         // Note: after an entry is appended, it may be popped if this loop or
         // the loop in startSection needs to rewind.
         if (!env->customSections.emplaceBack(name, payloadOffset, payloadEnd - payloadOffset))
@@ -181,79 +185,80 @@ Decoder::startCustomSection(const char* 
 
         // If this is the expected custom section, we're done.
         if (!expected || (expectedLength == name.length && !memcmp(cur_, expected, name.length))) {
             cur_ += name.length;
             return true;
         }
 
         // Otherwise, blindly skip the custom section and keep looking.
-        finishCustomSection(*sectionStart, *sectionSize);
+        finishCustomSection(**range);
+        range->reset();
     }
     MOZ_CRASH("unreachable");
 
   rewind:
     cur_ = initialCur;
     env->customSections.shrinkTo(initialCustomSectionsLength);
     return true;
 
   fail:
     return fail("failed to start custom section");
 }
 
 void
-Decoder::finishCustomSection(uint32_t sectionStart, uint32_t sectionSize)
+Decoder::finishCustomSection(const SectionRange& range)
 {
     MOZ_ASSERT(cur_ >= beg_);
     MOZ_ASSERT(cur_ <= end_);
-    cur_ = (beg_ + sectionStart) + sectionSize;
+    cur_ = (beg_ + range.start) + range.size;
     MOZ_ASSERT(cur_ <= end_);
     clearError();
 }
 
 bool
 Decoder::skipCustomSection(ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!startCustomSection(nullptr, 0, env, &sectionStart, &sectionSize))
+    MaybeSectionRange range;
+    if (!startCustomSection(nullptr, 0, env, &range))
         return false;
-    if (sectionStart == NotStarted)
+    if (!range)
         return fail("expected custom section");
 
-    finishCustomSection(sectionStart, sectionSize);
+    finishCustomSection(*range);
     return true;
 }
 
 bool
-Decoder::startNameSubsection(NameType nameType, uint32_t* endOffset)
+Decoder::startNameSubsection(NameType nameType, Maybe<uint32_t>* endOffset)
 {
+    MOZ_ASSERT(!*endOffset);
+
     const uint8_t* initialPosition = cur_;
 
     uint8_t nameTypeValue;
     if (!readFixedU8(&nameTypeValue))
         return false;
 
     if (nameTypeValue != uint8_t(nameType)) {
         cur_ = initialPosition;
-        *endOffset = NotStarted;
         return true;
     }
 
     uint32_t payloadLength;
     if (!readVarU32(&payloadLength) || payloadLength > bytesRemain())
         return false;
 
-    *endOffset = (cur_ - beg_) + payloadLength;
+    *endOffset = Some((cur_ - beg_) + payloadLength);
     return true;
 }
 
 bool
 Decoder::finishNameSubsection(uint32_t endOffset)
 {
-    MOZ_ASSERT(endOffset != NotStarted);
     return endOffset == uint32_t(cur_ - beg_);
 }
 
 // Misc helpers.
 
 bool
 wasm::EncodeLocalEntries(Encoder& e, const ValTypeVector& locals)
 {
@@ -758,20 +763,20 @@ DecodePreamble(Decoder& d)
     }
 
     return true;
 }
 
 static bool
 DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Type, env, &sectionStart, &sectionSize, "type"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Type, env, &range, "type"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t numSigs;
     if (!d.readVarU32(&numSigs))
         return d.fail("expected number of signatures");
 
     if (numSigs > MaxTypes)
         return d.fail("too many signatures");
@@ -815,20 +820,17 @@ DecodeTypeSection(Decoder& d, ModuleEnvi
                 return false;
 
             result = ToExprType(type);
         }
 
         env->sigs[sigIndex] = Sig(Move(args), result);
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "type"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "type");
 }
 
 static UniqueChars
 DecodeName(Decoder& d)
 {
     uint32_t numBytes;
     if (!d.readVarU32(&numBytes))
         return nullptr;
@@ -1050,51 +1052,51 @@ DecodeImport(Decoder& d, ModuleEnvironme
     }
 
     return env->imports.emplaceBack(Move(moduleName), Move(funcName), importKind);
 }
 
 static bool
 DecodeImportSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Import, env, &sectionStart, &sectionSize, "import"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Import, env, &range, "import"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t numImports;
     if (!d.readVarU32(&numImports))
         return d.fail("failed to read number of imports");
 
     if (numImports > MaxImports)
         return d.fail("too many imports");
 
     for (uint32_t i = 0; i < numImports; i++) {
         if (!DecodeImport(d, env))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "import"))
+    if (!d.finishSection(*range, "import"))
         return false;
 
     // The global data offsets will be filled in by ModuleGenerator::init.
     if (!env->funcImportGlobalDataOffsets.resize(env->funcSigs.length()))
         return false;
 
     return true;
 }
 
 static bool
 DecodeFunctionSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Function, env, &sectionStart, &sectionSize, "function"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Function, env, &range, "function"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t numDefs;
     if (!d.readVarU32(&numDefs))
         return d.fail("expected number of function definitions");
 
     CheckedInt<uint32_t> numFuncs = env->funcSigs.length();
     numFuncs += numDefs;
@@ -1106,74 +1108,65 @@ DecodeFunctionSection(Decoder& d, Module
 
     for (uint32_t i = 0; i < numDefs; i++) {
         uint32_t sigIndex;
         if (!DecodeSignatureIndex(d, env->sigs, &sigIndex))
             return false;
         env->funcSigs.infallibleAppend(&env->sigs[sigIndex]);
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "function"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "function");
 }
 
 static bool
 DecodeTableSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Table, env, &sectionStart, &sectionSize, "table"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Table, env, &range, "table"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t numTables;
     if (!d.readVarU32(&numTables))
         return d.fail("failed to read number of tables");
 
     if (numTables > 1)
         return d.fail("the number of tables must be at most one");
 
     for (uint32_t i = 0; i < numTables; ++i) {
         if (!DecodeTableLimits(d, &env->tables))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "table"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "table");
 }
 
 static bool
 DecodeMemorySection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Memory, env, &sectionStart, &sectionSize, "memory"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Memory, env, &range, "memory"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t numMemories;
     if (!d.readVarU32(&numMemories))
         return d.fail("failed to read number of memories");
 
     if (numMemories > 1)
         return d.fail("the number of memories must be at most one");
 
     for (uint32_t i = 0; i < numMemories; ++i) {
         if (!DecodeMemoryLimits(d, env))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "memory"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "memory");
 }
 
 static bool
 DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected,
                             InitExpr* init)
 {
     OpBytes op;
     if (!d.readOp(&op))
@@ -1232,20 +1225,20 @@ DecodeInitializerExpression(Decoder& d, 
         return d.fail("failed to read end of initializer expression");
 
     return true;
 }
 
 static bool
 DecodeGlobalSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Global, env, &sectionStart, &sectionSize, "global"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Global, env, &range, "global"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t numDefs;
     if (!d.readVarU32(&numDefs))
         return d.fail("expected number of globals");
 
     CheckedInt<uint32_t> numGlobals = env->globals.length();
     numGlobals += numDefs;
@@ -1263,20 +1256,17 @@ DecodeGlobalSection(Decoder& d, ModuleEn
 
         InitExpr initializer;
         if (!DecodeInitializerExpression(d, env->globals, type, &initializer))
             return false;
 
         env->globals.infallibleAppend(GlobalDesc(initializer, isMutable));
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "global"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "global");
 }
 
 typedef HashSet<const char*, CStringHasher, SystemAllocPolicy> CStringSet;
 
 static UniqueChars
 DecodeExportName(Decoder& d, CStringSet* dupSet)
 {
     UniqueChars exportName = DecodeName(d);
@@ -1361,20 +1351,20 @@ DecodeExport(Decoder& d, ModuleEnvironme
     }
 
     MOZ_CRASH("unreachable");
 }
 
 static bool
 DecodeExportSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Export, env, &sectionStart, &sectionSize, "export"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Export, env, &range, "export"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     CStringSet dupSet;
     if (!dupSet.init())
         return false;
 
     uint32_t numExports;
     if (!d.readVarU32(&numExports))
@@ -1383,29 +1373,26 @@ DecodeExportSection(Decoder& d, ModuleEn
     if (numExports > MaxExports)
         return d.fail("too many exports");
 
     for (uint32_t i = 0; i < numExports; i++) {
         if (!DecodeExport(d, env, &dupSet))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "export"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "export");
 }
 
 static bool
 DecodeStartSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Start, env, &sectionStart, &sectionSize, "start"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Start, env, &range, "start"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     uint32_t funcIndex;
     if (!d.readVarU32(&funcIndex))
         return d.fail("failed to read start func index");
 
     if (funcIndex >= env->numFuncs())
         return d.fail("unknown start function");
@@ -1414,29 +1401,26 @@ DecodeStartSection(Decoder& d, ModuleEnv
     if (!IsVoid(sig.ret()))
         return d.fail("start function must not return anything");
 
     if (sig.args().length())
         return d.fail("start function must be nullary");
 
     env->startFuncIndex = Some(funcIndex);
 
-    if (!d.finishSection(sectionStart, sectionSize, "start"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "start");
 }
 
 static bool
 DecodeElemSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Elem, env, &sectionStart, &sectionSize, "elem"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Elem, env, &range, "elem"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         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");
@@ -1473,20 +1457,17 @@ DecodeElemSection(Decoder& d, ModuleEnvi
         }
 
         if (!env->elemSegments.emplaceBack(0, offset, Move(elemFuncIndices)))
             return false;
 
         env->tables[env->elemSegments.back().tableIndex].external = true;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "elem"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "elem");
 }
 
 bool
 wasm::DecodeModuleEnvironment(Decoder& d, ModuleEnvironment* env)
 {
     if (!DecodePreamble(d))
         return false;
 
@@ -1537,21 +1518,21 @@ DecodeFunctionBody(Decoder& d, const Mod
         return false;
 
     return true;
 }
 
 static bool
 DecodeCodeSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Code, env, &sectionStart, &sectionSize, "code"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Code, env, &range, "code"))
         return false;
 
-    if (sectionStart == Decoder::NotStarted) {
+    if (!range) {
         if (env->numFuncDefs() != 0)
             return d.fail("expected function bodies");
         return true;
     }
 
     uint32_t numFuncDefs;
     if (!d.readVarU32(&numFuncDefs))
         return d.fail("expected function body count");
@@ -1559,29 +1540,26 @@ DecodeCodeSection(Decoder& d, ModuleEnvi
     if (numFuncDefs != env->numFuncDefs())
         return d.fail("function body count does not match function signature count");
 
     for (uint32_t funcDefIndex = 0; funcDefIndex < numFuncDefs; funcDefIndex++) {
         if (!DecodeFunctionBody(d, *env, env->numFuncImports() + funcDefIndex))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "code"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "code");
 }
 
 static bool
 DecodeDataSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startSection(SectionId::Data, env, &sectionStart, &sectionSize, "data"))
+    MaybeSectionRange range;
+    if (!d.startSection(SectionId::Data, env, &range, "data"))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     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");
@@ -1611,29 +1589,26 @@ DecodeDataSection(Decoder& d, ModuleEnvi
 
         if (!d.readBytes(seg.length))
             return d.fail("data segment shorter than declared");
 
         if (!env->dataSegments.append(seg))
             return false;
     }
 
-    if (!d.finishSection(sectionStart, sectionSize, "data"))
-        return false;
-
-    return true;
+    return d.finishSection(*range, "data");
 }
 
 static bool
 DecodeModuleNameSubsection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t endOffset;
+    Maybe<uint32_t> endOffset;
     if (!d.startNameSubsection(NameType::Module, &endOffset))
         return false;
-    if (endOffset == Decoder::NotStarted)
+    if (!endOffset)
         return true;
 
     // Don't use NameInBytecode for module name; instead store a copy of the
     // string. This way supplying a module name doesn't need to save the whole
     // bytecode. While function names are likely to be stripped in practice,
     // module names aren't necessarily.
 
     uint32_t nameLength;
@@ -1642,26 +1617,26 @@ DecodeModuleNameSubsection(Decoder& d, M
 
     const uint8_t* bytes;
     if (!d.readBytes(nameLength, &bytes))
         return false;
 
     // Do nothing with module name for now; a future patch will incorporate the
     // module name into the callstack format.
 
-    return d.finishNameSubsection(endOffset);
+    return d.finishNameSubsection(*endOffset);
 }
 
 static bool
 DecodeFunctionNameSubsection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t endOffset;
+    Maybe<uint32_t> endOffset;
     if (!d.startNameSubsection(NameType::Function, &endOffset))
         return false;
-    if (endOffset == Decoder::NotStarted)
+    if (!endOffset)
         return true;
 
     uint32_t nameCount = 0;
     if (!d.readVarU32(&nameCount) || nameCount > MaxFuncs)
         return false;
 
     NameInBytecodeVector funcNames;
 
@@ -1685,48 +1660,48 @@ DecodeFunctionNameSubsection(Decoder& d,
             return false;
 
         funcNames[funcIndex] = NameInBytecode(d.currentOffset(), nameLength);
 
         if (!d.readBytes(nameLength))
             return false;
     }
 
-    if (!d.finishNameSubsection(endOffset))
+    if (!d.finishNameSubsection(*endOffset))
         return false;
 
     // To encourage fully valid function names subsections; only save names if
     // the entire subsection decoded correctly.
     env->funcNames = Move(funcNames);
     return true;
 }
 
 static bool
 DecodeNameSection(Decoder& d, ModuleEnvironment* env)
 {
-    uint32_t sectionStart, sectionSize;
-    if (!d.startCustomSection(NameSectionName, env, &sectionStart, &sectionSize))
+    MaybeSectionRange range;
+    if (!d.startCustomSection(NameSectionName, env, &range))
         return false;
-    if (sectionStart == Decoder::NotStarted)
+    if (!range)
         return true;
 
     // Once started, custom sections do not report validation errors.
 
     if (!DecodeModuleNameSubsection(d, env))
         goto finish;
 
     if (!DecodeFunctionNameSubsection(d, env))
         goto finish;
 
     // The names we care about have already been extracted into 'env' so don't
     // bother decoding the rest of the name section. finishCustomSection() will
     // skip to the end of the name section (as it would for any other error).
 
   finish:
-    d.finishCustomSection(sectionStart, sectionSize);
+    d.finishCustomSection(*range);
     return true;
 }
 
 bool
 wasm::DecodeModuleTail(Decoder& d, ModuleEnvironment* env)
 {
     if (!DecodeDataSection(d, env))
         return false;
--- a/js/src/wasm/WasmValidate.h
+++ b/js/src/wasm/WasmValidate.h
@@ -20,16 +20,27 @@
 #define wasm_validate_h
 
 #include "wasm/WasmCode.h"
 #include "wasm/WasmTypes.h"
 
 namespace js {
 namespace wasm {
 
+// This struct captures the bytecode offset of a section's payload (so not
+// including the header) and the size of the payload.
+
+struct SectionRange
+{
+    uint32_t start;
+    uint32_t size;
+};
+
+typedef Maybe<SectionRange> MaybeSectionRange;
+
 // ModuleEnvironment contains all the state necessary to validate, process or
 // render functions. It is created by decoding all the sections before the wasm
 // code section and then used immutably during. When compiling a module using a
 // ModuleGenerator, the ModuleEnvironment holds state shared between the
 // ModuleGenerator thread and background compile threads. All the threads
 // are given a read-only view of the ModuleEnvironment, thus preventing race
 // conditions.
 
@@ -548,56 +559,49 @@ class Decoder
         if (bytesRemain() < numBytes)
             return false;
         cur_ += numBytes;
         return true;
     }
 
     // See "section" description in Encoder.
 
-    static const uint32_t NotStarted = UINT32_MAX;
-
     MOZ_MUST_USE bool startSection(SectionId id,
                                    ModuleEnvironment* env,
-                                   uint32_t* sectionStart,
-                                   uint32_t* sectionSize,
+                                   MaybeSectionRange* range,
                                    const char* sectionName,
                                    bool peeking = false);
-    MOZ_MUST_USE bool finishSection(uint32_t sectionStart,
-                                    uint32_t sectionSize,
+    MOZ_MUST_USE bool finishSection(const SectionRange& range,
                                     const char* sectionName);
     MOZ_MUST_USE bool peekSectionSize(SectionId id,
                                       ModuleEnvironment* env,
                                       const char* sectionName,
                                       uint32_t* sectionSize);
 
     // Custom sections do not cause validation errors unless the error is in
     // the section header itself.
 
     MOZ_MUST_USE bool startCustomSection(const char* expected,
                                          size_t expectedLength,
                                          ModuleEnvironment* env,
-                                         uint32_t* sectionStart,
-                                         uint32_t* sectionSize);
+                                         MaybeSectionRange* range);
     template <size_t NameSizeWith0>
     MOZ_MUST_USE bool startCustomSection(const char (&name)[NameSizeWith0],
                                          ModuleEnvironment* env,
-                                         uint32_t* sectionStart,
-                                         uint32_t* sectionSize)
+                                         MaybeSectionRange* range)
     {
         MOZ_ASSERT(name[NameSizeWith0 - 1] == '\0');
-        return startCustomSection(name, NameSizeWith0 - 1, env, sectionStart, sectionSize);
+        return startCustomSection(name, NameSizeWith0 - 1, env, range);
     }
-    void finishCustomSection(uint32_t sectionStart, uint32_t sectionSize);
+    void finishCustomSection(const SectionRange& range);
     MOZ_MUST_USE bool skipCustomSection(ModuleEnvironment* env);
 
-    // The Name section has its own subsections. Like startSection, NotStart is
-    // returned as the endOffset if the given name subsection wasn't present.
+    // The Name section has its own optional subsections.
 
-    MOZ_MUST_USE bool startNameSubsection(NameType nameType, uint32_t* endOffset);
+    MOZ_MUST_USE bool startNameSubsection(NameType nameType, Maybe<uint32_t>* endOffset);
     MOZ_MUST_USE bool finishNameSubsection(uint32_t endOffset);
 
     // The infallible "unchecked" decoding functions can be used when we are
     // sure that the bytes are well-formed (by construction or due to previous
     // validation).
 
     uint8_t uncheckedReadFixedU8() {
         return uncheckedRead<uint8_t>();