|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
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 /* |
|
8 * Helper classes encapsulating access to the callee, |this| value, arguments, |
|
9 * and argument count for a function call. |
|
10 * |
|
11 * The intent of JS::CallArgs and JS::CallReceiver is that they be used to |
|
12 * encapsulate access to the un-abstracted |unsigned argc, Value *vp| arguments |
|
13 * to a function. It's possible (albeit deprecated) to manually index into |
|
14 * |vp| to access the callee, |this|, and arguments of a function, and to set |
|
15 * its return value. It's also possible to use the supported API of JS_CALLEE, |
|
16 * JS_THIS, JS_ARGV, JS_RVAL and JS_SET_RVAL to the same ends. But neither API |
|
17 * has the error-handling or moving-GC correctness of CallArgs or CallReceiver. |
|
18 * New code should use CallArgs and CallReceiver instead whenever possible. |
|
19 * |
|
20 * The eventual plan is to change JSNative to take |const CallArgs&| directly, |
|
21 * for automatic assertion of correct use and to make calling functions more |
|
22 * efficient. Embedders should start internally switching away from using |
|
23 * |argc| and |vp| directly, except to create a |CallArgs|. Then, when an |
|
24 * eventual release making that change occurs, porting efforts will require |
|
25 * changing methods' signatures but won't require invasive changes to the |
|
26 * methods' implementations, potentially under time pressure. |
|
27 */ |
|
28 |
|
29 #ifndef js_CallArgs_h |
|
30 #define js_CallArgs_h |
|
31 |
|
32 #include "mozilla/Assertions.h" |
|
33 #include "mozilla/Attributes.h" |
|
34 #include "mozilla/TypeTraits.h" |
|
35 |
|
36 #include "jstypes.h" |
|
37 |
|
38 #include "js/RootingAPI.h" |
|
39 #include "js/Value.h" |
|
40 |
|
41 /* Typedef for native functions called by the JS VM. */ |
|
42 typedef bool |
|
43 (* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp); |
|
44 |
|
45 /* Typedef for native functions that may be called in parallel. */ |
|
46 typedef bool |
|
47 (* JSParallelNative)(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp); |
|
48 |
|
49 /* |
|
50 * Typedef for native functions that may be called either in parallel or |
|
51 * sequential execution. |
|
52 */ |
|
53 typedef bool |
|
54 (* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp); |
|
55 |
|
56 /* |
|
57 * Convenience wrappers for passing in ThreadSafeNative to places that expect |
|
58 * a JSNative or a JSParallelNative. |
|
59 */ |
|
60 template <JSThreadSafeNative threadSafeNative> |
|
61 inline bool |
|
62 JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp); |
|
63 |
|
64 template <JSThreadSafeNative threadSafeNative> |
|
65 inline bool |
|
66 JSParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp); |
|
67 |
|
68 /* |
|
69 * Compute |this| for the |vp| inside a JSNative, either boxing primitives or |
|
70 * replacing with the global object as necessary. |
|
71 * |
|
72 * This method will go away at some point: instead use |args.thisv()|. If the |
|
73 * value is an object, no further work is required. If that value is |null| or |
|
74 * |undefined|, use |JS_GetGlobalForObject| to compute the global object. If |
|
75 * the value is some other primitive, use |JS_ValueToObject| to box it. |
|
76 */ |
|
77 extern JS_PUBLIC_API(JS::Value) |
|
78 JS_ComputeThis(JSContext *cx, JS::Value *vp); |
|
79 |
|
80 namespace JS { |
|
81 |
|
82 extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; |
|
83 |
|
84 /* |
|
85 * JS::CallReceiver encapsulates access to the callee, |this|, and eventual |
|
86 * return value for a function call. The principal way to create a |
|
87 * CallReceiver is using JS::CallReceiverFromVp: |
|
88 * |
|
89 * static bool |
|
90 * FunctionReturningThis(JSContext *cx, unsigned argc, JS::Value *vp) |
|
91 * { |
|
92 * JS::CallReceiver rec = JS::CallReceiverFromVp(vp); |
|
93 * |
|
94 * // Access to the callee must occur before accessing/setting |
|
95 * // the return value. |
|
96 * JSObject &callee = rec.callee(); |
|
97 * rec.rval().set(JS::ObjectValue(callee)); |
|
98 * |
|
99 * // callee() and calleev() will now assert. |
|
100 * |
|
101 * // It's always fine to access thisv(). |
|
102 * HandleValue thisv = rec.thisv(); |
|
103 * rec.rval().set(thisv); |
|
104 * |
|
105 * // As the return value was last set to |this|, returns |this|. |
|
106 * return true; |
|
107 * } |
|
108 * |
|
109 * A note on JS_ComputeThis and JS_THIS_OBJECT: these methods currently aren't |
|
110 * part of the CallReceiver interface. We will likely add them at some point. |
|
111 * Until then, you should probably continue using |vp| directly for these two |
|
112 * cases. |
|
113 * |
|
114 * CallReceiver is exposed publicly and used internally. Not all parts of its |
|
115 * public interface are meant to be used by embedders! See inline comments to |
|
116 * for details. |
|
117 */ |
|
118 |
|
119 namespace detail { |
|
120 |
|
121 #ifdef JS_DEBUG |
|
122 extern JS_PUBLIC_API(void) |
|
123 CheckIsValidConstructible(Value v); |
|
124 #endif |
|
125 |
|
126 enum UsedRval { IncludeUsedRval, NoUsedRval }; |
|
127 |
|
128 template<UsedRval WantUsedRval> |
|
129 class MOZ_STACK_CLASS UsedRvalBase; |
|
130 |
|
131 template<> |
|
132 class MOZ_STACK_CLASS UsedRvalBase<IncludeUsedRval> |
|
133 { |
|
134 protected: |
|
135 mutable bool usedRval_; |
|
136 void setUsedRval() const { usedRval_ = true; } |
|
137 void clearUsedRval() const { usedRval_ = false; } |
|
138 }; |
|
139 |
|
140 template<> |
|
141 class MOZ_STACK_CLASS UsedRvalBase<NoUsedRval> |
|
142 { |
|
143 protected: |
|
144 void setUsedRval() const {} |
|
145 void clearUsedRval() const {} |
|
146 }; |
|
147 |
|
148 template<UsedRval WantUsedRval> |
|
149 class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase< |
|
150 #ifdef JS_DEBUG |
|
151 WantUsedRval |
|
152 #else |
|
153 NoUsedRval |
|
154 #endif |
|
155 > |
|
156 { |
|
157 protected: |
|
158 Value *argv_; |
|
159 |
|
160 public: |
|
161 /* |
|
162 * Returns the function being called, as an object. Must not be called |
|
163 * after rval() has been used! |
|
164 */ |
|
165 JSObject &callee() const { |
|
166 MOZ_ASSERT(!this->usedRval_); |
|
167 return argv_[-2].toObject(); |
|
168 } |
|
169 |
|
170 /* |
|
171 * Returns the function being called, as a value. Must not be called after |
|
172 * rval() has been used! |
|
173 */ |
|
174 HandleValue calleev() const { |
|
175 MOZ_ASSERT(!this->usedRval_); |
|
176 return HandleValue::fromMarkedLocation(&argv_[-2]); |
|
177 } |
|
178 |
|
179 /* |
|
180 * Returns the |this| value passed to the function. This method must not |
|
181 * be called when the function is being called as a constructor via |new|. |
|
182 * The value may or may not be an object: it is the individual function's |
|
183 * responsibility to box the value if needed. |
|
184 */ |
|
185 HandleValue thisv() const { |
|
186 // Some internal code uses thisv() in constructing cases, so don't do |
|
187 // this yet. |
|
188 // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); |
|
189 return HandleValue::fromMarkedLocation(&argv_[-1]); |
|
190 } |
|
191 |
|
192 Value computeThis(JSContext *cx) const { |
|
193 if (thisv().isObject()) |
|
194 return thisv(); |
|
195 |
|
196 return JS_ComputeThis(cx, base()); |
|
197 } |
|
198 |
|
199 bool isConstructing() const { |
|
200 #ifdef JS_DEBUG |
|
201 if (this->usedRval_) |
|
202 CheckIsValidConstructible(calleev()); |
|
203 #endif |
|
204 return argv_[-1].isMagic(); |
|
205 } |
|
206 |
|
207 /* |
|
208 * Returns the currently-set return value. The initial contents of this |
|
209 * value are unspecified. Once this method has been called, callee() and |
|
210 * calleev() can no longer be used. (If you're compiling against a debug |
|
211 * build of SpiderMonkey, these methods will assert to aid debugging.) |
|
212 * |
|
213 * If the method you're implementing succeeds by returning true, you *must* |
|
214 * set this. (SpiderMonkey doesn't currently assert this, but it will do |
|
215 * so eventually.) You don't need to use or change this if your method |
|
216 * fails. |
|
217 */ |
|
218 MutableHandleValue rval() const { |
|
219 this->setUsedRval(); |
|
220 return MutableHandleValue::fromMarkedLocation(&argv_[-2]); |
|
221 } |
|
222 |
|
223 public: |
|
224 // These methods are only intended for internal use. Embedders shouldn't |
|
225 // use them! |
|
226 |
|
227 Value *base() const { return argv_ - 2; } |
|
228 |
|
229 Value *spAfterCall() const { |
|
230 this->setUsedRval(); |
|
231 return argv_ - 1; |
|
232 } |
|
233 |
|
234 public: |
|
235 // These methods are publicly exposed, but they are *not* to be used when |
|
236 // implementing a JSNative method and encapsulating access to |vp| within |
|
237 // it. You probably don't want to use these! |
|
238 |
|
239 void setCallee(Value aCalleev) const { |
|
240 this->clearUsedRval(); |
|
241 argv_[-2] = aCalleev; |
|
242 } |
|
243 |
|
244 void setThis(Value aThisv) const { |
|
245 argv_[-1] = aThisv; |
|
246 } |
|
247 |
|
248 MutableHandleValue mutableThisv() const { |
|
249 return MutableHandleValue::fromMarkedLocation(&argv_[-1]); |
|
250 } |
|
251 }; |
|
252 |
|
253 } // namespace detail |
|
254 |
|
255 class MOZ_STACK_CLASS CallReceiver : public detail::CallReceiverBase<detail::IncludeUsedRval> |
|
256 { |
|
257 private: |
|
258 friend CallReceiver CallReceiverFromVp(Value *vp); |
|
259 friend CallReceiver CallReceiverFromArgv(Value *argv); |
|
260 }; |
|
261 |
|
262 MOZ_ALWAYS_INLINE CallReceiver |
|
263 CallReceiverFromArgv(Value *argv) |
|
264 { |
|
265 CallReceiver receiver; |
|
266 receiver.clearUsedRval(); |
|
267 receiver.argv_ = argv; |
|
268 return receiver; |
|
269 } |
|
270 |
|
271 MOZ_ALWAYS_INLINE CallReceiver |
|
272 CallReceiverFromVp(Value *vp) |
|
273 { |
|
274 return CallReceiverFromArgv(vp + 2); |
|
275 } |
|
276 |
|
277 /* |
|
278 * JS::CallArgs encapsulates everything JS::CallReceiver does, plus access to |
|
279 * the function call's arguments. The principal way to create a CallArgs is |
|
280 * like so, using JS::CallArgsFromVp: |
|
281 * |
|
282 * static bool |
|
283 * FunctionReturningArgcTimesArg0(JSContext *cx, unsigned argc, JS::Value *vp) |
|
284 * { |
|
285 * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
|
286 * |
|
287 * // Guard against no arguments or a non-numeric arg0. |
|
288 * if (args.length() == 0 || !args[0].isNumber()) { |
|
289 * args.rval().setInt32(0); |
|
290 * return true; |
|
291 * } |
|
292 * |
|
293 * args.rval().set(JS::NumberValue(args.length() * args[0].toNumber())); |
|
294 * return true; |
|
295 * } |
|
296 * |
|
297 * CallArgs is exposed publicly and used internally. Not all parts of its |
|
298 * public interface are meant to be used by embedders! See inline comments to |
|
299 * for details. |
|
300 */ |
|
301 namespace detail { |
|
302 |
|
303 template<UsedRval WantUsedRval> |
|
304 class MOZ_STACK_CLASS CallArgsBase : |
|
305 public mozilla::Conditional<WantUsedRval == detail::IncludeUsedRval, |
|
306 CallReceiver, |
|
307 CallReceiverBase<NoUsedRval> >::Type |
|
308 { |
|
309 protected: |
|
310 unsigned argc_; |
|
311 |
|
312 public: |
|
313 /* Returns the number of arguments. */ |
|
314 unsigned length() const { return argc_; } |
|
315 |
|
316 /* Returns the i-th zero-indexed argument. */ |
|
317 MutableHandleValue operator[](unsigned i) const { |
|
318 MOZ_ASSERT(i < argc_); |
|
319 return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); |
|
320 } |
|
321 |
|
322 /* |
|
323 * Returns the i-th zero-indexed argument, or |undefined| if there's no |
|
324 * such argument. |
|
325 */ |
|
326 HandleValue get(unsigned i) const { |
|
327 return i < length() |
|
328 ? HandleValue::fromMarkedLocation(&this->argv_[i]) |
|
329 : UndefinedHandleValue; |
|
330 } |
|
331 |
|
332 /* |
|
333 * Returns true if the i-th zero-indexed argument is present and is not |
|
334 * |undefined|. |
|
335 */ |
|
336 bool hasDefined(unsigned i) const { |
|
337 return i < argc_ && !this->argv_[i].isUndefined(); |
|
338 } |
|
339 |
|
340 public: |
|
341 // These methods are publicly exposed, but we're less sure of the interface |
|
342 // here than we'd like (because they're hackish and drop assertions). Try |
|
343 // to avoid using these if you can. |
|
344 |
|
345 Value *array() const { return this->argv_; } |
|
346 Value *end() const { return this->argv_ + argc_; } |
|
347 }; |
|
348 |
|
349 } // namespace detail |
|
350 |
|
351 class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval> |
|
352 { |
|
353 private: |
|
354 friend CallArgs CallArgsFromVp(unsigned argc, Value *vp); |
|
355 friend CallArgs CallArgsFromSp(unsigned argc, Value *sp); |
|
356 |
|
357 static CallArgs create(unsigned argc, Value *argv) { |
|
358 CallArgs args; |
|
359 args.clearUsedRval(); |
|
360 args.argv_ = argv; |
|
361 args.argc_ = argc; |
|
362 return args; |
|
363 } |
|
364 |
|
365 }; |
|
366 |
|
367 MOZ_ALWAYS_INLINE CallArgs |
|
368 CallArgsFromVp(unsigned argc, Value *vp) |
|
369 { |
|
370 return CallArgs::create(argc, vp + 2); |
|
371 } |
|
372 |
|
373 // This method is only intended for internal use in SpiderMonkey. We may |
|
374 // eventually move it to an internal header. Embedders should use |
|
375 // JS::CallArgsFromVp! |
|
376 MOZ_ALWAYS_INLINE CallArgs |
|
377 CallArgsFromSp(unsigned argc, Value *sp) |
|
378 { |
|
379 return CallArgs::create(argc, sp - argc); |
|
380 } |
|
381 |
|
382 } // namespace JS |
|
383 |
|
384 /* |
|
385 * Macros to hide interpreter stack layout details from a JSNative using its |
|
386 * JS::Value *vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and |
|
387 * friends, above. These macros will be removed when we change JSNative to |
|
388 * take a const JS::CallArgs&. |
|
389 */ |
|
390 |
|
391 #define JS_THIS_OBJECT(cx,vp) (JSVAL_TO_OBJECT(JS_THIS(cx,vp))) |
|
392 |
|
393 /* |
|
394 * Note: if this method returns null, an error has occurred and must be |
|
395 * propagated or caught. |
|
396 */ |
|
397 MOZ_ALWAYS_INLINE JS::Value |
|
398 JS_THIS(JSContext *cx, JS::Value *vp) |
|
399 { |
|
400 return JSVAL_IS_PRIMITIVE(vp[1]) ? JS_ComputeThis(cx, vp) : vp[1]; |
|
401 } |
|
402 |
|
403 /* |
|
404 * |this| is passed to functions in ES5 without change. Functions themselves |
|
405 * do any post-processing they desire to box |this|, compute the global object, |
|
406 * &c. This macro retrieves a function's unboxed |this| value. |
|
407 * |
|
408 * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT, |
|
409 * or vice versa. Either use the provided this value with this macro, or |
|
410 * compute the boxed |this| value using those. JS_THIS_VALUE must not be used |
|
411 * if the function is being called as a constructor. |
|
412 * |
|
413 * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above. |
|
414 * |
|
415 */ |
|
416 #define JS_THIS_VALUE(cx,vp) ((vp)[1]) |
|
417 |
|
418 #endif /* js_CallArgs_h */ |