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