michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: 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: /* michael@0: * Helper classes encapsulating access to the callee, |this| value, arguments, michael@0: * and argument count for a function call. michael@0: * michael@0: * The intent of JS::CallArgs and JS::CallReceiver is that they be used to michael@0: * encapsulate access to the un-abstracted |unsigned argc, Value *vp| arguments michael@0: * to a function. It's possible (albeit deprecated) to manually index into michael@0: * |vp| to access the callee, |this|, and arguments of a function, and to set michael@0: * its return value. It's also possible to use the supported API of JS_CALLEE, michael@0: * JS_THIS, JS_ARGV, JS_RVAL and JS_SET_RVAL to the same ends. But neither API michael@0: * has the error-handling or moving-GC correctness of CallArgs or CallReceiver. michael@0: * New code should use CallArgs and CallReceiver instead whenever possible. michael@0: * michael@0: * The eventual plan is to change JSNative to take |const CallArgs&| directly, michael@0: * for automatic assertion of correct use and to make calling functions more michael@0: * efficient. Embedders should start internally switching away from using michael@0: * |argc| and |vp| directly, except to create a |CallArgs|. Then, when an michael@0: * eventual release making that change occurs, porting efforts will require michael@0: * changing methods' signatures but won't require invasive changes to the michael@0: * methods' implementations, potentially under time pressure. michael@0: */ michael@0: michael@0: #ifndef js_CallArgs_h michael@0: #define js_CallArgs_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: michael@0: #include "jstypes.h" michael@0: michael@0: #include "js/RootingAPI.h" michael@0: #include "js/Value.h" michael@0: michael@0: /* Typedef for native functions called by the JS VM. */ michael@0: typedef bool michael@0: (* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp); michael@0: michael@0: /* Typedef for native functions that may be called in parallel. */ michael@0: typedef bool michael@0: (* JSParallelNative)(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp); michael@0: michael@0: /* michael@0: * Typedef for native functions that may be called either in parallel or michael@0: * sequential execution. michael@0: */ michael@0: typedef bool michael@0: (* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp); michael@0: michael@0: /* michael@0: * Convenience wrappers for passing in ThreadSafeNative to places that expect michael@0: * a JSNative or a JSParallelNative. michael@0: */ michael@0: template michael@0: inline bool michael@0: JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp); michael@0: michael@0: template michael@0: inline bool michael@0: JSParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp); michael@0: michael@0: /* michael@0: * Compute |this| for the |vp| inside a JSNative, either boxing primitives or michael@0: * replacing with the global object as necessary. michael@0: * michael@0: * This method will go away at some point: instead use |args.thisv()|. If the michael@0: * value is an object, no further work is required. If that value is |null| or michael@0: * |undefined|, use |JS_GetGlobalForObject| to compute the global object. If michael@0: * the value is some other primitive, use |JS_ValueToObject| to box it. michael@0: */ michael@0: extern JS_PUBLIC_API(JS::Value) michael@0: JS_ComputeThis(JSContext *cx, JS::Value *vp); michael@0: michael@0: namespace JS { michael@0: michael@0: extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; michael@0: michael@0: /* michael@0: * JS::CallReceiver encapsulates access to the callee, |this|, and eventual michael@0: * return value for a function call. The principal way to create a michael@0: * CallReceiver is using JS::CallReceiverFromVp: michael@0: * michael@0: * static bool michael@0: * FunctionReturningThis(JSContext *cx, unsigned argc, JS::Value *vp) michael@0: * { michael@0: * JS::CallReceiver rec = JS::CallReceiverFromVp(vp); michael@0: * michael@0: * // Access to the callee must occur before accessing/setting michael@0: * // the return value. michael@0: * JSObject &callee = rec.callee(); michael@0: * rec.rval().set(JS::ObjectValue(callee)); michael@0: * michael@0: * // callee() and calleev() will now assert. michael@0: * michael@0: * // It's always fine to access thisv(). michael@0: * HandleValue thisv = rec.thisv(); michael@0: * rec.rval().set(thisv); michael@0: * michael@0: * // As the return value was last set to |this|, returns |this|. michael@0: * return true; michael@0: * } michael@0: * michael@0: * A note on JS_ComputeThis and JS_THIS_OBJECT: these methods currently aren't michael@0: * part of the CallReceiver interface. We will likely add them at some point. michael@0: * Until then, you should probably continue using |vp| directly for these two michael@0: * cases. michael@0: * michael@0: * CallReceiver is exposed publicly and used internally. Not all parts of its michael@0: * public interface are meant to be used by embedders! See inline comments to michael@0: * for details. michael@0: */ michael@0: michael@0: namespace detail { michael@0: michael@0: #ifdef JS_DEBUG michael@0: extern JS_PUBLIC_API(void) michael@0: CheckIsValidConstructible(Value v); michael@0: #endif michael@0: michael@0: enum UsedRval { IncludeUsedRval, NoUsedRval }; michael@0: michael@0: template michael@0: class MOZ_STACK_CLASS UsedRvalBase; michael@0: michael@0: template<> michael@0: class MOZ_STACK_CLASS UsedRvalBase michael@0: { michael@0: protected: michael@0: mutable bool usedRval_; michael@0: void setUsedRval() const { usedRval_ = true; } michael@0: void clearUsedRval() const { usedRval_ = false; } michael@0: }; michael@0: michael@0: template<> michael@0: class MOZ_STACK_CLASS UsedRvalBase michael@0: { michael@0: protected: michael@0: void setUsedRval() const {} michael@0: void clearUsedRval() const {} michael@0: }; michael@0: michael@0: template michael@0: class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase< michael@0: #ifdef JS_DEBUG michael@0: WantUsedRval michael@0: #else michael@0: NoUsedRval michael@0: #endif michael@0: > michael@0: { michael@0: protected: michael@0: Value *argv_; michael@0: michael@0: public: michael@0: /* michael@0: * Returns the function being called, as an object. Must not be called michael@0: * after rval() has been used! michael@0: */ michael@0: JSObject &callee() const { michael@0: MOZ_ASSERT(!this->usedRval_); michael@0: return argv_[-2].toObject(); michael@0: } michael@0: michael@0: /* michael@0: * Returns the function being called, as a value. Must not be called after michael@0: * rval() has been used! michael@0: */ michael@0: HandleValue calleev() const { michael@0: MOZ_ASSERT(!this->usedRval_); michael@0: return HandleValue::fromMarkedLocation(&argv_[-2]); michael@0: } michael@0: michael@0: /* michael@0: * Returns the |this| value passed to the function. This method must not michael@0: * be called when the function is being called as a constructor via |new|. michael@0: * The value may or may not be an object: it is the individual function's michael@0: * responsibility to box the value if needed. michael@0: */ michael@0: HandleValue thisv() const { michael@0: // Some internal code uses thisv() in constructing cases, so don't do michael@0: // this yet. michael@0: // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); michael@0: return HandleValue::fromMarkedLocation(&argv_[-1]); michael@0: } michael@0: michael@0: Value computeThis(JSContext *cx) const { michael@0: if (thisv().isObject()) michael@0: return thisv(); michael@0: michael@0: return JS_ComputeThis(cx, base()); michael@0: } michael@0: michael@0: bool isConstructing() const { michael@0: #ifdef JS_DEBUG michael@0: if (this->usedRval_) michael@0: CheckIsValidConstructible(calleev()); michael@0: #endif michael@0: return argv_[-1].isMagic(); michael@0: } michael@0: michael@0: /* michael@0: * Returns the currently-set return value. The initial contents of this michael@0: * value are unspecified. Once this method has been called, callee() and michael@0: * calleev() can no longer be used. (If you're compiling against a debug michael@0: * build of SpiderMonkey, these methods will assert to aid debugging.) michael@0: * michael@0: * If the method you're implementing succeeds by returning true, you *must* michael@0: * set this. (SpiderMonkey doesn't currently assert this, but it will do michael@0: * so eventually.) You don't need to use or change this if your method michael@0: * fails. michael@0: */ michael@0: MutableHandleValue rval() const { michael@0: this->setUsedRval(); michael@0: return MutableHandleValue::fromMarkedLocation(&argv_[-2]); michael@0: } michael@0: michael@0: public: michael@0: // These methods are only intended for internal use. Embedders shouldn't michael@0: // use them! michael@0: michael@0: Value *base() const { return argv_ - 2; } michael@0: michael@0: Value *spAfterCall() const { michael@0: this->setUsedRval(); michael@0: return argv_ - 1; michael@0: } michael@0: michael@0: public: michael@0: // These methods are publicly exposed, but they are *not* to be used when michael@0: // implementing a JSNative method and encapsulating access to |vp| within michael@0: // it. You probably don't want to use these! michael@0: michael@0: void setCallee(Value aCalleev) const { michael@0: this->clearUsedRval(); michael@0: argv_[-2] = aCalleev; michael@0: } michael@0: michael@0: void setThis(Value aThisv) const { michael@0: argv_[-1] = aThisv; michael@0: } michael@0: michael@0: MutableHandleValue mutableThisv() const { michael@0: return MutableHandleValue::fromMarkedLocation(&argv_[-1]); michael@0: } michael@0: }; michael@0: michael@0: } // namespace detail michael@0: michael@0: class MOZ_STACK_CLASS CallReceiver : public detail::CallReceiverBase michael@0: { michael@0: private: michael@0: friend CallReceiver CallReceiverFromVp(Value *vp); michael@0: friend CallReceiver CallReceiverFromArgv(Value *argv); michael@0: }; michael@0: michael@0: MOZ_ALWAYS_INLINE CallReceiver michael@0: CallReceiverFromArgv(Value *argv) michael@0: { michael@0: CallReceiver receiver; michael@0: receiver.clearUsedRval(); michael@0: receiver.argv_ = argv; michael@0: return receiver; michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE CallReceiver michael@0: CallReceiverFromVp(Value *vp) michael@0: { michael@0: return CallReceiverFromArgv(vp + 2); michael@0: } michael@0: michael@0: /* michael@0: * JS::CallArgs encapsulates everything JS::CallReceiver does, plus access to michael@0: * the function call's arguments. The principal way to create a CallArgs is michael@0: * like so, using JS::CallArgsFromVp: michael@0: * michael@0: * static bool michael@0: * FunctionReturningArgcTimesArg0(JSContext *cx, unsigned argc, JS::Value *vp) michael@0: * { michael@0: * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); michael@0: * michael@0: * // Guard against no arguments or a non-numeric arg0. michael@0: * if (args.length() == 0 || !args[0].isNumber()) { michael@0: * args.rval().setInt32(0); michael@0: * return true; michael@0: * } michael@0: * michael@0: * args.rval().set(JS::NumberValue(args.length() * args[0].toNumber())); michael@0: * return true; michael@0: * } michael@0: * michael@0: * CallArgs is exposed publicly and used internally. Not all parts of its michael@0: * public interface are meant to be used by embedders! See inline comments to michael@0: * for details. michael@0: */ michael@0: namespace detail { michael@0: michael@0: template michael@0: class MOZ_STACK_CLASS CallArgsBase : michael@0: public mozilla::Conditional >::Type michael@0: { michael@0: protected: michael@0: unsigned argc_; michael@0: michael@0: public: michael@0: /* Returns the number of arguments. */ michael@0: unsigned length() const { return argc_; } michael@0: michael@0: /* Returns the i-th zero-indexed argument. */ michael@0: MutableHandleValue operator[](unsigned i) const { michael@0: MOZ_ASSERT(i < argc_); michael@0: return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); michael@0: } michael@0: michael@0: /* michael@0: * Returns the i-th zero-indexed argument, or |undefined| if there's no michael@0: * such argument. michael@0: */ michael@0: HandleValue get(unsigned i) const { michael@0: return i < length() michael@0: ? HandleValue::fromMarkedLocation(&this->argv_[i]) michael@0: : UndefinedHandleValue; michael@0: } michael@0: michael@0: /* michael@0: * Returns true if the i-th zero-indexed argument is present and is not michael@0: * |undefined|. michael@0: */ michael@0: bool hasDefined(unsigned i) const { michael@0: return i < argc_ && !this->argv_[i].isUndefined(); michael@0: } michael@0: michael@0: public: michael@0: // These methods are publicly exposed, but we're less sure of the interface michael@0: // here than we'd like (because they're hackish and drop assertions). Try michael@0: // to avoid using these if you can. michael@0: michael@0: Value *array() const { return this->argv_; } michael@0: Value *end() const { return this->argv_ + argc_; } michael@0: }; michael@0: michael@0: } // namespace detail michael@0: michael@0: class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase michael@0: { michael@0: private: michael@0: friend CallArgs CallArgsFromVp(unsigned argc, Value *vp); michael@0: friend CallArgs CallArgsFromSp(unsigned argc, Value *sp); michael@0: michael@0: static CallArgs create(unsigned argc, Value *argv) { michael@0: CallArgs args; michael@0: args.clearUsedRval(); michael@0: args.argv_ = argv; michael@0: args.argc_ = argc; michael@0: return args; michael@0: } michael@0: michael@0: }; michael@0: michael@0: MOZ_ALWAYS_INLINE CallArgs michael@0: CallArgsFromVp(unsigned argc, Value *vp) michael@0: { michael@0: return CallArgs::create(argc, vp + 2); michael@0: } michael@0: michael@0: // This method is only intended for internal use in SpiderMonkey. We may michael@0: // eventually move it to an internal header. Embedders should use michael@0: // JS::CallArgsFromVp! michael@0: MOZ_ALWAYS_INLINE CallArgs michael@0: CallArgsFromSp(unsigned argc, Value *sp) michael@0: { michael@0: return CallArgs::create(argc, sp - argc); michael@0: } michael@0: michael@0: } // namespace JS michael@0: michael@0: /* michael@0: * Macros to hide interpreter stack layout details from a JSNative using its michael@0: * JS::Value *vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and michael@0: * friends, above. These macros will be removed when we change JSNative to michael@0: * take a const JS::CallArgs&. michael@0: */ michael@0: michael@0: #define JS_THIS_OBJECT(cx,vp) (JSVAL_TO_OBJECT(JS_THIS(cx,vp))) michael@0: michael@0: /* michael@0: * Note: if this method returns null, an error has occurred and must be michael@0: * propagated or caught. michael@0: */ michael@0: MOZ_ALWAYS_INLINE JS::Value michael@0: JS_THIS(JSContext *cx, JS::Value *vp) michael@0: { michael@0: return JSVAL_IS_PRIMITIVE(vp[1]) ? JS_ComputeThis(cx, vp) : vp[1]; michael@0: } michael@0: michael@0: /* michael@0: * |this| is passed to functions in ES5 without change. Functions themselves michael@0: * do any post-processing they desire to box |this|, compute the global object, michael@0: * &c. This macro retrieves a function's unboxed |this| value. michael@0: * michael@0: * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT, michael@0: * or vice versa. Either use the provided this value with this macro, or michael@0: * compute the boxed |this| value using those. JS_THIS_VALUE must not be used michael@0: * if the function is being called as a constructor. michael@0: * michael@0: * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above. michael@0: * michael@0: */ michael@0: #define JS_THIS_VALUE(cx,vp) ((vp)[1]) michael@0: michael@0: #endif /* js_CallArgs_h */