1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/public/CallArgs.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,418 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 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 +/* 1.11 + * Helper classes encapsulating access to the callee, |this| value, arguments, 1.12 + * and argument count for a function call. 1.13 + * 1.14 + * The intent of JS::CallArgs and JS::CallReceiver is that they be used to 1.15 + * encapsulate access to the un-abstracted |unsigned argc, Value *vp| arguments 1.16 + * to a function. It's possible (albeit deprecated) to manually index into 1.17 + * |vp| to access the callee, |this|, and arguments of a function, and to set 1.18 + * its return value. It's also possible to use the supported API of JS_CALLEE, 1.19 + * JS_THIS, JS_ARGV, JS_RVAL and JS_SET_RVAL to the same ends. But neither API 1.20 + * has the error-handling or moving-GC correctness of CallArgs or CallReceiver. 1.21 + * New code should use CallArgs and CallReceiver instead whenever possible. 1.22 + * 1.23 + * The eventual plan is to change JSNative to take |const CallArgs&| directly, 1.24 + * for automatic assertion of correct use and to make calling functions more 1.25 + * efficient. Embedders should start internally switching away from using 1.26 + * |argc| and |vp| directly, except to create a |CallArgs|. Then, when an 1.27 + * eventual release making that change occurs, porting efforts will require 1.28 + * changing methods' signatures but won't require invasive changes to the 1.29 + * methods' implementations, potentially under time pressure. 1.30 + */ 1.31 + 1.32 +#ifndef js_CallArgs_h 1.33 +#define js_CallArgs_h 1.34 + 1.35 +#include "mozilla/Assertions.h" 1.36 +#include "mozilla/Attributes.h" 1.37 +#include "mozilla/TypeTraits.h" 1.38 + 1.39 +#include "jstypes.h" 1.40 + 1.41 +#include "js/RootingAPI.h" 1.42 +#include "js/Value.h" 1.43 + 1.44 +/* Typedef for native functions called by the JS VM. */ 1.45 +typedef bool 1.46 +(* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp); 1.47 + 1.48 +/* Typedef for native functions that may be called in parallel. */ 1.49 +typedef bool 1.50 +(* JSParallelNative)(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp); 1.51 + 1.52 +/* 1.53 + * Typedef for native functions that may be called either in parallel or 1.54 + * sequential execution. 1.55 + */ 1.56 +typedef bool 1.57 +(* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp); 1.58 + 1.59 +/* 1.60 + * Convenience wrappers for passing in ThreadSafeNative to places that expect 1.61 + * a JSNative or a JSParallelNative. 1.62 + */ 1.63 +template <JSThreadSafeNative threadSafeNative> 1.64 +inline bool 1.65 +JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp); 1.66 + 1.67 +template <JSThreadSafeNative threadSafeNative> 1.68 +inline bool 1.69 +JSParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp); 1.70 + 1.71 +/* 1.72 + * Compute |this| for the |vp| inside a JSNative, either boxing primitives or 1.73 + * replacing with the global object as necessary. 1.74 + * 1.75 + * This method will go away at some point: instead use |args.thisv()|. If the 1.76 + * value is an object, no further work is required. If that value is |null| or 1.77 + * |undefined|, use |JS_GetGlobalForObject| to compute the global object. If 1.78 + * the value is some other primitive, use |JS_ValueToObject| to box it. 1.79 + */ 1.80 +extern JS_PUBLIC_API(JS::Value) 1.81 +JS_ComputeThis(JSContext *cx, JS::Value *vp); 1.82 + 1.83 +namespace JS { 1.84 + 1.85 +extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; 1.86 + 1.87 +/* 1.88 + * JS::CallReceiver encapsulates access to the callee, |this|, and eventual 1.89 + * return value for a function call. The principal way to create a 1.90 + * CallReceiver is using JS::CallReceiverFromVp: 1.91 + * 1.92 + * static bool 1.93 + * FunctionReturningThis(JSContext *cx, unsigned argc, JS::Value *vp) 1.94 + * { 1.95 + * JS::CallReceiver rec = JS::CallReceiverFromVp(vp); 1.96 + * 1.97 + * // Access to the callee must occur before accessing/setting 1.98 + * // the return value. 1.99 + * JSObject &callee = rec.callee(); 1.100 + * rec.rval().set(JS::ObjectValue(callee)); 1.101 + * 1.102 + * // callee() and calleev() will now assert. 1.103 + * 1.104 + * // It's always fine to access thisv(). 1.105 + * HandleValue thisv = rec.thisv(); 1.106 + * rec.rval().set(thisv); 1.107 + * 1.108 + * // As the return value was last set to |this|, returns |this|. 1.109 + * return true; 1.110 + * } 1.111 + * 1.112 + * A note on JS_ComputeThis and JS_THIS_OBJECT: these methods currently aren't 1.113 + * part of the CallReceiver interface. We will likely add them at some point. 1.114 + * Until then, you should probably continue using |vp| directly for these two 1.115 + * cases. 1.116 + * 1.117 + * CallReceiver is exposed publicly and used internally. Not all parts of its 1.118 + * public interface are meant to be used by embedders! See inline comments to 1.119 + * for details. 1.120 + */ 1.121 + 1.122 +namespace detail { 1.123 + 1.124 +#ifdef JS_DEBUG 1.125 +extern JS_PUBLIC_API(void) 1.126 +CheckIsValidConstructible(Value v); 1.127 +#endif 1.128 + 1.129 +enum UsedRval { IncludeUsedRval, NoUsedRval }; 1.130 + 1.131 +template<UsedRval WantUsedRval> 1.132 +class MOZ_STACK_CLASS UsedRvalBase; 1.133 + 1.134 +template<> 1.135 +class MOZ_STACK_CLASS UsedRvalBase<IncludeUsedRval> 1.136 +{ 1.137 + protected: 1.138 + mutable bool usedRval_; 1.139 + void setUsedRval() const { usedRval_ = true; } 1.140 + void clearUsedRval() const { usedRval_ = false; } 1.141 +}; 1.142 + 1.143 +template<> 1.144 +class MOZ_STACK_CLASS UsedRvalBase<NoUsedRval> 1.145 +{ 1.146 + protected: 1.147 + void setUsedRval() const {} 1.148 + void clearUsedRval() const {} 1.149 +}; 1.150 + 1.151 +template<UsedRval WantUsedRval> 1.152 +class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase< 1.153 +#ifdef JS_DEBUG 1.154 + WantUsedRval 1.155 +#else 1.156 + NoUsedRval 1.157 +#endif 1.158 + > 1.159 +{ 1.160 + protected: 1.161 + Value *argv_; 1.162 + 1.163 + public: 1.164 + /* 1.165 + * Returns the function being called, as an object. Must not be called 1.166 + * after rval() has been used! 1.167 + */ 1.168 + JSObject &callee() const { 1.169 + MOZ_ASSERT(!this->usedRval_); 1.170 + return argv_[-2].toObject(); 1.171 + } 1.172 + 1.173 + /* 1.174 + * Returns the function being called, as a value. Must not be called after 1.175 + * rval() has been used! 1.176 + */ 1.177 + HandleValue calleev() const { 1.178 + MOZ_ASSERT(!this->usedRval_); 1.179 + return HandleValue::fromMarkedLocation(&argv_[-2]); 1.180 + } 1.181 + 1.182 + /* 1.183 + * Returns the |this| value passed to the function. This method must not 1.184 + * be called when the function is being called as a constructor via |new|. 1.185 + * The value may or may not be an object: it is the individual function's 1.186 + * responsibility to box the value if needed. 1.187 + */ 1.188 + HandleValue thisv() const { 1.189 + // Some internal code uses thisv() in constructing cases, so don't do 1.190 + // this yet. 1.191 + // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); 1.192 + return HandleValue::fromMarkedLocation(&argv_[-1]); 1.193 + } 1.194 + 1.195 + Value computeThis(JSContext *cx) const { 1.196 + if (thisv().isObject()) 1.197 + return thisv(); 1.198 + 1.199 + return JS_ComputeThis(cx, base()); 1.200 + } 1.201 + 1.202 + bool isConstructing() const { 1.203 +#ifdef JS_DEBUG 1.204 + if (this->usedRval_) 1.205 + CheckIsValidConstructible(calleev()); 1.206 +#endif 1.207 + return argv_[-1].isMagic(); 1.208 + } 1.209 + 1.210 + /* 1.211 + * Returns the currently-set return value. The initial contents of this 1.212 + * value are unspecified. Once this method has been called, callee() and 1.213 + * calleev() can no longer be used. (If you're compiling against a debug 1.214 + * build of SpiderMonkey, these methods will assert to aid debugging.) 1.215 + * 1.216 + * If the method you're implementing succeeds by returning true, you *must* 1.217 + * set this. (SpiderMonkey doesn't currently assert this, but it will do 1.218 + * so eventually.) You don't need to use or change this if your method 1.219 + * fails. 1.220 + */ 1.221 + MutableHandleValue rval() const { 1.222 + this->setUsedRval(); 1.223 + return MutableHandleValue::fromMarkedLocation(&argv_[-2]); 1.224 + } 1.225 + 1.226 + public: 1.227 + // These methods are only intended for internal use. Embedders shouldn't 1.228 + // use them! 1.229 + 1.230 + Value *base() const { return argv_ - 2; } 1.231 + 1.232 + Value *spAfterCall() const { 1.233 + this->setUsedRval(); 1.234 + return argv_ - 1; 1.235 + } 1.236 + 1.237 + public: 1.238 + // These methods are publicly exposed, but they are *not* to be used when 1.239 + // implementing a JSNative method and encapsulating access to |vp| within 1.240 + // it. You probably don't want to use these! 1.241 + 1.242 + void setCallee(Value aCalleev) const { 1.243 + this->clearUsedRval(); 1.244 + argv_[-2] = aCalleev; 1.245 + } 1.246 + 1.247 + void setThis(Value aThisv) const { 1.248 + argv_[-1] = aThisv; 1.249 + } 1.250 + 1.251 + MutableHandleValue mutableThisv() const { 1.252 + return MutableHandleValue::fromMarkedLocation(&argv_[-1]); 1.253 + } 1.254 +}; 1.255 + 1.256 +} // namespace detail 1.257 + 1.258 +class MOZ_STACK_CLASS CallReceiver : public detail::CallReceiverBase<detail::IncludeUsedRval> 1.259 +{ 1.260 + private: 1.261 + friend CallReceiver CallReceiverFromVp(Value *vp); 1.262 + friend CallReceiver CallReceiverFromArgv(Value *argv); 1.263 +}; 1.264 + 1.265 +MOZ_ALWAYS_INLINE CallReceiver 1.266 +CallReceiverFromArgv(Value *argv) 1.267 +{ 1.268 + CallReceiver receiver; 1.269 + receiver.clearUsedRval(); 1.270 + receiver.argv_ = argv; 1.271 + return receiver; 1.272 +} 1.273 + 1.274 +MOZ_ALWAYS_INLINE CallReceiver 1.275 +CallReceiverFromVp(Value *vp) 1.276 +{ 1.277 + return CallReceiverFromArgv(vp + 2); 1.278 +} 1.279 + 1.280 +/* 1.281 + * JS::CallArgs encapsulates everything JS::CallReceiver does, plus access to 1.282 + * the function call's arguments. The principal way to create a CallArgs is 1.283 + * like so, using JS::CallArgsFromVp: 1.284 + * 1.285 + * static bool 1.286 + * FunctionReturningArgcTimesArg0(JSContext *cx, unsigned argc, JS::Value *vp) 1.287 + * { 1.288 + * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.289 + * 1.290 + * // Guard against no arguments or a non-numeric arg0. 1.291 + * if (args.length() == 0 || !args[0].isNumber()) { 1.292 + * args.rval().setInt32(0); 1.293 + * return true; 1.294 + * } 1.295 + * 1.296 + * args.rval().set(JS::NumberValue(args.length() * args[0].toNumber())); 1.297 + * return true; 1.298 + * } 1.299 + * 1.300 + * CallArgs is exposed publicly and used internally. Not all parts of its 1.301 + * public interface are meant to be used by embedders! See inline comments to 1.302 + * for details. 1.303 + */ 1.304 +namespace detail { 1.305 + 1.306 +template<UsedRval WantUsedRval> 1.307 +class MOZ_STACK_CLASS CallArgsBase : 1.308 + public mozilla::Conditional<WantUsedRval == detail::IncludeUsedRval, 1.309 + CallReceiver, 1.310 + CallReceiverBase<NoUsedRval> >::Type 1.311 +{ 1.312 + protected: 1.313 + unsigned argc_; 1.314 + 1.315 + public: 1.316 + /* Returns the number of arguments. */ 1.317 + unsigned length() const { return argc_; } 1.318 + 1.319 + /* Returns the i-th zero-indexed argument. */ 1.320 + MutableHandleValue operator[](unsigned i) const { 1.321 + MOZ_ASSERT(i < argc_); 1.322 + return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); 1.323 + } 1.324 + 1.325 + /* 1.326 + * Returns the i-th zero-indexed argument, or |undefined| if there's no 1.327 + * such argument. 1.328 + */ 1.329 + HandleValue get(unsigned i) const { 1.330 + return i < length() 1.331 + ? HandleValue::fromMarkedLocation(&this->argv_[i]) 1.332 + : UndefinedHandleValue; 1.333 + } 1.334 + 1.335 + /* 1.336 + * Returns true if the i-th zero-indexed argument is present and is not 1.337 + * |undefined|. 1.338 + */ 1.339 + bool hasDefined(unsigned i) const { 1.340 + return i < argc_ && !this->argv_[i].isUndefined(); 1.341 + } 1.342 + 1.343 + public: 1.344 + // These methods are publicly exposed, but we're less sure of the interface 1.345 + // here than we'd like (because they're hackish and drop assertions). Try 1.346 + // to avoid using these if you can. 1.347 + 1.348 + Value *array() const { return this->argv_; } 1.349 + Value *end() const { return this->argv_ + argc_; } 1.350 +}; 1.351 + 1.352 +} // namespace detail 1.353 + 1.354 +class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval> 1.355 +{ 1.356 + private: 1.357 + friend CallArgs CallArgsFromVp(unsigned argc, Value *vp); 1.358 + friend CallArgs CallArgsFromSp(unsigned argc, Value *sp); 1.359 + 1.360 + static CallArgs create(unsigned argc, Value *argv) { 1.361 + CallArgs args; 1.362 + args.clearUsedRval(); 1.363 + args.argv_ = argv; 1.364 + args.argc_ = argc; 1.365 + return args; 1.366 + } 1.367 + 1.368 +}; 1.369 + 1.370 +MOZ_ALWAYS_INLINE CallArgs 1.371 +CallArgsFromVp(unsigned argc, Value *vp) 1.372 +{ 1.373 + return CallArgs::create(argc, vp + 2); 1.374 +} 1.375 + 1.376 +// This method is only intended for internal use in SpiderMonkey. We may 1.377 +// eventually move it to an internal header. Embedders should use 1.378 +// JS::CallArgsFromVp! 1.379 +MOZ_ALWAYS_INLINE CallArgs 1.380 +CallArgsFromSp(unsigned argc, Value *sp) 1.381 +{ 1.382 + return CallArgs::create(argc, sp - argc); 1.383 +} 1.384 + 1.385 +} // namespace JS 1.386 + 1.387 +/* 1.388 + * Macros to hide interpreter stack layout details from a JSNative using its 1.389 + * JS::Value *vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and 1.390 + * friends, above. These macros will be removed when we change JSNative to 1.391 + * take a const JS::CallArgs&. 1.392 + */ 1.393 + 1.394 +#define JS_THIS_OBJECT(cx,vp) (JSVAL_TO_OBJECT(JS_THIS(cx,vp))) 1.395 + 1.396 +/* 1.397 + * Note: if this method returns null, an error has occurred and must be 1.398 + * propagated or caught. 1.399 + */ 1.400 +MOZ_ALWAYS_INLINE JS::Value 1.401 +JS_THIS(JSContext *cx, JS::Value *vp) 1.402 +{ 1.403 + return JSVAL_IS_PRIMITIVE(vp[1]) ? JS_ComputeThis(cx, vp) : vp[1]; 1.404 +} 1.405 + 1.406 +/* 1.407 + * |this| is passed to functions in ES5 without change. Functions themselves 1.408 + * do any post-processing they desire to box |this|, compute the global object, 1.409 + * &c. This macro retrieves a function's unboxed |this| value. 1.410 + * 1.411 + * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT, 1.412 + * or vice versa. Either use the provided this value with this macro, or 1.413 + * compute the boxed |this| value using those. JS_THIS_VALUE must not be used 1.414 + * if the function is being called as a constructor. 1.415 + * 1.416 + * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above. 1.417 + * 1.418 + */ 1.419 +#define JS_THIS_VALUE(cx,vp) ((vp)[1]) 1.420 + 1.421 +#endif /* js_CallArgs_h */