Bug 901364 - Make operation callbacks runtime-wide. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Mon, 12 Aug 2013 12:54:50 -0700
changeset 155151 c698c9d89b9143aa8b4ff771e2e7266faba1e4f9
parent 155150 3f73532b694cffc2204bb7a4abee2df186e6f510
child 155152 72bc1aebb5d0e8e025ab8c57149949c167c3d823
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs901364
milestone26.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 901364 - Make operation callbacks runtime-wide. r=mrbkap
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/workers/RuntimeService.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/shell/js.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9514,24 +9514,25 @@ nsGlobalWindow::ShowSlowScriptDialog()
                          (nsIPrompt::BUTTON_TITLE_IS_STRING *
                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
 
   // Add a third button if necessary.
   if (debugPossible)
     buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
 
   // Null out the operation callback while we're re-entering JS here.
-  JSOperationCallback old = JS_SetOperationCallback(cx, nullptr);
+  JSRuntime* rt = JS_GetRuntime(cx);
+  JSOperationCallback old = JS_SetOperationCallback(rt, nullptr);
 
   // Open the dialog.
   rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
                          debugButton, neverShowDlg, &neverShowDlgChk,
                          &buttonPressed);
 
-  JS_SetOperationCallback(cx, old);
+  JS_SetOperationCallback(rt, old);
 
   if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
     return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;
   }
   if ((buttonPressed == 2) && debugPossible) {
     return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript;
   }
   JS_ClearPendingException(cx);
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -860,18 +860,16 @@ nsJSContext::nsJSContext(JSRuntime *aRun
     mDefaultJSOptions |= ::JS_GetOptions(mContext);
 
     // Make sure the new context gets the default context options
     ::JS_SetOptions(mContext, mDefaultJSOptions);
 
     // Watch for the JS boolean options
     Preferences::RegisterCallback(JSOptionChangedCallback,
                                   js_options_dot_str, this);
-
-    ::JS_SetOperationCallback(mContext, xpc::OperationCallback);
   }
   mIsInitialized = false;
   mScriptsEnabled = true;
   mModalStateDepth = 0;
   mProcessingScriptTag = false;
 }
 
 nsJSContext::~nsJSContext()
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -796,17 +796,17 @@ CreateJSContextForWorker(WorkerPrivate* 
     NS_WARNING("Could not create new context!");
     return nullptr;
   }
 
   JS_SetRuntimePrivate(aRuntime, aWorkerPrivate);
 
   JS_SetErrorReporter(workerCx, ErrorReporter);
 
-  JS_SetOperationCallback(workerCx, OperationCallback);
+  JS_SetOperationCallback(aRuntime, OperationCallback);
 
   js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
 
   JS_SetOptions(workerCx,
                 aWorkerPrivate->IsChromeWorker() ? settings.chrome.options :
                                                    settings.content.options);
 
   JS_SetJitHardening(aRuntime, settings.jitHardening);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5414,27 +5414,27 @@ JS_New(JSContext *cx, JSObject *ctorArg,
         }
         return NULL;
     }
 
     return &args.rval().toObject();
 }
 
 JS_PUBLIC_API(JSOperationCallback)
-JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
-{
-    JSOperationCallback old = cx->operationCallback;
-    cx->operationCallback = callback;
+JS_SetOperationCallback(JSRuntime *rt, JSOperationCallback callback)
+{
+    JSOperationCallback old = rt->operationCallback;
+    rt->operationCallback = callback;
     return old;
 }
 
 JS_PUBLIC_API(JSOperationCallback)
-JS_GetOperationCallback(JSContext *cx)
-{
-    return cx->operationCallback;
+JS_GetOperationCallback(JSRuntime *rt)
+{
+    return rt->operationCallback;
 }
 
 JS_PUBLIC_API(void)
 JS_TriggerOperationCallback(JSRuntime *rt)
 {
     rt->triggerOperationCallback();
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4324,20 +4324,20 @@ Call(JSContext *cx, jsval thisv, JSObjec
  * operation callbacks. The embedding should thus not rely on callbacks being
  * triggered through the external API only.
  *
  * Important note: Additional callbacks can occur inside the callback handler
  * if it re-enters the JS engine. The embedding must ensure that the callback
  * is disconnected before attempting such re-entry.
  */
 extern JS_PUBLIC_API(JSOperationCallback)
-JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback);
+JS_SetOperationCallback(JSRuntime *rt, JSOperationCallback callback);
 
 extern JS_PUBLIC_API(JSOperationCallback)
-JS_GetOperationCallback(JSContext *cx);
+JS_GetOperationCallback(JSRuntime *rt);
 
 extern JS_PUBLIC_API(void)
 JS_TriggerOperationCallback(JSRuntime *rt);
 
 extern JS_PUBLIC_API(bool)
 JS_IsRunning(JSContext *cx);
 
 /*
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1023,17 +1023,17 @@ js_InvokeOperationCallback(JSContext *cx
     ion::AttachFinishedCompilations(cx);
 #endif
 
     /*
      * Important: Additional callbacks can occur inside the callback handler
      * if it re-enters the JS engine. The embedding must ensure that the
      * callback is disconnected before attempting such re-entry.
      */
-    JSOperationCallback cb = cx->operationCallback;
+    JSOperationCallback cb = cx->runtime()->operationCallback;
     return !cb || cb(cx);
 }
 
 bool
 js_HandleExecutionInterrupt(JSContext *cx)
 {
     if (cx->runtime()->interrupt)
         return js_InvokeOperationCallback(cx);
@@ -1067,17 +1067,16 @@ JSContext::JSContext(JSRuntime *rt)
     options_(0),
     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
     resolvingList(NULL),
     generatingError(false),
     savedFrameChains_(),
     defaultCompartmentObject_(NULL),
     cycleDetectorSet(MOZ_THIS_IN_INITIALIZER_LIST()),
     errorReporter(NULL),
-    operationCallback(NULL),
     data(NULL),
     data2(NULL),
 #ifdef JS_THREADSAFE
     outstandingRequests(0),
 #endif
     resolveFlags(0),
     iterValue(MagicValue(JS_NO_ITER_VALUE)),
     jitIsBroken(false),
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -440,19 +440,16 @@ struct JSContext : public js::ExclusiveC
     void wrapPendingException();
 
     /* State for object and array toSource conversion. */
     js::ObjectSet       cycleDetectorSet;
 
     /* Per-context optional error reporter. */
     JSErrorReporter     errorReporter;
 
-    /* Branch callback. */
-    JSOperationCallback operationCallback;
-
     /* Client opaque pointers. */
     void                *data;
     void                *data2;
 
   public:
 
     /*
      * Return:
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -369,22 +369,16 @@ ShellOperationCallback(JSContext *cx)
     }
 
     if (!result && gExitCode == 0)
         gExitCode = EXITCODE_TIMEOUT;
 
     return result;
 }
 
-static void
-SetContextOptions(JSContext *cx)
-{
-    JS_SetOperationCallback(cx, ShellOperationCallback);
-}
-
 /*
  * Some UTF-8 files, notably those written using Notepad, have a Unicode
  * Byte-Order-Mark (BOM) as their first character. This is useless (byte-order
  * is meaningless for UTF-8) but causes a syntax error unless we skip it.
  */
 static void
 SkipUTF8BOM(FILE* file)
 {
@@ -567,18 +561,16 @@ Process(JSContext *cx, JSObject *obj_, c
             JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
                                  JSSMSG_CANT_OPEN, filename, strerror(errno));
             gExitCode = EXITCODE_FILE_NOT_FOUND;
             return;
         }
     }
     AutoCloseInputFile autoClose(file);
 
-    SetContextOptions(cx);
-
     if (!forceTTY && !isatty(fileno(file))) {
         // It's not interactive - just execute it.
         RunFile(cx, obj, filename, file, compileOnly);
     } else {
         // It's an interactive filehandle; drop into read-eval-print loop.
         ReadEvalPrintLoop(cx, obj, file, gOutFile, compileOnly);
     }
 }
@@ -4860,17 +4852,16 @@ NewContext(JSRuntime *rt)
     JSShellContextData *data = NewContextData();
     if (!data) {
         DestroyContext(cx, false);
         return NULL;
     }
 
     JS_SetContextPrivate(cx, data);
     JS_SetErrorReporter(cx, my_ErrorReporter);
-    SetContextOptions(cx);
     if (enableTypeInference)
         JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
     if (enableIon)
         JS_ToggleOptions(cx, JSOPTION_ION);
     if (enableBaseline)
         JS_ToggleOptions(cx, JSOPTION_BASELINE);
     if (enableAsmJS)
         JS_ToggleOptions(cx, JSOPTION_ASMJS);
@@ -5465,16 +5456,17 @@ main(int argc, char **argv, char **envp)
     JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
 #ifdef JSGC_GENERATIONAL
     if (op.getBoolOption("no-ggc"))
         JS::DisableGenerationalGC(rt);
 #endif
 
     JS_SetTrustedPrincipals(rt, &shellTrustedPrincipals);
     JS_SetSecurityCallbacks(rt, &securityCallbacks);
+    JS_SetOperationCallback(rt, ShellOperationCallback);
 
     JS_SetNativeStackQuota(rt, gMaxStackSize);
 
     if (!InitWatchdog(rt))
         return 1;
 
     cx = NewContext(rt);
     if (!cx)
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -94,16 +94,17 @@ PerThreadData::removeFromThreadList()
 {
     JS_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
     removeFrom(runtime_->threadList);
 }
 
 JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
   : mainThread(this),
     interrupt(0),
+    operationCallback(NULL),
 #ifdef JS_THREADSAFE
     operationCallbackLock(NULL),
 #ifdef DEBUG
     operationCallbackOwner(NULL),
 #endif
     exclusiveAccessLock(NULL),
     exclusiveAccessOwner(NULL),
     mainThreadHasExclusiveAccess(false),
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -688,16 +688,19 @@ struct JSRuntime : public JS::shadow::Ru
     mozilla::LinkedList<js::PerThreadData> threadList;
 
     /*
      * If non-zero, we were been asked to call the operation callback as soon
      * as possible.
      */
     volatile int32_t    interrupt;
 
+    /* Branch callback */
+    JSOperationCallback operationCallback;
+
 #ifdef JS_THREADSAFE
   private:
     /*
      * Lock taken when triggering the operation callback from another thread.
      * Protects all data that is touched in this process.
      */
     PRLock *operationCallbackLock;
 #ifdef DEBUG
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1461,20 +1461,18 @@ XPCShellErrorReporter(JSContext *cx, con
 
     // Delegate to the system error reporter for heavy lifting.
     xpc::SystemErrorReporterExternal(cx, message, rep);
 }
 
 static bool
 ContextCallback(JSContext *cx, unsigned contextOp)
 {
-    if (contextOp == JSCONTEXT_NEW) {
+    if (contextOp == JSCONTEXT_NEW)
         JS_SetErrorReporter(cx, XPCShellErrorReporter);
-        JS_SetOperationCallback(cx, XPCShellOperationCallback);
-    }
     return true;
 }
 
 static bool
 GetCurrentWorkingDirectory(nsAString& workingDirectory)
 {
 #if !defined(XP_WIN) && !defined(XP_UNIX)
     //XXX: your platform should really implement this
@@ -1637,16 +1635,21 @@ main(int argc, char **argv, char **envp)
 
         if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
             printf("failed to get JSRuntime from nsJSRuntimeService!\n");
             return 1;
         }
 
         rtsvc->RegisterContextCallback(ContextCallback);
 
+        // Override the default XPConnect operation callback. We could store the
+        // old one and restore it before shutting down, but there's not really a
+        // reason to bother.
+        JS_SetOperationCallback(rt, XPCShellOperationCallback);
+
         cx = JS_NewContext(rt, 8192);
         if (!cx) {
             printf("JS_NewContext failed!\n");
             return 1;
         }
 
         argc--;
         argv++;
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3732,69 +3732,49 @@ public:
         return mJSContext;
     }
 
     nsIPrincipal * GetPrincipal() { return mPrincipal; }
 
     NS_DECL_ISUPPORTS
 
 private:
-    static bool ContextHolderOperationCallback(JSContext *cx);
-
     JSContext* mJSContext;
-    JSContext* mOrigCx;
     nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 NS_IMPL_ISUPPORTS1(ContextHolder, nsIScriptObjectPrincipal)
 
 ContextHolder::ContextHolder(JSContext *aOuterCx,
                              HandleObject aSandbox,
                              nsIPrincipal *aPrincipal)
     : mJSContext(JS_NewContext(JS_GetRuntime(aOuterCx), 1024)),
-      mOrigCx(aOuterCx),
       mPrincipal(aPrincipal)
 {
     if (mJSContext) {
         bool isChrome;
         DebugOnly<nsresult> rv = XPCWrapper::GetSecurityManager()->
                                    IsSystemPrincipal(mPrincipal, &isChrome);
         MOZ_ASSERT(NS_SUCCEEDED(rv));
 
         JS_SetOptions(mJSContext,
                       JS_GetOptions(mJSContext) |
                       JSOPTION_DONT_REPORT_UNCAUGHT |
                       JSOPTION_PRIVATE_IS_NSISUPPORTS);
         js::SetDefaultObjectForContext(mJSContext, aSandbox);
         JS_SetContextPrivate(mJSContext, this);
-        JS_SetOperationCallback(mJSContext, ContextHolderOperationCallback);
     }
 }
 
 ContextHolder::~ContextHolder()
 {
     if (mJSContext)
         JS_DestroyContextNoGC(mJSContext);
 }
 
-bool
-ContextHolder::ContextHolderOperationCallback(JSContext *cx)
-{
-    ContextHolder* thisObject =
-        static_cast<ContextHolder*>(JS_GetContextPrivate(cx));
-    NS_ASSERTION(thisObject, "How did that happen?");
-
-    JSContext *origCx = thisObject->mOrigCx;
-    JSOperationCallback callback = JS_GetOperationCallback(origCx);
-    bool ok = true;
-    if (callback)
-        ok = callback(origCx);
-    return ok;
-}
-
 /***************************************************************************/
 
 /* void evalInSandbox(in AString source, in nativeobj sandbox); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::EvalInSandbox(const nsAString& source,
                                      const JS::Value& sandboxVal,
                                      const JS::Value& version,
                                      const JS::Value& filenameVal,
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1279,22 +1279,16 @@ XPCJSRuntime::OperationCallback(JSContex
     // machinery with a pref of the user opted out of future slow-script dialogs.
     self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
     if (response == nsGlobalWindow::AlwaysContinueSlowScript)
         Preferences::SetInt(prefName, 0);
 
     return true;
 }
 
-bool
-xpc::OperationCallback(JSContext *cx)
-{
-    return XPCJSRuntime::OperationCallback(cx);
-}
-
 size_t
 XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
     n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
     n += mIID2NativeInterfaceMap->SizeOfIncludingThis(mallocSizeOf);
     n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
@@ -2934,16 +2928,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
 #endif
 #ifdef MOZ_ENABLE_PROFILER_SPS
     if (PseudoStack *stack = mozilla_get_pseudo_stack())
         stack->sampleRuntime(runtime);
 #endif
     JS_SetAccumulateTelemetryCallback(runtime, AccumulateTelemetryCallback);
     js::SetActivityCallback(runtime, ActivityCallback, this);
     js::SetCTypesActivityCallback(runtime, CTypesActivityCallback);
+    JS_SetOperationCallback(runtime, OperationCallback);
 
     // The JS engine needs to keep the source code around in order to implement
     // Function.prototype.toSource(). It'd be nice to not have to do this for
     // chrome code and simply stub out requests for source on it. Life is not so
     // easy, unfortunately. Nobody relies on chrome toSource() working in core
     // browser code, but chrome tests use it. The worst offenders are addons,
     // which like to monkeypatch chrome functions by calling toSource() on them
     // and using regular expressions to modify them. We avoid keeping most browser
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -62,20 +62,16 @@ GetXBLScope(JSContext *cx, JSObject *con
 // Returns whether XBL scopes have been explicitly disabled for code running
 // in this compartment. See the comment around mAllowXBLScope.
 bool
 AllowXBLScope(JSCompartment *c);
 
 bool
 IsSandboxPrototypeProxy(JSObject *obj);
 
-// XXXbholley - Temporary - goes away in future patches.
-bool
-OperationCallback(JSContext* cx);
-
 } /* namespace xpc */
 
 #define XPCONNECT_GLOBAL_FLAGS                                                \
     JSCLASS_DOM_GLOBAL | JSCLASS_HAS_PRIVATE |                                \
     JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_IMPLEMENTS_BARRIERS |            \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(2)
 
 void