Bug 937317 - Implement basic script settings stack machinery. r=bz
☠☠ backed out by 1510de2380a6 ☠ ☠
authorBobby Holley <bobbyholley@gmail.com>
Thu, 05 Dec 2013 21:34:16 -0800
changeset 174779 004fa11e352a30a170ec7d1a4a6b1fd3e97ede14
parent 174778 f65970fe598fdfa0bb069c6d7d62761a23905259
child 174780 1f45be0c248554d0ed70b47a3de4e6302573d281
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs937317
milestone28.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 937317 - Implement basic script settings stack machinery. r=bz
dom/base/ScriptSettings.cpp
dom/base/ScriptSettings.h
mfbt/ThreadLocal.h
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -1,23 +1,101 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 // vim: ft=cpp tw=78 sw=2 et ts=2
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/ThreadLocal.h"
+#include "mozilla/Assertions.h"
 
+#include "jsapi.h"
+#include "nsIGlobalObject.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsContentUtils.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
+class ScriptSettingsStack;
+static mozilla::ThreadLocal<ScriptSettingsStack*> sScriptSettingsTLS;
+
+ScriptSettingsStackEntry ScriptSettingsStackEntry::SystemSingleton;
+
+class ScriptSettingsStack {
+public:
+  static ScriptSettingsStack& Ref() {
+    return *sScriptSettingsTLS.get();
+  }
+  ScriptSettingsStack() {};
+
+  void Push(ScriptSettingsStackEntry* aSettings) {
+    // The bottom-most entry must always be a candidate entry point.
+    MOZ_ASSERT_IF(mStack.Length() == 0 || mStack.LastElement()->IsSystemSingleton(),
+                  aSettings->mIsCandidateEntryPoint);
+    mStack.AppendElement(aSettings);
+  }
+
+  void PushSystem() {
+    mStack.AppendElement(&ScriptSettingsStackEntry::SystemSingleton);
+  }
+
+  void Pop() {
+    MOZ_ASSERT(mStack.Length() > 0);
+    mStack.RemoveElementAt(mStack.Length() - 1);
+  }
+
+  nsIGlobalObject* Incumbent() {
+    if (!mStack.Length()) {
+      return nullptr;
+    }
+    return mStack.LastElement()->mGlobalObject;
+  }
+
+  nsIGlobalObject* EntryPoint() {
+    if (!mStack.Length())
+      return nullptr;
+    for (int i = mStack.Length() - 1; i >= 0; --i) {
+      if (mStack[i]->mIsCandidateEntryPoint) {
+        return mStack[i]->mGlobalObject;
+      }
+    }
+    MOZ_ASSUME_UNREACHABLE();
+  }
+
+private:
+  // These pointers are caller-owned.
+  nsTArray<ScriptSettingsStackEntry*> mStack;
+};
+
+void
+InitScriptSettings()
+{
+  if (!sScriptSettingsTLS.initialized()) {
+    bool success = sScriptSettingsTLS.init();
+    if (!success) {
+      MOZ_CRASH();
+    }
+  }
+
+  ScriptSettingsStack* ptr = new ScriptSettingsStack();
+  sScriptSettingsTLS.set(ptr);
+}
+
+void DestroyScriptSettings()
+{
+  ScriptSettingsStack* ptr = sScriptSettingsTLS.get();
+  MOZ_ASSERT(ptr);
+  sScriptSettingsTLS.set(nullptr);
+  delete ptr;
+}
+
 AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
                                  bool aIsMainThread,
                                  JSContext* aCx)
 {
   MOZ_ASSERT(aGlobalObject);
   if (!aCx) {
     // If the caller didn't provide a cx, hunt one down. This isn't exactly
     // fast, but the callers that care about performance can pass an explicit
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -6,25 +6,62 @@
 
 /* Utilities for managing the script settings object stack defined in webapps */
 
 #ifndef mozilla_dom_ScriptSettings_h
 #define mozilla_dom_ScriptSettings_h
 
 #include "nsCxPusher.h"
 #include "MainThreadUtils.h"
+#include "nsIGlobalObject.h"
 
 #include "mozilla/Maybe.h"
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 /*
+ * System-wide setup/teardown routines. Init and Destroy should be invoked
+ * once each, at startup and shutdown (respectively).
+ */
+void InitScriptSettings();
+void DestroyScriptSettings();
+
+struct ScriptSettingsStackEntry {
+  nsCOMPtr<nsIGlobalObject> mGlobalObject;
+  bool mIsCandidateEntryPoint;
+
+  ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate)
+    : mGlobalObject(aGlobal)
+    , mIsCandidateEntryPoint(aCandidate)
+  {
+    MOZ_ASSERT(mGlobalObject);
+    MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
+               "Must have an actual JS global for the duration on the stack");
+    MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
+               "No outer windows allowed");
+  }
+
+  ~ScriptSettingsStackEntry() {
+    // We must have an actual JS global for the entire time this is on the stack.
+    MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
+  }
+
+  bool IsSystemSingleton() { return this == &SystemSingleton; }
+  static ScriptSettingsStackEntry SystemSingleton;
+
+private:
+  ScriptSettingsStackEntry() : mGlobalObject(nullptr)
+                             , mIsCandidateEntryPoint(true)
+  {}
+};
+
+/*
  * A class that represents a new script entry point.
  */
 class AutoEntryScript {
 public:
   AutoEntryScript(nsIGlobalObject* aGlobalObject,
                   bool aIsMainThread = NS_IsMainThread(),
                   // Note: aCx is mandatory off-main-thread.
                   JSContext* aCx = nullptr);
--- a/mfbt/ThreadLocal.h
+++ b/mfbt/ThreadLocal.h
@@ -49,17 +49,20 @@ typedef sig_atomic_t sig_safe_t;
  *
  * Only static-storage-duration (e.g. global variables, or static class members)
  * objects of this class should be instantiated. This class relies on
  * zero-initialization, which is implicit for static-storage-duration objects.
  * It doesn't have a custom default constructor, to avoid static initializers.
  *
  * API usage:
  *
- * // Create a TLS item
+ * // Create a TLS item.
+ * //
+ * // Note that init() should be invoked exactly once, before any usage of set()
+ * // or get().
  * mozilla::ThreadLocal<int> tlsKey;
  * if (!tlsKey.init()) {
  *   // deal with the error
  * }
  *
  * // Set the TLS value
  * tlsKey.set(123);
  *
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -54,16 +54,17 @@
 // To improve debugging, if WantAllTraces() is true all JS objects are
 // traversed.
 
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include <algorithm>
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMJSClass.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "jsprf.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsIException.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
@@ -436,16 +437,18 @@ static const JSZoneParticipant sJSZoneCy
 
 CycleCollectedJSRuntime::CycleCollectedJSRuntime(uint32_t aMaxbytes,
                                                  JSUseHelperThreads aUseHelperThreads)
   : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal),
     mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal),
     mJSRuntime(nullptr),
     mJSHolders(512)
 {
+  mozilla::dom::InitScriptSettings();
+
   mJSRuntime = JS_NewRuntime(aMaxbytes, aUseHelperThreads);
   if (!mJSRuntime) {
     MOZ_CRASH();
   }
 
   if (!JS_AddExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this)) {
     MOZ_CRASH();
   }
@@ -465,16 +468,18 @@ CycleCollectedJSRuntime::~CycleCollected
   MOZ_ASSERT(!mDeferredSupports.Length());
 
   // Clear mPendingException first, since it might be cycle collected.
   mPendingException = nullptr;
 
   JS_DestroyRuntime(mJSRuntime);
   mJSRuntime = nullptr;
   nsCycleCollector_forgetJSRuntime();
+
+  mozilla::dom::DestroyScriptSettings();
 }
 
 size_t
 CycleCollectedJSRuntime::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
 
   // nullptr for the second arg;  we're not measuring anything hanging off the