Backed out 11 changesets (bug 1535994) for BytecodeEmitter.cpp related build bustages CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Wed, 10 Apr 2019 12:30:10 +0300
changeset 468747 7fb3acf38591979f105306e0c8f3441e75c95bd5
parent 468746 d5975f907521e4a5fe727cd52e3799b60b97beb7
child 468748 35e35da9ae0ef007456cb049b6a4973684710601
push id35850
push userdvarga@mozilla.com
push dateWed, 10 Apr 2019 21:52:56 +0000
treeherdermozilla-central@9d3dbe3fef26 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1535994
milestone68.0a1
backs outd5975f907521e4a5fe727cd52e3799b60b97beb7
e56d1810fb40cb7f3e312a55ebdfcd88bb4ef7b9
fdd1177e499a08b4cde3e80992e288e5ee8084d5
db520471b4073f6ca3a9f671d522987f1298fa50
096ab8585046007ed3a7853e4b2ce6ce37f55243
8a480b0bbd0565adc7dfac295f6cac482e4d3350
7c763b9a2118ade0f7b0e372da562e415679c610
4f5084424c22603d3d6f87e9d283c6bf4421558f
ee3359178d5f37c951dd146926c4035d6245299f
b77efa8567a299f90c926f5623a6f07325fcfa32
384cdd1ee833dfa72b957072651c1bde10dacf7c
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
Backed out 11 changesets (bug 1535994) for BytecodeEmitter.cpp related build bustages CLOSED TREE Backed out changeset d5975f907521 (bug 1535994) Backed out changeset e56d1810fb40 (bug 1535994) Backed out changeset fdd1177e499a (bug 1535994) Backed out changeset db520471b407 (bug 1535994) Backed out changeset 096ab8585046 (bug 1535994) Backed out changeset 8a480b0bbd05 (bug 1535994) Backed out changeset 7c763b9a2118 (bug 1535994) Backed out changeset 4f5084424c22 (bug 1535994) Backed out changeset ee3359178d5f (bug 1535994) Backed out changeset b77efa8567a2 (bug 1535994) Backed out changeset 384cdd1ee833 (bug 1535994)
js/src/frontend/BytecodeControlStructures.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/CForEmitter.cpp
js/src/frontend/DoWhileEmitter.cpp
js/src/frontend/EmitterScope.cpp
js/src/frontend/ExpressionStatementEmitter.cpp
js/src/frontend/ForInEmitter.cpp
js/src/frontend/ForOfEmitter.cpp
js/src/frontend/ForOfLoopControl.cpp
js/src/frontend/FunctionEmitter.cpp
js/src/frontend/IfEmitter.cpp
js/src/frontend/LabelEmitter.cpp
js/src/frontend/ObjectEmitter.cpp
js/src/frontend/SwitchEmitter.cpp
js/src/frontend/TryEmitter.cpp
js/src/frontend/WhileEmitter.cpp
js/src/vm/JSScript.cpp
--- a/js/src/frontend/BytecodeControlStructures.cpp
+++ b/js/src/frontend/BytecodeControlStructures.cpp
@@ -36,17 +36,17 @@ LabelControl::LabelControl(BytecodeEmitt
       startOffset_(startOffset) {}
 
 LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
     : BreakableControl(bce, loopKind), tdzCache_(bce) {
   MOZ_ASSERT(is<LoopControl>());
 
   LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
 
-  stackDepth_ = bce->bytecodeSection().stackDepth();
+  stackDepth_ = bce->stackDepth;
   loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
 
   int loopSlots;
   if (loopKind == StatementKind::Spread) {
     // The iterator next method, the iterator, the result array, and
     // the current array index are on the stack.
     loopSlots = 4;
   } else if (loopKind == StatementKind::ForOfLoop) {
@@ -76,17 +76,17 @@ bool LoopControl::emitContinueTarget(Byt
     return false;
   }
   return true;
 }
 
 bool LoopControl::emitSpecialBreakForDone(BytecodeEmitter* bce) {
   // This doesn't pop stack values, nor handle any other controls.
   // Should be called on the toplevel of the loop.
-  MOZ_ASSERT(bce->bytecodeSection().stackDepth() == stackDepth_);
+  MOZ_ASSERT(bce->stackDepth == stackDepth_);
   MOZ_ASSERT(bce->innermostNestableControl == this);
 
   if (!bce->newSrcNote(SRC_BREAK)) {
     return false;
   }
   if (!bce->emitJump(JSOP_GOTO, &breaks)) {
     return false;
   }
@@ -104,44 +104,43 @@ bool LoopControl::emitEntryJump(Bytecode
 bool LoopControl::emitLoopHead(BytecodeEmitter* bce,
                                const Maybe<uint32_t>& nextPos) {
   if (nextPos) {
     if (!bce->updateSourceCoordNotes(*nextPos)) {
       return false;
     }
   }
 
-  head_ = {bce->bytecodeSection().offset()};
+  head_ = {bce->offset()};
   ptrdiff_t off;
   if (!bce->emitJumpTargetOp(JSOP_LOOPHEAD, &off)) {
     return false;
   }
 
   return true;
 }
 
 bool LoopControl::emitLoopEntry(BytecodeEmitter* bce,
                                 const Maybe<uint32_t>& nextPos) {
   if (nextPos) {
     if (!bce->updateSourceCoordNotes(*nextPos)) {
       return false;
     }
   }
 
-  JumpTarget entry = {bce->bytecodeSection().offset()};
+  JumpTarget entry = {bce->offset()};
   bce->patchJumpsToTarget(entryJump_, entry);
 
   MOZ_ASSERT(loopDepth_ > 0);
 
   ptrdiff_t off;
   if (!bce->emitJumpTargetOp(JSOP_LOOPENTRY, &off)) {
     return false;
   }
-  SetLoopEntryDepthHintAndFlags(bce->bytecodeSection().code(off), loopDepth_,
-                                canIonOsr_);
+  SetLoopEntryDepthHintAndFlags(bce->code(off), loopDepth_, canIonOsr_);
 
   return true;
 }
 
 bool LoopControl::emitLoopEnd(BytecodeEmitter* bce, JSOp op) {
   JumpList beq;
   if (!bce->emitBackwardJump(op, head_, &beq, &breakTarget_)) {
     return false;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -86,54 +86,42 @@ static bool ParseNodeRequiresSpecialLine
   // handling to avoid strange stepping behavior.
   // Functions usually shouldn't have location information (bug 1431202).
 
   ParseNodeKind kind = pn->getKind();
   return kind == ParseNodeKind::WhileStmt || kind == ParseNodeKind::ForStmt ||
          kind == ParseNodeKind::Function;
 }
 
-BytecodeEmitter::BytecodeSection::BytecodeSection(JSContext* cx,
-                                                  uint32_t lineNum)
-    : code_(cx),
-      notes_(cx),
-      tryNoteList_(cx),
-      scopeNoteList_(cx),
-      resumeOffsetList_(cx),
-      currentLine_(lineNum) {}
-
-BytecodeEmitter::PerScriptData::PerScriptData(JSContext* cx)
-    : scopeList_(cx),
-      numberList_(cx),
-      atomIndices_(cx->frontendCollectionPool()) {}
-
-bool BytecodeEmitter::PerScriptData::init(JSContext* cx) {
-  return atomIndices_.acquire(cx);
-}
-
 BytecodeEmitter::BytecodeEmitter(
     BytecodeEmitter* parent, SharedContext* sc, HandleScript script,
     Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode,
     FieldInitializers fieldInitializers /* = FieldInitializers::Invalid() */)
     : sc(sc),
       cx(sc->cx_),
       parent(parent),
       script(cx, script),
       lazyScript(cx, lazyScript),
-      bytecodeSection_(cx, lineNum),
-      perScriptData_(cx),
+      code_(cx),
+      notes_(cx),
+      currentLine_(lineNum),
       fieldInitializers_(fieldInitializers),
+      atomIndices(cx->frontendCollectionPool()),
       firstLine(lineNum),
+      numberList(cx),
+      scopeList(cx),
+      tryNoteList(cx),
+      scopeNoteList(cx),
+      resumeOffsetList(cx),
       emitterMode(emitterMode) {
   MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
 
   if (sc->isFunctionBox()) {
     // Functions have IC entries for type monitoring |this| and arguments.
-    bytecodeSection().setNumICEntries(sc->asFunctionBox()->function()->nargs() +
-                                      1);
+    numICEntries = sc->asFunctionBox()->function()->nargs() + 1;
   }
 }
 
 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
                                  BCEParserHandle* handle, SharedContext* sc,
                                  HandleScript script,
                                  Handle<LazyScript*> lazyScript,
                                  uint32_t lineNum, EmitterMode emitterMode,
@@ -155,17 +143,17 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
   this->parser = ep_.ptr();
 }
 
 void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition) {
   setScriptStartOffsetIfUnset(bodyPosition.begin);
   setFunctionBodyEndPos(bodyPosition.end);
 }
 
-bool BytecodeEmitter::init() { return perScriptData_.init(cx); }
+bool BytecodeEmitter::init() { return atomIndices.acquire(cx); }
 
 template <typename T>
 T* BytecodeEmitter::findInnermostNestableControl() const {
   return NestableControl::findNearest<T>(innermostNestableControl);
 }
 
 template <typename T, typename Predicate /* (T*) -> bool */>
 T* BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const {
@@ -201,74 +189,79 @@ bool BytecodeEmitter::markStepBreakpoint
 
   if (!newSrcNote(SRC_BREAKPOINT)) {
     return false;
   }
 
   // We track the location of the most recent separator for use in
   // markSimpleBreakpoint. Note that this means that the position must already
   // be set before markStepBreakpoint is called.
-  bytecodeSection().updateSeparatorPosition();
+  lastSeparatorOffet_ = code().length();
+  lastSeparatorLine_ = currentLine_;
+  lastSeparatorColumn_ = lastColumn_;
 
   return true;
 }
 
 bool BytecodeEmitter::markSimpleBreakpoint() {
   if (inPrologue()) {
     return true;
   }
 
   // If a breakable call ends up being the same location as the most recent
   // expression start, we need to skip marking it breakable in order to avoid
   // having two breakpoints with the same line/column position.
   // Note: This assumes that the position for the call has already been set.
-  if (!bytecodeSection().isDuplicateLocation()) {
+  bool isDuplicateLocation =
+      lastSeparatorLine_ == currentLine_ && lastSeparatorColumn_ == lastColumn_;
+
+  if (!isDuplicateLocation) {
     if (!newSrcNote(SRC_BREAKPOINT)) {
       return false;
     }
   }
 
   return true;
 }
 
 bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) {
-  *offset = bytecodeSection().code().length();
-
-  if (!bytecodeSection().code().growByUninitialized(delta)) {
+  *offset = code().length();
+
+  if (!code().growByUninitialized(delta)) {
     ReportOutOfMemory(cx);
     return false;
   }
 
   // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
   // reserve a type set to store its result.
   if (CodeSpec[op].format & JOF_TYPESET) {
-    if (bytecodeSection().typesetCount() < JSScript::MaxBytecodeTypeSets) {
-      bytecodeSection().addTypesetCount();
+    if (typesetCount < JSScript::MaxBytecodeTypeSets) {
+      typesetCount++;
     }
   }
 
   if (BytecodeOpHasIC(op)) {
-    bytecodeSection().addNumICEntries();
-  }
-
-  return true;
-}
-
-void BytecodeEmitter::BytecodeSection::updateDepth(ptrdiff_t target) {
+    numICEntries++;
+  }
+
+  return true;
+}
+
+void BytecodeEmitter::updateDepth(ptrdiff_t target) {
   jsbytecode* pc = code(target);
 
   int nuses = StackUses(pc);
   int ndefs = StackDefs(pc);
 
-  stackDepth_ -= nuses;
-  MOZ_ASSERT(stackDepth_ >= 0);
-  stackDepth_ += ndefs;
-
-  if ((uint32_t)stackDepth_ > maxStackDepth_) {
-    maxStackDepth_ = stackDepth_;
+  stackDepth -= nuses;
+  MOZ_ASSERT(stackDepth >= 0);
+  stackDepth += ndefs;
+
+  if ((uint32_t)stackDepth > maxStackDepth) {
+    maxStackDepth = stackDepth;
   }
 }
 
 #ifdef DEBUG
 bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
   if (IsCheckStrictOp(op) && !sc->strict()) {
     return false;
   }
@@ -282,129 +275,128 @@ bool BytecodeEmitter::checkStrictOrSlopp
 bool BytecodeEmitter::emit1(JSOp op) {
   MOZ_ASSERT(checkStrictOrSloppy(op));
 
   ptrdiff_t offset;
   if (!emitCheck(op, 1, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = jsbytecode(op);
-  bytecodeSection().updateDepth(offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::emit2(JSOp op, uint8_t op1) {
   MOZ_ASSERT(checkStrictOrSloppy(op));
 
   ptrdiff_t offset;
   if (!emitCheck(op, 2, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = jsbytecode(op);
   code[1] = jsbytecode(op1);
-  bytecodeSection().updateDepth(offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) {
   MOZ_ASSERT(checkStrictOrSloppy(op));
 
   /* These should filter through emitVarOp. */
   MOZ_ASSERT(!IsArgOp(op));
   MOZ_ASSERT(!IsLocalOp(op));
 
   ptrdiff_t offset;
   if (!emitCheck(op, 3, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = jsbytecode(op);
   code[1] = op1;
   code[2] = op2;
-  bytecodeSection().updateDepth(offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) {
   MOZ_ASSERT(checkStrictOrSloppy(op));
   ptrdiff_t length = 1 + ptrdiff_t(extra);
 
   ptrdiff_t off;
   if (!emitCheck(op, length, &off)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(off);
+  jsbytecode* code = this->code(off);
   code[0] = jsbytecode(op);
   /* The remaining |extra| bytes are set by the caller */
 
   /*
    * Don't updateDepth if op's use-count comes from the immediate
    * operand yet to be stored in the extra bytes after op.
    */
   if (CodeSpec[op].nuses >= 0) {
-    bytecodeSection().updateDepth(off);
+    updateDepth(off);
   }
 
   if (offset) {
     *offset = off;
   }
   return true;
 }
 
 bool BytecodeEmitter::emitJumpTargetOp(JSOp op, ptrdiff_t* off) {
   MOZ_ASSERT(BytecodeIsJumpTarget(op));
 
-  size_t numEntries = bytecodeSection().numICEntries();
+  size_t numEntries = numICEntries;
   if (MOZ_UNLIKELY(numEntries > UINT32_MAX)) {
     reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
     return false;
   }
 
   if (!emitN(op, CodeSpec[op].length - 1, off)) {
     return false;
   }
 
-  SET_ICINDEX(bytecodeSection().code(*off), numEntries);
+  SET_ICINDEX(code(*off), numEntries);
   return true;
 }
 
 bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
-  ptrdiff_t off = bytecodeSection().offset();
+  ptrdiff_t off = offset();
 
   // Alias consecutive jump targets.
-  if (off == bytecodeSection().lastTargetOffset() +
-                 ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
-    target->offset = bytecodeSection().lastTargetOffset();
+  if (off == lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
+    target->offset = lastTarget.offset;
     return true;
   }
 
   target->offset = off;
-  bytecodeSection().setLastTargetOffset(off);
+  lastTarget.offset = off;
 
   ptrdiff_t opOff;
   return emitJumpTargetOp(JSOP_JUMPTARGET, &opOff);
 }
 
 bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
   ptrdiff_t offset;
   if (!emitCheck(op, 5, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = jsbytecode(op);
   MOZ_ASSERT(-1 <= jump->offset && jump->offset < offset);
-  jump->push(bytecodeSection().code(0), offset);
-  bytecodeSection().updateDepth(offset);
+  jump->push(this->code(0), offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::emitJump(JSOp op, JumpList* jump) {
   if (!emitJumpNoFallthrough(op, jump)) {
     return false;
   }
   if (BytecodeFallsThrough(op)) {
@@ -428,22 +420,21 @@ bool BytecodeEmitter::emitBackwardJump(J
   // target for break statements.
   if (!emitJumpTarget(fallthrough)) {
     return false;
   }
   return true;
 }
 
 void BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target) {
-  MOZ_ASSERT(-1 <= jump.offset && jump.offset <= bytecodeSection().offset());
-  MOZ_ASSERT(0 <= target.offset && target.offset <= bytecodeSection().offset());
-  MOZ_ASSERT_IF(
-      jump.offset != -1 && target.offset + 4 <= bytecodeSection().offset(),
-      BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target.offset))));
-  jump.patchAll(bytecodeSection().code(0), target);
+  MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset());
+  MOZ_ASSERT(0 <= target.offset && target.offset <= offset());
+  MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),
+                BytecodeIsJumpTarget(JSOp(*code(target.offset))));
+  jump.patchAll(code(0), target);
 }
 
 bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump) {
   if (jump.offset == -1) {
     return true;
   }
   JumpTarget target;
   if (!emitJumpTarget(&target)) {
@@ -463,33 +454,33 @@ bool BytecodeEmitter::emitCall(JSOp op, 
   return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
 }
 
 bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) {
   return emitCall(op, argc, pn ? Some(pn->pn_pos.begin) : Nothing());
 }
 
 bool BytecodeEmitter::emitDupAt(unsigned slotFromTop) {
-  MOZ_ASSERT(slotFromTop < unsigned(bytecodeSection().stackDepth()));
+  MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
 
   if (slotFromTop == 0) {
     return emit1(JSOP_DUP);
   }
 
   if (slotFromTop >= JS_BIT(24)) {
     reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
     return false;
   }
 
   ptrdiff_t off;
   if (!emitN(JSOP_DUPAT, 3, &off)) {
     return false;
   }
 
-  jsbytecode* pc = bytecodeSection().code(off);
+  jsbytecode* pc = code(off);
   SET_UINT24(pc, slotFromTop);
   return true;
 }
 
 bool BytecodeEmitter::emitPopN(unsigned n) {
   MOZ_ASSERT(n != 0);
 
   if (n == 1) {
@@ -520,84 +511,91 @@ static inline unsigned LengthOfSetLine(u
 bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
   // Don't emit line/column number notes in the prologue.
   if (inPrologue()) {
     return true;
   }
 
   ErrorReporter* er = &parser->errorReporter();
   bool onThisLine;
-  if (!er->isOnThisLine(offset, bytecodeSection().currentLine(), &onThisLine)) {
+  if (!er->isOnThisLine(offset, currentLine(), &onThisLine)) {
     er->errorNoOffset(JSMSG_OUT_OF_MEMORY);
     return false;
   }
 
   if (!onThisLine) {
     unsigned line = er->lineAt(offset);
-    unsigned delta = line - bytecodeSection().currentLine();
+    unsigned delta = line - currentLine();
 
     /*
      * Encode any change in the current source line number by using
      * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
      * whichever consumes less space.
      *
      * NB: We handle backward line number deltas (possible with for
      * loops where the update part is emitted after the body, but its
      * line number is <= any line number in the body) here by letting
      * unsigned delta_ wrap to a very large number, which triggers a
      * SRC_SETLINE.
      */
-    bytecodeSection().setCurrentLine(line);
+    setCurrentLine(line);
     if (delta >= LengthOfSetLine(line)) {
       if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line))) {
         return false;
       }
     } else {
       do {
         if (!newSrcNote(SRC_NEWLINE)) {
           return false;
         }
       } while (--delta != 0);
     }
 
-    bytecodeSection().updateSeparatorPositionIfPresent();
+    updateSeparatorPosition();
   }
   return true;
 }
 
 /* Updates the line number and column number information in the source notes. */
 bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
   if (!updateLineNumberNotes(offset)) {
     return false;
   }
 
   // Don't emit line/column number notes in the prologue.
   if (inPrologue()) {
     return true;
   }
 
   uint32_t columnIndex = parser->errorReporter().columnAt(offset);
-  ptrdiff_t colspan =
-      ptrdiff_t(columnIndex) - ptrdiff_t(bytecodeSection().lastColumn());
+  ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(lastColumn_);
   if (colspan != 0) {
     // If the column span is so large that we can't store it, then just
     // discard this information. This can happen with minimized or otherwise
     // machine-generated code. Even gigantic column numbers are still
     // valuable if you have a source map to relate them to something real;
     // but it's better to fail soft here.
     if (!SN_REPRESENTABLE_COLSPAN(colspan)) {
       return true;
     }
     if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan))) {
       return false;
     }
-    bytecodeSection().setLastColumn(columnIndex);
-    bytecodeSection().updateSeparatorPositionIfPresent();
-  }
-  return true;
+    lastColumn_ = columnIndex;
+    updateSeparatorPosition();
+  }
+  return true;
+}
+
+/* Updates the last separator position, if present */
+void BytecodeEmitter::updateSeparatorPosition() {
+  if (!inPrologue() && lastSeparatorOffet_ == code().length()) {
+    lastSeparatorLine_ = currentLine_;
+    lastSeparatorColumn_ = lastColumn_;
+  }
 }
 
 Maybe<uint32_t> BytecodeEmitter::getOffsetForLoop(ParseNode* nextpn) {
   if (!nextpn) {
     return Nothing();
   }
 
   // Try to give the JSOP_LOOPHEAD and JSOP_LOOPENTRY the same line number as
@@ -623,17 +621,17 @@ bool BytecodeEmitter::emitUint16Operand(
   return true;
 }
 
 bool BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) {
   ptrdiff_t off;
   if (!emitN(op, 4, &off)) {
     return false;
   }
-  SET_UINT32(bytecodeSection().code(off), operand);
+  SET_UINT32(code(off), operand);
   return true;
 }
 
 namespace {
 
 class NonLocalExitControl {
  public:
   enum Kind {
@@ -660,28 +658,27 @@ class NonLocalExitControl {
 
   NonLocalExitControl(const NonLocalExitControl&) = delete;
 
   MOZ_MUST_USE bool leaveScope(EmitterScope* scope);
 
  public:
   NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
       : bce_(bce),
-        savedScopeNoteIndex_(bce->bytecodeSection().scopeNoteList().length()),
-        savedDepth_(bce->bytecodeSection().stackDepth()),
+        savedScopeNoteIndex_(bce->scopeNoteList.length()),
+        savedDepth_(bce->stackDepth),
         openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
         kind_(kind) {}
 
   ~NonLocalExitControl() {
-    for (uint32_t n = savedScopeNoteIndex_;
-         n < bce_->bytecodeSection().scopeNoteList().length(); n++) {
-      bce_->bytecodeSection().scopeNoteList().recordEnd(
-          n, bce_->bytecodeSection().offset());
-    }
-    bce_->bytecodeSection().setStackDepth(savedDepth_);
+    for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length();
+         n++) {
+      bce_->scopeNoteList.recordEnd(n, bce_->offset());
+    }
+    bce_->stackDepth = savedDepth_;
   }
 
   MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
 
   MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
     return prepareForNonLocalJump(nullptr);
   }
 };
@@ -693,22 +690,21 @@ bool NonLocalExitControl::leaveScope(Emi
 
   // As we pop each scope due to the non-local jump, emit notes that
   // record the extent of the enclosing scope. These notes will have
   // their ends recorded in ~NonLocalExitControl().
   uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
   if (es->enclosingInFrame()) {
     enclosingScopeIndex = es->enclosingInFrame()->index();
   }
-  if (!bce_->bytecodeSection().scopeNoteList().append(
-          enclosingScopeIndex, bce_->bytecodeSection().offset(),
-          openScopeNoteIndex_)) {
-    return false;
-  }
-  openScopeNoteIndex_ = bce_->bytecodeSection().scopeNoteList().length() - 1;
+  if (!bce_->scopeNoteList.append(enclosingScopeIndex, bce_->offset(),
+                                  openScopeNoteIndex_)) {
+    return false;
+  }
+  openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
 
   return true;
 }
 
 /*
  * Emit additional bytecode(s) for non-local jumps.
  */
 bool NonLocalExitControl::prepareForNonLocalJump(NestableControl* target) {
@@ -837,17 +833,17 @@ bool NonLocalExitControl::prepareForNonL
       target ? target->emitterScope() : bce_->varEmitterScope;
   for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
     if (!leaveScope(es)) {
       return false;
     }
   }
 
   // Close FOR_OF_ITERCLOSE trynotes.
-  ptrdiff_t end = bce_->bytecodeSection().offset();
+  ptrdiff_t end = bce_->offset();
   for (ptrdiff_t start : forOfIterCloseScopeStarts) {
     if (!bce_->addTryNote(JSTRY_FOR_OF_ITERCLOSE, 0, start, end)) {
       return false;
     }
   }
 
   return true;
 }
@@ -883,38 +879,38 @@ bool BytecodeEmitter::emitIndex32(JSOp o
   const size_t len = 1 + UINT32_INDEX_LEN;
   MOZ_ASSERT(len == size_t(CodeSpec[op].length));
 
   ptrdiff_t offset;
   if (!emitCheck(op, len, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = jsbytecode(op);
   SET_UINT32_INDEX(code, index);
-  bytecodeSection().updateDepth(offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index) {
   MOZ_ASSERT(checkStrictOrSloppy(op));
 
   const size_t len = CodeSpec[op].length;
   MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN);
 
   ptrdiff_t offset;
   if (!emitCheck(op, len, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = jsbytecode(op);
   SET_UINT32_INDEX(code, index);
-  bytecodeSection().updateDepth(offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::emitAtomOp(JSAtom* atom, JSOp op) {
   MOZ_ASSERT(atom);
 
   // .generator lookups should be emitted as JSOP_GETALIASEDVAR instead of
   // JSOP_GETNAME etc, to bypass |with| objects on the scope chain.
@@ -939,77 +935,77 @@ bool BytecodeEmitter::emitAtomOp(JSAtom*
 bool BytecodeEmitter::emitAtomOp(uint32_t atomIndex, JSOp op) {
   MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
 
   return emitIndexOp(op, atomIndex);
 }
 
 bool BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op) {
   MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
-  MOZ_ASSERT(index < perScriptData().scopeList().length());
+  MOZ_ASSERT(index < scopeList.length());
   return emitIndex32(op, index);
 }
 
 bool BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op) {
   MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
-  MOZ_ASSERT(index < perScriptData().objectList().length);
+  MOZ_ASSERT(index < objectList.length);
   return emitIndex32(op, index);
 }
 
 bool BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op) {
-  return emitInternedObjectOp(perScriptData().objectList().add(objbox), op);
+  return emitInternedObjectOp(objectList.add(objbox), op);
 }
 
 bool BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2,
                                        JSOp op) {
-  uint32_t index = perScriptData().objectList().add(objbox1);
-  perScriptData().objectList().add(objbox2);
+  uint32_t index = objectList.add(objbox1);
+  objectList.add(objbox2);
   return emitInternedObjectOp(index, op);
 }
 
 bool BytecodeEmitter::emitRegExp(uint32_t index) {
   return emitIndex32(JSOP_REGEXP, index);
 }
 
 bool BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) {
   MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
   MOZ_ASSERT(IsLocalOp(op));
 
   ptrdiff_t off;
   if (!emitN(op, LOCALNO_LEN, &off)) {
     return false;
   }
 
-  SET_LOCALNO(bytecodeSection().code(off), slot);
+  SET_LOCALNO(code(off), slot);
   return true;
 }
 
 bool BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot) {
   MOZ_ASSERT(IsArgOp(op));
   ptrdiff_t off;
   if (!emitN(op, ARGNO_LEN, &off)) {
     return false;
   }
 
-  SET_ARGNO(bytecodeSection().code(off), slot);
+  SET_ARGNO(code(off), slot);
   return true;
 }
 
 bool BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) {
   MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD);
 
   unsigned n = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
   MOZ_ASSERT(int(n) + 1 /* op */ == CodeSpec[op].length);
 
   ptrdiff_t off;
   if (!emitN(op, n, &off)) {
     return false;
   }
 
-  jsbytecode* pc = bytecodeSection().code(off);
+  jsbytecode* pc = code(off);
   SET_ENVCOORD_HOPS(pc, ec.hops());
   pc += ENVCOORD_HOPS_LEN;
   SET_ENVCOORD_SLOT(pc, ec.slot());
   pc += ENVCOORD_SLOT_LEN;
   return true;
 }
 
 JSOp BytecodeEmitter::strictifySetNameOp(JSOp op) {
@@ -1679,23 +1675,23 @@ bool BytecodeEmitter::reportExtraWarning
 
 bool BytecodeEmitter::emitNewInit() {
   const size_t len = 1 + UINT32_INDEX_LEN;
   ptrdiff_t offset;
   if (!emitCheck(JSOP_NEWINIT, len, &offset)) {
     return false;
   }
 
-  jsbytecode* code = bytecodeSection().code(offset);
+  jsbytecode* code = this->code(offset);
   code[0] = JSOP_NEWINIT;
   code[1] = 0;
   code[2] = 0;
   code[3] = 0;
   code[4] = 0;
-  bytecodeSection().updateDepth(offset);
+  updateDepth(offset);
   return true;
 }
 
 bool BytecodeEmitter::iteratorResultShape(unsigned* shape) {
   // No need to do any guessing for the object kind, since we know exactly how
   // many properties we plan to have.
   gc::AllocKind kind = gc::GetGCObjectKind(2);
   RootedPlainObject obj(
@@ -1715,17 +1711,17 @@ bool BytecodeEmitter::iteratorResultShap
     return false;
   }
 
   ObjectBox* objbox = parser->newObjectBox(obj);
   if (!objbox) {
     return false;
   }
 
-  *shape = perScriptData().objectList().add(objbox);
+  *shape = objectList.add(objbox);
 
   return true;
 }
 
 bool BytecodeEmitter::emitPrepareIteratorResult() {
   unsigned shape;
   if (!iteratorResultShape(&shape)) {
     return false;
@@ -2046,23 +2042,23 @@ bool BytecodeEmitter::emitNumberOp(doubl
       if (!emitUint16Operand(JSOP_UINT16, u)) {
         return false;
       }
     } else if (u < JS_BIT(24)) {
       ptrdiff_t off;
       if (!emitN(JSOP_UINT24, 3, &off)) {
         return false;
       }
-      SET_UINT24(bytecodeSection().code(off), u);
+      SET_UINT24(code(off), u);
     } else {
       ptrdiff_t off;
       if (!emitN(JSOP_INT32, 4, &off)) {
         return false;
       }
-      SET_INT32(bytecodeSection().code(off), ival);
+      SET_INT32(code(off), ival);
     }
     return true;
   }
 
   return emitDouble(dval);
 }
 
 /*
@@ -2253,23 +2249,23 @@ bool BytecodeEmitter::allocateResumeInde
       MaxResumeIndex < uint32_t(AbstractGeneratorObject::RESUME_INDEX_CLOSING),
       "resumeIndex should not include magic AbstractGeneratorObject "
       "resumeIndex values");
   static_assert(
       MaxResumeIndex <= INT32_MAX / sizeof(uintptr_t),
       "resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
       "on this when loading resume entries from BaselineScript");
 
-  *resumeIndex = bytecodeSection().resumeOffsetList().length();
+  *resumeIndex = resumeOffsetList.length();
   if (*resumeIndex > MaxResumeIndex) {
     reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES);
     return false;
   }
 
-  return bytecodeSection().resumeOffsetList().append(offset);
+  return resumeOffsetList.append(offset);
 }
 
 bool BytecodeEmitter::allocateResumeIndexRange(mozilla::Span<ptrdiff_t> offsets,
                                                uint32_t* firstResumeIndex) {
   *firstResumeIndex = 0;
 
   for (size_t i = 0, len = offsets.size(); i < len; i++) {
     uint32_t resumeIndex;
@@ -2292,25 +2288,25 @@ bool BytecodeEmitter::emitYieldOp(JSOp o
   MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
 
   ptrdiff_t off;
   if (!emitN(op, 3, &off)) {
     return false;
   }
 
   if (op == JSOP_INITIALYIELD || op == JSOP_YIELD) {
-    bytecodeSection().addNumYields();
+    numYields++;
   }
 
   uint32_t resumeIndex;
-  if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex)) {
-    return false;
-  }
-
-  SET_RESUMEINDEX(bytecodeSection().code(off), resumeIndex);
+  if (!allocateResumeIndex(offset(), &resumeIndex)) {
+    return false;
+  }
+
+  SET_RESUMEINDEX(code(off), resumeIndex);
 
   return emit1(JSOP_DEBUGAFTERYIELD);
 }
 
 bool BytecodeEmitter::emitSetThis(BinaryNode* setThisNode) {
   // ParseNodeKind::SetThis is used to update |this| after a super() call
   // in a derived class constructor.
 
@@ -2568,17 +2564,17 @@ bool BytecodeEmitter::emitDestructuringL
   // setting or initializing value.  Getting reference doesn't recur.
   if (target->isKind(ParseNodeKind::Name) ||
       target->isKind(ParseNodeKind::ArrayExpr) ||
       target->isKind(ParseNodeKind::ObjectExpr)) {
     return true;
   }
 
 #ifdef DEBUG
-  int depth = bytecodeSection().stackDepth();
+  int depth = stackDepth;
 #endif
 
   switch (target->getKind()) {
     case ParseNodeKind::DotExpr: {
       PropertyAccess* prop = &target->as<PropertyAccess>();
       bool isSuper = prop->isSuper();
       PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
                         isSuper ? PropOpEmitter::ObjKind::Super
@@ -2646,17 +2642,17 @@ bool BytecodeEmitter::emitDestructuringL
           "rejects function calls as assignment "
           "targets in destructuring assignments");
       break;
 
     default:
       MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
   }
 
-  MOZ_ASSERT(bytecodeSection().stackDepth() == depth + int(*emitted));
+  MOZ_ASSERT(stackDepth == depth + int(*emitted));
 
   return true;
 }
 
 bool BytecodeEmitter::emitSetOrInitializeDestructuring(
     ParseNode* target, DestructuringFlavor flav) {
   // Now emit the lvalue opcode sequence. If the lvalue is a nested
   // destructuring initialiser-form, call ourselves to handle it, then pop
@@ -2809,17 +2805,17 @@ bool BytecodeEmitter::emitIteratorNext(
     const Maybe<uint32_t>& callSourceCoordOffset,
     IteratorKind iterKind /* = IteratorKind::Sync */,
     bool allowSelfHosted /* = false */) {
   MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
              ".next() iteration is prohibited in self-hosted code because it "
              "can run user-modifiable iteration code");
 
   //                [stack] ... NEXT ITER
-  MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
+  MOZ_ASSERT(this->stackDepth >= 2);
 
   if (!emitCall(JSOP_CALL, 0, callSourceCoordOffset)) {
     //              [stack] ... RESULT
     return false;
   }
 
   if (iterKind == IteratorKind::Async) {
     if (!emitAwaitInInnermostScope()) {
@@ -2832,17 +2828,17 @@ bool BytecodeEmitter::emitIteratorNext(
     //              [stack] ... RESULT
     return false;
   }
   return true;
 }
 
 bool BytecodeEmitter::emitPushNotUndefinedOrNull() {
   //                [stack] V
-  MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
+  MOZ_ASSERT(this->stackDepth > 0);
 
   if (!emit1(JSOP_DUP)) {
     //              [stack] V V
     return false;
   }
   if (!emit1(JSOP_UNDEFINED)) {
     //              [stack] V V UNDEFINED
     return false;
@@ -3080,32 +3076,32 @@ bool BytecodeEmitter::emitIteratorCloseI
 
   return emit1(JSOP_POP);
   //                [stack] ...
 }
 
 template <typename InnerEmitter>
 bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth,
                                                    InnerEmitter emitter) {
-  MOZ_ASSERT(bytecodeSection().stackDepth() >= iterDepth);
+  MOZ_ASSERT(this->stackDepth >= iterDepth);
 
   // Pad a nop at the beginning of the bytecode covered by the trynote so
   // that when unwinding environments, we may unwind to the scope
   // corresponding to the pc *before* the start, in case the first bytecode
   // emitted by |emitter| is the start of an inner scope. See comment above
   // UnwindEnvironmentToTryPc.
   if (!emit1(JSOP_TRY_DESTRUCTURING)) {
     return false;
   }
 
-  ptrdiff_t start = bytecodeSection().offset();
+  ptrdiff_t start = offset();
   if (!emitter(this)) {
     return false;
   }
-  ptrdiff_t end = bytecodeSection().offset();
+  ptrdiff_t end = offset();
   if (start != end) {
     return addTryNote(JSTRY_DESTRUCTURING, iterDepth, start, end);
   }
   return true;
 }
 
 bool BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern) {
   //                [stack] VALUE
@@ -3201,17 +3197,17 @@ bool BytecodeEmitter::emitInitializer(Pa
   }
 
   return true;
 }
 
 bool BytecodeEmitter::emitDestructuringOpsArray(ListNode* pattern,
                                                 DestructuringFlavor flav) {
   MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr));
-  MOZ_ASSERT(bytecodeSection().stackDepth() != 0);
+  MOZ_ASSERT(this->stackDepth != 0);
 
   // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
   //
   // Lines that are annotated "covered by trynote" mean that upon throwing
   // an exception, IteratorClose is called on iter only if done is false.
   //
   //   let x, y;
   //   let a, b, c, d;
@@ -3325,17 +3321,17 @@ bool BytecodeEmitter::emitDestructuringO
   if (!emit1(JSOP_FALSE)) {
     //              [stack] ... OBJ NEXT ITER FALSE
     return false;
   }
 
   // JSTRY_DESTRUCTURING expects the iterator and the done value
   // to be the second to top and the top of the stack, respectively.
   // IteratorClose is called upon exception only if done is false.
-  int32_t tryNoteDepth = bytecodeSection().stackDepth();
+  int32_t tryNoteDepth = stackDepth;
 
   for (ParseNode* member : pattern->contents()) {
     bool isFirst = member == pattern->head();
     DebugOnly<bool> hasNext = !!member->pn_next;
 
     size_t emitted = 0;
 
     // Spec requires LHS reference to be evaluated first.
@@ -3634,17 +3630,17 @@ bool BytecodeEmitter::emitComputedProper
   return emitTree(computedPropName->kid()) && emit1(JSOP_TOID);
 }
 
 bool BytecodeEmitter::emitDestructuringOpsObject(ListNode* pattern,
                                                  DestructuringFlavor flav) {
   MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
 
   //                [stack] ... RHS
-  MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
+  MOZ_ASSERT(this->stackDepth > 0);
 
   if (!emit1(JSOP_CHECKOBJCOERCIBLE)) {
     //              [stack] ... RHS
     return false;
   }
 
   bool needsRestPropertyExcludedSet =
       pattern->count() > 1 && pattern->last()->isKind(ParseNodeKind::Spread);
@@ -3814,17 +3810,17 @@ bool BytecodeEmitter::emitDestructuringO
 
   return true;
 }
 
 bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode* pattern) {
   MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
   MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
 
-  ptrdiff_t offset = bytecodeSection().offset();
+  ptrdiff_t offset = this->offset();
   if (!emitNewInit()) {
     return false;
   }
 
   // Try to construct the shape of the object as we go, so we can emit a
   // JSOP_NEWOBJECT with the final shape instead.
   // In the case of computed property names and indices, we cannot fix the
   // shape at bytecode compile time. When the shape cannot be determined,
@@ -4689,21 +4685,21 @@ MOZ_MUST_USE bool BytecodeEmitter::emitG
     return false;
   }
 
   if (!emitJump(JSOP_GOSUB, jump)) {
     return false;
   }
 
   uint32_t resumeIndex;
-  if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex)) {
-    return false;
-  }
-
-  SET_RESUMEINDEX(bytecodeSection().code(off), resumeIndex);
+  if (!allocateResumeIndex(offset(), &resumeIndex)) {
+    return false;
+  }
+
+  SET_RESUMEINDEX(code(off), resumeIndex);
   return true;
 }
 
 bool BytecodeEmitter::emitIf(TernaryNode* ifNode) {
   IfEmitter ifThenElse(this);
 
   if (!ifThenElse.emitIf(Some(ifNode->kid1()->pn_pos.begin))) {
     return false;
@@ -4898,17 +4894,17 @@ bool BytecodeEmitter::emitWith(BinaryNod
   if (!emitTree(withNode->right())) {
     return false;
   }
 
   return emitterScope.leave(this);
 }
 
 bool BytecodeEmitter::emitCopyDataProperties(CopyOption option) {
-  DebugOnly<int32_t> depth = bytecodeSection().stackDepth();
+  DebugOnly<int32_t> depth = this->stackDepth;
 
   uint32_t argc;
   if (option == CopyOption::Filtered) {
     MOZ_ASSERT(depth > 2);
     //              [stack] TARGET SOURCE SET
     argc = 3;
 
     if (!emitAtomOp(cx->names().CopyDataProperties, JSOP_GETINTRINSIC)) {
@@ -4953,25 +4949,25 @@ bool BytecodeEmitter::emitCopyDataProper
     return false;
   }
 
   if (!emit1(JSOP_POP)) {
     //              [stack]
     return false;
   }
 
-  MOZ_ASSERT(depth - int(argc) == bytecodeSection().stackDepth());
+  MOZ_ASSERT(depth - int(argc) == this->stackDepth);
   return true;
 }
 
 bool BytecodeEmitter::emitBigIntOp(BigInt* bigint) {
-  if (!perScriptData().numberList().append(BigIntValue(bigint))) {
-    return false;
-  }
-  return emitIndex32(JSOP_BIGINT, perScriptData().numberList().length() - 1);
+  if (!numberList.append(BigIntValue(bigint))) {
+    return false;
+  }
+  return emitIndex32(JSOP_BIGINT, numberList.length() - 1);
 }
 
 bool BytecodeEmitter::emitIterator() {
   // Convert iterable to iterator.
   if (!emit1(JSOP_DUP)) {
     //              [stack] OBJ OBJ
     return false;
   }
@@ -5144,34 +5140,34 @@ bool BytecodeEmitter::emitSpread(bool al
     //              [stack] NEXT ITER ARR I
     return false;
   }
 
   // When we enter the goto above, we have NEXT ITER ARR I on the stack. But
   // when we reach this point on the loop backedge (if spreading produces at
   // least one value), we've additionally pushed a RESULT iteration value.
   // Increment manually to reflect this.
-  bytecodeSection().setStackDepth(bytecodeSection().stackDepth() + 1);
+  this->stackDepth++;
 
   {
 #ifdef DEBUG
-    auto loopDepth = bytecodeSection().stackDepth();
+    auto loopDepth = this->stackDepth;
 #endif
 
     // Emit code to assign result.value to the iteration variable.
     if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
       //            [stack] NEXT ITER ARR I VALUE
       return false;
     }
     if (!emit1(JSOP_INITELEM_INC)) {
       //            [stack] NEXT ITER ARR (I+1)
       return false;
     }
 
-    MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth - 1);
+    MOZ_ASSERT(this->stackDepth == loopDepth - 1);
 
     // Spread operations can't contain |continue|, so don't bother setting loop
     // and enclosing "update" offsets, as we do with for-loops.
 
     // COME FROM the beginning of the loop to here.
     if (!loopInfo.emitLoopEntry(this, Nothing())) {
       //            [stack] NEXT ITER ARR I
       return false;
@@ -5198,31 +5194,31 @@ bool BytecodeEmitter::emitSpread(bool al
       return false;
     }
 
     if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ)) {
       //            [stack] NEXT ITER ARR I RESULT
       return false;
     }
 
-    MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth);
+    MOZ_ASSERT(this->stackDepth == loopDepth);
   }
 
   // Let Ion know where the closing jump of this loop is.
   if (!setSrcNoteOffset(noteIndex, SrcNote::ForOf::BackJumpOffset,
                         loopInfo.loopEndOffsetFromEntryJump())) {
     return false;
   }
 
   // No breaks or continues should occur in spreads.
   MOZ_ASSERT(loopInfo.breaks.offset == -1);
   MOZ_ASSERT(loopInfo.continues.offset == -1);
 
-  if (!addTryNote(JSTRY_FOR_OF, bytecodeSection().stackDepth(),
-                  loopInfo.headOffset(), loopInfo.breakTargetOffset())) {
+  if (!addTryNote(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
+                  loopInfo.breakTargetOffset())) {
     return false;
   }
 
   if (!emit2(JSOP_PICK, 4)) {
     //              [stack] ITER ARR FINAL_INDEX RESULT NEXT
     return false;
   }
   if (!emit2(JSOP_PICK, 4)) {
@@ -5233,17 +5229,17 @@ bool BytecodeEmitter::emitSpread(bool al
   return emitPopN(3);
   //                [stack] ARR FINAL_INDEX
 }
 
 bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
   MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
              forHead->isKind(ParseNodeKind::ForOf));
 
-  MOZ_ASSERT(bytecodeSection().stackDepth() >= 1,
+  MOZ_ASSERT(this->stackDepth >= 1,
              "must have a per-iteration value for initializing");
 
   ParseNode* target = forHead->kid1();
   MOZ_ASSERT(!forHead->kid2());
 
   // If the for-in/of loop didn't have a variable declaration, per-loop
   // initialization is just assigning the iteration value to a target
   // expression.
@@ -5281,24 +5277,24 @@ bool BytecodeEmitter::emitInitializeForI
     if (!noe.prepareForRhs()) {
       return false;
     }
     if (noe.emittedBindOp()) {
       // Per-iteration initialization in for-in/of loops computes the
       // iteration value *before* initializing.  Thus the initializing
       // value may be buried under a bind-specific value on the stack.
       // Swap it to the top of the stack.
-      MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
+      MOZ_ASSERT(stackDepth >= 2);
       if (!emit1(JSOP_SWAP)) {
         return false;
       }
     } else {
       // In cases of emitting a frame slot or environment slot,
       // nothing needs be done.
-      MOZ_ASSERT(bytecodeSection().stackDepth() >= 1);
+      MOZ_ASSERT(stackDepth >= 1);
     }
     if (!noe.emitAssignment()) {
       return false;
     }
 
     // The caller handles removing the iteration value from the stack.
     return true;
   }
@@ -5966,17 +5962,17 @@ bool BytecodeEmitter::emitReturn(UnaryNo
    * We can't simply transfer control flow to our caller in that case,
    * because we must gosub to those finally clauses from inner to outer,
    * with the correct stack pointer (i.e., after popping any with,
    * for/in, etc., slots nested inside the finally's try).
    *
    * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
    * extra JSOP_RETRVAL after the fixups.
    */
-  ptrdiff_t top = bytecodeSection().offset();
+  ptrdiff_t top = offset();
 
   bool needsFinalYield =
       sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
   bool isDerivedClassConstructor =
       sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
 
   if (!emit1((needsFinalYield || isDerivedClassConstructor) ? JSOP_SETRVAL
                                                             : JSOP_RETURN)) {
@@ -6027,23 +6023,22 @@ bool BytecodeEmitter::emitReturn(UnaryNo
 
     if (!emitGetNameAtLocation(cx->names().dotGenerator, loc)) {
       return false;
     }
     if (!emitYieldOp(JSOP_FINALYIELDRVAL)) {
       return false;
     }
   } else if (isDerivedClassConstructor) {
-    MOZ_ASSERT(bytecodeSection().code()[top] == JSOP_SETRVAL);
+    MOZ_ASSERT(code()[top] == JSOP_SETRVAL);
     if (!emit1(JSOP_RETRVAL)) {
       return false;
     }
-  } else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) !=
-             bytecodeSection().offset()) {
-    bytecodeSection().code()[top] = JSOP_SETRVAL;
+  } else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != offset()) {
+    code()[top] = JSOP_SETRVAL;
     if (!emit1(JSOP_RETRVAL)) {
       return false;
     }
   }
 
   return true;
 }
 
@@ -6213,17 +6208,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
   // Step 6.
   // Initial send value is undefined.
   if (!emit1(JSOP_UNDEFINED)) {
     //              [stack] NEXT ITER RECEIVED
     return false;
   }
 
   int32_t savedDepthTemp;
-  int32_t startDepth = bytecodeSection().stackDepth();
+  int32_t startDepth = stackDepth;
   MOZ_ASSERT(startDepth >= 3);
 
   TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
                       TryEmitter::ControlKind::NonSyntactic);
   if (!tryCatch.emitJumpOverCatchAndFinally()) {
     //              [stack] NEXT ITER RESULT
     return false;
   }
@@ -6245,17 +6240,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
     }
   }
 
   if (!tryCatch.emitTry()) {
     //              [stack] NEXT ITER RESULT
     return false;
   }
 
-  MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
+  MOZ_ASSERT(this->stackDepth == startDepth);
 
   // Step 7.a.vi.
   // Step 7.b.ii.7.
   // Step 7.c.ix.
   //   25.5.3.7 AsyncGeneratorYield, step 5.
   if (iterKind == IteratorKind::Async) {
     if (!emitAwaitInInnermostScope()) {
       //            [stack] NEXT ITER RESULT
@@ -6278,17 +6273,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
     return false;
   }
 
   if (!tryCatch.emitCatch()) {
     //              [stack] NEXT ITER RESULT
     return false;
   }
 
-  MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
+  MOZ_ASSERT(stackDepth == startDepth);
 
   if (!emit1(JSOP_EXCEPTION)) {
     //              [stack] NEXT ITER RESULT EXCEPTION
     return false;
   }
   if (!emitDupAt(2)) {
     //              [stack] NEXT ITER RESULT EXCEPTION ITER
     return false;
@@ -6297,17 +6292,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
     //              [stack] NEXT ITER RESULT EXCEPTION ITER ITER
     return false;
   }
   if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP)) {
     //              [stack] NEXT ITER RESULT EXCEPTION ITER THROW
     return false;
   }
 
-  savedDepthTemp = bytecodeSection().stackDepth();
+  savedDepthTemp = stackDepth;
   InternalIfEmitter ifThrowMethodIsNotDefined(this);
   if (!emitPushNotUndefinedOrNull()) {
     //              [stack] NEXT ITER RESULT EXCEPTION ITER THROW
     //                    NOT-UNDEF-OR-NULL
     return false;
   }
 
   if (!ifThrowMethodIsNotDefined.emitThenElse()) {
@@ -6348,28 +6343,28 @@ bool BytecodeEmitter::emitYieldStar(Pars
   if (!emit1(JSOP_SWAP)) {
     //              [stack] NEXT ITER RESULT OLDRESULT
     return false;
   }
   if (!emit1(JSOP_POP)) {
     //              [stack] NEXT ITER RESULT
     return false;
   }
-  MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
+  MOZ_ASSERT(this->stackDepth == startDepth);
 
   JumpList checkResult;
   // Note that there is no GOSUB to the finally block here. If the iterator has
   // a "throw" method, it does not perform IteratorClose.
   if (!emitJump(JSOP_GOTO, &checkResult)) {
     //              [stack] NEXT ITER RESULT
     //              [stack] # goto checkResult
     return false;
   }
 
-  bytecodeSection().setStackDepth(savedDepthTemp);
+  stackDepth = savedDepthTemp;
   if (!ifThrowMethodIsNotDefined.emitElse()) {
     //              [stack] NEXT ITER RESULT EXCEPTION ITER THROW
     return false;
   }
 
   if (!emit1(JSOP_POP)) {
     //              [stack] NEXT ITER RESULT EXCEPTION ITER
     return false;
@@ -6384,22 +6379,22 @@ bool BytecodeEmitter::emitYieldStar(Pars
   }
   // Steps 7.b.iii.5-6.
   if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) {
     //              [stack] NEXT ITER RESULT EXCEPTION
     //              [stack] # throw
     return false;
   }
 
-  bytecodeSection().setStackDepth(savedDepthTemp);
+  stackDepth = savedDepthTemp;
   if (!ifThrowMethodIsNotDefined.emitEnd()) {
     return false;
   }
 
-  bytecodeSection().setStackDepth(startDepth);
+  stackDepth = startDepth;
   if (!tryCatch.emitFinally()) {
     return false;
   }
 
   // Step 7.c.i.
   //
   // Call iterator.return() for receiving a "forced return" completion from
   // the generator.
@@ -6516,17 +6511,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
       //            [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
       return false;
     }
   }
   if (!emit1(JSOP_SETRVAL)) {
     //              [stack] NEXT ITER OLDRESULT FTYPE FVALUE
     return false;
   }
-  savedDepthTemp = bytecodeSection().stackDepth();
+  savedDepthTemp = this->stackDepth;
   if (!ifReturnDone.emitElse()) {
     //              [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
     return false;
   }
   if (!emit2(JSOP_UNPICK, 3)) {
     //              [stack] NEXT ITER RESULT OLDRESULT FTYPE FVALUE
     return false;
   }
@@ -6538,17 +6533,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
     // goto tryStart;
     JumpList beq;
     JumpTarget breakTarget{-1};
     if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq, &breakTarget)) {
       //            [stack] NEXT ITER RESULT
       return false;
     }
   }
-  bytecodeSection().setStackDepth(savedDepthTemp);
+  this->stackDepth = savedDepthTemp;
   if (!ifReturnDone.emitEnd()) {
     return false;
   }
 
   if (!ifReturnMethodIsDefined.emitElse()) {
     //              [stack] NEXT ITER RESULT FTYPE FVALUE ITER RET
     return false;
   }
@@ -6613,17 +6608,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
     }
   }
 
   // Step 7.a.iii.
   if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
     //              [stack] NEXT ITER RESULT
     return false;
   }
-  MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
+  MOZ_ASSERT(this->stackDepth == startDepth);
 
   // Steps 7.a.iv-v.
   // Steps 7.b.ii.5-6.
   if (!emitJumpTargetAndPatch(checkResult)) {
     //              [stack] NEXT ITER RESULT
     //              [stack] # checkResult:
     return false;
   }
@@ -6658,17 +6653,17 @@ bool BytecodeEmitter::emitYieldStar(Pars
     //              [stack] RESULT
     return false;
   }
   if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
     //              [stack] VALUE
     return false;
   }
 
-  MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth - 2);
+  MOZ_ASSERT(this->stackDepth == startDepth - 2);
 
   return true;
 }
 
 bool BytecodeEmitter::emitStatementList(ListNode* stmtList) {
   for (ParseNode* stmt : stmtList->contents()) {
     if (!emitTree(stmt)) {
       return false;
@@ -6707,17 +6702,17 @@ bool BytecodeEmitter::emitExpressionStat
     /*
      * Don't eliminate apparently useless expressions if they are labeled
      * expression statements. The startOffset() test catches the case
      * where we are nesting in emitTree for a labeled compound statement.
      */
     if (innermostNestableControl &&
         innermostNestableControl->is<LabelControl>() &&
         innermostNestableControl->as<LabelControl>().startOffset() >=
-            bytecodeSection().offset()) {
+            offset()) {
       useful = true;
     }
   }
 
   if (useful) {
     ValueUsage valueUsage =
         wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
     ExpressionStatementEmitter ese(this, valueUsage);
@@ -8182,18 +8177,18 @@ bool BytecodeEmitter::replaceNewInitWith
   if (!objbox) {
     return false;
   }
 
   static_assert(
       JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
       "newinit and newobject must have equal length to edit in-place");
 
-  uint32_t index = perScriptData().objectList().add(objbox);
-  jsbytecode* code = bytecodeSection().code(offset);
+  uint32_t index = objectList.add(objbox);
+  jsbytecode* code = this->code(offset);
 
   MOZ_ASSERT(code[0] == JSOP_NEWINIT);
   code[0] = JSOP_NEWOBJECT;
   SET_UINT32(code, index);
 
   return true;
 }
 
@@ -9233,18 +9228,17 @@ bool BytecodeEmitter::emitTree(
 
     case ParseNodeKind::BigIntExpr:
       if (!emitBigIntOp(pn->as<BigIntLiteral>().box()->value())) {
         return false;
       }
       break;
 
     case ParseNodeKind::RegExpExpr:
-      if (!emitRegExp(perScriptData().objectList().add(
-              pn->as<RegExpLiteral>().objbox()))) {
+      if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox()))) {
         return false;
       }
       break;
 
     case ParseNodeKind::TrueExpr:
       if (!emit1(JSOP_TRUE)) {
         return false;
       }
@@ -9335,35 +9329,33 @@ static bool AllocSrcNote(JSContext* cx, 
 
   *index = notes.length() - 1;
   return true;
 }
 
 bool BytecodeEmitter::addTryNote(JSTryNoteKind kind, uint32_t stackDepth,
                                  size_t start, size_t end) {
   MOZ_ASSERT(!inPrologue());
-  return bytecodeSection().tryNoteList().append(kind, stackDepth, start, end);
+  return tryNoteList.append(kind, stackDepth, start, end);
 }
 
 bool BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) {
-  // Prologue shouldn't have source notes.
-  MOZ_ASSERT(!inPrologue());
-  SrcNotesVector& notes = bytecodeSection().notes();
+  SrcNotesVector& notes = this->notes();
   unsigned index;
   if (!AllocSrcNote(cx, notes, &index)) {
     return false;
   }
 
   /*
    * Compute delta from the last annotated bytecode's offset.  If it's too
    * big to fit in sn, allocate one or more xdelta notes and reset sn.
    */
-  ptrdiff_t offset = bytecodeSection().offset();
-  ptrdiff_t delta = offset - bytecodeSection().lastNoteOffset();
-  bytecodeSection().setLastNoteOffset(offset);
+  ptrdiff_t offset = this->offset();
+  ptrdiff_t delta = offset - lastNoteOffset();
+  lastNoteOffset_ = offset;
   if (delta >= SN_DELTA_LIMIT) {
     do {
       ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK);
       SN_MAKE_XDELTA(&notes[index], xdelta);
       delta -= xdelta;
       if (!AllocSrcNote(cx, notes, &index)) {
         return false;
       }
@@ -9423,17 +9415,17 @@ bool BytecodeEmitter::newSrcNote3(SrcNot
 
 bool BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which,
                                        ptrdiff_t offset) {
   if (!SN_REPRESENTABLE_OFFSET(offset)) {
     reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
     return false;
   }
 
-  SrcNotesVector& notes = bytecodeSection().notes();
+  SrcNotesVector& notes = this->notes();
 
   /* Find the offset numbered which (i.e., skip exactly which offsets). */
   jssrcnote* sn = &notes[index];
   MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
   MOZ_ASSERT((int)which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
   for (sn++; which; sn++, which--) {
     if (*sn & SN_4BYTE_OFFSET_FLAG) {
       sn += 3;
@@ -9461,20 +9453,20 @@ bool BytecodeEmitter::setSrcNoteOffset(u
     *sn++ = (jssrcnote)(offset >> 16);
     *sn++ = (jssrcnote)(offset >> 8);
   }
   *sn = (jssrcnote)offset;
   return true;
 }
 
 void BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes) {
-  unsigned count = bytecodeSection().notes().length();
+  unsigned count = notes_.length();
   // nsrcnotes includes SN_MAKE_TERMINATOR in addition to the srcnotes.
   MOZ_ASSERT(nsrcnotes == count + 1);
-  PodCopy(destination, bytecodeSection().notes().begin(), count);
+  PodCopy(destination, notes_.begin(), count);
   SN_MAKE_TERMINATOR(&destination[count]);
 }
 
 void CGNumberList::finish(mozilla::Span<GCPtrValue> array) {
   MOZ_ASSERT(length() == array.size());
 
   for (unsigned i = 0; i < length(); i++) {
     array[i].init(vector[i]);
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -119,274 +119,62 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
 
   // The JSScript we're ultimately producing.
   Rooted<JSScript*> script;
 
   // The lazy script if mode is LazyFunction, nullptr otherwise.
   Rooted<LazyScript*> lazyScript;
 
  private:
-  // Bytecode and all data directly associated with specific opcode/index inside
-  // bytecode is stored in this class.
-  class BytecodeSection {
-   public:
-    BytecodeSection(JSContext* cx, uint32_t lineNum);
-
-    // ---- Bytecode ----
-
-    BytecodeVector& code() { return code_; }
-    const BytecodeVector& code() const { return code_; }
-
-    jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
-    ptrdiff_t offset() const { return code_.end() - code_.begin(); }
-
-    // ---- Source notes ----
-
-    SrcNotesVector& notes() { return notes_; }
-    const SrcNotesVector& notes() const { return notes_; }
-
-    ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
-    void setLastNoteOffset(ptrdiff_t offset) { lastNoteOffset_ = offset; }
-
-    // ---- Jump ----
-
-    ptrdiff_t lastTargetOffset() const { return lastTarget_.offset; }
-    void setLastTargetOffset(ptrdiff_t offset) { lastTarget_.offset = offset; }
+  BytecodeVector code_;  /* bytecode */
+  SrcNotesVector notes_; /* source notes, see below */
 
-    // Check if the last emitted opcode is a jump target.
-    bool lastOpcodeIsJumpTarget() const {
-      return offset() - lastTarget_.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
-    }
-
-    // JumpTarget should not be part of the emitted statement, as they can be
-    // aliased by multiple statements. If we included the jump target as part of
-    // the statement we might have issues where the enclosing statement might
-    // not contain all the opcodes of the enclosed statements.
-    ptrdiff_t lastNonJumpTargetOffset() const {
-      return lastOpcodeIsJumpTarget() ? lastTarget_.offset : offset();
-    }
-
-    // ---- Stack ----
-
-    int32_t stackDepth() const { return stackDepth_; }
-    void setStackDepth(int32_t depth) { stackDepth_ = depth; }
-
-    uint32_t maxStackDepth() const { return maxStackDepth_; }
-
-    void updateDepth(ptrdiff_t target);
-
-    // ---- Try notes ----
-
-    CGTryNoteList& tryNoteList() { return tryNoteList_; };
-    const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
-
-    // ---- Scope ----
-
-    CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
-    const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
-
-    // ---- Generator ----
+  // Code offset for last source note
+  ptrdiff_t lastNoteOffset_ = 0;
 
-    CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
-    const CGResumeOffsetList& resumeOffsetList() const {
-      return resumeOffsetList_;
-    }
-
-    uint32_t numYields() const { return numYields_; }
-    void addNumYields() { numYields_++; }
-
-    // ---- Line and column ----
-
-    uint32_t currentLine() const { return currentLine_; }
-    uint32_t lastColumn() const { return lastColumn_; }
-    void setCurrentLine(uint32_t line) {
-      currentLine_ = line;
-      lastColumn_ = 0;
-    }
-    void setLastColumn(uint32_t column) { lastColumn_ = column; }
-
-    void updateSeparatorPosition() {
-      lastSeparatorOffet_ = code().length();
-      lastSeparatorLine_ = currentLine_;
-      lastSeparatorColumn_ = lastColumn_;
-    }
-
-    void updateSeparatorPositionIfPresent() {
-      if (lastSeparatorOffet_ == code().length()) {
-        lastSeparatorLine_ = currentLine_;
-        lastSeparatorColumn_ = lastColumn_;
-      }
-    }
-
-    bool isDuplicateLocation() const {
-      return lastSeparatorLine_ == currentLine_ &&
-             lastSeparatorColumn_ == lastColumn_;
-    }
-
-    // ---- JIT ----
-
-    size_t numICEntries() const { return numICEntries_; }
-    void addNumICEntries() { numICEntries_++; }
-    void setNumICEntries(size_t entries) { numICEntries_ = entries; }
-
-    uint16_t typesetCount() const { return typesetCount_; }
-    void addTypesetCount() { typesetCount_++; }
-
-   private:
-    // ---- Bytecode ----
-
-    // Bytecode.
-    BytecodeVector code_;
-
-    // ---- Source notes ----
-
-    // Source notes
-    SrcNotesVector notes_;
-
-    // Code offset for last source note
-    ptrdiff_t lastNoteOffset_ = 0;
-
-    // ---- Jump ----
+  // Line number for srcnotes.
+  //
+  // WARNING: If this becomes out of sync with already-emitted srcnotes,
+  // we can get undefined behavior.
+  uint32_t currentLine_ = 0;
 
-    // Last jump target emitted.
-    JumpTarget lastTarget_ = {-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)};
-
-    // ---- Stack ----
-
-    // Maximum number of expression stack slots so far.
-    uint32_t maxStackDepth_ = 0;
-
-    // Current stack depth in script frame.
-    int32_t stackDepth_ = 0;
-
-    // ---- Try notes ----
-
-    // List of emitted try notes.
-    CGTryNoteList tryNoteList_;
-
-    // ---- Scope ----
-
-    // List of emitted block scope notes.
-    CGScopeNoteList scopeNoteList_;
-
-    // ---- Generator ----
-
-    // Certain ops (yield, await, gosub) have an entry in the script's
-    // resumeOffsets list. This can be used to map from the op's resumeIndex to
-    // the bytecode offset of the next pc. This indirection makes it easy to
-    // resume in the JIT (because BaselineScript stores a resumeIndex => native
-    // code array).
-    CGResumeOffsetList resumeOffsetList_;
-
-    // Number of yield instructions emitted. Does not include JSOP_AWAIT.
-    uint32_t numYields_ = 0;
-
-    // ---- Line and column ----
-
-    // Line number for srcnotes.
-    //
-    // WARNING: If this becomes out of sync with already-emitted srcnotes,
-    // we can get undefined behavior.
-    uint32_t currentLine_;
-
-    // Zero-based column index on currentLine_ of last SRC_COLSPAN-annotated
-    // opcode.
-    //
-    // WARNING: If this becomes out of sync with already-emitted srcnotes,
-    // we can get undefined behavior.
-    uint32_t lastColumn_ = 0;
-
-    // The offset, line and column numbers of the last opcode for the
-    // breakpoint for step execution.
-    uint32_t lastSeparatorOffet_ = 0;
-    uint32_t lastSeparatorLine_ = 0;
-    uint32_t lastSeparatorColumn_ = 0;
-
-    // ---- JIT ----
-
-    // Number of JOF_IC opcodes emitted.
-    size_t numICEntries_ = 0;
+  // Zero-based column index on currentLine of last SRC_COLSPAN-annotated
+  // opcode.
+  //
+  // WARNING: If this becomes out of sync with already-emitted srcnotes,
+  // we can get undefined behavior.
+  uint32_t lastColumn_ = 0;
 
-    // Number of JOF_TYPESET opcodes generated.
-    uint16_t typesetCount_ = 0;
-  };
-
-  BytecodeSection bytecodeSection_;
-
- public:
-  BytecodeSection& bytecodeSection() { return bytecodeSection_; }
-  const BytecodeSection& bytecodeSection() const { return bytecodeSection_; }
-
- private:
-  // Data that is not directly associated with specific opcode/index inside
-  // bytecode, but referred from bytecode is stored in this class.
-  class PerScriptData {
-   public:
-    explicit PerScriptData(JSContext* cx);
-
-    MOZ_MUST_USE bool init(JSContext* cx);
-
-    // ---- Scope ----
-
-    CGScopeList& scopeList() { return scopeList_; }
-    const CGScopeList& scopeList() const { return scopeList_; }
-
-    // ---- Literals ----
-
-    CGNumberList& numberList() { return numberList_; }
-    const CGNumberList& numberList() const { return numberList_; }
+  uint32_t lastSeparatorOffet_ = 0;
+  uint32_t lastSeparatorLine_ = 0;
+  uint32_t lastSeparatorColumn_ = 0;
 
-    CGObjectList& objectList() { return objectList_; }
-    const CGObjectList& objectList() const { return objectList_; }
-
-    PooledMapPtr<AtomIndexMap>& atomIndices() { return atomIndices_; }
-    const PooledMapPtr<AtomIndexMap>& atomIndices() const {
-      return atomIndices_;
-    }
-
-   private:
-    // ---- Scope ----
-
-    // List of emitted scopes.
-    CGScopeList scopeList_;
-
-    // ---- Literals ----
-
-    // List of double and bigint values used by script.
-    CGNumberList numberList_;
-
-    // List of emitted objects.
-    CGObjectList objectList_;
-
-    // Map from atom to index.
-    PooledMapPtr<AtomIndexMap> atomIndices_;
-  };
-
-  PerScriptData perScriptData_;
-
- public:
-  PerScriptData& perScriptData() { return perScriptData_; }
-  const PerScriptData& perScriptData() const { return perScriptData_; }
-
- private:
   // switchToMain sets this to the bytecode offset of the main section.
   mozilla::Maybe<uint32_t> mainOffset_ = {};
 
   /* field info for enclosing class */
   const FieldInitializers fieldInitializers_;
 
  public:
+  // Last jump target emitted.
+  JumpTarget lastTarget = {-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)};
+
   // Private storage for parser wrapper. DO NOT REFERENCE INTERNALLY. May not be
   // initialized. Use |parser| instead.
   mozilla::Maybe<EitherParser> ep_ = {};
   BCEParserHandle* parser = nullptr;
 
+  PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */
   unsigned firstLine = 0; /* first line, for JSScript::initFromEmitter */
 
   uint32_t maxFixedSlots = 0; /* maximum number of fixed frame slots so far */
+  uint32_t maxStackDepth =
+      0; /* maximum number of expression stack slots so far */
+
+  int32_t stackDepth = 0; /* current stack depth in script frame */
 
   uint32_t bodyScopeIndex =
       UINT32_MAX; /* index into scopeList of the body scope */
 
   EmitterScope* varEmitterScope = nullptr;
   NestableControl* innermostNestableControl = nullptr;
   EmitterScope* innermostEmitterScope_ = nullptr;
   TDZCheckCache* innermostTDZCheckCache = nullptr;
@@ -402,16 +190,38 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   EmitterScope* innermostEmitterScope() const {
     MOZ_ASSERT(!unstableEmitterScope);
     return innermostEmitterScopeNoCheck();
   }
   EmitterScope* innermostEmitterScopeNoCheck() const {
     return innermostEmitterScope_;
   }
 
+  CGNumberList numberList;       /* double and bigint values used by script */
+  CGObjectList objectList;       /* list of emitted objects */
+  CGScopeList scopeList;         /* list of emitted scopes */
+  CGTryNoteList tryNoteList;     /* list of emitted try notes */
+  CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
+
+  // Certain ops (yield, await, gosub) have an entry in the script's
+  // resumeOffsets list. This can be used to map from the op's resumeIndex to
+  // the bytecode offset of the next pc. This indirection makes it easy to
+  // resume in the JIT (because BaselineScript stores a resumeIndex => native
+  // code array).
+  CGResumeOffsetList resumeOffsetList;
+
+  // Number of JOF_IC opcodes emitted.
+  size_t numICEntries = 0;
+
+  // Number of yield instructions emitted. Does not include JSOP_AWAIT.
+  uint32_t numYields = 0;
+
+  // Number of JOF_TYPESET opcodes generated.
+  uint16_t typesetCount = 0;
+
   // Script contains singleton initializer JSOP_OBJECT.
   bool hasSingletons = false;
 
   // Script contains finally block.
   bool hasTryFinally = false;
 
   // True while emitting a lambda which is only expected to run once.
   bool emittingRunOnceLambda = false;
@@ -545,36 +355,34 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   }
 
   void setVarEmitterScope(EmitterScope* emitterScope) {
     MOZ_ASSERT(emitterScope);
     MOZ_ASSERT(!varEmitterScope);
     varEmitterScope = emitterScope;
   }
 
-  Scope* outermostScope() const {
-    return perScriptData().scopeList().vector[0];
-  }
+  Scope* outermostScope() const { return scopeList.vector[0]; }
   Scope* innermostScope() const;
   Scope* bodyScope() const {
-    MOZ_ASSERT(bodyScopeIndex < perScriptData().scopeList().length());
-    return perScriptData().scopeList().vector[bodyScopeIndex];
+    MOZ_ASSERT(bodyScopeIndex < scopeList.length());
+    return scopeList.vector[bodyScopeIndex];
   }
 
   MOZ_ALWAYS_INLINE
   MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) {
-    MOZ_ASSERT(perScriptData().atomIndices());
-    AtomIndexMap::AddPtr p = perScriptData().atomIndices()->lookupForAdd(atom);
+    MOZ_ASSERT(atomIndices);
+    AtomIndexMap::AddPtr p = atomIndices->lookupForAdd(atom);
     if (p) {
       *indexp = p->value();
       return true;
     }
 
-    uint32_t index = perScriptData().atomIndices()->count();
-    if (!perScriptData().atomIndices()->add(p, atom, index)) {
+    uint32_t index = atomIndices->count();
+    if (!atomIndices->add(p, atom, index)) {
       ReportOutOfMemory(cx);
       return false;
     }
 
     *indexp = index;
     return true;
   }
 
@@ -587,23 +395,55 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
 
   bool needsImplicitThis();
 
   MOZ_MUST_USE bool emitThisEnvironmentCallee();
   MOZ_MUST_USE bool emitSuperBase();
 
   void tellDebuggerAboutCompiledScript(JSContext* cx);
 
+  BytecodeVector& code() { return code_; }
+  const BytecodeVector& code() const { return code_; }
+
+  jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
+  ptrdiff_t offset() const { return code_.end() - code_.begin(); }
+
   uint32_t mainOffset() const { return *mainOffset_; }
 
   bool inPrologue() const { return mainOffset_.isNothing(); }
 
   void switchToMain() {
     MOZ_ASSERT(inPrologue());
-    mainOffset_.emplace(bytecodeSection().code().length());
+    mainOffset_.emplace(code_.length());
+  }
+
+  SrcNotesVector& notes() {
+    // Prologue shouldn't have source notes.
+    MOZ_ASSERT(!inPrologue());
+    return notes_;
+  }
+  ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
+  unsigned currentLine() const { return currentLine_; }
+
+  void setCurrentLine(uint32_t line) {
+    currentLine_ = line;
+    lastColumn_ = 0;
+  }
+
+  // Check if the last emitted opcode is a jump target.
+  bool lastOpcodeIsJumpTarget() const {
+    return offset() - lastTarget.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
+  }
+
+  // JumpTarget should not be part of the emitted statement, as they can be
+  // aliased by multiple statements. If we included the jump target as part of
+  // the statement we might have issues where the enclosing statement might
+  // not contain all the opcodes of the enclosed statements.
+  ptrdiff_t lastNonJumpTargetOffset() const {
+    return lastOpcodeIsJumpTarget() ? lastTarget.offset : offset();
   }
 
   void setFunctionBodyEndPos(uint32_t pos) {
     functionBodyEndPos = mozilla::Some(pos);
   }
 
   void setScriptStartOffsetIfUnset(uint32_t pos) {
     if (scriptStartOffset.isNothing()) {
@@ -664,20 +504,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   // encompasses the entire source.
   MOZ_MUST_USE bool emitScript(ParseNode* body);
 
   // Emit function code for the tree rooted at body.
   enum class TopLevelFunction { No, Yes };
   MOZ_MUST_USE bool emitFunctionScript(FunctionNode* funNode,
                                        TopLevelFunction isTopLevel);
 
+  void updateDepth(ptrdiff_t target);
   MOZ_MUST_USE bool markStepBreakpoint();
   MOZ_MUST_USE bool markSimpleBreakpoint();
   MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset);
   MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset);
+  void updateSeparatorPosition();
 
   JSOp strictifySetNameOp(JSOp op);
 
   MOZ_MUST_USE bool emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset);
 
   // Emit one bytecode.
   MOZ_MUST_USE bool emit1(JSOp op);
 
--- a/js/src/frontend/CForEmitter.cpp
+++ b/js/src/frontend/CForEmitter.cpp
@@ -70,17 +70,17 @@ bool CForEmitter::emitBody(Cond cond, co
   if (!bce_->newSrcNote(SRC_FOR, &noteIndex_)) {
     return false;
   }
   if (!bce_->emit1(JSOP_NOP)) {
     //              [stack]
     return false;
   }
 
-  biasedTop_ = bce_->bytecodeSection().offset();
+  biasedTop_ = bce_->offset();
 
   if (cond_ == Cond::Present) {
     // Goto the loop condition, which branches back to iterate.
     if (!loopInfo_->emitEntryJump(bce_)) {
       return false;
     }
   }
 
@@ -158,30 +158,30 @@ bool CForEmitter::emitCond(const Maybe<u
     if (!bce_->emit1(JSOP_POP)) {
       //            [stack]
       return false;
     }
 
     // Restore the absolute line number for source note readers.
     if (endPos) {
       uint32_t lineNum = bce_->parser->errorReporter().lineAt(*endPos);
-      if (bce_->bytecodeSection().currentLine() != lineNum) {
+      if (bce_->currentLine() != lineNum) {
         if (!bce_->newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum))) {
           return false;
         }
-        bce_->bytecodeSection().setCurrentLine(lineNum);
+        bce_->setCurrentLine(lineNum);
       }
     }
   }
 
   if (update_ == Update::Present) {
     tdzCache_.reset();
   }
 
-  condOffset_ = bce_->bytecodeSection().offset();
+  condOffset_ = bce_->offset();
 
   if (cond_ == Cond::Present) {
     if (!loopInfo_->emitLoopEntry(bce_, condPos)) {
       //            [stack]
       return false;
     }
   } else if (update_ == Update::Missing) {
     // If there is no condition clause and no update clause, mark
@@ -223,18 +223,17 @@ bool CForEmitter::emitEnd() {
   // The third note offset helps us find the loop-closing jump.
   if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::For::BackJumpOffset,
                               loopInfo_->loopEndOffset() - biasedTop_))
 
   {
     return false;
   }
 
-  if (!bce_->addTryNote(JSTRY_LOOP, bce_->bytecodeSection().stackDepth(),
-                        loopInfo_->headOffset(),
+  if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
                         loopInfo_->breakTargetOffset())) {
     return false;
   }
 
   if (!loopInfo_->patchBreaksAndContinues(bce_)) {
     //              [stack]
     return false;
   }
--- a/js/src/frontend/DoWhileEmitter.cpp
+++ b/js/src/frontend/DoWhileEmitter.cpp
@@ -70,18 +70,17 @@ bool DoWhileEmitter::emitCond() {
 
 bool DoWhileEmitter::emitEnd() {
   MOZ_ASSERT(state_ == State::Cond);
 
   if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFNE)) {
     return false;
   }
 
-  if (!bce_->addTryNote(JSTRY_LOOP, bce_->bytecodeSection().stackDepth(),
-                        loopInfo_->headOffset(),
+  if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
                         loopInfo_->breakTargetOffset())) {
     return false;
   }
 
   // Update the annotations with the update and back edge positions, for
   // IonBuilder.
   if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::CondOffset,
                               loopInfo_->continueTargetOffsetFromLoopHead())) {
--- a/js/src/frontend/EmitterScope.cpp
+++ b/js/src/frontend/EmitterScope.cpp
@@ -337,37 +337,37 @@ NameLocation EmitterScope::searchAndCach
 template <typename ScopeCreator>
 bool EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope) {
   RootedScope enclosing(bce->cx, enclosingScope(bce));
   Scope* scope = createScope(bce->cx, enclosing);
   if (!scope) {
     return false;
   }
   hasEnvironment_ = scope->hasEnvironment();
-  scopeIndex_ = bce->perScriptData().scopeList().length();
-  return bce->perScriptData().scopeList().append(scope);
+  scopeIndex_ = bce->scopeList.length();
+  return bce->scopeList.append(scope);
 }
 
 template <typename ScopeCreator>
 bool EmitterScope::internBodyScope(BytecodeEmitter* bce,
                                    ScopeCreator createScope) {
   MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX,
              "There can be only one body scope");
-  bce->bodyScopeIndex = bce->perScriptData().scopeList().length();
+  bce->bodyScopeIndex = bce->scopeList.length();
   return internScope(bce, createScope);
 }
 
 bool EmitterScope::appendScopeNote(BytecodeEmitter* bce) {
   MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
              "Scope notes are not needed for body-level scopes.");
-  noteIndex_ = bce->bytecodeSection().scopeNoteList().length();
-  return bce->bytecodeSection().scopeNoteList().append(
-      index(), bce->bytecodeSection().offset(),
-      enclosingInFrame() ? enclosingInFrame()->noteIndex()
-                         : ScopeNote::NoScopeNoteIndex);
+  noteIndex_ = bce->scopeNoteList.length();
+  return bce->scopeNoteList.append(index(), bce->offset(),
+                                   enclosingInFrame()
+                                       ? enclosingInFrame()->noteIndex()
+                                       : ScopeNote::NoScopeNoteIndex);
 }
 
 bool EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce,
                                           uint32_t slotStart,
                                           uint32_t slotEnd) const {
   // Lexical bindings throw ReferenceErrors if they are used before
   // initialization. See ES6 8.1.1.1.6.
   //
@@ -1052,28 +1052,27 @@ bool EmitterScope::leave(BytecodeEmitter
 
   // Finish up the scope if we are leaving it in LIFO fashion.
   if (!nonLocal) {
     // Popping scopes due to non-local jumps generate additional scope
     // notes. See NonLocalExitControl::prepareForNonLocalJump.
     if (ScopeKindIsInBody(kind)) {
       // The extra function var scope is never popped once it's pushed,
       // so its scope note extends until the end of any possible code.
-      uint32_t offset = kind == ScopeKind::FunctionBodyVar
-                            ? UINT32_MAX
-                            : bce->bytecodeSection().offset();
-      bce->bytecodeSection().scopeNoteList().recordEnd(noteIndex_, offset);
+      uint32_t offset =
+          kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
+      bce->scopeNoteList.recordEnd(noteIndex_, offset);
     }
   }
 
   return true;
 }
 
 Scope* EmitterScope::scope(const BytecodeEmitter* bce) const {
-  return bce->perScriptData().scopeList().vector[index()];
+  return bce->scopeList.vector[index()];
 }
 
 NameLocation EmitterScope::lookup(BytecodeEmitter* bce, JSAtom* name) {
   if (Maybe<NameLocation> loc = lookupInCache(bce, name)) {
     return *loc;
   }
   return searchAndCache(bce, name);
 }
--- a/js/src/frontend/ExpressionStatementEmitter.cpp
+++ b/js/src/frontend/ExpressionStatementEmitter.cpp
@@ -24,25 +24,25 @@ bool ExpressionStatementEmitter::prepare
 
   if (beginPos) {
     if (!bce_->updateSourceCoordNotes(*beginPos)) {
       return false;
     }
   }
 
 #ifdef DEBUG
-  depth_ = bce_->bytecodeSection().stackDepth();
+  depth_ = bce_->stackDepth;
   state_ = State::Expr;
 #endif
   return true;
 }
 
 bool ExpressionStatementEmitter::emitEnd() {
   MOZ_ASSERT(state_ == State::Expr);
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_ + 1);
+  MOZ_ASSERT(bce_->stackDepth == depth_ + 1);
 
   //                [stack] VAL
 
   JSOp op = valueUsage_ == ValueUsage::WantValue ? JSOP_SETRVAL : JSOP_POP;
   if (!bce_->emit1(op)) {
     //              [stack] # if WantValue
     //              [stack] VAL
     //              [stack] # otherwise
--- a/js/src/frontend/ForInEmitter.cpp
+++ b/js/src/frontend/ForInEmitter.cpp
@@ -89,17 +89,17 @@ bool ForInEmitter::emitInitialize() {
 
     // For uncaptured bindings, put them back in TDZ.
     if (!headLexicalEmitterScope_->deadZoneFrameSlots(bce_)) {
       return false;
     }
   }
 
 #ifdef DEBUG
-  loopDepth_ = bce_->bytecodeSection().stackDepth();
+  loopDepth_ = bce_->stackDepth;
 #endif
   MOZ_ASSERT(loopDepth_ >= 2);
 
   if (!bce_->emit1(JSOP_ITERNEXT)) {
     //              [stack] ITER ITERVAL
     return false;
   }
 
@@ -107,29 +107,29 @@ bool ForInEmitter::emitInitialize() {
   state_ = State::Initialize;
 #endif
   return true;
 }
 
 bool ForInEmitter::emitBody() {
   MOZ_ASSERT(state_ == State::Initialize);
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_,
+  MOZ_ASSERT(bce_->stackDepth == loopDepth_,
              "iterator and iterval must be left on the stack");
 
 #ifdef DEBUG
   state_ = State::Body;
 #endif
   return true;
 }
 
 bool ForInEmitter::emitEnd(const Maybe<uint32_t>& forPos) {
   MOZ_ASSERT(state_ == State::Body);
 
-  loopInfo_->setContinueTarget(bce_->bytecodeSection().offset());
+  loopInfo_->setContinueTarget(bce_->offset());
 
   if (forPos) {
     // Make sure this code is attributed to the "for".
     if (!bce_->updateSourceCoordNotes(*forPos)) {
       return false;
     }
   }
 
@@ -166,19 +166,18 @@ bool ForInEmitter::emitEnd(const Maybe<u
   }
 
   // Pop the enumeration value.
   if (!bce_->emit1(JSOP_POP)) {
     //              [stack] ITER
     return false;
   }
 
-  if (!bce_->addTryNote(JSTRY_FOR_IN, bce_->bytecodeSection().stackDepth(),
-                        loopInfo_->headOffset(),
-                        bce_->bytecodeSection().offset())) {
+  if (!bce_->addTryNote(JSTRY_FOR_IN, bce_->stackDepth, loopInfo_->headOffset(),
+                        bce_->offset())) {
     return false;
   }
 
   if (!bce_->emit1(JSOP_ENDITER)) {
     //              [stack]
     return false;
   }
 
--- a/js/src/frontend/ForOfEmitter.cpp
+++ b/js/src/frontend/ForOfEmitter.cpp
@@ -53,17 +53,17 @@ bool ForOfEmitter::emitInitialize(const 
     }
   } else {
     if (!bce_->emitIterator()) {
       //            [stack] NEXT ITER
       return false;
     }
   }
 
-  int32_t iterDepth = bce_->bytecodeSection().stackDepth();
+  int32_t iterDepth = bce_->stackDepth;
 
   // For-of loops have the iterator next method, the iterator itself, and
   // the result.value on the stack.
   // Push an undefined to balance the stack.
   if (!bce_->emit1(JSOP_UNDEFINED)) {
     //              [stack] NEXT ITER UNDEF
     return false;
   }
@@ -106,17 +106,17 @@ bool ForOfEmitter::emitInitialize(const 
 
     // For uncaptured bindings, put them back in TDZ.
     if (!headLexicalEmitterScope_->deadZoneFrameSlots(bce_)) {
       return false;
     }
   }
 
 #ifdef DEBUG
-  loopDepth_ = bce_->bytecodeSection().stackDepth();
+  loopDepth_ = bce_->stackDepth;
 #endif
 
   // Make sure this code is attributed to the "for".
   if (forPos) {
     if (!bce_->updateSourceCoordNotes(*forPos)) {
       return false;
     }
   }
@@ -190,17 +190,17 @@ bool ForOfEmitter::emitInitialize(const 
   state_ = State::Initialize;
 #endif
   return true;
 }
 
 bool ForOfEmitter::emitBody() {
   MOZ_ASSERT(state_ == State::Initialize);
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_,
+  MOZ_ASSERT(bce_->stackDepth == loopDepth_,
              "the stack must be balanced around the initializing "
              "operation");
 
   // Remove VALUE from the stack to release it.
   if (!bce_->emit1(JSOP_POP)) {
     //              [stack] NEXT ITER
     return false;
   }
@@ -213,24 +213,24 @@ bool ForOfEmitter::emitBody() {
   state_ = State::Body;
 #endif
   return true;
 }
 
 bool ForOfEmitter::emitEnd(const Maybe<uint32_t>& iteratedPos) {
   MOZ_ASSERT(state_ == State::Body);
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_,
+  MOZ_ASSERT(bce_->stackDepth == loopDepth_,
              "the stack must be balanced around the for-of body");
 
   if (!loopInfo_->emitEndCodeNeedingIteratorClose(bce_)) {
     return false;
   }
 
-  loopInfo_->setContinueTarget(bce_->bytecodeSection().offset());
+  loopInfo_->setContinueTarget(bce_->offset());
 
   // We use the iterated value's position to attribute JSOP_LOOPENTRY,
   // which corresponds to the iteration protocol.
   // This is a bit misleading for 2nd and later iterations and might need
   // some fix (bug 1482003).
   if (!loopInfo_->emitLoopEntry(bce_, iteratedPos)) {
     return false;
   }
@@ -239,30 +239,29 @@ bool ForOfEmitter::emitEnd(const Maybe<u
     //              [stack] NEXT ITER UNDEF FALSE
     return false;
   }
   if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ)) {
     //              [stack] NEXT ITER UNDEF
     return false;
   }
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_);
+  MOZ_ASSERT(bce_->stackDepth == loopDepth_);
 
   // Let Ion know where the closing jump of this loop is.
   if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::ForOf::BackJumpOffset,
                               loopInfo_->loopEndOffsetFromEntryJump())) {
     return false;
   }
 
   if (!loopInfo_->patchBreaksAndContinues(bce_)) {
     return false;
   }
 
-  if (!bce_->addTryNote(JSTRY_FOR_OF, bce_->bytecodeSection().stackDepth(),
-                        loopInfo_->headOffset(),
+  if (!bce_->addTryNote(JSTRY_FOR_OF, bce_->stackDepth, loopInfo_->headOffset(),
                         loopInfo_->breakTargetOffset())) {
     return false;
   }
 
   if (!bce_->emitPopN(3)) {
     //              [stack]
     return false;
   }
--- a/js/src/frontend/ForOfLoopControl.cpp
+++ b/js/src/frontend/ForOfLoopControl.cpp
@@ -25,32 +25,32 @@ bool ForOfLoopControl::emitBeginCodeNeed
   tryCatch_.emplace(bce, TryEmitter::Kind::TryCatch,
                     TryEmitter::ControlKind::NonSyntactic);
 
   if (!tryCatch_->emitTry()) {
     return false;
   }
 
   MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
-  numYieldsAtBeginCodeNeedingIterClose_ = bce->bytecodeSection().numYields();
+  numYieldsAtBeginCodeNeedingIterClose_ = bce->numYields;
 
   return true;
 }
 
 bool ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
   if (!tryCatch_->emitCatch()) {
     //              [stack] ITER ...
     return false;
   }
 
   if (!bce->emit1(JSOP_EXCEPTION)) {
     //              [stack] ITER ... EXCEPTION
     return false;
   }
-  unsigned slotFromTop = bce->bytecodeSection().stackDepth() - iterDepth_;
+  unsigned slotFromTop = bce->stackDepth - iterDepth_;
   if (!bce->emitDupAt(slotFromTop)) {
     //              [stack] ITER ... EXCEPTION ITER
     return false;
   }
 
   // If ITER is undefined, it means the exception is thrown by
   // IteratorClose for non-local jump, and we should't perform
   // IteratorClose again here.
@@ -64,18 +64,17 @@ bool ForOfLoopControl::emitEndCodeNeedin
   }
 
   InternalIfEmitter ifIteratorIsNotClosed(bce);
   if (!ifIteratorIsNotClosed.emitThen()) {
     //              [stack] ITER ... EXCEPTION
     return false;
   }
 
-  MOZ_ASSERT(slotFromTop ==
-             unsigned(bce->bytecodeSection().stackDepth() - iterDepth_));
+  MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
   if (!bce->emitDupAt(slotFromTop)) {
     //              [stack] ITER ... EXCEPTION ITER
     return false;
   }
   if (!emitIteratorCloseInInnermostScopeWithTryNote(bce,
                                                     CompletionKind::Throw)) {
     return false;  // ITER ... EXCEPTION
   }
@@ -88,17 +87,17 @@ bool ForOfLoopControl::emitEndCodeNeedin
   if (!bce->emit1(JSOP_THROW)) {
     //              [stack] ITER ...
     return false;
   }
 
   // If any yields were emitted, then this for-of loop is inside a star
   // generator and must handle the case of Generator.return. Like in
   // yield*, it is handled with a finally block.
-  uint32_t numYieldsEmitted = bce->bytecodeSection().numYields();
+  uint32_t numYieldsEmitted = bce->numYields;
   if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
     if (!tryCatch_->emitFinally()) {
       return false;
     }
 
     InternalIfEmitter ifGeneratorClosing(bce);
     if (!bce->emit1(JSOP_ISGENCLOSING)) {
       //            [stack] ITER ... FTYPE FVALUE CLOSING
@@ -131,22 +130,22 @@ bool ForOfLoopControl::emitEndCodeNeedin
   numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
 
   return true;
 }
 
 bool ForOfLoopControl::emitIteratorCloseInInnermostScopeWithTryNote(
     BytecodeEmitter* bce,
     CompletionKind completionKind /* = CompletionKind::Normal */) {
-  ptrdiff_t start = bce->bytecodeSection().offset();
+  ptrdiff_t start = bce->offset();
   if (!emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(),
                                 completionKind)) {
     return false;
   }
-  ptrdiff_t end = bce->bytecodeSection().offset();
+  ptrdiff_t end = bce->offset();
   return bce->addTryNote(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
 }
 
 bool ForOfLoopControl::emitIteratorCloseInScope(
     BytecodeEmitter* bce, EmitterScope& currentScope,
     CompletionKind completionKind /* = CompletionKind::Normal */) {
   return bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
                                        allowSelfHosted_);
@@ -189,17 +188,17 @@ bool ForOfLoopControl::emitPrepareForNon
     //              [stack] ITER UNDEF
     return false;
   }
   if (!bce->emit1(JSOP_SWAP)) {
     //              [stack] UNDEF ITER
     return false;
   }
 
-  *tryNoteStart = bce->bytecodeSection().offset();
+  *tryNoteStart = bce->offset();
   if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) {
     //              [stack] UNDEF
     return false;
   }
 
   if (isTarget) {
     // At the level of the target block, there's bytecode after the
     // loop that will pop the next method, the iterator, and the
--- a/js/src/frontend/FunctionEmitter.cpp
+++ b/js/src/frontend/FunctionEmitter.cpp
@@ -215,17 +215,17 @@ bool FunctionEmitter::emitAsmJSModule() 
 #ifdef DEBUG
   state_ = State::End;
 #endif
   return true;
 }
 
 bool FunctionEmitter::emitFunction() {
   // Make the function object a literal in the outer script's pool.
-  unsigned index = bce_->perScriptData().objectList().add(funbox_);
+  unsigned index = bce_->objectList.add(funbox_);
 
   //                [stack]
 
   if (isHoisted_ == IsHoisted::No) {
     return emitNonHoisted(index);
     //              [stack] FUN?
   }
 
--- a/js/src/frontend/IfEmitter.cpp
+++ b/js/src/frontend/IfEmitter.cpp
@@ -36,38 +36,38 @@ bool BranchEmitterBase::emitThenInternal
   }
   if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_)) {
     return false;
   }
 
   // To restore stack depth in else part, save depth of the then part.
 #ifdef DEBUG
   // If DEBUG, this is also necessary to calculate |pushed_|.
-  thenDepth_ = bce_->bytecodeSection().stackDepth();
+  thenDepth_ = bce_->stackDepth;
 #else
   if (type == SRC_COND || type == SRC_IF_ELSE) {
-    thenDepth_ = bce_->bytecodeSection().stackDepth();
+    thenDepth_ = bce_->stackDepth;
   }
 #endif
 
   // Enclose then-branch with TDZCheckCache.
   if (kind_ == Kind::MayContainLexicalAccessInBranch) {
     tdzCache_.emplace(bce_);
   }
 
   return true;
 }
 
 void BranchEmitterBase::calculateOrCheckPushed() {
 #ifdef DEBUG
   if (!calculatedPushed_) {
-    pushed_ = bce_->bytecodeSection().stackDepth() - thenDepth_;
+    pushed_ = bce_->stackDepth - thenDepth_;
     calculatedPushed_ = true;
   } else {
-    MOZ_ASSERT(pushed_ == bce_->bytecodeSection().stackDepth() - thenDepth_);
+    MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
   }
 #endif
 }
 
 bool BranchEmitterBase::emitElseInternal() {
   calculateOrCheckPushed();
 
   // The end of TDZCheckCache for then-clause.
@@ -87,17 +87,17 @@ bool BranchEmitterBase::emitElseInternal
   if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) {
     return false;
   }
 
   // Clear jumpAroundThen_ offset, to tell emitEnd there was an else part.
   jumpAroundThen_ = JumpList();
 
   // Restore stack depth of the then part.
-  bce_->bytecodeSection().setStackDepth(thenDepth_);
+  bce_->stackDepth = thenDepth_;
 
   // Enclose else-branch with TDZCheckCache.
   if (kind_ == Kind::MayContainLexicalAccessInBranch) {
     tdzCache_.emplace(bce_);
   }
 
   return true;
 }
--- a/js/src/frontend/LabelEmitter.cpp
+++ b/js/src/frontend/LabelEmitter.cpp
@@ -22,30 +22,30 @@ bool LabelEmitter::emitLabel(JSAtom* nam
   uint32_t index;
   if (!bce_->makeAtomIndex(name, &index)) {
     return false;
   }
   if (!bce_->emitN(JSOP_LABEL, 4, &top_)) {
     return false;
   }
 
-  controlInfo_.emplace(bce_, name, bce_->bytecodeSection().offset());
+  controlInfo_.emplace(bce_, name, bce_->offset());
 
 #ifdef DEBUG
   state_ = State::Label;
 #endif
   return true;
 }
 
 bool LabelEmitter::emitEnd() {
   MOZ_ASSERT(state_ == State::Label);
 
   // Patch the JSOP_LABEL offset.
-  jsbytecode* labelpc = bce_->bytecodeSection().code(top_);
-  int32_t offset = bce_->bytecodeSection().lastNonJumpTargetOffset() - top_;
+  jsbytecode* labelpc = bce_->code(top_);
+  int32_t offset = bce_->lastNonJumpTargetOffset() - top_;
   MOZ_ASSERT(*labelpc == JSOP_LABEL);
   SET_CODE_OFFSET(labelpc, offset);
 
   // Patch the break/continue to this label.
   if (!controlInfo_->patchBreaks(bce_)) {
     return false;
   }
 
--- a/js/src/frontend/ObjectEmitter.cpp
+++ b/js/src/frontend/ObjectEmitter.cpp
@@ -407,17 +407,17 @@ bool ObjectEmitter::emitObject(size_t pr
   MOZ_ASSERT(propertyState_ == PropertyState::Start);
   MOZ_ASSERT(objectState_ == ObjectState::Start);
 
   //                [stack]
 
   // Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
   // a new object and defining (in source order) each property on the object
   // (or mutating the object's [[Prototype]], in the case of __proto__).
-  top_ = bce_->bytecodeSection().offset();
+  top_ = bce_->offset();
   if (!bce_->emitNewInit()) {
     //              [stack] OBJ
     return false;
   }
 
   // Try to construct the shape of the object as we go, so we can emit a
   // JSOP_NEWOBJECT with the final shape instead.
   // In the case of computed property names and indices, we cannot fix the
--- a/js/src/frontend/SwitchEmitter.cpp
+++ b/js/src/frontend/SwitchEmitter.cpp
@@ -146,66 +146,66 @@ bool SwitchEmitter::validateCaseCount(ui
 
 bool SwitchEmitter::emitCond() {
   MOZ_ASSERT(state_ == State::CaseCount);
 
   kind_ = Kind::Cond;
 
   // After entering the scope if necessary, push the switch control.
   controlInfo_.emplace(bce_, StatementKind::Switch);
-  top_ = bce_->bytecodeSection().offset();
+  top_ = bce_->offset();
 
   if (!caseOffsets_.resize(caseCount_)) {
     ReportOutOfMemory(bce_->cx);
     return false;
   }
 
   // The note has two offsets: first tells total switch code length;
   // second tells offset to first JSOP_CASE.
   if (!bce_->newSrcNote3(SRC_CONDSWITCH, 0, 0, &noteIndex_)) {
     return false;
   }
 
-  MOZ_ASSERT(top_ == bce_->bytecodeSection().offset());
+  MOZ_ASSERT(top_ == bce_->offset());
   if (!bce_->emitN(JSOP_CONDSWITCH, 0)) {
     return false;
   }
 
   tdzCacheCaseAndBody_.emplace(bce_);
 
   state_ = State::Cond;
   return true;
 }
 
 bool SwitchEmitter::emitTable(const TableGenerator& tableGen) {
   MOZ_ASSERT(state_ == State::CaseCount);
   kind_ = Kind::Table;
 
   // After entering the scope if necessary, push the switch control.
   controlInfo_.emplace(bce_, StatementKind::Switch);
-  top_ = bce_->bytecodeSection().offset();
+  top_ = bce_->offset();
 
   // The note has one offset that tells total switch code length.
   if (!bce_->newSrcNote2(SRC_TABLESWITCH, 0, &noteIndex_)) {
     return false;
   }
 
   if (!caseOffsets_.resize(tableGen.tableLength())) {
     ReportOutOfMemory(bce_->cx);
     return false;
   }
 
-  MOZ_ASSERT(top_ == bce_->bytecodeSection().offset());
+  MOZ_ASSERT(top_ == bce_->offset());
   if (!bce_->emitN(JSOP_TABLESWITCH,
                    JSOP_TABLESWITCH_LENGTH - sizeof(jsbytecode))) {
     return false;
   }
 
   // Skip default offset.
-  jsbytecode* pc = bce_->bytecodeSection().code(top_ + JUMP_OFFSET_LEN);
+  jsbytecode* pc = bce_->code(top_ + JUMP_OFFSET_LEN);
 
   // Fill in switch bounds, which we know fit in 16-bit offsets.
   SET_JUMP_OFFSET(pc, tableGen.low());
   SET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN, tableGen.high());
 
   state_ = State::Table;
   return true;
 }
@@ -218,19 +218,19 @@ bool SwitchEmitter::emitCaseOrDefaultJum
       return false;
     }
     return true;
   }
 
   if (caseIndex > 0) {
     // Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE for the
     // benefit of IonBuilder.
-    if (!bce_->setSrcNoteOffset(
-            caseNoteIndex_, SrcNote::NextCase::NextCaseOffset,
-            bce_->bytecodeSection().offset() - lastCaseOffset_)) {
+    if (!bce_->setSrcNoteOffset(caseNoteIndex_,
+                                SrcNote::NextCase::NextCaseOffset,
+                                bce_->offset() - lastCaseOffset_)) {
       return false;
     }
   }
 
   if (!bce_->newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex_)) {
     return false;
   }
 
@@ -238,22 +238,21 @@ bool SwitchEmitter::emitCaseOrDefaultJum
   if (!bce_->emitJump(JSOP_CASE, &caseJump)) {
     return false;
   }
   caseOffsets_[caseIndex] = caseJump.offset;
   lastCaseOffset_ = caseJump.offset;
 
   if (caseIndex == 0) {
     // Switch note's second offset is to first JSOP_CASE.
-    unsigned noteCount = bce_->bytecodeSection().notes().length();
+    unsigned noteCount = bce_->notes().length();
     if (!bce_->setSrcNoteOffset(noteIndex_, 1, lastCaseOffset_ - top_)) {
       return false;
     }
-    unsigned noteCountDelta =
-        bce_->bytecodeSection().notes().length() - noteCount;
+    unsigned noteCountDelta = bce_->notes().length() - noteCount;
     if (noteCountDelta != 0) {
       caseNoteIndex_ += noteCountDelta;
     }
   }
 
   return true;
 }
 
@@ -394,29 +393,28 @@ bool SwitchEmitter::emitEnd() {
   // Set the default offset (to end of switch if no default).
   jsbytecode* pc;
   if (kind_ == Kind::Cond) {
     pc = nullptr;
     bce_->patchJumpsToTarget(condSwitchDefaultOffset_,
                              defaultJumpTargetOffset_);
   } else {
     // Fill in the default jump target.
-    pc = bce_->bytecodeSection().code(top_);
+    pc = bce_->code(top_);
     SET_JUMP_OFFSET(pc, defaultJumpTargetOffset_.offset - top_);
     pc += JUMP_OFFSET_LEN;
   }
 
   // Set the SRC_SWITCH note's offset operand to tell end of switch.
   // This code is shared between table switch and cond switch.
   static_assert(unsigned(SrcNote::TableSwitch::EndOffset) ==
                     unsigned(SrcNote::CondSwitch::EndOffset),
                 "{TableSwitch,CondSwitch}::EndOffset should be same");
-  if (!bce_->setSrcNoteOffset(
-          noteIndex_, SrcNote::TableSwitch::EndOffset,
-          bce_->bytecodeSection().lastNonJumpTargetOffset() - top_)) {
+  if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::TableSwitch::EndOffset,
+                              bce_->lastNonJumpTargetOffset() - top_)) {
     return false;
   }
 
   if (kind_ == Kind::Table) {
     // Skip over the already-initialized switch bounds.
     pc += 2 * JUMP_OFFSET_LEN;
 
     // Use the 'default' offset for missing cases.
--- a/js/src/frontend/TryEmitter.cpp
+++ b/js/src/frontend/TryEmitter.cpp
@@ -48,48 +48,47 @@ bool TryEmitter::emitTry() {
 
   // Since an exception can be thrown at any place inside the try block,
   // we need to restore the stack and the scope chain before we transfer
   // the control to the exception handler.
   //
   // For that we store in a try note associated with the catch or
   // finally block the stack depth upon the try entry. The interpreter
   // uses this depth to properly unwind the stack and the scope chain.
-  depth_ = bce_->bytecodeSection().stackDepth();
+  depth_ = bce_->stackDepth;
 
   // Record the try location, then emit the try block.
   if (!bce_->newSrcNote(SRC_TRY, &noteIndex_)) {
     return false;
   }
   if (!bce_->emit1(JSOP_TRY)) {
     return false;
   }
-  tryStart_ = bce_->bytecodeSection().offset();
+  tryStart_ = bce_->offset();
 
 #ifdef DEBUG
   state_ = State::Try;
 #endif
   return true;
 }
 
 bool TryEmitter::emitTryEnd() {
   MOZ_ASSERT(state_ == State::Try);
-  MOZ_ASSERT(depth_ == bce_->bytecodeSection().stackDepth());
+  MOZ_ASSERT(depth_ == bce_->stackDepth);
 
   // GOSUB to finally, if present.
   if (hasFinally() && controlInfo_) {
     if (!bce_->emitGoSub(&controlInfo_->gosubs)) {
       return false;
     }
   }
 
   // Source note points to the jump at the end of the try block.
-  if (!bce_->setSrcNoteOffset(
-          noteIndex_, SrcNote::Try::EndOfTryJumpOffset,
-          bce_->bytecodeSection().offset() - tryStart_ + JSOP_TRY_LENGTH)) {
+  if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::Try::EndOfTryJumpOffset,
+                              bce_->offset() - tryStart_ + JSOP_TRY_LENGTH)) {
     return false;
   }
 
   // Emit jump over catch and/or finally.
   if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_)) {
     return false;
   }
 
@@ -101,17 +100,17 @@ bool TryEmitter::emitTryEnd() {
 }
 
 bool TryEmitter::emitCatch() {
   MOZ_ASSERT(state_ == State::Try);
   if (!emitTryEnd()) {
     return false;
   }
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
+  MOZ_ASSERT(bce_->stackDepth == depth_);
 
   if (controlKind_ == ControlKind::Syntactic) {
     // Clear the frame's return value that might have been set by the
     // try block:
     //
     //   eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
     if (!bce_->emit1(JSOP_UNDEFINED)) {
       return false;
@@ -134,17 +133,17 @@ bool TryEmitter::emitCatchEnd() {
     return true;
   }
 
   // gosub <finally>, if required.
   if (hasFinally()) {
     if (!bce_->emitGoSub(&controlInfo_->gosubs)) {
       return false;
     }
-    MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
+    MOZ_ASSERT(bce_->stackDepth == depth_);
 
     // Jump over the finally block.
     if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_)) {
       return false;
     }
   }
 
   return true;
@@ -173,17 +172,17 @@ bool TryEmitter::emitFinally(
     }
   } else {
     MOZ_ASSERT(state_ == State::Catch);
     if (!emitCatchEnd()) {
       return false;
     }
   }
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
+  MOZ_ASSERT(bce_->stackDepth == depth_);
 
   if (!bce_->emitJumpTarget(&finallyStart_)) {
     return false;
   }
 
   if (controlInfo_) {
     // Fix up the gosubs that might have been emitted before non-local
     // jumps to the finally code.
@@ -249,17 +248,17 @@ bool TryEmitter::emitEnd() {
     }
   } else {
     MOZ_ASSERT(state_ == State::Finally);
     if (!emitFinallyEnd()) {
       return false;
     }
   }
 
-  MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
+  MOZ_ASSERT(bce_->stackDepth == depth_);
 
   // ReconstructPCStack needs a NOP here to mark the end of the last
   // catch block.
   if (!bce_->emit1(JSOP_NOP)) {
     return false;
   }
 
   // Fix up the end-of-try/catch jumps to come here.
--- a/js/src/frontend/WhileEmitter.cpp
+++ b/js/src/frontend/WhileEmitter.cpp
@@ -95,18 +95,17 @@ bool WhileEmitter::emitCond(const Maybe<
 
 bool WhileEmitter::emitEnd() {
   MOZ_ASSERT(state_ == State::Cond);
 
   if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFNE)) {
     return false;
   }
 
-  if (!bce_->addTryNote(JSTRY_LOOP, bce_->bytecodeSection().stackDepth(),
-                        loopInfo_->headOffset(),
+  if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
                         loopInfo_->breakTargetOffset())) {
     return false;
   }
 
   if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::While::BackJumpOffset,
                               loopInfo_->loopEndOffsetFromEntryJump())) {
     return false;
   }
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -3233,48 +3233,48 @@ PrivateScriptData* PrivateScriptData::ne
   // Constuct the PrivateScriptData. Trailing arrays are uninitialized but
   // GCPtrs are put into a safe state.
   return new (raw) PrivateScriptData(nscopes, nconsts, nobjects, ntrynotes,
                                      nscopenotes, nresumeoffsets);
 }
 
 /* static */ bool PrivateScriptData::InitFromEmitter(
     JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) {
-  uint32_t nscopes = bce->perScriptData().scopeList().length();
-  uint32_t nconsts = bce->perScriptData().numberList().length();
-  uint32_t nobjects = bce->perScriptData().objectList().length;
-  uint32_t ntrynotes = bce->bytecodeSection().tryNoteList().length();
-  uint32_t nscopenotes = bce->bytecodeSection().scopeNoteList().length();
-  uint32_t nresumeoffsets = bce->bytecodeSection().resumeOffsetList().length();
+  uint32_t nscopes = bce->scopeList.length();
+  uint32_t nconsts = bce->numberList.length();
+  uint32_t nobjects = bce->objectList.length;
+  uint32_t ntrynotes = bce->tryNoteList.length();
+  uint32_t nscopenotes = bce->scopeNoteList.length();
+  uint32_t nresumeoffsets = bce->resumeOffsetList.length();
 
   // Create and initialize PrivateScriptData
   if (!JSScript::createPrivateScriptData(cx, script, nscopes, nconsts, nobjects,
                                          ntrynotes, nscopenotes,
                                          nresumeoffsets)) {
     return false;
   }
 
   js::PrivateScriptData* data = script->data_;
   if (nscopes) {
-    bce->perScriptData().scopeList().finish(data->scopes());
+    bce->scopeList.finish(data->scopes());
   }
   if (nconsts) {
-    bce->perScriptData().numberList().finish(data->consts());
+    bce->numberList.finish(data->consts());
   }
   if (nobjects) {
-    bce->perScriptData().objectList().finish(data->objects());
+    bce->objectList.finish(data->objects());
   }
   if (ntrynotes) {
-    bce->bytecodeSection().tryNoteList().finish(data->tryNotes());
+    bce->tryNoteList.finish(data->tryNotes());
   }
   if (nscopenotes) {
-    bce->bytecodeSection().scopeNoteList().finish(data->scopeNotes());
+    bce->scopeNoteList.finish(data->scopeNotes());
   }
   if (nresumeoffsets) {
-    bce->bytecodeSection().resumeOffsetList().finish(data->resumeOffsets());
+    bce->resumeOffsetList.finish(data->resumeOffsets());
   }
 
   return true;
 }
 
 void PrivateScriptData::trace(JSTracer* trc) {
   auto scopearray = scopes();
   TraceRange(trc, scopearray.size(), scopearray.data(), "scopes");
@@ -3560,34 +3560,33 @@ bool JSScript::fullyInitFromEmitter(JSCo
 
   // If initialization fails, we must call JSScript::freeScriptData in order to
   // neuter the script. Various things that iterate raw scripts in a GC arena
   // use the presense of this data to detect if initialization is complete.
   auto scriptDataGuard =
       mozilla::MakeScopeExit([&] { script->freeScriptData(); });
 
   /* The counts of indexed things must be checked during code generation. */
-  MOZ_ASSERT(bce->perScriptData().atomIndices()->count() <= INDEX_LIMIT);
-  MOZ_ASSERT(bce->perScriptData().objectList().length <= INDEX_LIMIT);
+  MOZ_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
+  MOZ_ASSERT(bce->objectList.length <= INDEX_LIMIT);
 
   uint64_t nslots =
-      bce->maxFixedSlots +
-      static_cast<uint64_t>(bce->bytecodeSection().maxStackDepth());
+      bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
   if (nslots > UINT32_MAX) {
     bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
     return false;
   }
 
   // Initialize POD fields
   script->lineno_ = bce->firstLine;
   script->mainOffset_ = bce->mainOffset();
   script->nfixed_ = bce->maxFixedSlots;
   script->nslots_ = nslots;
   script->bodyScopeIndex_ = bce->bodyScopeIndex;
-  script->numBytecodeTypeSets_ = bce->bytecodeSection().typesetCount();
+  script->numBytecodeTypeSets_ = bce->typesetCount;
 
   // Initialize script flags from BytecodeEmitter
   script->setFlag(ImmutableFlags::Strict, bce->sc->strict());
   script->setFlag(ImmutableFlags::BindingsAccessedDynamically,
                   bce->sc->bindingsAccessedDynamically());
   script->setFlag(ImmutableFlags::HasSingletons, bce->hasSingletons);
   script->setFlag(ImmutableFlags::IsForEval, bce->sc->isEvalContext());
   script->setFlag(ImmutableFlags::IsModule, bce->sc->isModuleContext());
@@ -3624,17 +3623,17 @@ bool JSScript::fullyInitFromEmitter(JSCo
     } else {
       fun->setScript(script);
     }
   }
 
   // Part of the parse result – the scope containing each inner function – must
   // be stored in the inner function itself. Do this now that compilation is
   // complete and can no longer fail.
-  bce->perScriptData().objectList().finishInnerFunctions();
+  bce->objectList.finishInnerFunctions();
 
 #ifdef JS_STRUCTURED_SPEW
   // We want this to happen after line number initialization to allow filtering
   // to work.
   script->setSpewEnabled(StructuredSpewer::enabled(script));
 #endif
 
 #ifdef DEBUG
@@ -4518,34 +4517,34 @@ bool JSScript::hasBreakpointsAt(jsbyteco
     return false;
   }
 
   return site->enabledCount > 0;
 }
 
 /* static */ bool SharedScriptData::InitFromEmitter(
     JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) {
-  uint32_t natoms = bce->perScriptData().atomIndices()->count();
-  uint32_t codeLength = bce->bytecodeSection().code().length();
+  uint32_t natoms = bce->atomIndices->count();
+  uint32_t codeLength = bce->code().length();
 
   // The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended
   // when the notes are copied to their final destination by copySrcNotes.
-  uint32_t noteLength = bce->bytecodeSection().notes().length() + 1;
+  uint32_t noteLength = bce->notes().length() + 1;
 
   // Create and initialize SharedScriptData
   if (!script->createSharedScriptData(cx, codeLength, noteLength, natoms)) {
     return false;
   }
 
   js::SharedScriptData* data = script->scriptData_;
 
   // Initialize trailing arrays
-  std::copy_n(bce->bytecodeSection().code().begin(), codeLength, data->code());
+  std::copy_n(bce->code().begin(), codeLength, data->code());
   bce->copySrcNotes(data->notes(), noteLength);
-  InitAtomMap(*bce->perScriptData().atomIndices(), data->atoms());
+  InitAtomMap(*bce->atomIndices, data->atoms());
 
   return true;
 }
 
 void SharedScriptData::traceChildren(JSTracer* trc) {
   MOZ_ASSERT(refCount() != 0);
   for (uint32_t i = 0; i < natoms(); ++i) {
     TraceNullableEdge(trc, &atoms()[i], "atom");