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 */