Bug 1257919 part 6. Make the filename getter on JSStackFrame take an explicit JSContext. r=khuey
☠☠ backed out by 692110787614 ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 22 Mar 2016 13:50:31 -0400
changeset 289879 6e95ee3cd4c6f40c3fa28e6bcd36e814e74701b0
parent 289878 83dfa9e03d0e2299e1acf4fc04dbd0119c7605ec
child 289880 c4faeb0be959d57b19477286b691bce439a62a1e
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1257919
milestone48.0a1
Bug 1257919 part 6. Make the filename getter on JSStackFrame take an explicit JSContext. r=khuey
dom/base/Console.cpp
dom/base/DOMException.cpp
dom/base/nsHostObjectProtocolHandler.cpp
dom/bindings/Bindings.conf
dom/bindings/Exceptions.cpp
dom/workers/ServiceWorkerEvents.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
security/sandbox/linux/glue/SandboxCrash.cpp
xpcom/base/nsIException.idl
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -1028,22 +1028,22 @@ Console::NoopMethod()
 {
   AssertIsOnOwningThread();
 
   // Nothing to do.
 }
 
 static
 nsresult
-StackFrameToStackEntry(nsIStackFrame* aStackFrame,
+StackFrameToStackEntry(JSContext* aCx, nsIStackFrame* aStackFrame,
                        ConsoleStackEntry& aStackEntry)
 {
   MOZ_ASSERT(aStackFrame);
 
-  nsresult rv = aStackFrame->GetFilename(aStackEntry.mFilename);
+  nsresult rv = aStackFrame->GetFilename(aCx, aStackEntry.mFilename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t lineNumber;
   rv = aStackFrame->GetLineNumber(&lineNumber);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aStackEntry.mLineNumber = lineNumber;
 
@@ -1064,23 +1064,24 @@ StackFrameToStackEntry(nsIStackFrame* aS
   }
 
   aStackEntry.mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
   return NS_OK;
 }
 
 static
 nsresult
-ReifyStack(nsIStackFrame* aStack, nsTArray<ConsoleStackEntry>& aRefiedStack)
+ReifyStack(JSContext* aCx, nsIStackFrame* aStack,
+           nsTArray<ConsoleStackEntry>& aRefiedStack)
 {
   nsCOMPtr<nsIStackFrame> stack(aStack);
 
   while (stack) {
     ConsoleStackEntry& data = *aRefiedStack.AppendElement();
-    nsresult rv = StackFrameToStackEntry(stack, data);
+    nsresult rv = StackFrameToStackEntry(aCx, stack, data);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIStackFrame> caller;
     rv = stack->GetCaller(getter_AddRefs(caller));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!caller) {
       rv = stack->GetAsyncCaller(getter_AddRefs(caller));
@@ -1119,30 +1120,30 @@ Console::Method(JSContext* aCx, MethodNa
   }
 
   uint32_t maxDepth = ShouldIncludeStackTrace(aMethodName) ?
                       DEFAULT_MAX_STACKTRACE_DEPTH : 1;
   nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, maxDepth);
 
   if (stack) {
     callData->mTopStackFrame.emplace();
-    nsresult rv = StackFrameToStackEntry(stack,
+    nsresult rv = StackFrameToStackEntry(aCx, stack,
                                          *callData->mTopStackFrame);
     if (NS_FAILED(rv)) {
       return;
     }
   }
 
   if (NS_IsMainThread()) {
     callData->mStack = stack;
   } else {
     // nsIStackFrame is not threadsafe, so we need to snapshot it now,
     // before we post our runnable to the main thread.
     callData->mReifiedStack.emplace();
-    nsresult rv = ReifyStack(stack, *callData->mReifiedStack);
+    nsresult rv = ReifyStack(aCx, stack, *callData->mReifiedStack);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   }
 
   DOMHighResTimeStamp monotonicTimer;
 
   // Monotonic timer for 'time' and 'timeEnd'
@@ -1265,17 +1266,17 @@ LazyStackGetter(JSContext* aCx, unsigned
   if (v.isUndefined()) {
     // Already reified.
     args.rval().set(js::GetFunctionNativeReserved(callee, SLOT_STACKOBJ));
     return true;
   }
 
   nsIStackFrame* stack = reinterpret_cast<nsIStackFrame*>(v.toPrivate());
   nsTArray<ConsoleStackEntry> reifiedStack;
-  nsresult rv = ReifyStack(stack, reifiedStack);
+  nsresult rv = ReifyStack(aCx, stack, reifiedStack);
   if (NS_FAILED(rv)) {
     Throw(aCx, rv);
     return false;
   }
 
   JS::Rooted<JS::Value> stackVal(aCx);
   if (!ToJSValue(aCx, reifiedStack, &stackVal)) {
     return false;
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -303,22 +303,22 @@ Exception::GetName(nsACString& aName)
       aName.Assign(name);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Exception::GetFilename(nsAString& aFilename)
+Exception::GetFilename(JSContext* aCx, nsAString& aFilename)
 {
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (mLocation) {
-    return mLocation->GetFilename(aFilename);
+    return mLocation->GetFilename(aCx, aFilename);
   }
 
   aFilename.Assign(mFilename);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Exception::GetLineNumber(uint32_t *aLineNumber)
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -206,21 +206,26 @@ class BlobURLsReporter final : public ns
 
     nsAutoCString origin;
     nsCOMPtr<nsIURI> principalURI;
     if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI)))
         && principalURI) {
       principalURI->GetPrePath(origin);
     }
 
+    // If we got a frame, we better have a current JSContext.  This is cheating
+    // a bit; ideally we'd have our caller pass in a JSContext, or have
+    // GetCurrentJSStack() hand out the JSContext it found.
+    JSContext* cx = frame ? nsContentUtils::GetCurrentJSContext() : nullptr;
+
     for (uint32_t i = 0; frame; ++i) {
       nsString fileNameUTF16;
       int32_t lineNumber = 0;
 
-      frame->GetFilename(fileNameUTF16);
+      frame->GetFilename(cx, fileNameUTF16);
       frame->GetLineNumber(&lineNumber);
 
       if (!fileNameUTF16.IsEmpty()) {
         NS_ConvertUTF16toUTF8 fileName(fileNameUTF16);
         stack += "js(";
         if (!origin.IsEmpty()) {
           // Make the file name root-relative for conciseness if possible.
           const char* originData;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -404,16 +404,17 @@ DOMInterfaces = {
 'DominatorTree': {
     'nativeType': 'mozilla::devtools::DominatorTree'
 },
 
 'DOMException': {
     'binaryNames': {
         'message': 'messageMoz',
     },
+    'implicitJSContext': [ 'filename' ],
 },
 
 'DOMMatrixReadOnly': {
     'headerFile': 'mozilla/dom/DOMMatrix.h',
     'concrete': False,
 },
 
 'DOMPointReadOnly': {
@@ -473,17 +474,17 @@ DOMInterfaces = {
     'jsImplParent': 'mozilla::DOMEventTargetHelper'
 },
 
 'Exception': {
     'headerFile': 'mozilla/dom/DOMException.h',
     'binaryNames': {
         'message': 'messageMoz',
     },
-    'implicitJSContext': [ '__stringifier' ],
+    'implicitJSContext': [ '__stringifier', 'filename' ],
 },
 
 'ExtendableEvent': {
     'headerFile': 'mozilla/dom/ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::ExtendableEvent',
     'implicitJSContext': [ 'waitUntil' ],
 },
 
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -173,24 +173,17 @@ CreateException(JSContext* aCx, nsresult
     new Exception(aMessage, aRv, EmptyCString(), nullptr, nullptr);
   return exception.forget();
 }
 
 already_AddRefed<nsIStackFrame>
 GetCurrentJSStack(int32_t aMaxDepth)
 {
   // is there a current context available?
-  JSContext* cx = nullptr;
-
-  if (NS_IsMainThread()) {
-    MOZ_ASSERT(nsContentUtils::XPConnect());
-    cx = nsContentUtils::GetCurrentJSContext();
-  } else {
-    cx = workers::GetCurrentThreadJSContext();
-  }
+  JSContext* cx = nsContentUtils::GetCurrentJSContextForThread();
 
   if (!cx || !js::GetContextCompartment(cx)) {
     return nullptr;
   }
 
   return exceptions::CreateStack(cx, aMaxDepth);
 }
 
@@ -338,36 +331,36 @@ GetValueIfNotCached(JSContext* aCx, JSOb
   }
 
   *aUseCachedValue = false;
   JS::ExposeObjectToActiveJS(stack);
 
   aPropGetter(aCx, stack, aValue, JS::SavedFrameSelfHosted::Exclude);
 }
 
-NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
+NS_IMETHODIMP JSStackFrame::GetFilename(JSContext* aCx, nsAString& aFilename)
 {
   if (!mStack) {
     aFilename.Truncate();
     return NS_OK;
   }
 
-  ThreadsafeAutoJSContext cx;
-  JS::Rooted<JSString*> filename(cx);
+  JS::Rooted<JSString*> filename(aCx);
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameSource, mFilenameInitialized,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameSource,
+                      mFilenameInitialized,
                       &canCache, &useCachedValue, &filename);
   if (useCachedValue) {
     aFilename = mFilename;
     return NS_OK;
   }
 
   nsAutoJSString str;
-  if (!str.init(cx, filename)) {
-    JS_ClearPendingException(cx);
+  if (!str.init(aCx, filename)) {
+    JS_ClearPendingException(aCx);
     aFilename.Truncate();
     return NS_OK;
   }
   aFilename = str;
 
   if (canCache) {
     mFilename = str;
     mFilenameInitialized = true;
@@ -638,17 +631,17 @@ NS_IMETHODIMP JSStackFrame::GetNativeSav
   return NS_OK;
 }
 
 NS_IMETHODIMP JSStackFrame::ToString(JSContext* aCx, nsACString& _retval)
 {
   _retval.Truncate();
 
   nsString filename;
-  nsresult rv = GetFilename(filename);
+  nsresult rv = GetFilename(aCx, filename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (filename.IsEmpty()) {
     filename.AssignLiteral("<unknown filename>");
   }
 
   nsString funname;
   rv = GetName(funname);
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -423,17 +423,17 @@ ExtractErrorValues(JSContext* aCx, JS::H
       }
       aMessageOut.Assign(report->mErrorMsg);
     }
 
     // Next, try to unwrap the rejection value as a DOMException.
     else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
 
       nsAutoString filename;
-      domException->GetFilename(filename);
+      domException->GetFilename(aCx, filename);
       if (!filename.IsEmpty()) {
         CopyUTF16toUTF8(filename, aSourceSpecOut);
         *aLineOut = domException->LineNumber();
         *aColumnOut = domException->ColumnNumber();
       }
 
       domException->GetName(aMessageOut);
       aMessageOut.AppendLiteral(": ");
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1574,17 +1574,17 @@ AssembleSandboxMemoryReporterName(JSCont
     // Get the current source info from xpc.
     nsCOMPtr<nsIStackFrame> frame;
     xpc->GetCurrentJSStack(getter_AddRefs(frame));
 
     // Append the caller's location information.
     if (frame) {
         nsString location;
         int32_t lineNumber = 0;
-        frame->GetFilename(location);
+        frame->GetFilename(cx, location);
         frame->GetLineNumber(&lineNumber);
 
         sandboxName.AppendLiteral(" (from: ");
         sandboxName.Append(NS_ConvertUTF16toUTF8(location));
         sandboxName.Append(':');
         sandboxName.AppendInt(lineNumber);
         sandboxName.Append(')');
     }
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2317,17 +2317,17 @@ nsXPCComponents_Utils::ReportError(Handl
     }
 
     nsString fileName;
     int32_t lineNo = 0;
 
     if (!scripterr) {
         nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
         if (frame) {
-            frame->GetFilename(fileName);
+            frame->GetFilename(cx, fileName);
             frame->GetLineNumber(&lineNo);
             JS::Rooted<JS::Value> stack(cx);
             nsresult rv = frame->GetNativeSavedFrame(&stack);
             if (NS_SUCCEEDED(rv) && stack.isObject()) {
               JS::Rooted<JSObject*> stackObj(cx, &stack.toObject());
               scripterr = new nsScriptErrorWithStack(stackObj);
             }
         }
@@ -2424,17 +2424,17 @@ nsXPCComponents_Utils::EvalInSandbox(con
         nsresult rv;
         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
         NS_ENSURE_SUCCESS(rv, rv);
 
         nsCOMPtr<nsIStackFrame> frame;
         xpc->GetCurrentJSStack(getter_AddRefs(frame));
         if (frame) {
             nsString frameFile;
-            frame->GetFilename(frameFile);
+            frame->GetFilename(cx, frameFile);
             CopyUTF16toUTF8(frameFile, filename);
             frame->GetLineNumber(&lineNo);
         }
     }
 
     return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo,
                               jsVersion, retval);
 }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -915,17 +915,17 @@ nsXPCWrappedJSClass::CheckForException(X
                                 nsCOMPtr<nsIStackFrame> location;
                                 xpc_exception->
                                     GetLocation(getter_AddRefs(location));
                                 if (location) {
                                     // Get line number w/o checking; 0 is ok.
                                     location->GetLineNumber(&lineNumber);
 
                                     // get a filename.
-                                    rv = location->GetFilename(sourceName);
+                                    rv = location->GetFilename(cx, sourceName);
                                 }
 
                                 rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(newMessage),
                                                                    sourceName,
                                                                    EmptyString(),
                                                                    lineNumber, 0, 0,
                                                                    "XPConnect JavaScript",
                                                                    nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
--- a/security/sandbox/linux/glue/SandboxCrash.cpp
+++ b/security/sandbox/linux/glue/SandboxCrash.cpp
@@ -40,23 +40,27 @@ SandboxLogJSStack(void)
     return;
   }
   if (!nsContentUtils::XPConnect()) {
     // There is no content (e.g., the process is a media plugin), in
     // which case this will probably crash and definitely not work.
     return;
   }
   nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
+  // If we got a stack, we must have a current JSContext.  This is icky.  :(
+  // Would be better if GetCurrentJSStack() handed out the JSContext it ended up
+  // using or something.
+  JSContext* cx = frame ? nsContentUtils::GetCurrentJSContext() : nullptr;
   for (int i = 0; frame != nullptr; ++i) {
     nsAutoString fileName, funName;
     int32_t lineNumber;
 
     // Don't stop unwinding if an attribute can't be read.
     fileName.SetIsVoid(true);
-    Unused << frame->GetFilename(fileName);
+    Unused << frame->GetFilename(cx, fileName);
     lineNumber = 0;
     Unused << frame->GetLineNumber(&lineNumber);
     funName.SetIsVoid(true);
     Unused << frame->GetName(funName);
 
     if (!funName.IsVoid() || !fileName.IsVoid()) {
       SANDBOX_LOG_ERROR("JS frame %d: %s %s line %d", i,
                         funName.IsVoid() ?
--- a/xpcom/base/nsIException.idl
+++ b/xpcom/base/nsIException.idl
@@ -11,16 +11,17 @@
 #include "nsISupports.idl"
 
 [scriptable, builtinclass, uuid(28bfb2a2-5ea6-4738-918b-049dc4d51f0b)]
 interface nsIStackFrame : nsISupports
 {
     // see nsIProgrammingLanguage for list of language consts
     readonly attribute uint32_t                language;
     readonly attribute AUTF8String             languageName;
+    [implicit_jscontext]
     readonly attribute AString                 filename;
     readonly attribute AString                 name;
     // Valid line numbers begin at '1'. '0' indicates unknown.
     readonly attribute int32_t                 lineNumber;
     readonly attribute int32_t                 columnNumber;
     readonly attribute AUTF8String             sourceLine;
     readonly attribute AString                 asyncCause;
     readonly attribute nsIStackFrame           asyncCaller;
@@ -52,16 +53,17 @@ interface nsIException : nsISupports
     // Filename location.  This is the location that caused the
     // error, which may or may not be a source file location.
     // For example, standard language errors would generally have
     // the same location as their top stack entry.  File
     // parsers may put the location of the file they were parsing,
     // etc.
 
     // null indicates "no data"
+    [implicit_jscontext]
     readonly attribute AString                 filename;
     // Valid line numbers begin at '1'. '0' indicates unknown.
     readonly attribute uint32_t                lineNumber;
     // Valid column numbers begin at 0.
     // We don't have an unambiguous indicator for unknown.
     readonly attribute uint32_t                columnNumber;
 
     // A stack trace, if available.