Bug 1395587 - Baldr: remove FunctionGenerator (r=lth)
authorLuke Wagner <luke@mozilla.com>
Wed, 06 Sep 2017 08:31:02 -0500
changeset 379360 32df4db6c1503deeb20e50d6e76d0c8cd0d2d5ef
parent 379359 7189690845fb45120bd74ebe6d9d7c10d206cd08
child 379361 3bd70f5f356be8f9aaaab1f09f5dde758b565782
push id50642
push userarchaeopteryx@coole-files.de
push dateThu, 07 Sep 2017 10:41:07 +0000
treeherderautoland@bd0ce93776fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1395587
milestone57.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 1395587 - Baldr: remove FunctionGenerator (r=lth) MozReview-Commit-ID: 4MIQEVy94OU
js/src/wasm/AsmJS.cpp
js/src/wasm/WasmBaselineCompile.cpp
js/src/wasm/WasmCompile.cpp
js/src/wasm/WasmGenerator.cpp
js/src/wasm/WasmGenerator.h
js/src/wasm/WasmIonCompile.cpp
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -2887,66 +2887,61 @@ class MOZ_STACK_CLASS FunctionValidator
     };
 
   private:
     typedef HashMap<PropertyName*, Local> LocalMap;
     typedef HashMap<PropertyName*, uint32_t> LabelMap;
 
     ModuleValidator&  m_;
     ParseNode*        fn_;
-
-    FunctionGenerator fg_;
-    Maybe<Encoder>    encoder_;
-
+    Bytes             bytes_;
+    Encoder           encoder_;
+    Uint32Vector      callSiteLineNums_;
     LocalMap          locals_;
 
     // Labels
     LabelMap          breakLabels_;
     LabelMap          continueLabels_;
     Uint32Vector      breakableStack_;
     Uint32Vector      continuableStack_;
     uint32_t          blockDepth_;
 
     bool              hasAlreadyReturned_;
     ExprType          ret_;
 
   public:
     FunctionValidator(ModuleValidator& m, ParseNode* fn)
       : m_(m),
         fn_(fn),
+        encoder_(bytes_),
         locals_(m.cx()),
         breakLabels_(m.cx()),
         continueLabels_(m.cx()),
         blockDepth_(0),
         hasAlreadyReturned_(false),
         ret_(ExprType::Limit)
     {}
 
     ModuleValidator& m() const        { return m_; }
     JSContext* cx() const             { return m_.cx(); }
     ParseNode* fn() const             { return fn_; }
 
-    bool init(PropertyName* name, unsigned line) {
-        if (!locals_.init() || !breakLabels_.init() || !continueLabels_.init())
-            return false;
-
-        if (!m_.mg().startFuncDef(line, &fg_))
-            return false;
-
-        encoder_.emplace(fg_.bytes());
-        return true;
-    }
-
-    bool finish(uint32_t funcIndex) {
+    bool init() {
+        return locals_.init() &&
+               breakLabels_.init() &&
+               continueLabels_.init();
+    }
+
+    bool finish(uint32_t funcIndex, unsigned line) {
         MOZ_ASSERT(!blockDepth_);
         MOZ_ASSERT(breakableStack_.empty());
         MOZ_ASSERT(continuableStack_.empty());
         MOZ_ASSERT(breakLabels_.empty());
         MOZ_ASSERT(continueLabels_.empty());
-        return m_.mg().finishFuncDef(funcIndex, &fg_);
+        return m_.mg().compileFuncDef(funcIndex, line, Move(bytes_), Move(callSiteLineNums_));
     }
 
     bool fail(ParseNode* pn, const char* str) {
         return m_.fail(pn, str);
     }
 
     bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
         va_list ap;
@@ -3131,17 +3126,17 @@ class MOZ_STACK_CLASS FunctionValidator
             return nullptr;
         return m_.lookupGlobal(name);
     }
 
     size_t numLocals() const { return locals_.count(); }
 
     /**************************************************** Encoding interface */
 
-    Encoder& encoder() { return *encoder_; }
+    Encoder& encoder() { return encoder_; }
 
     MOZ_MUST_USE bool writeInt32Lit(int32_t i32) {
         return encoder().writeOp(Op::I32Const) &&
                encoder().writeVarS32(i32);
     }
     MOZ_MUST_USE bool writeConstExpr(const NumLit& lit) {
         switch (lit.which()) {
           case NumLit::Fixnum:
@@ -3183,24 +3178,24 @@ class MOZ_STACK_CLASS FunctionValidator
                    encoder().writeFixedI32x4(lit.simdValue().asInt32x4());
           case NumLit::OutOfRangeInt:
             break;
         }
         MOZ_CRASH("unexpected literal type");
     }
     MOZ_MUST_USE bool writeCall(ParseNode* pn, Op op) {
         return encoder().writeOp(op) &&
-               fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
+               callSiteLineNums_.append(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
     }
     MOZ_MUST_USE bool writeCall(ParseNode* pn, MozOp op) {
         return encoder().writeOp(op) &&
-               fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
+               callSiteLineNums_.append(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
     }
     MOZ_MUST_USE bool prepareCall(ParseNode* pn) {
-        return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
+        return callSiteLineNums_.append(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
     }
     MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation simdOp) {
         MozOp op = SimdToOp(simdType, simdOp);
         if (op == MozOp::Limit)
             return true;
         return encoder().writeOp(op);
     }
 };
@@ -7099,17 +7094,17 @@ CheckFunction(ModuleValidator& m)
     unsigned line = 0;
     if (!ParseFunction(m, &fn, &line))
         return false;
 
     if (!CheckFunctionHead(m, fn))
         return false;
 
     FunctionValidator f(m, fn);
-    if (!f.init(FunctionName(fn), line))
+    if (!f.init())
         return m.fail(fn, "internal compiler failure (probably out of memory)");
 
     ParseNode* stmtIter = ListHead(FunctionStatementList(fn));
 
     if (!CheckProcessingDirectives(m, &stmtIter))
         return false;
 
     ValTypeVector args;
@@ -7133,17 +7128,17 @@ CheckFunction(ModuleValidator& m)
     if (!CheckFunctionSignature(m, fn, Sig(Move(args), f.returnedType()), FunctionName(fn), &func))
         return false;
 
     if (func->defined())
         return m.failName(fn, "function '%s' already defined", FunctionName(fn));
 
     func->define(fn);
 
-    if (!f.finish(func->index()))
+    if (!f.finish(func->index(), line))
         return m.fail(fn, "internal compiler failure (probably out of memory)");
 
     // Release the parser's lifo memory only after the last use of a parse node.
     m.parser().release(mark);
     return true;
 }
 
 static bool
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -565,17 +565,17 @@ class BaseCompiler
     enum class LatentOp {
         None,
         Compare,
         Eqz
     };
 
     const ModuleEnvironment&    env_;
     BaseOpIter                  iter_;
-    const FuncBytes&            func_;
+    const FuncCompileUnit&      func_;
     size_t                      lastReadCallSite_;
     TempAllocator&              alloc_;
     const ValTypeVector&        locals_;         // Types of parameters and locals
     int32_t                     localSize_;      // Size of local area in bytes (stable after beginFunction)
     int32_t                     varLow_;         // Low byte offset of local area for true locals (not parameters)
     int32_t                     varHigh_;        // High byte offset + 1 of local area for true locals
     int32_t                     maxFramePushed_; // Max value of masm.framePushed() observed
     bool                        deadCode_;       // Flag indicating we should decode & discard the opcode
@@ -640,30 +640,32 @@ class BaseCompiler
     RegF32 joinRegF32;
     RegF64 joinRegF64;
 
     // There are more members scattered throughout.
 
   public:
     BaseCompiler(const ModuleEnvironment& env,
                  Decoder& decoder,
-                 const FuncBytes& func,
+                 const FuncCompileUnit& func,
                  const ValTypeVector& locals,
                  bool debugEnabled,
                  TempAllocator* alloc,
                  MacroAssembler* masm,
                  CompileMode mode);
 
     MOZ_MUST_USE bool init();
 
     FuncOffsets finish();
 
     MOZ_MUST_USE bool emitFunction();
     void emitInitStackLocals();
 
+    const SigWithId& sig() const { return *env_.funcSigs[func_.index()]; }
+
     // Used by some of the ScratchRegister implementations.
     operator MacroAssembler&() const { return masm; }
 
 #ifdef DEBUG
     bool scratchRegisterTaken() const {
         return scratchRegisterTaken_;
     }
     void setScratchRegisterTaken(bool state) {
@@ -2231,17 +2233,17 @@ class BaseCompiler
         // ScratchReg may be used by branchPtr(), so use ABINonArgReg0/1 for
         // temporaries.
 
         stackAddOffset_ = masm.add32ToPtrWithPatch(StackPointer, ABINonArgReg0);
         masm.wasmEmitStackCheck(ABINonArgReg0, ABINonArgReg1, &stackOverflowLabel_);
 
         // Copy arguments from registers to stack.
 
-        const ValTypeVector& args = func_.sig().args();
+        const ValTypeVector& args = sig().args();
 
         for (ABIArgIter<const ValTypeVector> i(args); !i.done(); i++) {
             Local& l = localInfo_[i.index()];
             switch (i.mirType()) {
               case MIRType::Int32:
                 if (i->argInRegister())
                     storeToFrameI32(i->gpr(), l.offs());
                 break;
@@ -2268,17 +2270,17 @@ class BaseCompiler
         if (debugEnabled_)
             insertBreakablePoint(CallSiteDesc::EnterFrame);
     }
 
     void saveResult() {
         MOZ_ASSERT(debugEnabled_);
         size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
         Address resultsAddress(StackPointer, debugFrameOffset + DebugFrame::offsetOfResults());
-        switch (func_.sig().ret()) {
+        switch (sig().ret()) {
           case ExprType::Void:
             break;
           case ExprType::I32:
             masm.store32(RegI32(ReturnReg), resultsAddress);
             break;
 
           case ExprType::I64:
             masm.store64(RegI64(ReturnReg64), resultsAddress);
@@ -2293,17 +2295,17 @@ class BaseCompiler
             MOZ_CRASH("Function return type");
         }
     }
 
     void restoreResult() {
         MOZ_ASSERT(debugEnabled_);
         size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
         Address resultsAddress(StackPointer, debugFrameOffset + DebugFrame::offsetOfResults());
-        switch (func_.sig().ret()) {
+        switch (sig().ret()) {
           case ExprType::Void:
             break;
           case ExprType::I32:
             masm.load32(resultsAddress, RegI32(ReturnReg));
             break;
           case ExprType::I64:
             masm.load64(resultsAddress, RegI64(ReturnReg64));
             break;
@@ -5817,17 +5819,17 @@ BaseCompiler::emitReturn()
 {
     Nothing unused_value;
     if (!iter_.readReturn(&unused_value))
         return false;
 
     if (deadCode_)
         return true;
 
-    doReturn(func_.sig().ret(), PopStack(true));
+    doReturn(sig().ret(), PopStack(true));
     deadCode_ = true;
 
     return true;
 }
 
 bool
 BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall& baselineCall)
 {
@@ -6886,17 +6888,17 @@ BaseCompiler::emitCurrentMemory()
     pushReturned(baselineCall, ExprType::I32);
 
     return true;
 }
 
 bool
 BaseCompiler::emitBody()
 {
-    if (!iter_.readFunctionStart(func_.sig().ret()))
+    if (!iter_.readFunctionStart(sig().ret()))
         return false;
 
     initControl(controlItem());
 
     uint32_t overhead = 0;
 
     for (;;) {
 
@@ -6968,17 +6970,17 @@ BaseCompiler::emitBody()
 
         switch (op.b0) {
           case uint16_t(Op::End):
             if (!emitEnd())
                 return false;
 
             if (iter_.controlStackEmpty()) {
                 if (!deadCode_)
-                    doReturn(func_.sig().ret(), PopStack(false));
+                    doReturn(sig().ret(), PopStack(false));
                 return iter_.readFunctionEnd(iter_.end());
             }
             NEXT();
 
           // Control opcodes
           case uint16_t(Op::Nop):
             CHECK_NEXT(iter_.readNop());
           case uint16_t(Op::Drop):
@@ -7579,17 +7581,17 @@ BaseCompiler::emitInitStackLocals()
 
     freeGPR(p);
     freeGPR(lim);
     freeGPR(zero);
 }
 
 BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
                            Decoder& decoder,
-                           const FuncBytes& func,
+                           const FuncCompileUnit& func,
                            const ValTypeVector& locals,
                            bool debugEnabled,
                            TempAllocator* alloc,
                            MacroAssembler* masm,
                            CompileMode mode)
     : env_(env),
       iter_(env, decoder),
       func_(func),
@@ -7668,21 +7670,20 @@ BaseCompiler::init()
         return false;
     if (!SigP_.append(MIRType::Pointer))
         return false;
     if (!SigPI_.append(MIRType::Pointer) || !SigPI_.append(MIRType::Int32))
         return false;
     if (!SigI64I64_.append(ValType::I64) || !SigI64I64_.append(ValType::I64))
         return false;
 
-    const ValTypeVector& args = func_.sig().args();
-
     if (!localInfo_.resize(locals_.length()))
         return false;
 
+    const ValTypeVector& args = sig().args();
     BaseLocalIter i(locals_, args.length(), debugEnabled_);
     varLow_ = i.reservedSize();
     for (; !i.done() && i.index() < args.length(); i++) {
         MOZ_ASSERT(i.isArg());
         Local& l = localInfo_[i.index()];
         l.init(i.mirType(), i.frameOffset());
         varLow_ = i.currentLocalSize();
     }
@@ -7737,46 +7738,44 @@ js::wasm::BaselineCanCompile()
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
     return true;
 #else
     return false;
 #endif
 }
 
 bool
-js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars *error)
+js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* func, UniqueChars* error)
 {
     MOZ_ASSERT(task->tier() == Tier::Baseline);
     MOZ_ASSERT(task->env().kind == ModuleKind::Wasm);
 
-    const FuncBytes& func = unit->func();
-
-    Decoder d(func.bytes().begin(), func.bytes().end(), func.lineOrBytecode(), error);
+    Decoder d(func->begin(), func->end(), func->lineOrBytecode(), error);
 
     // Build the local types vector.
 
     ValTypeVector locals;
-    if (!locals.appendAll(func.sig().args()))
+    if (!locals.appendAll(task->env().funcSigs[func->index()]->args()))
         return false;
     if (!DecodeLocalEntries(d, task->env().kind, &locals))
         return false;
 
     // The MacroAssembler will sometimes access the jitContext.
 
     JitContext jitContext(&task->alloc());
 
     // One-pass baseline compilation.
 
-    BaseCompiler f(task->env(), d, func, locals, task->debugEnabled(), &task->alloc(),
+    BaseCompiler f(task->env(), d, *func, locals, task->debugEnabled(), &task->alloc(),
                    &task->masm(), task->mode());
     if (!f.init())
         return false;
 
     if (!f.emitFunction())
         return false;
 
-    unit->finish(f.finish());
+    func->finish(f.finish());
     return true;
 }
 
 #undef INT_DIV_I64_CALLOUT
 #undef I64_TO_FLOAT_CALLOUT
 #undef FLOAT_TO_I64_CALLOUT
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -37,31 +37,22 @@ 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");
 
     const size_t offsetInModule = d.currentOffset();
 
-    // Skip over the function body; we'll validate it later.
+    // Skip over the function body; it will be validated by the compilation thread.
     const uint8_t* bodyBegin;
     if (!d.readBytes(bodySize, &bodyBegin))
         return d.fail("function body length too big");
 
-    FunctionGenerator fg;
-    if (!mg.startFuncDef(offsetInModule, &fg))
-        return false;
-
-    if (!fg.bytes().resize(bodySize))
-        return false;
-
-    memcpy(fg.bytes().begin(), bodyBegin, bodySize);
-
-    return mg.finishFuncDef(funcIndex, &fg);
+    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"))
         return false;
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -59,17 +59,16 @@ ModuleGenerator::ModuleGenerator(const C
     masmAlloc_(&lifo_),
     masm_(MacroAssembler::WasmToken(), masmAlloc_),
     lastPatchedCallsite_(0),
     startOfUnpatchedCallsites_(0),
     parallel_(false),
     outstanding_(0),
     currentTask_(nullptr),
     batchedBytecode_(0),
-    activeFuncDef_(nullptr),
     startedFuncDefs_(false),
     finishedFuncDefs_(false),
     numFinishedFuncDefs_(0)
 {
     MOZ_ASSERT(IsCompilingWasm());
 }
 
 ModuleGenerator::~ModuleGenerator()
@@ -427,22 +426,20 @@ ModuleGenerator::finishTask(CompileTask*
     // body might go out of range, insert far jumps to extend the range.
     if ((masm_.size() - startOfUnpatchedCallsites_) + task->masm().size() > JumpRange()) {
         startOfUnpatchedCallsites_ = masm_.size();
         if (!patchCallSites())
             return false;
     }
 
     uint32_t offsetInWhole = masm_.size();
-    for (const FuncCompileUnit& unit : task->units()) {
-        const FuncBytes& func = unit.func();
-
+    for (const FuncCompileUnit& func : task->units()) {
         // Offset the recorded FuncOffsets by the offset of the function in the
         // whole module's code segment.
-        FuncOffsets offsets = unit.offsets();
+        FuncOffsets offsets = func.offsets();
         offsets.offsetBy(offsetInWhole);
 
         // Add the CodeRange for this function.
         uint32_t funcCodeRangeIndex = metadataTier_->codeRanges.length();
         if (!metadataTier_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), offsets))
             return false;
 
         MOZ_ASSERT(!funcIsCompiled(func.index()));
@@ -450,17 +447,17 @@ ModuleGenerator::finishTask(CompileTask*
     }
 
     // Merge the compiled results into the whole-module masm.
     mozilla::DebugOnly<size_t> sizeBefore = masm_.size();
     if (!masm_.asmMergeWith(task->masm()))
         return false;
     MOZ_ASSERT(masm_.size() == offsetInWhole + task->masm().size());
 
-    if (!task->reset(&freeFuncBytes_))
+    if (!task->reset())
         return false;
 
     freeTasks_.infallibleAppend(task);
     return true;
 }
 
 bool
 ModuleGenerator::finishFuncExports()
@@ -881,44 +878,16 @@ ModuleGenerator::startFuncDefs()
         freeTasks_.infallibleAppend(&tasks_[i]);
 
     startedFuncDefs_ = true;
     MOZ_ASSERT(!finishedFuncDefs_);
     return true;
 }
 
 bool
-ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg)
-{
-    MOZ_ASSERT(startedFuncDefs_);
-    MOZ_ASSERT(!activeFuncDef_);
-    MOZ_ASSERT(!finishedFuncDefs_);
-
-    if (!freeFuncBytes_.empty()) {
-        fg->funcBytes_ = Move(freeFuncBytes_.back());
-        freeFuncBytes_.popBack();
-    } else {
-        fg->funcBytes_ = js::MakeUnique<FuncBytes>();
-        if (!fg->funcBytes_)
-            return false;
-    }
-
-    if (!currentTask_) {
-        if (freeTasks_.empty() && !finishOutstandingTask())
-            return false;
-        currentTask_ = freeTasks_.popCopy();
-    }
-
-    fg->funcBytes_->setLineOrBytecode(lineOrBytecode);
-    fg->m_ = this;
-    activeFuncDef_ = fg;
-    return true;
-}
-
-bool
 ModuleGenerator::launchBatchCompile()
 {
     MOZ_ASSERT(currentTask_);
 
     if (cancelled_ && *cancelled_)
         return false;
 
     size_t numBatchedFuncs = currentTask_->units().length();
@@ -938,49 +907,66 @@ ModuleGenerator::launchBatchCompile()
     currentTask_ = nullptr;
     batchedBytecode_ = 0;
 
     numFinishedFuncDefs_ += numBatchedFuncs;
     return true;
 }
 
 bool
-ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg)
+ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
+                                Bytes&& bytes, const uint8_t* begin, const uint8_t* end,
+                                Uint32Vector&& lineNums)
 {
-    MOZ_ASSERT(activeFuncDef_ == fg);
+    MOZ_ASSERT(startedFuncDefs_);
+    MOZ_ASSERT(!finishedFuncDefs_);
     MOZ_ASSERT_IF(mode() == CompileMode::Tier1, funcIndex < env_->numFuncs());
 
-    UniqueFuncBytes func = Move(fg->funcBytes_);
-    func->setFunc(funcIndex, &funcSig(funcIndex));
-    uint32_t funcBytecodeLength = func->bytes().length();
-    if (!currentTask_->units().emplaceBack(Move(func)))
+    if (!currentTask_) {
+        if (freeTasks_.empty() && !finishOutstandingTask())
+            return false;
+        currentTask_ = freeTasks_.popCopy();
+    }
+
+    uint32_t funcBytecodeLength = end - begin;
+
+    FuncCompileUnitVector& units = currentTask_->units();
+    if (!units.emplaceBack(funcIndex, lineOrBytecode, Move(bytes), begin, end, Move(lineNums)))
         return false;
 
     uint32_t threshold;
     switch (tier()) {
       case Tier::Baseline: threshold = JitOptions.wasmBatchBaselineThreshold; break;
       case Tier::Ion:      threshold = JitOptions.wasmBatchIonThreshold;      break;
       default:             MOZ_CRASH("Invalid tier value");                   break;
     }
 
     batchedBytecode_ += funcBytecodeLength;
     MOZ_ASSERT(batchedBytecode_ <= MaxModuleBytes);
-    if (batchedBytecode_ > threshold && !launchBatchCompile())
-        return false;
+    return batchedBytecode_ <= threshold || launchBatchCompile();
+}
 
-    fg->m_ = nullptr;
-    activeFuncDef_ = nullptr;
-    return true;
+bool
+ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
+                                const uint8_t* begin, const uint8_t* end)
+{
+    return compileFuncDef(funcIndex, lineOrBytecode, Bytes(), begin, end, Uint32Vector());
+}
+
+bool
+ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
+                                Bytes&& bytes, Uint32Vector&& lineNums)
+{
+    return compileFuncDef(funcIndex, lineOrBytecode, Move(bytes), bytes.begin(), bytes.end(), Move(lineNums));
 }
 
 bool
 ModuleGenerator::finishFuncDefs()
 {
     MOZ_ASSERT(startedFuncDefs_);
-    MOZ_ASSERT(!activeFuncDef_);
     MOZ_ASSERT(!finishedFuncDefs_);
 
     if (currentTask_ && !launchBatchCompile())
         return false;
 
     while (outstanding_ > 0) {
         if (!finishOutstandingTask())
             return false;
@@ -1150,17 +1136,16 @@ ModuleGenerator::finishMetadata(const Sh
     generateBytecodeHash(bytecode);
 
     return true;
 }
 
 UniqueConstCodeSegment
 ModuleGenerator::finishCodeSegment(const ShareableBytes& bytecode)
 {
-    MOZ_ASSERT(!activeFuncDef_);
     MOZ_ASSERT(finishedFuncDefs_);
 
     if (!finishFuncExports())
         return nullptr;
 
     if (!finishCodegen())
         return nullptr;
 
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -24,109 +24,68 @@
 #include "wasm/WasmModule.h"
 #include "wasm/WasmValidate.h"
 
 namespace js {
 namespace wasm {
 
 struct CompileArgs;
 struct ModuleEnvironment;
-class FunctionGenerator;
-
-// The FuncBytes class represents a single, concurrently-compilable function.
-// A FuncBytes object is composed of the wasm function body bytes along with the
-// ambient metadata describing the function necessary to compile it.
-
-class FuncBytes
-{
-    Bytes            bytes_;
-    uint32_t         index_;
-    const SigWithId* sig_;
-    uint32_t         lineOrBytecode_;
-    Uint32Vector     callSiteLineNums_;
-
-  public:
-    FuncBytes()
-      : index_(UINT32_MAX),
-        sig_(nullptr),
-        lineOrBytecode_(UINT32_MAX)
-    {}
-
-    Bytes& bytes() {
-        return bytes_;
-    }
-    MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
-        return callSiteLineNums_.append(lineno);
-    }
-    void setLineOrBytecode(uint32_t lineOrBytecode) {
-        MOZ_ASSERT(lineOrBytecode_ == UINT32_MAX);
-        lineOrBytecode_ = lineOrBytecode;
-    }
-    void setFunc(uint32_t index, const SigWithId* sig) {
-        MOZ_ASSERT(index_ == UINT32_MAX);
-        MOZ_ASSERT(sig_ == nullptr);
-        index_ = index;
-        sig_ = sig;
-    }
-    void reset() {
-        bytes_.clear();
-        index_ = UINT32_MAX;
-        sig_ = nullptr;
-        lineOrBytecode_ = UINT32_MAX;
-        callSiteLineNums_.clear();
-    }
-
-    const Bytes& bytes() const { return bytes_; }
-    uint32_t index() const { return index_; }
-    const SigWithId& sig() const { return *sig_; }
-    uint32_t lineOrBytecode() const { return lineOrBytecode_; }
-    const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; }
-};
-
-typedef UniquePtr<FuncBytes> UniqueFuncBytes;
-typedef Vector<UniqueFuncBytes, 8, SystemAllocPolicy> UniqueFuncBytesVector;
 
 // FuncCompileUnit contains all the data necessary to produce and store the
 // results of a single function's compilation.
 
 class FuncCompileUnit
 {
-    UniqueFuncBytes func_;
+    // Input:
+    Bytes bytesToDelete_;
+    const uint8_t* begin_;
+    const uint8_t* end_;
+    uint32_t index_;
+    uint32_t lineOrBytecode_;
+    Uint32Vector callSiteLineNums_;
+
+    // Output:
     FuncOffsets offsets_;
     DebugOnly<bool> finished_;
 
   public:
-    explicit FuncCompileUnit(UniqueFuncBytes func)
-      : func_(Move(func)),
+    explicit FuncCompileUnit(uint32_t index, uint32_t lineOrBytecode,
+                             Bytes&& bytesToDelete, const uint8_t* begin, const uint8_t* end,
+                             Uint32Vector&& callSiteLineNums)
+      : bytesToDelete_(Move(bytesToDelete)),
+        begin_(begin),
+        end_(end),
+        index_(index),
+        lineOrBytecode_(lineOrBytecode),
+        callSiteLineNums_(Move(callSiteLineNums)),
         finished_(false)
     {}
 
-    const FuncBytes& func() const { return *func_; }
+    const uint8_t* begin() const { return begin_; }
+    const uint8_t* end() const { return end_; }
+    uint32_t index() const { return index_; }
+    uint32_t lineOrBytecode() const { return lineOrBytecode_; }
+    const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; }
+
     FuncOffsets offsets() const { MOZ_ASSERT(finished_); return offsets_; }
 
     void finish(FuncOffsets offsets) {
         MOZ_ASSERT(!finished_);
         offsets_ = offsets;
         finished_ = true;
     }
-
-    UniqueFuncBytes recycle() {
-        MOZ_ASSERT(finished_);
-        func_->reset();
-        return Move(func_);
-    }
 };
 
 typedef Vector<FuncCompileUnit, 8, SystemAllocPolicy> FuncCompileUnitVector;
 
 // A CompileTask represents the task of compiling a batch of functions. It is
 // filled with a certain number of function's bodies that are sent off to a
 // compilation helper thread, which fills in the resulting code offsets, and
-// finally sent back to the validation thread. To save time allocating and
-// freeing memory, CompileTasks are reset() and reused.
+// finally sent back to the validation thread.
 
 class CompileTask
 {
     const ModuleEnvironment&   env_;
     LifoAlloc                  lifo_;
     Maybe<jit::TempAllocator>  alloc_;
     Maybe<jit::MacroAssembler> masm_;
     FuncCompileUnitVector      units_;
@@ -165,27 +124,21 @@ class CompileTask
         return env_.tier;
     }
     CompileMode mode() const {
         return env_.mode;
     }
     bool debugEnabled() const {
         return env_.debug == DebugEnabled::True;
     }
-    bool reset(UniqueFuncBytesVector* freeFuncBytes) {
-        for (FuncCompileUnit& unit : units_) {
-            if (!freeFuncBytes->emplaceBack(Move(unit.recycle())))
-                return false;
-        }
-
+    bool reset() {
         units_.clear();
         masm_.reset();
         alloc_.reset();
         lifo_.releaseAll();
-
         init();
         return true;
     }
 };
 
 struct Tier2GeneratorTask;
 
 // A ModuleGenerator encapsulates the creation of a wasm module. During the
@@ -228,22 +181,20 @@ class MOZ_STACK_CLASS ModuleGenerator
     uint32_t                        startOfUnpatchedCallsites_;
     Uint32Vector                    debugTrapFarJumps_;
 
     // Parallel compilation
     bool                            parallel_;
     uint32_t                        outstanding_;
     CompileTaskVector               tasks_;
     CompileTaskPtrVector            freeTasks_;
-    UniqueFuncBytesVector           freeFuncBytes_;
     CompileTask*                    currentTask_;
     uint32_t                        batchedBytecode_;
 
     // Assertions
-    DebugOnly<FunctionGenerator*>   activeFuncDef_;
     DebugOnly<bool>                 startedFuncDefs_;
     DebugOnly<bool>                 finishedFuncDefs_;
     DebugOnly<uint32_t>             numFinishedFuncDefs_;
 
     bool funcIsCompiled(uint32_t funcIndex) const;
     const CodeRange& funcCodeRange(uint32_t funcIndex) const;
     uint32_t numFuncImports() const;
     MOZ_MUST_USE bool patchCallSites();
@@ -257,16 +208,19 @@ class MOZ_STACK_CLASS ModuleGenerator
     MOZ_MUST_USE bool finishMetadata(const ShareableBytes& bytecode);
     MOZ_MUST_USE UniqueConstCodeSegment finishCodeSegment(const ShareableBytes& bytecode);
     UniqueJumpTable createJumpTable(const CodeSegment& codeSegment);
     MOZ_MUST_USE bool addFuncImport(const Sig& sig, uint32_t globalDataOffset);
     MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
     MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
 
     MOZ_MUST_USE bool launchBatchCompile();
+    MOZ_MUST_USE bool compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
+                                     Bytes&& bytes, const uint8_t* begin, const uint8_t* end,
+                                     Uint32Vector&& lineNums);
 
     MOZ_MUST_USE bool initAsmJS(Metadata* asmJSMetadata);
     MOZ_MUST_USE bool initWasm();
 
     bool isAsmJS() const { return env_->isAsmJS(); }
     Tier tier() const { return env_->tier; }
     CompileMode mode() const { return env_->mode; }
     bool debugEnabled() const { return env_->debugEnabled(); }
@@ -275,18 +229,20 @@ class MOZ_STACK_CLASS ModuleGenerator
     ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env,
                     Atomic<bool>* cancelled, UniqueChars* error);
     ~ModuleGenerator();
 
     MOZ_MUST_USE bool init(Metadata* maybeAsmJSMetadata = nullptr);
 
     // Function definitions:
     MOZ_MUST_USE bool startFuncDefs();
-    MOZ_MUST_USE bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
-    MOZ_MUST_USE bool finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg);
+    MOZ_MUST_USE bool compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
+                                     const uint8_t* begin, const uint8_t* end);
+    MOZ_MUST_USE bool compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
+                                     Bytes&& bytes, Uint32Vector&& callSiteLineNums);
     MOZ_MUST_USE bool finishFuncDefs();
 
     // asm.js accessors:
     uint32_t minMemoryLength() const { return env_->minMemoryLength; }
     uint32_t numSigs() const { return numSigs_; }
     const SigWithId& sig(uint32_t sigIndex) const;
     const SigWithId& funcSig(uint32_t funcIndex) const;
 
@@ -304,39 +260,12 @@ class MOZ_STACK_CLASS ModuleGenerator
     // Finish compilation of the given bytecode.
     SharedModule finishModule(const ShareableBytes& bytecode);
 
     // Finish compilation of the given bytecode, installing tier-variant parts
     // for Tier 2 into module.
     MOZ_MUST_USE bool finishTier2(Module& module);
 };
 
-// A FunctionGenerator encapsulates the generation of a single function body.
-// ModuleGenerator::startFuncDef must be called after construction and before
-// doing anything else.
-//
-// After the body is complete, ModuleGenerator::finishFuncDef must be called
-// before the FunctionGenerator is destroyed and the next function is started.
-
-class MOZ_STACK_CLASS FunctionGenerator
-{
-    friend class ModuleGenerator;
-
-    ModuleGenerator* m_;
-    UniqueFuncBytes  funcBytes_;
-
-  public:
-    FunctionGenerator()
-      : m_(nullptr), funcBytes_(nullptr)
-    {}
-
-    Bytes& bytes() {
-        return funcBytes_->bytes();
-    }
-    MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
-        return funcBytes_->addCallSiteLineNum(lineno);
-    }
-};
-
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_generator_h
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -121,17 +121,17 @@ class FunctionCompiler
     };
 
     typedef Vector<ControlFlowPatch, 0, SystemAllocPolicy> ControlFlowPatchVector;
     typedef Vector<ControlFlowPatchVector, 0, SystemAllocPolicy> ControlFlowPatchsVector;
     typedef Vector<CallCompileState*, 0, SystemAllocPolicy> CallCompileStateVector;
 
     const ModuleEnvironment&   env_;
     IonOpIter                  iter_;
-    const FuncBytes&           func_;
+    const FuncCompileUnit&     func_;
     const ValTypeVector&       locals_;
     size_t                     lastReadCallSite_;
 
     TempAllocator&             alloc_;
     MIRGraph&                  graph_;
     const CompileInfo&         info_;
     MIRGenerator&              mirGen_;
 
@@ -144,17 +144,17 @@ class FunctionCompiler
     ControlFlowPatchsVector    blockPatches_;
 
     // TLS pointer argument to the current function.
     MWasmParameter*            tlsPointer_;
 
   public:
     FunctionCompiler(const ModuleEnvironment& env,
                      Decoder& decoder,
-                     const FuncBytes& func,
+                     const FuncCompileUnit& func,
                      const ValTypeVector& locals,
                      MIRGenerator& mirGen)
       : env_(env),
         iter_(env, decoder),
         func_(func),
         locals_(locals),
         lastReadCallSite_(0),
         alloc_(mirGen.alloc()),
@@ -166,30 +166,30 @@ class FunctionCompiler
         loopDepth_(0),
         blockDepth_(0),
         tlsPointer_(nullptr)
     {}
 
     const ModuleEnvironment&   env() const   { return env_; }
     IonOpIter&                 iter()        { return iter_; }
     TempAllocator&             alloc() const { return alloc_; }
-    const Sig&                 sig() const   { return func_.sig(); }
+    const Sig&                 sig() const   { return *env_.funcSigs[func_.index()]; }
 
     BytecodeOffset bytecodeOffset() const {
         return iter_.bytecodeOffset();
     }
     Maybe<BytecodeOffset> bytecodeIfNotAsmJS() const {
         return env_.isAsmJS() ? Nothing() : Some(iter_.bytecodeOffset());
     }
 
     bool init()
     {
         // Prepare the entry block for MIR generation:
 
-        const ValTypeVector& args = func_.sig().args();
+        const ValTypeVector& args = sig().args();
 
         if (!mirGen_.ensureBallast())
             return false;
         if (!newBlock(/* prev */ nullptr, &curBlock_))
             return false;
 
         for (ABIArgIter<ValTypeVector> i(args); !i.done(); i++) {
             MWasmParameter* ins = MWasmParameter::New(alloc(), *i, i.mirType());
@@ -3847,46 +3847,45 @@ EmitBodyExprs(FunctionCompiler& f)
 
     MOZ_CRASH("unreachable");
 
 #undef CHECK
 #undef CHECK_ASMJS
 }
 
 bool
-wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* error)
+wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* func, UniqueChars* error)
 {
     MOZ_ASSERT(task->tier() == Tier::Ion);
 
-    const FuncBytes& func = unit->func();
     const ModuleEnvironment& env = task->env();
 
-    Decoder d(func.bytes().begin(), func.bytes().end(), func.lineOrBytecode(), error);
+    Decoder d(func->begin(), func->end(), func->lineOrBytecode(), error);
 
     // Build the local types vector.
 
     ValTypeVector locals;
-    if (!locals.appendAll(func.sig().args()))
+    if (!locals.appendAll(task->env().funcSigs[func->index()]->args()))
         return false;
     if (!DecodeLocalEntries(d, env.kind, &locals))
         return false;
 
     // Set up for Ion compilation.
 
     JitContext jitContext(&task->alloc());
     const JitCompileOptions options;
     MIRGraph graph(&task->alloc());
     CompileInfo compileInfo(locals.length());
     MIRGenerator mir(nullptr, options, &task->alloc(), &graph, &compileInfo,
                      IonOptimizations.get(OptimizationLevel::Wasm));
     mir.initMinWasmHeapLength(env.minMemoryLength);
 
     // Build MIR graph
     {
-        FunctionCompiler f(env, d, func, locals, mir);
+        FunctionCompiler f(env, d, *func, locals, mir);
         if (!f.init())
             return false;
 
         if (!f.startBlock())
             return false;
 
         if (!EmitBodyExprs(f))
             return false;
@@ -3901,22 +3900,22 @@ wasm::IonCompileFunction(CompileTask* ta
 
         if (!OptimizeMIR(&mir))
             return false;
 
         LIRGraph* lir = GenerateLIR(&mir);
         if (!lir)
             return false;
 
-        SigIdDesc sigId = env.funcSigs[func.index()]->id;
+        SigIdDesc sigId = env.funcSigs[func->index()]->id;
 
         CodeGenerator codegen(&mir, lir, &task->masm());
 
-        BytecodeOffset prologueTrapOffset(func.lineOrBytecode());
+        BytecodeOffset prologueTrapOffset(func->lineOrBytecode());
         FuncOffsets offsets;
         if (!codegen.generateWasm(sigId, prologueTrapOffset, &offsets))
             return false;
 
-        unit->finish(offsets);
+        func->finish(offsets);
     }
 
     return true;
 }