LCOV - code coverage report
Current view: top level - dom/bindings - Exceptions.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 140 316 44.3 %
Date: 2017-07-14 16:53:18 Functions: 28 43 65.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/Exceptions.h"
       8             : 
       9             : #include "js/GCAPI.h"
      10             : #include "js/TypeDecls.h"
      11             : #include "jsapi.h"
      12             : #include "jsprf.h"
      13             : #include "mozilla/CycleCollectedJSContext.h"
      14             : #include "mozilla/dom/BindingUtils.h"
      15             : #include "mozilla/dom/DOMException.h"
      16             : #include "mozilla/dom/ScriptSettings.h"
      17             : #include "nsIProgrammingLanguage.h"
      18             : #include "nsPIDOMWindow.h"
      19             : #include "nsServiceManagerUtils.h"
      20             : #include "nsThreadUtils.h"
      21             : #include "XPCWrapper.h"
      22             : #include "WorkerPrivate.h"
      23             : #include "nsContentUtils.h"
      24             : 
      25             : namespace mozilla {
      26             : namespace dom {
      27             : 
      28             : // Throw the given exception value if it's safe.  If it's not safe, then
      29             : // synthesize and throw a new exception value for NS_ERROR_UNEXPECTED.  The
      30             : // incoming value must be in the compartment of aCx.  This function guarantees
      31             : // that an exception is pending on aCx when it returns.
      32             : static void
      33        1979 : ThrowExceptionValueIfSafe(JSContext* aCx, JS::Handle<JS::Value> exnVal,
      34             :                           nsIException* aOriginalException)
      35             : {
      36        1979 :   MOZ_ASSERT(aOriginalException);
      37             : 
      38        1979 :   if (!exnVal.isObject()) {
      39           0 :     JS_SetPendingException(aCx, exnVal);
      40           0 :     return;
      41             :   }
      42             : 
      43        1979 :   JS::Rooted<JSObject*> exnObj(aCx, &exnVal.toObject());
      44        1979 :   MOZ_ASSERT(js::IsObjectInContextCompartment(exnObj, aCx),
      45             :              "exnObj needs to be in the right compartment for the "
      46             :              "CheckedUnwrap thing to make sense");
      47             : 
      48        1979 :   if (js::CheckedUnwrap(exnObj)) {
      49             :     // This is an object we're allowed to work with, so just go ahead and throw
      50             :     // it.
      51        1979 :     JS_SetPendingException(aCx, exnVal);
      52        1979 :     return;
      53             :   }
      54             : 
      55             :   // We could probably Throw(aCx, NS_ERROR_UNEXPECTED) here, and it would do the
      56             :   // right thing due to there not being an existing exception on the runtime at
      57             :   // this point, but it's clearer to explicitly do the thing we want done.  This
      58             :   // is also why we don't just call ThrowExceptionObject on the Exception we
      59             :   // create: it would do the right thing, but that fact is not obvious.
      60             :   RefPtr<Exception> syntheticException =
      61           0 :     CreateException(NS_ERROR_UNEXPECTED);
      62           0 :   JS::Rooted<JS::Value> syntheticVal(aCx);
      63           0 :   if (!GetOrCreateDOMReflector(aCx, syntheticException, &syntheticVal)) {
      64           0 :     return;
      65             :   }
      66           0 :   MOZ_ASSERT(syntheticVal.isObject() &&
      67             :              !js::IsWrapper(&syntheticVal.toObject()),
      68             :              "Must have a reflector here, not a wrapper");
      69           0 :   JS_SetPendingException(aCx, syntheticVal);
      70             : }
      71             : 
      72             : void
      73           0 : ThrowExceptionObject(JSContext* aCx, nsIException* aException)
      74             : {
      75             :   // See if we really have an Exception.
      76           0 :   nsCOMPtr<Exception> exception = do_QueryInterface(aException);
      77           0 :   if (exception) {
      78           0 :     ThrowExceptionObject(aCx, exception);
      79           0 :     return;
      80             :   }
      81             : 
      82             :   // We only have an nsIException (probably an XPCWrappedJS).  Fall back on old
      83             :   // wrapping.
      84           0 :   MOZ_ASSERT(NS_IsMainThread());
      85             : 
      86           0 :   JS::Rooted<JS::Value> val(aCx);
      87           0 :   if (!WrapObject(aCx, aException, &NS_GET_IID(nsIException), &val)) {
      88           0 :     return;
      89             :   }
      90             : 
      91           0 :   ThrowExceptionValueIfSafe(aCx, val, aException);
      92             : }
      93             : 
      94             : void
      95        1979 : ThrowExceptionObject(JSContext* aCx, Exception* aException)
      96             : {
      97        3958 :   JS::Rooted<JS::Value> thrown(aCx);
      98             : 
      99             :   // If we stored the original thrown JS value in the exception
     100             :   // (see XPCConvert::ConstructException) and we are in a web context
     101             :   // (i.e., not chrome), rethrow the original value. This only applies to JS
     102             :   // implemented components so we only need to check for this on the main
     103             :   // thread.
     104        1979 :   if (NS_IsMainThread() && !nsContentUtils::IsCallerChrome() &&
     105           0 :       aException->StealJSVal(thrown.address())) {
     106             :     // Now check for the case when thrown is a number which matches
     107             :     // aException->GetResult().  This would indicate that what actually got
     108             :     // thrown was an nsresult value.  In that situation, we should go back
     109             :     // through dom::Throw with that nsresult value, because it will make sure to
     110             :     // create the right sort of Exception or DOMException, with the right
     111             :     // global.
     112           0 :     if (thrown.isNumber()) {
     113             :       nsresult exceptionResult;
     114           0 :       if (NS_SUCCEEDED(aException->GetResult(&exceptionResult)) &&
     115           0 :           double(exceptionResult) == thrown.toNumber()) {
     116           0 :         Throw(aCx, exceptionResult);
     117           0 :         return;
     118             :       }
     119             :     }
     120           0 :     if (!JS_WrapValue(aCx, &thrown)) {
     121           0 :       return;
     122             :     }
     123           0 :     ThrowExceptionValueIfSafe(aCx, thrown, aException);
     124           0 :     return;
     125             :   }
     126             : 
     127        1979 :   if (!GetOrCreateDOMReflector(aCx, aException, &thrown)) {
     128           0 :     return;
     129             :   }
     130             : 
     131        1979 :   ThrowExceptionValueIfSafe(aCx, thrown, aException);
     132             : }
     133             : 
     134             : bool
     135        1979 : Throw(JSContext* aCx, nsresult aRv, const nsACString& aMessage)
     136             : {
     137        1979 :   if (aRv == NS_ERROR_UNCATCHABLE_EXCEPTION) {
     138             :     // Nuke any existing exception on aCx, to make sure we're uncatchable.
     139           0 :     JS_ClearPendingException(aCx);
     140           0 :     return false;
     141             :   }
     142             : 
     143        1979 :   if (JS_IsExceptionPending(aCx)) {
     144             :     // Don't clobber the existing exception.
     145           0 :     return false;
     146             :   }
     147             : 
     148        1979 :   CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
     149        3958 :   nsCOMPtr<nsIException> existingException = context->GetPendingException();
     150             :   // Make sure to clear the pending exception now.  Either we're going to reuse
     151             :   // it (and we already grabbed it), or we plan to throw something else and this
     152             :   // pending exception is no longer relevant.
     153        1979 :   context->SetPendingException(nullptr);
     154             : 
     155             :   // Ignore the pending exception if we have a non-default message passed in.
     156        1979 :   if (aMessage.IsEmpty() && existingException) {
     157             :     nsresult nr;
     158           0 :     if (NS_SUCCEEDED(existingException->GetResult(&nr)) &&
     159           0 :         aRv == nr) {
     160             :       // Reuse the existing exception.
     161           0 :       ThrowExceptionObject(aCx, existingException);
     162           0 :       return false;
     163             :     }
     164             :   }
     165             : 
     166        3958 :   RefPtr<Exception> finalException = CreateException(aRv, aMessage);
     167        1979 :   MOZ_ASSERT(finalException);
     168             : 
     169        1979 :   ThrowExceptionObject(aCx, finalException);
     170        1979 :   return false;
     171             : }
     172             : 
     173             : void
     174           0 : ThrowAndReport(nsPIDOMWindowInner* aWindow, nsresult aRv)
     175             : {
     176           0 :   MOZ_ASSERT(aRv != NS_ERROR_UNCATCHABLE_EXCEPTION,
     177             :              "Doesn't make sense to report uncatchable exceptions!");
     178           0 :   AutoJSAPI jsapi;
     179           0 :   if (NS_WARN_IF(!jsapi.Init(aWindow))) {
     180           0 :     return;
     181             :   }
     182             : 
     183           0 :   Throw(jsapi.cx(), aRv);
     184             : }
     185             : 
     186             : already_AddRefed<Exception>
     187        1979 : CreateException(nsresult aRv, const nsACString& aMessage)
     188             : {
     189             :   // Do we use DOM exceptions for this error code?
     190        1979 :   switch (NS_ERROR_GET_MODULE(aRv)) {
     191             :   case NS_ERROR_MODULE_DOM:
     192             :   case NS_ERROR_MODULE_SVG:
     193             :   case NS_ERROR_MODULE_DOM_XPATH:
     194             :   case NS_ERROR_MODULE_DOM_INDEXEDDB:
     195             :   case NS_ERROR_MODULE_DOM_FILEHANDLE:
     196             :   case NS_ERROR_MODULE_DOM_ANIM:
     197             :   case NS_ERROR_MODULE_DOM_PUSH:
     198             :   case NS_ERROR_MODULE_DOM_MEDIA:
     199           0 :     if (aMessage.IsEmpty()) {
     200           0 :       return DOMException::Create(aRv);
     201             :     }
     202           0 :     return DOMException::Create(aRv, aMessage);
     203             :   default:
     204        1979 :     break;
     205             :   }
     206             : 
     207             :   // If not, use the default.
     208             :   RefPtr<Exception> exception =
     209        5937 :     new Exception(aMessage, aRv, EmptyCString(), nullptr, nullptr);
     210        1979 :   return exception.forget();
     211             : }
     212             : 
     213             : already_AddRefed<nsIStackFrame>
     214        2024 : GetCurrentJSStack(int32_t aMaxDepth)
     215             : {
     216             :   // is there a current context available?
     217        2024 :   JSContext* cx = nsContentUtils::GetCurrentJSContextForThread();
     218             : 
     219        2024 :   if (!cx || !js::GetContextCompartment(cx)) {
     220           0 :     return nullptr;
     221             :   }
     222             : 
     223             :   static const unsigned MAX_FRAMES = 100;
     224        2024 :   if (aMaxDepth < 0) {
     225        2024 :     aMaxDepth = MAX_FRAMES;
     226             :   }
     227             : 
     228             :   JS::StackCapture captureMode = aMaxDepth == 0
     229        2024 :     ? JS::StackCapture(JS::AllFrames())
     230        6072 :     : JS::StackCapture(JS::MaxFrames(aMaxDepth));
     231             : 
     232        2024 :   return dom::exceptions::CreateStack(cx, mozilla::Move(captureMode));
     233             : }
     234             : 
     235             : namespace exceptions {
     236             : 
     237             : class JSStackFrame : public nsIStackFrame
     238             : {
     239             : public:
     240             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     241       26716 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSStackFrame)
     242             :   NS_DECL_NSISTACKFRAME
     243             : 
     244             :   // aStack must not be null.
     245             :   explicit JSStackFrame(JS::Handle<JSObject*> aStack);
     246             : 
     247             : protected:
     248             :   int32_t GetLineno(JSContext* aCx);
     249             : 
     250             :   int32_t GetColNo(JSContext* aCx);
     251             : 
     252             : private:
     253             :   virtual ~JSStackFrame();
     254             : 
     255             :   JS::Heap<JSObject*> mStack;
     256             :   nsString mFormattedStack;
     257             : 
     258             :   nsCOMPtr<nsIStackFrame> mCaller;
     259             :   nsCOMPtr<nsIStackFrame> mAsyncCaller;
     260             :   nsString mFilename;
     261             :   nsString mFunname;
     262             :   nsString mAsyncCause;
     263             :   int32_t mLineno;
     264             :   int32_t mColNo;
     265             : 
     266             :   bool mFilenameInitialized;
     267             :   bool mFunnameInitialized;
     268             :   bool mLinenoInitialized;
     269             :   bool mColNoInitialized;
     270             :   bool mAsyncCauseInitialized;
     271             :   bool mAsyncCallerInitialized;
     272             :   bool mCallerInitialized;
     273             :   bool mFormattedStackInitialized;
     274             : };
     275             : 
     276        2020 : JSStackFrame::JSStackFrame(JS::Handle<JSObject*> aStack)
     277             :   : mStack(aStack)
     278             :   , mLineno(0)
     279             :   , mColNo(0)
     280             :   , mFilenameInitialized(false)
     281             :   , mFunnameInitialized(false)
     282             :   , mLinenoInitialized(false)
     283             :   , mColNoInitialized(false)
     284             :   , mAsyncCauseInitialized(false)
     285             :   , mAsyncCallerInitialized(false)
     286             :   , mCallerInitialized(false)
     287        2020 :   , mFormattedStackInitialized(false)
     288             : {
     289        2020 :   MOZ_ASSERT(mStack);
     290             : 
     291        2020 :   mozilla::HoldJSObjects(this);
     292        2020 : }
     293             : 
     294          48 : JSStackFrame::~JSStackFrame()
     295             : {
     296          16 :   mozilla::DropJSObjects(this);
     297          48 : }
     298             : 
     299             : NS_IMPL_CYCLE_COLLECTION_CLASS(JSStackFrame)
     300           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(JSStackFrame)
     301           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCaller)
     302           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAsyncCaller)
     303           0 :   tmp->mStack = nullptr;
     304           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     305           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(JSStackFrame)
     306           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCaller)
     307           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAsyncCaller)
     308           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     309        2049 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(JSStackFrame)
     310        2049 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack)
     311        2049 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     312             : 
     313        6155 : NS_IMPL_CYCLE_COLLECTING_ADDREF(JSStackFrame)
     314        4141 : NS_IMPL_CYCLE_COLLECTING_RELEASE(JSStackFrame)
     315             : 
     316       14519 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame)
     317        4265 :   NS_INTERFACE_MAP_ENTRY(nsIStackFrame)
     318         184 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     319         157 : NS_INTERFACE_MAP_END
     320             : 
     321           0 : NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage)
     322             : {
     323           0 :   *aLanguage = nsIProgrammingLanguage::JAVASCRIPT;
     324           0 :   return NS_OK;
     325             : }
     326             : 
     327           0 : NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName)
     328             : {
     329           0 :   aLanguageName.AssignLiteral("JavaScript");
     330           0 :   return NS_OK;
     331             : }
     332             : 
     333             : // Helper method to get the value of a stack property, if it's not already
     334             : // cached.  This will make sure we skip the cache if the access is happening
     335             : // over Xrays.
     336             : //
     337             : // @argument aStack the stack we're working with; must be non-null.
     338             : // @argument aPropGetter the getter function to call.
     339             : // @argument aIsCached whether we've cached this property's value before.
     340             : //
     341             : // @argument [out] aCanCache whether the value can get cached.
     342             : // @argument [out] aUseCachedValue if true, just use the cached value.
     343             : // @argument [out] aValue the value we got from the stack.
     344             : template<typename ReturnType, typename GetterOutParamType>
     345             : static void
     346          37 : GetValueIfNotCached(JSContext* aCx, const JS::Heap<JSObject*>& aStack,
     347             :                     JS::SavedFrameResult (*aPropGetter)(JSContext*,
     348             :                                                         JS::Handle<JSObject*>,
     349             :                                                         GetterOutParamType,
     350             :                                                         JS::SavedFrameSelfHosted),
     351             :                     bool aIsCached, bool* aCanCache, bool* aUseCachedValue,
     352             :                     ReturnType aValue)
     353             : {
     354          37 :   MOZ_ASSERT(aStack);
     355             : 
     356          74 :   JS::Rooted<JSObject*> stack(aCx, aStack);
     357             :   // Allow caching if aCx and stack are same-compartment.  Otherwise take the
     358             :   // slow path.
     359          37 :   *aCanCache = js::GetContextCompartment(aCx) == js::GetObjectCompartment(stack);
     360          37 :   if (*aCanCache && aIsCached) {
     361           0 :     *aUseCachedValue = true;
     362           0 :     return;
     363             :   }
     364             : 
     365          37 :   *aUseCachedValue = false;
     366             : 
     367          37 :   aPropGetter(aCx, stack, aValue, JS::SavedFrameSelfHosted::Exclude);
     368             : }
     369             : 
     370          17 : NS_IMETHODIMP JSStackFrame::GetFilename(JSContext* aCx, nsAString& aFilename)
     371             : {
     372          17 :   if (!mStack) {
     373           0 :     aFilename.Truncate();
     374           0 :     return NS_OK;
     375             :   }
     376             : 
     377          34 :   JS::Rooted<JSString*> filename(aCx);
     378          17 :   bool canCache = false, useCachedValue = false;
     379          17 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameSource,
     380          17 :                       mFilenameInitialized,
     381          17 :                       &canCache, &useCachedValue, &filename);
     382          17 :   if (useCachedValue) {
     383           0 :     aFilename = mFilename;
     384           0 :     return NS_OK;
     385             :   }
     386             : 
     387          34 :   nsAutoJSString str;
     388          17 :   if (!str.init(aCx, filename)) {
     389           0 :     JS_ClearPendingException(aCx);
     390           0 :     aFilename.Truncate();
     391           0 :     return NS_OK;
     392             :   }
     393          17 :   aFilename = str;
     394             : 
     395          17 :   if (canCache) {
     396          17 :     mFilename = str;
     397          17 :     mFilenameInitialized = true;
     398             :   }
     399             : 
     400          17 :   return NS_OK;
     401             : }
     402             : 
     403           1 : NS_IMETHODIMP JSStackFrame::GetName(JSContext* aCx, nsAString& aFunction)
     404             : {
     405           1 :   if (!mStack) {
     406           0 :     aFunction.Truncate();
     407           0 :     return NS_OK;
     408             :   }
     409             : 
     410           2 :   JS::Rooted<JSString*> name(aCx);
     411           1 :   bool canCache = false, useCachedValue = false;
     412           1 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameFunctionDisplayName,
     413           1 :                       mFunnameInitialized, &canCache, &useCachedValue,
     414           1 :                       &name);
     415             : 
     416           1 :   if (useCachedValue) {
     417           0 :     aFunction = mFunname;
     418           0 :     return NS_OK;
     419             :   }
     420             : 
     421           1 :   if (name) {
     422           2 :     nsAutoJSString str;
     423           1 :     if (!str.init(aCx, name)) {
     424           0 :       JS_ClearPendingException(aCx);
     425           0 :       aFunction.Truncate();
     426           0 :       return NS_OK;
     427             :     }
     428           1 :     aFunction = str;
     429             :   } else {
     430           0 :     aFunction.SetIsVoid(true);
     431             :   }
     432             : 
     433           1 :   if (canCache) {
     434           1 :     mFunname = aFunction;
     435           1 :     mFunnameInitialized = true;
     436             :   }
     437             : 
     438           1 :   return NS_OK;
     439             : }
     440             : 
     441             : int32_t
     442          17 : JSStackFrame::GetLineno(JSContext* aCx)
     443             : {
     444          17 :   if (!mStack) {
     445           0 :     return 0;
     446             :   }
     447             : 
     448             :   uint32_t line;
     449          17 :   bool canCache = false, useCachedValue = false;
     450          17 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameLine, mLinenoInitialized,
     451          17 :                       &canCache, &useCachedValue, &line);
     452             : 
     453          17 :   if (useCachedValue) {
     454           0 :     return mLineno;
     455             :   }
     456             : 
     457          17 :   if (canCache) {
     458          17 :     mLineno = line;
     459          17 :     mLinenoInitialized = true;
     460             :   }
     461             : 
     462          17 :   return line;
     463             : }
     464             : 
     465          17 : NS_IMETHODIMP JSStackFrame::GetLineNumber(JSContext* aCx, int32_t* aLineNumber)
     466             : {
     467          17 :   *aLineNumber = GetLineno(aCx);
     468          17 :   return NS_OK;
     469             : }
     470             : 
     471             : int32_t
     472           1 : JSStackFrame::GetColNo(JSContext* aCx)
     473             : {
     474           1 :   if (!mStack) {
     475           0 :     return 0;
     476             :   }
     477             : 
     478             :   uint32_t col;
     479           1 :   bool canCache = false, useCachedValue = false;
     480           1 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameColumn, mColNoInitialized,
     481           1 :                       &canCache, &useCachedValue, &col);
     482             : 
     483           1 :   if (useCachedValue) {
     484           0 :     return mColNo;
     485             :   }
     486             : 
     487           1 :   if (canCache) {
     488           1 :     mColNo = col;
     489           1 :     mColNoInitialized = true;
     490             :   }
     491             : 
     492           1 :   return col;
     493             : }
     494             : 
     495           1 : NS_IMETHODIMP JSStackFrame::GetColumnNumber(JSContext* aCx,
     496             :                                             int32_t* aColumnNumber)
     497             : {
     498           1 :   *aColumnNumber = GetColNo(aCx);
     499           1 :   return NS_OK;
     500             : }
     501             : 
     502           0 : NS_IMETHODIMP JSStackFrame::GetSourceLine(nsACString& aSourceLine)
     503             : {
     504           0 :   aSourceLine.Truncate();
     505           0 :   return NS_OK;
     506             : }
     507             : 
     508           1 : NS_IMETHODIMP JSStackFrame::GetAsyncCause(JSContext* aCx,
     509             :                                           nsAString& aAsyncCause)
     510             : {
     511           1 :   if (!mStack) {
     512           0 :     aAsyncCause.Truncate();
     513           0 :     return NS_OK;
     514             :   }
     515             : 
     516           2 :   JS::Rooted<JSString*> asyncCause(aCx);
     517           1 :   bool canCache = false, useCachedValue = false;
     518           1 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameAsyncCause,
     519           1 :                       mAsyncCauseInitialized, &canCache, &useCachedValue,
     520           1 :                       &asyncCause);
     521             : 
     522           1 :   if (useCachedValue) {
     523           0 :     aAsyncCause = mAsyncCause;
     524           0 :     return NS_OK;
     525             :   }
     526             : 
     527           1 :   if (asyncCause) {
     528           0 :     nsAutoJSString str;
     529           0 :     if (!str.init(aCx, asyncCause)) {
     530           0 :       JS_ClearPendingException(aCx);
     531           0 :       aAsyncCause.Truncate();
     532           0 :       return NS_OK;
     533             :     }
     534           0 :     aAsyncCause = str;
     535             :   } else {
     536           1 :     aAsyncCause.SetIsVoid(true);
     537             :   }
     538             : 
     539           1 :   if (canCache) {
     540           1 :     mAsyncCause = aAsyncCause;
     541           1 :     mAsyncCauseInitialized = true;
     542             :   }
     543             : 
     544           1 :   return NS_OK;
     545             : }
     546             : 
     547           0 : NS_IMETHODIMP JSStackFrame::GetAsyncCaller(JSContext* aCx,
     548             :                                            nsIStackFrame** aAsyncCaller)
     549             : {
     550           0 :   if (!mStack) {
     551           0 :     *aAsyncCaller = nullptr;
     552           0 :     return NS_OK;
     553             :   }
     554             : 
     555           0 :   JS::Rooted<JSObject*> asyncCallerObj(aCx);
     556           0 :   bool canCache = false, useCachedValue = false;
     557           0 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameAsyncParent,
     558           0 :                       mAsyncCallerInitialized, &canCache, &useCachedValue,
     559           0 :                       &asyncCallerObj);
     560             : 
     561           0 :   if (useCachedValue) {
     562           0 :     NS_IF_ADDREF(*aAsyncCaller = mAsyncCaller);
     563           0 :     return NS_OK;
     564             :   }
     565             : 
     566             :   nsCOMPtr<nsIStackFrame> asyncCaller =
     567           0 :     asyncCallerObj ? new JSStackFrame(asyncCallerObj) : nullptr;
     568           0 :   asyncCaller.forget(aAsyncCaller);
     569             : 
     570           0 :   if (canCache) {
     571           0 :     mAsyncCaller = *aAsyncCaller;
     572           0 :     mAsyncCallerInitialized = true;
     573             :   }
     574             : 
     575           0 :   return NS_OK;
     576             : }
     577             : 
     578           0 : NS_IMETHODIMP JSStackFrame::GetCaller(JSContext* aCx, nsIStackFrame** aCaller)
     579             : {
     580           0 :   if (!mStack) {
     581           0 :     *aCaller = nullptr;
     582           0 :     return NS_OK;
     583             :   }
     584             : 
     585           0 :   JS::Rooted<JSObject*> callerObj(aCx);
     586           0 :   bool canCache = false, useCachedValue = false;
     587           0 :   GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameParent, mCallerInitialized,
     588           0 :                       &canCache, &useCachedValue, &callerObj);
     589             : 
     590           0 :   if (useCachedValue) {
     591           0 :     NS_IF_ADDREF(*aCaller = mCaller);
     592           0 :     return NS_OK;
     593             :   }
     594             : 
     595             :   nsCOMPtr<nsIStackFrame> caller =
     596           0 :     callerObj ? new JSStackFrame(callerObj) : nullptr;
     597           0 :   caller.forget(aCaller);
     598             : 
     599           0 :   if (canCache) {
     600           0 :     mCaller = *aCaller;
     601           0 :     mCallerInitialized = true;
     602             :   }
     603             : 
     604           0 :   return NS_OK;
     605             : }
     606             : 
     607           0 : NS_IMETHODIMP JSStackFrame::GetFormattedStack(JSContext* aCx, nsAString& aStack)
     608             : {
     609           0 :   if (!mStack) {
     610           0 :     aStack.Truncate();
     611           0 :     return NS_OK;
     612             :   }
     613             : 
     614             :   // Sadly we can't use GetValueIfNotCached here, because our getter
     615             :   // returns bool, not JS::SavedFrameResult.  Maybe it's possible to
     616             :   // make the templates more complicated to deal, but in the meantime
     617             :   // let's just inline GetValueIfNotCached here.
     618             : 
     619             :   // Allow caching if aCx and stack are same-compartment.  Otherwise take the
     620             :   // slow path.
     621             :   bool canCache =
     622           0 :     js::GetContextCompartment(aCx) == js::GetObjectCompartment(mStack);
     623           0 :   if (canCache && mFormattedStackInitialized) {
     624           0 :     aStack = mFormattedStack;
     625           0 :     return NS_OK;
     626             :   }
     627             : 
     628           0 :   JS::Rooted<JSObject*> stack(aCx, mStack);
     629             : 
     630           0 :   JS::Rooted<JSString*> formattedStack(aCx);
     631           0 :   if (!JS::BuildStackString(aCx, stack, &formattedStack)) {
     632           0 :     JS_ClearPendingException(aCx);
     633           0 :     aStack.Truncate();
     634           0 :     return NS_OK;
     635             :   }
     636             : 
     637           0 :   nsAutoJSString str;
     638           0 :   if (!str.init(aCx, formattedStack)) {
     639           0 :     JS_ClearPendingException(aCx);
     640           0 :     aStack.Truncate();
     641           0 :     return NS_OK;
     642             :   }
     643             : 
     644           0 :   aStack = str;
     645             : 
     646           0 :   if (canCache) {
     647           0 :     mFormattedStack = str;
     648           0 :     mFormattedStackInitialized = true;
     649             :   }
     650             : 
     651           0 :   return NS_OK;
     652             : }
     653             : 
     654           0 : NS_IMETHODIMP JSStackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
     655             : {
     656           0 :   aSavedFrame.setObjectOrNull(mStack);
     657           0 :   return NS_OK;
     658             : }
     659             : 
     660           0 : NS_IMETHODIMP JSStackFrame::ToString(JSContext* aCx, nsACString& _retval)
     661             : {
     662           0 :   _retval.Truncate();
     663             : 
     664           0 :   nsString filename;
     665           0 :   nsresult rv = GetFilename(aCx, filename);
     666           0 :   NS_ENSURE_SUCCESS(rv, rv);
     667             : 
     668           0 :   if (filename.IsEmpty()) {
     669           0 :     filename.AssignLiteral("<unknown filename>");
     670             :   }
     671             : 
     672           0 :   nsString funname;
     673           0 :   rv = GetName(aCx, funname);
     674           0 :   NS_ENSURE_SUCCESS(rv, rv);
     675             : 
     676           0 :   if (funname.IsEmpty()) {
     677           0 :     funname.AssignLiteral("<TOP_LEVEL>");
     678             :   }
     679             : 
     680           0 :   int32_t lineno = GetLineno(aCx);
     681             : 
     682             :   static const char format[] = "JS frame :: %s :: %s :: line %d";
     683           0 :   _retval.AppendPrintf(format,
     684           0 :                        NS_ConvertUTF16toUTF8(filename).get(),
     685           0 :                        NS_ConvertUTF16toUTF8(funname).get(),
     686           0 :                        lineno);
     687           0 :   return NS_OK;
     688             : }
     689             : 
     690             : already_AddRefed<nsIStackFrame>
     691        2025 : CreateStack(JSContext* aCx, JS::StackCapture&& aCaptureMode)
     692             : {
     693        4050 :   JS::Rooted<JSObject*> stack(aCx);
     694        2025 :   if (!JS::CaptureCurrentStack(aCx, &stack, mozilla::Move(aCaptureMode))) {
     695           0 :     return nullptr;
     696             :   }
     697             : 
     698        2025 :   if (!stack) {
     699           5 :     return nullptr;
     700             :   }
     701             : 
     702        6060 :   nsCOMPtr<nsIStackFrame> frame = new JSStackFrame(stack);
     703        2020 :   return frame.forget();
     704             : }
     705             : 
     706             : } // namespace exceptions
     707             : } // namespace dom
     708             : } // namespace mozilla

Generated by: LCOV version 1.13