Bug 1535994 - Part 6: Move scope to BytecodeSection class and PerScriptData class. r=jorendorff
☠☠ backed out by 7fb3acf38591 ☠ ☠
authorTooru Fujisawa <arai_a@mac.com>
Wed, 10 Apr 2019 08:26:54 +0000
changeset 468741 8a480b0bbd0565adc7dfac295f6cac482e4d3350
parent 468740 7c763b9a2118ade0f7b0e372da562e415679c610
child 468742 096ab8585046007ed3a7853e4b2ce6ce37f55243
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)
reviewersjorendorff
bugs1535994
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1535994 - Part 6: Move scope to BytecodeSection class and PerScriptData class. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D25736
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/EmitterScope.cpp
js/src/vm/JSScript.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -87,35 +87,36 @@ static bool ParseNodeRequiresSpecialLine
   // 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)
-    : code_(cx), notes_(cx), tryNoteList_(cx) {}
+    : code_(cx), notes_(cx), tryNoteList_(cx), scopeNoteList_(cx) {}
+
+BytecodeEmitter::PerScriptData::PerScriptData(JSContext* cx) : scopeList_(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),
+      perScriptData_(cx),
       currentLine_(lineNum),
       fieldInitializers_(fieldInitializers),
       atomIndices(cx->frontendCollectionPool()),
       firstLine(lineNum),
       numberList(cx),
-      scopeList(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.
     numICEntries = sc->asFunctionBox()->function()->nargs() + 1;
   }
@@ -662,25 +663,26 @@ class NonLocalExitControl {
 
   NonLocalExitControl(const NonLocalExitControl&) = delete;
 
   MOZ_MUST_USE bool leaveScope(EmitterScope* scope);
 
  public:
   NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
       : bce_(bce),
-        savedScopeNoteIndex_(bce->scopeNoteList.length()),
+        savedScopeNoteIndex_(bce->bytecodeSection().scopeNoteList().length()),
         savedDepth_(bce->bytecodeSection().stackDepth()),
         openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
         kind_(kind) {}
 
   ~NonLocalExitControl() {
-    for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length();
-         n++) {
-      bce_->scopeNoteList.recordEnd(n, bce_->bytecodeSection().offset());
+    for (uint32_t n = savedScopeNoteIndex_;
+         n < bce_->bytecodeSection().scopeNoteList().length(); n++) {
+      bce_->bytecodeSection().scopeNoteList().recordEnd(
+          n, bce_->bytecodeSection().offset());
     }
     bce_->bytecodeSection().setStackDepth(savedDepth_);
   }
 
   MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
 
   MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
     return prepareForNonLocalJump(nullptr);
@@ -694,22 +696,22 @@ 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_->scopeNoteList.append(enclosingScopeIndex,
-                                  bce_->bytecodeSection().offset(),
-                                  openScopeNoteIndex_)) {
-    return false;
-  }
-  openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
+  if (!bce_->bytecodeSection().scopeNoteList().append(
+          enclosingScopeIndex, bce_->bytecodeSection().offset(),
+          openScopeNoteIndex_)) {
+    return false;
+  }
+  openScopeNoteIndex_ = bce_->bytecodeSection().scopeNoteList().length() - 1;
 
   return true;
 }
 
 /*
  * Emit additional bytecode(s) for non-local jumps.
  */
 bool NonLocalExitControl::prepareForNonLocalJump(NestableControl* target) {
@@ -940,17 +942,17 @@ 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 < scopeList.length());
+  MOZ_ASSERT(index < perScriptData().scopeList().length());
   return emitIndex32(op, index);
 }
 
 bool BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op) {
   MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
   MOZ_ASSERT(index < objectList.length);
   return emitIndex32(op, index);
 }
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -173,16 +173,21 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
 
     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_; };
+
    private:
     // ---- Bytecode ----
 
     // Bytecode.
     BytecodeVector code_;
 
     // ---- Source notes ----
 
@@ -204,25 +209,55 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
 
     // 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_;
   };
 
   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);
+
+    // ---- Scope ----
+
+    CGScopeList& scopeList() { return scopeList_; }
+    const CGScopeList& scopeList() const { return scopeList_; }
+
+   private:
+    // ---- Scope ----
+
+    // List of emitted scopes.
+    CGScopeList scopeList_;
+  };
+
+  PerScriptData perScriptData_;
+
+ public:
+  PerScriptData& perScriptData() { return perScriptData_; }
+  const PerScriptData& perScriptData() const { return perScriptData_; }
+
+ private:
   // Line number for srcnotes.
   //
   // WARNING: If this becomes out of sync with already-emitted srcnotes,
   // we can get undefined behavior.
   uint32_t currentLine_ = 0;
 
   // Zero-based column index on currentLine of last SRC_COLSPAN-annotated
   // opcode.
@@ -271,20 +306,18 @@ 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 */
-  CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
+  CGNumberList numberList; /* double and bigint values used by script */
+  CGObjectList objectList; /* list of emitted objects */
 
   // 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;
 
@@ -435,21 +468,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   }
 
   void setVarEmitterScope(EmitterScope* emitterScope) {
     MOZ_ASSERT(emitterScope);
     MOZ_ASSERT(!varEmitterScope);
     varEmitterScope = emitterScope;
   }
 
-  Scope* outermostScope() const { return scopeList.vector[0]; }
+  Scope* outermostScope() const {
+    return perScriptData().scopeList().vector[0];
+  }
   Scope* innermostScope() const;
   Scope* bodyScope() const {
-    MOZ_ASSERT(bodyScopeIndex < scopeList.length());
-    return scopeList.vector[bodyScopeIndex];
+    MOZ_ASSERT(bodyScopeIndex < perScriptData().scopeList().length());
+    return perScriptData().scopeList().vector[bodyScopeIndex];
   }
 
   MOZ_ALWAYS_INLINE
   MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) {
     MOZ_ASSERT(atomIndices);
     AtomIndexMap::AddPtr p = atomIndices->lookupForAdd(atom);
     if (p) {
       *indexp = p->value();
--- 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->scopeList.length();
-  return bce->scopeList.append(scope);
+  scopeIndex_ = bce->perScriptData().scopeList().length();
+  return bce->perScriptData().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->scopeList.length();
+  bce->bodyScopeIndex = bce->perScriptData().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->scopeNoteList.length();
-  return bce->scopeNoteList.append(index(), bce->bytecodeSection().offset(),
-                                   enclosingInFrame()
-                                       ? enclosingInFrame()->noteIndex()
-                                       : ScopeNote::NoScopeNoteIndex);
+  noteIndex_ = bce->bytecodeSection().scopeNoteList().length();
+  return bce->bytecodeSection().scopeNoteList().append(
+      index(), bce->bytecodeSection().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.
   //
@@ -1055,25 +1055,25 @@ bool EmitterScope::leave(BytecodeEmitter
     // 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->scopeNoteList.recordEnd(noteIndex_, offset);
+      bce->bytecodeSection().scopeNoteList().recordEnd(noteIndex_, offset);
     }
   }
 
   return true;
 }
 
 Scope* EmitterScope::scope(const BytecodeEmitter* bce) const {
-  return bce->scopeList.vector[index()];
+  return bce->perScriptData().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/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -3233,45 +3233,45 @@ 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->scopeList.length();
+  uint32_t nscopes = bce->perScriptData().scopeList().length();
   uint32_t nconsts = bce->numberList.length();
   uint32_t nobjects = bce->objectList.length;
   uint32_t ntrynotes = bce->bytecodeSection().tryNoteList().length();
-  uint32_t nscopenotes = bce->scopeNoteList.length();
+  uint32_t nscopenotes = bce->bytecodeSection().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->scopeList.finish(data->scopes());
+    bce->perScriptData().scopeList().finish(data->scopes());
   }
   if (nconsts) {
     bce->numberList.finish(data->consts());
   }
   if (nobjects) {
     bce->objectList.finish(data->objects());
   }
   if (ntrynotes) {
     bce->bytecodeSection().tryNoteList().finish(data->tryNotes());
   }
   if (nscopenotes) {
-    bce->scopeNoteList.finish(data->scopeNotes());
+    bce->bytecodeSection().scopeNoteList().finish(data->scopeNotes());
   }
   if (nresumeoffsets) {
     bce->resumeOffsetList.finish(data->resumeOffsets());
   }
 
   return true;
 }