js/xpconnect/src/nsCxPusher.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     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/. */
     7 #include "nsCxPusher.h"
     9 #include "nsIScriptContext.h"
    10 #include "mozilla/dom/EventTarget.h"
    11 #include "nsDOMJSUtils.h"
    12 #include "xpcprivate.h"
    13 #include "WorkerPrivate.h"
    15 using mozilla::dom::EventTarget;
    16 using mozilla::DebugOnly;
    18 bool
    19 nsCxPusher::Push(EventTarget *aCurrentTarget)
    20 {
    21   MOZ_ASSERT(mPusher.empty());
    22   NS_ENSURE_TRUE(aCurrentTarget, false);
    23   nsresult rv;
    24   nsIScriptContext* scx =
    25     aCurrentTarget->GetContextForEventHandlers(&rv);
    26 #ifdef DEBUG_smaug
    27   NS_ENSURE_SUCCESS(rv, false);
    28 #else
    29   if(NS_FAILED(rv)) {
    30     return false;
    31   }
    32 #endif
    34   if (!scx) {
    35     // The target may have a special JS context for event handlers.
    36     JSContext* cx = aCurrentTarget->GetJSContextForEventHandlers();
    37     if (cx) {
    38       mPusher.construct(cx);
    39     }
    41     // Nothing to do here, I guess.  Have to return true so that event firing
    42     // will still work correctly even if there is no associated JSContext
    43     return true;
    44   }
    46   mPusher.construct(scx->GetNativeContext());
    47   return true;
    48 }
    50 bool
    51 nsCxPusher::RePush(EventTarget *aCurrentTarget)
    52 {
    53   if (mPusher.empty()) {
    54     return Push(aCurrentTarget);
    55   }
    57   if (aCurrentTarget) {
    58     nsresult rv;
    59     nsIScriptContext* scx =
    60       aCurrentTarget->GetContextForEventHandlers(&rv);
    61     if (NS_FAILED(rv)) {
    62       mPusher.destroy();
    63       return false;
    64     }
    66     // If we have the same script context and native context is still
    67     // alive, no need to Pop/Push.
    68     if (scx && scx == mPusher.ref().GetScriptContext() &&
    69         scx->GetNativeContext()) {
    70       return true;
    71     }
    72   }
    74   mPusher.destroy();
    75   return Push(aCurrentTarget);
    76 }
    78 void
    79 nsCxPusher::Push(JSContext *cx)
    80 {
    81   mPusher.construct(cx);
    82 }
    84 void
    85 nsCxPusher::PushNull()
    86 {
    87   // Note: The Maybe<> template magic seems to need the static_cast below to
    88   // work right on some older compilers.
    89   mPusher.construct(static_cast<JSContext*>(nullptr), /* aAllowNull = */ true);
    90 }
    92 void
    93 nsCxPusher::Pop()
    94 {
    95   if (!mPusher.empty())
    96     mPusher.destroy();
    97 }
    99 namespace mozilla {
   101 AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull)
   102 {
   103   MOZ_ASSERT_IF(!allowNull, cx);
   105   // Hold a strong ref to the nsIScriptContext, if any. This ensures that we
   106   // only destroy the mContext of an nsJSContext when it is not on the cx stack
   107   // (and therefore not in use). See nsJSContext::DestroyJSContext().
   108   if (cx)
   109     mScx = GetScriptContextFromJSContext(cx);
   111   XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
   112   if (!stack->Push(cx)) {
   113     MOZ_CRASH();
   114   }
   115   mStackDepthAfterPush = stack->Count();
   117 #ifdef DEBUG
   118   mPushedContext = cx;
   119   mCompartmentDepthOnEntry = cx ? js::GetEnterCompartmentDepth(cx) : 0;
   120 #endif
   122   // Enter a request and a compartment for the duration that the cx is on the
   123   // stack if non-null.
   124   if (cx) {
   125     mAutoRequest.construct(cx);
   127     // DOM JSContexts don't store their default compartment object on the cx.
   128     JSObject *compartmentObject = mScx ? mScx->GetWindowProxy()
   129                                        : js::DefaultObjectForContextOrNull(cx);
   130     if (compartmentObject)
   131       mAutoCompartment.construct(cx, compartmentObject);
   132   }
   133 }
   135 AutoCxPusher::~AutoCxPusher()
   136 {
   137   // GC when we pop a script entry point. This is a useful heuristic that helps
   138   // us out on certain (flawed) benchmarks like sunspider, because it lets us
   139   // avoid GCing during the timing loop.
   140   //
   141   // NB: We need to take care to only do this if we're in a compartment,
   142   // otherwise JS_MaybeGC will segfault.
   143   if (mScx && !mAutoCompartment.empty())
   144     JS_MaybeGC(nsXPConnect::XPConnect()->GetCurrentJSContext());
   146   // Leave the compartment and request before popping.
   147   mAutoCompartment.destroyIfConstructed();
   148   mAutoRequest.destroyIfConstructed();
   150   // When we push a context, we may save the frame chain and pretend like we
   151   // haven't entered any compartment. This gets restored on Pop(), but we can
   152   // run into trouble if a Push/Pop are interleaved with a
   153   // JSAutoEnterCompartment. Make sure the compartment depth right before we
   154   // pop is the same as it was right after we pushed.
   155   MOZ_ASSERT_IF(mPushedContext, mCompartmentDepthOnEntry ==
   156                                 js::GetEnterCompartmentDepth(mPushedContext));
   157   DebugOnly<JSContext*> stackTop;
   158   MOZ_ASSERT(mPushedContext == nsXPConnect::XPConnect()->GetCurrentJSContext());
   159   XPCJSRuntime::Get()->GetJSContextStack()->Pop();
   160   mScx = nullptr;
   161 }
   163 bool
   164 AutoCxPusher::IsStackTop()
   165 {
   166   uint32_t currentDepth = XPCJSRuntime::Get()->GetJSContextStack()->Count();
   167   MOZ_ASSERT(currentDepth >= mStackDepthAfterPush);
   168   return currentDepth == mStackDepthAfterPush;
   169 }
   171 AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
   172   : mCx(nullptr)
   173 {
   174   Init(false MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
   175 }
   177 AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   178   : mCx(nullptr)
   179 {
   180   Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
   181 }
   183 void
   184 AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   185 {
   186   JS::AutoAssertNoGC nogc;
   187   MOZ_ASSERT(!mCx, "mCx should not be initialized!");
   189   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   191   nsXPConnect *xpc = nsXPConnect::XPConnect();
   192   if (!aSafe) {
   193     mCx = xpc->GetCurrentJSContext();
   194   }
   196   if (!mCx) {
   197     mCx = xpc->GetSafeJSContext();
   198     mPusher.construct(mCx);
   199   }
   200 }
   202 AutoJSContext::operator JSContext*() const
   203 {
   204   return mCx;
   205 }
   207 ThreadsafeAutoJSContext::ThreadsafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
   208 {
   209   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   211   if (NS_IsMainThread()) {
   212     mCx = nullptr;
   213     mAutoJSContext.construct();
   214   } else {
   215     mCx = mozilla::dom::workers::GetCurrentThreadJSContext();
   216     mRequest.construct(mCx);
   217   }
   218 }
   220 ThreadsafeAutoJSContext::operator JSContext*() const
   221 {
   222   if (mCx) {
   223     return mCx;
   224   } else {
   225     return mAutoJSContext.ref();
   226   }
   227 }
   229 AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
   230   : AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
   231   , mAc(mCx, XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContextGlobal())
   232 {
   233 }
   235 ThreadsafeAutoSafeJSContext::ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
   236 {
   237   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   239   if (NS_IsMainThread()) {
   240     mCx = nullptr;
   241     mAutoSafeJSContext.construct();
   242   } else {
   243     mCx = mozilla::dom::workers::GetCurrentThreadJSContext();
   244     mRequest.construct(mCx);
   245   }
   246 }
   248 ThreadsafeAutoSafeJSContext::operator JSContext*() const
   249 {
   250   if (mCx) {
   251     return mCx;
   252   } else {
   253     return mAutoSafeJSContext.ref();
   254   }
   255 }
   257 AutoPushJSContext::AutoPushJSContext(JSContext *aCx) : mCx(aCx)
   258 {
   259   if (mCx && mCx != nsXPConnect::XPConnect()->GetCurrentJSContext()) {
   260     mPusher.construct(mCx);
   261   }
   262 }
   264 } // namespace mozilla

mercurial