js/xpconnect/src/nsCxPusher.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/xpconnect/src/nsCxPusher.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,183 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef nsCxPusher_h
    1.11 +#define nsCxPusher_h
    1.12 +
    1.13 +#include "jsapi.h"
    1.14 +#include "mozilla/Maybe.h"
    1.15 +#include "nsCOMPtr.h"
    1.16 +
    1.17 +namespace mozilla {
    1.18 +namespace dom {
    1.19 +class EventTarget;
    1.20 +}
    1.21 +}
    1.22 +
    1.23 +class nsIScriptContext;
    1.24 +
    1.25 +namespace mozilla {
    1.26 +
    1.27 +/**
    1.28 + * Fundamental cx pushing class. All other cx pushing classes are implemented
    1.29 + * in terms of this class.
    1.30 + */
    1.31 +class MOZ_STACK_CLASS AutoCxPusher
    1.32 +{
    1.33 +public:
    1.34 +  AutoCxPusher(JSContext *aCx, bool aAllowNull = false);
    1.35 +  // XPCShell uses an nsCxPusher, which contains an AutoCxPusher.
    1.36 +  ~AutoCxPusher();
    1.37 +
    1.38 +  nsIScriptContext* GetScriptContext() { return mScx; }
    1.39 +
    1.40 +  // Returns true if this AutoCxPusher performed the push that is currently at
    1.41 +  // the top of the cx stack.
    1.42 +  bool IsStackTop();
    1.43 +
    1.44 +private:
    1.45 +  mozilla::Maybe<JSAutoRequest> mAutoRequest;
    1.46 +  mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
    1.47 +  nsCOMPtr<nsIScriptContext> mScx;
    1.48 +  uint32_t mStackDepthAfterPush;
    1.49 +#ifdef DEBUG
    1.50 +  JSContext* mPushedContext;
    1.51 +  unsigned mCompartmentDepthOnEntry;
    1.52 +#endif
    1.53 +};
    1.54 +
    1.55 +} /* namespace mozilla */
    1.56 +
    1.57 +/**
    1.58 + * Legacy cx pushing class.
    1.59 + *
    1.60 + * This class provides a rather wonky interface, with the following quirks:
    1.61 + *   * The constructor is a no-op, and callers must explicitly call one of
    1.62 + *     the Push() methods.
    1.63 + *   * Null must be pushed with PushNull().
    1.64 + *   * The cx pusher can be reused multiple times with RePush().
    1.65 + *
    1.66 + * This class implements this interface in terms of the much simpler
    1.67 + * AutoCxPusher class below.
    1.68 + */
    1.69 +class MOZ_STACK_CLASS nsCxPusher
    1.70 +{
    1.71 +public:
    1.72 +  // Returns false if something erroneous happened.
    1.73 +  bool Push(mozilla::dom::EventTarget *aCurrentTarget);
    1.74 +  // If nothing has been pushed to stack, this works like Push.
    1.75 +  // Otherwise if context will change, Pop and Push will be called.
    1.76 +  bool RePush(mozilla::dom::EventTarget *aCurrentTarget);
    1.77 +  // If a null JSContext is passed to Push(), that will cause no
    1.78 +  // push to happen and false to be returned.
    1.79 +  void Push(JSContext *cx);
    1.80 +  // Explicitly push a null JSContext on the the stack
    1.81 +  void PushNull();
    1.82 +
    1.83 +  // Pop() will be a no-op if Push() or PushNull() fail
    1.84 +  void Pop();
    1.85 +
    1.86 +  nsIScriptContext* GetCurrentScriptContext() {
    1.87 +    return mPusher.empty() ? nullptr : mPusher.ref().GetScriptContext();
    1.88 +  }
    1.89 +
    1.90 +private:
    1.91 +  mozilla::Maybe<mozilla::AutoCxPusher> mPusher;
    1.92 +};
    1.93 +
    1.94 +namespace mozilla {
    1.95 +
    1.96 +/**
    1.97 + * Use AutoJSContext when you need a JS context on the stack but don't have one
    1.98 + * passed as a parameter. AutoJSContext will take care of finding the most
    1.99 + * appropriate JS context and release it when leaving the stack.
   1.100 + */
   1.101 +class MOZ_STACK_CLASS AutoJSContext {
   1.102 +public:
   1.103 +  AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
   1.104 +  operator JSContext*() const;
   1.105 +
   1.106 +protected:
   1.107 +  AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
   1.108 +
   1.109 +  // We need this Init() method because we can't use delegating constructor for
   1.110 +  // the moment. It is a C++11 feature and we do not require C++11 to be
   1.111 +  // supported to be able to compile Gecko.
   1.112 +  void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
   1.113 +
   1.114 +  JSContext* mCx;
   1.115 +  Maybe<AutoCxPusher> mPusher;
   1.116 +  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   1.117 +};
   1.118 +
   1.119 +/**
   1.120 + * Use ThreadsafeAutoJSContext when you want an AutoJSContext but might be
   1.121 + * running on a worker thread.
   1.122 + */
   1.123 +class MOZ_STACK_CLASS ThreadsafeAutoJSContext {
   1.124 +public:
   1.125 +  ThreadsafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
   1.126 +  operator JSContext*() const;
   1.127 +
   1.128 +private:
   1.129 +  JSContext* mCx; // Used on workers.  Null means mainthread.
   1.130 +  Maybe<JSAutoRequest> mRequest; // Used on workers.
   1.131 +  Maybe<AutoJSContext> mAutoJSContext; // Used on main thread.
   1.132 +  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   1.133 +};
   1.134 +
   1.135 +/**
   1.136 + * AutoSafeJSContext is similar to AutoJSContext but will only return the safe
   1.137 + * JS context. That means it will never call ::GetCurrentJSContext().
   1.138 + */
   1.139 +class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext {
   1.140 +public:
   1.141 +  AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
   1.142 +private:
   1.143 +  JSAutoCompartment mAc;
   1.144 +};
   1.145 +
   1.146 +/**
   1.147 + * Like AutoSafeJSContext but can be used safely on worker threads.
   1.148 + */
   1.149 +class MOZ_STACK_CLASS ThreadsafeAutoSafeJSContext {
   1.150 +public:
   1.151 +  ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
   1.152 +  operator JSContext*() const;
   1.153 +
   1.154 +private:
   1.155 +  JSContext* mCx; // Used on workers.  Null means mainthread.
   1.156 +  Maybe<JSAutoRequest> mRequest; // Used on workers.
   1.157 +  Maybe<AutoSafeJSContext> mAutoSafeJSContext; // Used on main thread.
   1.158 +  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   1.159 +};
   1.160 +
   1.161 +/**
   1.162 + * Use AutoPushJSContext when you want to use a specific JSContext that may or
   1.163 + * may not be already on the stack. This differs from nsCxPusher in that it only
   1.164 + * pushes in the case that the given cx is not the active cx on the JSContext
   1.165 + * stack, which avoids an expensive JS_SaveFrameChain in the common case.
   1.166 + *
   1.167 + * Most consumers of this should probably just use AutoJSContext. But the goal
   1.168 + * here is to preserve the existing behavior while ensure proper cx-stack
   1.169 + * semantics in edge cases where the context being used doesn't match the active
   1.170 + * context.
   1.171 + *
   1.172 + * NB: This will not push a null cx even if aCx is null. Make sure you know what
   1.173 + * you're doing.
   1.174 + */
   1.175 +class MOZ_STACK_CLASS AutoPushJSContext {
   1.176 +  Maybe<AutoCxPusher> mPusher;
   1.177 +  JSContext* mCx;
   1.178 +
   1.179 +public:
   1.180 +  AutoPushJSContext(JSContext* aCx);
   1.181 +  operator JSContext*() { return mCx; }
   1.182 +};
   1.183 +
   1.184 +} // namespace mozilla
   1.185 +
   1.186 +#endif /* nsCxPusher_h */

mercurial