Bug 1592102 - Refactor Scope allocation paths to support code sharing r=tcampbell
authorMatthew Gaudet <mgaudet@mozilla.com>
Fri, 06 Dec 2019 16:25:27 +0000
changeset 505832 351c88e680a33ea769a863b67800afedc75319fb
parent 505831 325e83234dd53f2abdb182acc382857978c57666
child 505833 0f59860a21ef5cd460d9850bcb7719de85c5eca3
push id36889
push userdluca@mozilla.com
push dateFri, 06 Dec 2019 21:48:33 +0000
treeherdermozilla-central@0d24f14c0847 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1592102
milestone73.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 1592102 - Refactor Scope allocation paths to support code sharing r=tcampbell Differential Revision: https://phabricator.services.mozilla.com/D51910
js/src/vm/Scope.cpp
js/src/vm/Scope.h
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -558,33 +558,45 @@ LexicalScope* LexicalScope::create(JSCon
   Rooted<UniquePtr<Data>> copy(cx, CopyScopeData<LexicalScope>(cx, data));
   if (!copy) {
     return nullptr;
   }
 
   return createWithData(cx, kind, &copy, firstFrameSlot, enclosing);
 }
 
-/* static */
-LexicalScope* LexicalScope::createWithData(JSContext* cx, ScopeKind kind,
+bool LexicalScope::prepareForScopeCreation(JSContext* cx, ScopeKind kind,
+                                           uint32_t firstFrameSlot,
+                                           HandleScope enclosing,
                                            MutableHandle<UniquePtr<Data>> data,
-                                           uint32_t firstFrameSlot,
-                                           HandleScope enclosing) {
+                                           MutableHandleShape envShape) {
   bool isNamedLambda =
       kind == ScopeKind::NamedLambda || kind == ScopeKind::StrictNamedLambda;
 
   MOZ_ASSERT_IF(!isNamedLambda && firstFrameSlot != 0,
                 firstFrameSlot == nextFrameSlot(enclosing));
   MOZ_ASSERT_IF(isNamedLambda, firstFrameSlot == LOCALNO_LIMIT);
 
-  RootedShape envShape(cx);
   BindingIter bi(*data, firstFrameSlot, isNamedLambda);
   if (!PrepareScopeData<LexicalScope>(
           cx, bi, data, &LexicalEnvironmentObject::class_,
-          BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE, &envShape)) {
+          BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE, envShape)) {
+    return false;
+  }
+  return true;
+}
+
+/* static */
+LexicalScope* LexicalScope::createWithData(JSContext* cx, ScopeKind kind,
+                                           MutableHandle<UniquePtr<Data>> data,
+                                           uint32_t firstFrameSlot,
+                                           HandleScope enclosing) {
+  RootedShape envShape(cx);
+  if (!prepareForScopeCreation(cx, kind, firstFrameSlot, enclosing, data,
+                               &envShape)) {
     return nullptr;
   }
 
   auto scope = Scope::create<LexicalScope>(cx, kind, enclosing, envShape, data);
   if (!scope) {
     return nullptr;
   }
 
@@ -675,53 +687,64 @@ FunctionScope* FunctionScope::create(JSC
   }
 
   return createWithData(
       cx, &data, hasParameterExprs,
       dataArg ? dataArg->isFieldInitializer : IsFieldInitializer::No,
       needsEnvironment, fun, enclosing);
 }
 
-/* static */
-FunctionScope* FunctionScope::createWithData(
+bool FunctionScope::prepareForScopeCreation(
     JSContext* cx, MutableHandle<UniquePtr<Data>> data, bool hasParameterExprs,
     IsFieldInitializer isFieldInitializer, bool needsEnvironment,
-    HandleFunction fun, HandleScope enclosing) {
-  MOZ_ASSERT(data);
-  MOZ_ASSERT(fun->isTenured());
-
-  // FunctionScope::Data has GCManagedDeletePolicy because it contains a
-  // GCPtr. Destruction of |data| below may trigger calls into the GC.
-
-  RootedShape envShape(cx);
-
+    HandleFunction fun, MutableHandleShape envShape) {
   BindingIter bi(*data, hasParameterExprs);
   uint32_t shapeFlags = FunctionScopeEnvShapeFlags(hasParameterExprs);
   if (!PrepareScopeData<FunctionScope>(cx, bi, data, &CallObject::class_,
-                                       shapeFlags, &envShape)) {
-    return nullptr;
+                                       shapeFlags, envShape)) {
+    return false;
   }
 
   data->isFieldInitializer = isFieldInitializer;
   data->hasParameterExprs = hasParameterExprs;
   data->canonicalFunction.init(fun);
 
   // An environment may be needed regardless of existence of any closed over
   // bindings:
   //   - Extensible scopes (i.e., due to direct eval)
   //   - Needing a home object
   //   - Being a derived class constructor
   //   - Being a generator
   if (!envShape && needsEnvironment) {
-    envShape = getEmptyEnvironmentShape(cx, hasParameterExprs);
+    envShape.set(getEmptyEnvironmentShape(cx, hasParameterExprs));
     if (!envShape) {
-      return nullptr;
+      return false;
     }
   }
 
+  return true;
+}
+
+/* static */
+FunctionScope* FunctionScope::createWithData(
+    JSContext* cx, MutableHandle<UniquePtr<Data>> data, bool hasParameterExprs,
+    IsFieldInitializer isFieldInitializer, bool needsEnvironment,
+    HandleFunction fun, HandleScope enclosing) {
+  MOZ_ASSERT(data);
+  MOZ_ASSERT(fun->isTenured());
+
+  // FunctionScope::Data has GCManagedDeletePolicy because it contains a
+  // GCPtr. Destruction of |data| below may trigger calls into the GC.
+  RootedShape envShape(cx);
+
+  if (!prepareForScopeCreation(cx, data, hasParameterExprs, isFieldInitializer,
+                               needsEnvironment, fun, &envShape)) {
+    return nullptr;
+  }
+
   return Scope::create<FunctionScope>(cx, ScopeKind::Function, enclosing,
                                       envShape, data);
 }
 
 JSScript* FunctionScope::script() const {
   return canonicalFunction()->nonLazyScript();
 }
 
@@ -862,42 +885,54 @@ VarScope* VarScope::create(JSContext* cx
   if (!data) {
     return nullptr;
   }
 
   return createWithData(cx, kind, &data, firstFrameSlot, needsEnvironment,
                         enclosing);
 }
 
+bool VarScope::prepareForScopeCreation(JSContext* cx, ScopeKind kind,
+                                       MutableHandle<UniquePtr<Data>> data,
+                                       uint32_t firstFrameSlot,
+                                       bool needsEnvironment,
+                                       MutableHandleShape envShape) {
+  BindingIter bi(*data, firstFrameSlot);
+  if (!PrepareScopeData<VarScope>(cx, bi, data, &VarEnvironmentObject::class_,
+                                  VarScopeEnvShapeFlags, envShape)) {
+    return false;
+  }
+
+  // An environment may be needed regardless of existence of any closed over
+  // bindings:
+  //   - Extensible scopes (i.e., due to direct eval)
+  //   - Being a generator
+  if (!envShape && needsEnvironment) {
+    envShape.set(getEmptyEnvironmentShape(cx));
+    if (!envShape) {
+      return false;
+    }
+  }
+  return true;
+}
+
 /* static */
 VarScope* VarScope::createWithData(JSContext* cx, ScopeKind kind,
                                    MutableHandle<UniquePtr<Data>> data,
                                    uint32_t firstFrameSlot,
                                    bool needsEnvironment,
                                    HandleScope enclosing) {
   MOZ_ASSERT(data);
 
   RootedShape envShape(cx);
-  BindingIter bi(*data, firstFrameSlot);
-  if (!PrepareScopeData<VarScope>(cx, bi, data, &VarEnvironmentObject::class_,
-                                  VarScopeEnvShapeFlags, &envShape)) {
+  if (!prepareForScopeCreation(cx, kind, data, firstFrameSlot, needsEnvironment,
+                               &envShape)) {
     return nullptr;
   }
 
-  // An environment may be needed regardless of existence of any closed over
-  // bindings:
-  //   - Extensible scopes (i.e., due to direct eval)
-  //   - Being a generator
-  if (!envShape && needsEnvironment) {
-    envShape = getEmptyEnvironmentShape(cx);
-    if (!envShape) {
-      return nullptr;
-    }
-  }
-
   return Scope::create<VarScope>(cx, kind, enclosing, envShape, data);
 }
 
 /* static */
 Shape* VarScope::getEmptyEnvironmentShape(JSContext* cx) {
   const JSClass* cls = &VarEnvironmentObject::class_;
   return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls),
                                VarScopeEnvShapeFlags);
@@ -1102,39 +1137,48 @@ EvalScope* EvalScope::create(JSContext* 
                                        : NewEmptyScopeData<EvalScope>(cx));
   if (!data) {
     return nullptr;
   }
 
   return createWithData(cx, scopeKind, &data, enclosing);
 }
 
+bool EvalScope::prepareForScopeCreation(JSContext* cx, ScopeKind scopeKind,
+                                        MutableHandle<UniquePtr<Data>> data,
+                                        MutableHandleShape envShape) {
+  if (scopeKind == ScopeKind::StrictEval) {
+    BindingIter bi(*data, true);
+    if (!PrepareScopeData<EvalScope>(cx, bi, data,
+                                     &VarEnvironmentObject::class_,
+                                     EvalScopeEnvShapeFlags, envShape)) {
+      return false;
+    }
+  }
+
+  // Strict eval and direct eval in parameter expressions always get their own
+  // var environment even if there are no bindings.
+  if (!envShape && scopeKind == ScopeKind::StrictEval) {
+    envShape.set(getEmptyEnvironmentShape(cx));
+    if (!envShape) {
+      return false;
+    }
+  }
+  return true;
+}
+
 /* static */
 EvalScope* EvalScope::createWithData(JSContext* cx, ScopeKind scopeKind,
                                      MutableHandle<UniquePtr<Data>> data,
                                      HandleScope enclosing) {
   MOZ_ASSERT(data);
 
   RootedShape envShape(cx);
-  if (scopeKind == ScopeKind::StrictEval) {
-    BindingIter bi(*data, true);
-    if (!PrepareScopeData<EvalScope>(cx, bi, data,
-                                     &VarEnvironmentObject::class_,
-                                     EvalScopeEnvShapeFlags, &envShape)) {
-      return nullptr;
-    }
-  }
-
-  // Strict eval and direct eval in parameter expressions always get their own
-  // var environment even if there are no bindings.
-  if (!envShape && scopeKind == ScopeKind::StrictEval) {
-    envShape = getEmptyEnvironmentShape(cx);
-    if (!envShape) {
-      return nullptr;
-    }
+  if (!prepareForScopeCreation(cx, scopeKind, data, &envShape)) {
+    return nullptr;
   }
 
   return Scope::create<EvalScope>(cx, scopeKind, enclosing, envShape, data);
 }
 
 /* static */
 Scope* EvalScope::nearestVarScopeForDirectEval(Scope* scope) {
   for (ScopeIter si(scope); si; si++) {
@@ -1208,57 +1252,68 @@ static const uint32_t ModuleScopeEnvShap
 Zone* ModuleScope::Data::zone() const {
   return module ? module->zone() : nullptr;
 }
 
 /* static */
 ModuleScope* ModuleScope::create(JSContext* cx, Handle<Data*> dataArg,
                                  HandleModuleObject module,
                                  HandleScope enclosing) {
+  // ModuleScope::Data has GCManagedDeletePolicy because it contains a
+  // GCPtr. Destruction of |data| below may trigger calls into the GC.
+
+  // The data that's passed in is from the frontend and is LifoAlloc'd.
+  // Copy it now that we're creating a permanent VM scope.
   Rooted<UniquePtr<Data>> data(cx, dataArg
                                        ? CopyScopeData<ModuleScope>(cx, dataArg)
                                        : NewEmptyScopeData<ModuleScope>(cx));
   if (!data) {
     return nullptr;
   }
 
   return createWithData(cx, &data, module, enclosing);
 }
 
 /* static */
+bool ModuleScope::prepareForScopeCreation(JSContext* cx,
+                                          MutableHandle<UniquePtr<Data>> data,
+                                          HandleModuleObject module,
+                                          MutableHandleShape envShape) {
+  BindingIter bi(*data);
+  if (!PrepareScopeData<ModuleScope>(cx, bi, data,
+                                     &ModuleEnvironmentObject::class_,
+                                     ModuleScopeEnvShapeFlags, envShape)) {
+    return false;
+  }
+
+  // Modules always need an environment object for now.
+  if (!envShape) {
+    envShape.set(getEmptyEnvironmentShape(cx));
+    if (!envShape) {
+      return false;
+    }
+  }
+
+  data->module.init(module);
+  return true;
+}
+
+/* static */
 ModuleScope* ModuleScope::createWithData(JSContext* cx,
                                          MutableHandle<UniquePtr<Data>> data,
                                          HandleModuleObject module,
                                          HandleScope enclosing) {
   MOZ_ASSERT(data);
   MOZ_ASSERT(enclosing->is<GlobalScope>());
 
-  // ModuleScope::Data has GCManagedDeletePolicy because it contains a
-  // GCPtr. Destruction of |copy| below may trigger calls into the GC.
-
-  // The data that's passed in is from the frontend and is LifoAlloc'd.
-  // Copy it now that we're creating a permanent VM scope.
   RootedShape envShape(cx);
-  BindingIter bi(*data);
-  if (!PrepareScopeData<ModuleScope>(cx, bi, data,
-                                     &ModuleEnvironmentObject::class_,
-                                     ModuleScopeEnvShapeFlags, &envShape)) {
+  if (!prepareForScopeCreation(cx, data, module, &envShape)) {
     return nullptr;
   }
 
-  // Modules always need an environment object for now.
-  if (!envShape) {
-    envShape = getEmptyEnvironmentShape(cx);
-    if (!envShape) {
-      return nullptr;
-    }
-  }
-
-  data->module.init(module);
-
   return Scope::create<ModuleScope>(cx, ScopeKind::Module, enclosing, envShape,
                                     data);
 }
 
 /* static */
 Shape* ModuleScope::getEmptyEnvironmentShape(JSContext* cx) {
   const JSClass* cls = &ModuleEnvironmentObject::class_;
   return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls),
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -423,16 +423,22 @@ class LexicalScope : public Scope {
                        HandleScope enclosing, MutableHandleScope scope);
 
  private:
   static LexicalScope* createWithData(JSContext* cx, ScopeKind kind,
                                       MutableHandle<UniquePtr<Data>> data,
                                       uint32_t firstFrameSlot,
                                       HandleScope enclosing);
 
+  static bool prepareForScopeCreation(JSContext* cx, ScopeKind kind,
+                                      uint32_t firstFrameSlot,
+                                      HandleScope enclosing,
+                                      MutableHandle<UniquePtr<Data>> data,
+                                      MutableHandleShape envShape);
+
   Data& data() { return *static_cast<Data*>(data_); }
 
   const Data& data() const { return *static_cast<Data*>(data_); }
 
   static uint32_t nextFrameSlot(Scope* start);
 
  public:
   uint32_t firstFrameSlot() const;
@@ -536,16 +542,23 @@ class FunctionScope : public Scope {
 
     void trace(JSTracer* trc);
   };
 
   static FunctionScope* create(JSContext* cx, Handle<Data*> data,
                                bool hasParameterExprs, bool needsEnvironment,
                                HandleFunction fun, HandleScope enclosing);
 
+  static bool prepareForScopeCreation(JSContext* cx,
+                                      MutableHandle<UniquePtr<Data>> data,
+                                      bool hasParameterExprs,
+                                      IsFieldInitializer isFieldInitializer,
+                                      bool needsEnvironment, HandleFunction fun,
+                                      MutableHandleShape envShape);
+
   static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope,
                               HandleFunction fun, HandleScope enclosing);
 
   template <XDRMode mode>
   static XDRResult XDR(XDRState<mode>* xdr, HandleFunction fun,
                        HandleScope enclosing, MutableHandleScope scope);
 
  private:
@@ -634,16 +647,22 @@ class VarScope : public Scope {
                        HandleScope enclosing, MutableHandleScope scope);
 
  private:
   static VarScope* createWithData(JSContext* cx, ScopeKind kind,
                                   MutableHandle<UniquePtr<Data>> data,
                                   uint32_t firstFrameSlot,
                                   bool needsEnvironment, HandleScope enclosing);
 
+  static bool prepareForScopeCreation(JSContext* cx, ScopeKind kind,
+                                      MutableHandle<UniquePtr<Data>> data,
+                                      uint32_t firstFrameSlot,
+                                      bool needsEnvironment,
+                                      MutableHandleShape envShape);
+
   Data& data() { return *static_cast<Data*>(data_); }
 
   const Data& data() const { return *static_cast<Data*>(data_); }
 
  public:
   uint32_t firstFrameSlot() const;
 
   uint32_t nextFrameSlot() const { return data().nextFrameSlot; }
@@ -806,16 +825,20 @@ class EvalScope : public Scope {
   static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind,
                        HandleScope enclosing, MutableHandleScope scope);
 
  private:
   static EvalScope* createWithData(JSContext* cx, ScopeKind kind,
                                    MutableHandle<UniquePtr<Data>> data,
                                    HandleScope enclosing);
 
+  static bool prepareForScopeCreation(JSContext* cx, ScopeKind scopeKind,
+                                      MutableHandle<UniquePtr<Data>> data,
+                                      MutableHandleShape envShape);
+
   Data& data() { return *static_cast<Data*>(data_); }
 
   const Data& data() const { return *static_cast<Data*>(data_); }
 
  public:
   // Starting a scope, the nearest var scope that a direct eval can
   // introduce vars on.
   static Scope* nearestVarScopeForDirectEval(Scope* scope);
@@ -893,16 +916,21 @@ class ModuleScope : public Scope {
                              HandleScope enclosing);
 
  private:
   static ModuleScope* createWithData(JSContext* cx,
                                      MutableHandle<UniquePtr<Data>> data,
                                      Handle<ModuleObject*> module,
                                      HandleScope enclosing);
 
+  static bool prepareForScopeCreation(JSContext* cx,
+                                      MutableHandle<UniquePtr<Data>> data,
+                                      HandleModuleObject module,
+                                      MutableHandleShape envShape);
+
   Data& data() { return *static_cast<Data*>(data_); }
 
   const Data& data() const { return *static_cast<Data*>(data_); }
 
  public:
   uint32_t nextFrameSlot() const { return data().nextFrameSlot; }
 
   ModuleObject* module() const { return data().module; }