js/xpconnect/src/nsCxPusher.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:c76a40a6b4ae
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 #ifndef nsCxPusher_h
8 #define nsCxPusher_h
9
10 #include "jsapi.h"
11 #include "mozilla/Maybe.h"
12 #include "nsCOMPtr.h"
13
14 namespace mozilla {
15 namespace dom {
16 class EventTarget;
17 }
18 }
19
20 class nsIScriptContext;
21
22 namespace mozilla {
23
24 /**
25 * Fundamental cx pushing class. All other cx pushing classes are implemented
26 * in terms of this class.
27 */
28 class MOZ_STACK_CLASS AutoCxPusher
29 {
30 public:
31 AutoCxPusher(JSContext *aCx, bool aAllowNull = false);
32 // XPCShell uses an nsCxPusher, which contains an AutoCxPusher.
33 ~AutoCxPusher();
34
35 nsIScriptContext* GetScriptContext() { return mScx; }
36
37 // Returns true if this AutoCxPusher performed the push that is currently at
38 // the top of the cx stack.
39 bool IsStackTop();
40
41 private:
42 mozilla::Maybe<JSAutoRequest> mAutoRequest;
43 mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
44 nsCOMPtr<nsIScriptContext> mScx;
45 uint32_t mStackDepthAfterPush;
46 #ifdef DEBUG
47 JSContext* mPushedContext;
48 unsigned mCompartmentDepthOnEntry;
49 #endif
50 };
51
52 } /* namespace mozilla */
53
54 /**
55 * Legacy cx pushing class.
56 *
57 * This class provides a rather wonky interface, with the following quirks:
58 * * The constructor is a no-op, and callers must explicitly call one of
59 * the Push() methods.
60 * * Null must be pushed with PushNull().
61 * * The cx pusher can be reused multiple times with RePush().
62 *
63 * This class implements this interface in terms of the much simpler
64 * AutoCxPusher class below.
65 */
66 class MOZ_STACK_CLASS nsCxPusher
67 {
68 public:
69 // Returns false if something erroneous happened.
70 bool Push(mozilla::dom::EventTarget *aCurrentTarget);
71 // If nothing has been pushed to stack, this works like Push.
72 // Otherwise if context will change, Pop and Push will be called.
73 bool RePush(mozilla::dom::EventTarget *aCurrentTarget);
74 // If a null JSContext is passed to Push(), that will cause no
75 // push to happen and false to be returned.
76 void Push(JSContext *cx);
77 // Explicitly push a null JSContext on the the stack
78 void PushNull();
79
80 // Pop() will be a no-op if Push() or PushNull() fail
81 void Pop();
82
83 nsIScriptContext* GetCurrentScriptContext() {
84 return mPusher.empty() ? nullptr : mPusher.ref().GetScriptContext();
85 }
86
87 private:
88 mozilla::Maybe<mozilla::AutoCxPusher> mPusher;
89 };
90
91 namespace mozilla {
92
93 /**
94 * Use AutoJSContext when you need a JS context on the stack but don't have one
95 * passed as a parameter. AutoJSContext will take care of finding the most
96 * appropriate JS context and release it when leaving the stack.
97 */
98 class MOZ_STACK_CLASS AutoJSContext {
99 public:
100 AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
101 operator JSContext*() const;
102
103 protected:
104 AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
105
106 // We need this Init() method because we can't use delegating constructor for
107 // the moment. It is a C++11 feature and we do not require C++11 to be
108 // supported to be able to compile Gecko.
109 void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
110
111 JSContext* mCx;
112 Maybe<AutoCxPusher> mPusher;
113 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
114 };
115
116 /**
117 * Use ThreadsafeAutoJSContext when you want an AutoJSContext but might be
118 * running on a worker thread.
119 */
120 class MOZ_STACK_CLASS ThreadsafeAutoJSContext {
121 public:
122 ThreadsafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
123 operator JSContext*() const;
124
125 private:
126 JSContext* mCx; // Used on workers. Null means mainthread.
127 Maybe<JSAutoRequest> mRequest; // Used on workers.
128 Maybe<AutoJSContext> mAutoJSContext; // Used on main thread.
129 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
130 };
131
132 /**
133 * AutoSafeJSContext is similar to AutoJSContext but will only return the safe
134 * JS context. That means it will never call ::GetCurrentJSContext().
135 */
136 class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext {
137 public:
138 AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
139 private:
140 JSAutoCompartment mAc;
141 };
142
143 /**
144 * Like AutoSafeJSContext but can be used safely on worker threads.
145 */
146 class MOZ_STACK_CLASS ThreadsafeAutoSafeJSContext {
147 public:
148 ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
149 operator JSContext*() const;
150
151 private:
152 JSContext* mCx; // Used on workers. Null means mainthread.
153 Maybe<JSAutoRequest> mRequest; // Used on workers.
154 Maybe<AutoSafeJSContext> mAutoSafeJSContext; // Used on main thread.
155 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
156 };
157
158 /**
159 * Use AutoPushJSContext when you want to use a specific JSContext that may or
160 * may not be already on the stack. This differs from nsCxPusher in that it only
161 * pushes in the case that the given cx is not the active cx on the JSContext
162 * stack, which avoids an expensive JS_SaveFrameChain in the common case.
163 *
164 * Most consumers of this should probably just use AutoJSContext. But the goal
165 * here is to preserve the existing behavior while ensure proper cx-stack
166 * semantics in edge cases where the context being used doesn't match the active
167 * context.
168 *
169 * NB: This will not push a null cx even if aCx is null. Make sure you know what
170 * you're doing.
171 */
172 class MOZ_STACK_CLASS AutoPushJSContext {
173 Maybe<AutoCxPusher> mPusher;
174 JSContext* mCx;
175
176 public:
177 AutoPushJSContext(JSContext* aCx);
178 operator JSContext*() { return mCx; }
179 };
180
181 } // namespace mozilla
182
183 #endif /* nsCxPusher_h */

mercurial