michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsCxPusher_h michael@0: #define nsCxPusher_h michael@0: michael@0: #include "jsapi.h" michael@0: #include "mozilla/Maybe.h" michael@0: #include "nsCOMPtr.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: class EventTarget; michael@0: } michael@0: } michael@0: michael@0: class nsIScriptContext; michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * Fundamental cx pushing class. All other cx pushing classes are implemented michael@0: * in terms of this class. michael@0: */ michael@0: class MOZ_STACK_CLASS AutoCxPusher michael@0: { michael@0: public: michael@0: AutoCxPusher(JSContext *aCx, bool aAllowNull = false); michael@0: // XPCShell uses an nsCxPusher, which contains an AutoCxPusher. michael@0: ~AutoCxPusher(); michael@0: michael@0: nsIScriptContext* GetScriptContext() { return mScx; } michael@0: michael@0: // Returns true if this AutoCxPusher performed the push that is currently at michael@0: // the top of the cx stack. michael@0: bool IsStackTop(); michael@0: michael@0: private: michael@0: mozilla::Maybe mAutoRequest; michael@0: mozilla::Maybe mAutoCompartment; michael@0: nsCOMPtr mScx; michael@0: uint32_t mStackDepthAfterPush; michael@0: #ifdef DEBUG michael@0: JSContext* mPushedContext; michael@0: unsigned mCompartmentDepthOnEntry; michael@0: #endif michael@0: }; michael@0: michael@0: } /* namespace mozilla */ michael@0: michael@0: /** michael@0: * Legacy cx pushing class. michael@0: * michael@0: * This class provides a rather wonky interface, with the following quirks: michael@0: * * The constructor is a no-op, and callers must explicitly call one of michael@0: * the Push() methods. michael@0: * * Null must be pushed with PushNull(). michael@0: * * The cx pusher can be reused multiple times with RePush(). michael@0: * michael@0: * This class implements this interface in terms of the much simpler michael@0: * AutoCxPusher class below. michael@0: */ michael@0: class MOZ_STACK_CLASS nsCxPusher michael@0: { michael@0: public: michael@0: // Returns false if something erroneous happened. michael@0: bool Push(mozilla::dom::EventTarget *aCurrentTarget); michael@0: // If nothing has been pushed to stack, this works like Push. michael@0: // Otherwise if context will change, Pop and Push will be called. michael@0: bool RePush(mozilla::dom::EventTarget *aCurrentTarget); michael@0: // If a null JSContext is passed to Push(), that will cause no michael@0: // push to happen and false to be returned. michael@0: void Push(JSContext *cx); michael@0: // Explicitly push a null JSContext on the the stack michael@0: void PushNull(); michael@0: michael@0: // Pop() will be a no-op if Push() or PushNull() fail michael@0: void Pop(); michael@0: michael@0: nsIScriptContext* GetCurrentScriptContext() { michael@0: return mPusher.empty() ? nullptr : mPusher.ref().GetScriptContext(); michael@0: } michael@0: michael@0: private: michael@0: mozilla::Maybe mPusher; michael@0: }; michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * Use AutoJSContext when you need a JS context on the stack but don't have one michael@0: * passed as a parameter. AutoJSContext will take care of finding the most michael@0: * appropriate JS context and release it when leaving the stack. michael@0: */ michael@0: class MOZ_STACK_CLASS AutoJSContext { michael@0: public: michael@0: AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); michael@0: operator JSContext*() const; michael@0: michael@0: protected: michael@0: AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM); michael@0: michael@0: // We need this Init() method because we can't use delegating constructor for michael@0: // the moment. It is a C++11 feature and we do not require C++11 to be michael@0: // supported to be able to compile Gecko. michael@0: void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM); michael@0: michael@0: JSContext* mCx; michael@0: Maybe mPusher; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: /** michael@0: * Use ThreadsafeAutoJSContext when you want an AutoJSContext but might be michael@0: * running on a worker thread. michael@0: */ michael@0: class MOZ_STACK_CLASS ThreadsafeAutoJSContext { michael@0: public: michael@0: ThreadsafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); michael@0: operator JSContext*() const; michael@0: michael@0: private: michael@0: JSContext* mCx; // Used on workers. Null means mainthread. michael@0: Maybe mRequest; // Used on workers. michael@0: Maybe mAutoJSContext; // Used on main thread. michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: /** michael@0: * AutoSafeJSContext is similar to AutoJSContext but will only return the safe michael@0: * JS context. That means it will never call ::GetCurrentJSContext(). michael@0: */ michael@0: class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext { michael@0: public: michael@0: AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); michael@0: private: michael@0: JSAutoCompartment mAc; michael@0: }; michael@0: michael@0: /** michael@0: * Like AutoSafeJSContext but can be used safely on worker threads. michael@0: */ michael@0: class MOZ_STACK_CLASS ThreadsafeAutoSafeJSContext { michael@0: public: michael@0: ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); michael@0: operator JSContext*() const; michael@0: michael@0: private: michael@0: JSContext* mCx; // Used on workers. Null means mainthread. michael@0: Maybe mRequest; // Used on workers. michael@0: Maybe mAutoSafeJSContext; // Used on main thread. michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: /** michael@0: * Use AutoPushJSContext when you want to use a specific JSContext that may or michael@0: * may not be already on the stack. This differs from nsCxPusher in that it only michael@0: * pushes in the case that the given cx is not the active cx on the JSContext michael@0: * stack, which avoids an expensive JS_SaveFrameChain in the common case. michael@0: * michael@0: * Most consumers of this should probably just use AutoJSContext. But the goal michael@0: * here is to preserve the existing behavior while ensure proper cx-stack michael@0: * semantics in edge cases where the context being used doesn't match the active michael@0: * context. michael@0: * michael@0: * NB: This will not push a null cx even if aCx is null. Make sure you know what michael@0: * you're doing. michael@0: */ michael@0: class MOZ_STACK_CLASS AutoPushJSContext { michael@0: Maybe mPusher; michael@0: JSContext* mCx; michael@0: michael@0: public: michael@0: AutoPushJSContext(JSContext* aCx); michael@0: operator JSContext*() { return mCx; } michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif /* nsCxPusher_h */