CallArgs.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /*
  6. * Helper classes encapsulating access to the callee, |this| value, arguments,
  7. * and argument count for a call/construct operation.
  8. *
  9. * JS::CallArgs encapsulates access to a JSNative's un-abstracted
  10. * |unsigned argc, Value* vp| arguments. The principal way to create a
  11. * JS::CallArgs is using JS::CallArgsFromVp:
  12. *
  13. * // If provided no arguments or a non-numeric first argument, return zero.
  14. * // Otherwise return |this| exactly as given, without boxing.
  15. * static bool
  16. * Func(JSContext* cx, unsigned argc, JS::Value* vp)
  17. * {
  18. * JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  19. *
  20. * // Guard against no arguments or a non-numeric arg0.
  21. * if (args.length() == 0 || !args[0].isNumber()) {
  22. * args.rval().setInt32(0);
  23. * return true;
  24. * }
  25. *
  26. * // Access to the callee must occur before accessing/setting
  27. * // the return value.
  28. * JSObject& callee = args.callee();
  29. * args.rval().setObject(callee);
  30. *
  31. * // callee() and calleev() will now assert.
  32. *
  33. * // It's always fine to access thisv().
  34. * HandleValue thisv = args.thisv();
  35. * args.rval().set(thisv);
  36. *
  37. * // As the return value was last set to |this|, returns |this|.
  38. * return true;
  39. * }
  40. *
  41. * CallArgs is exposed publicly and used internally. Not all parts of its
  42. * public interface are meant to be used by embedders! See inline comments to
  43. * for details.
  44. *
  45. * It's possible (albeit deprecated) to manually index into |vp| to access the
  46. * callee, |this|, and arguments of a function, and to set its return value.
  47. * It's also possible to use the supported API of JS_CALLEE, JS_THIS, JS_ARGV,
  48. * JS_RVAL, and JS_SET_RVAL to the same ends.
  49. *
  50. * But neither API has the error-handling or moving-GC correctness of CallArgs.
  51. * New code should use CallArgs instead whenever possible.
  52. *
  53. * The eventual plan is to change JSNative to take |const CallArgs&| directly,
  54. * for automatic assertion of correct use and to make calling functions more
  55. * efficient. Embedders should start internally switching away from using
  56. * |argc| and |vp| directly, except to create a |CallArgs|. Then, when an
  57. * eventual release making that change occurs, porting efforts will require
  58. * changing methods' signatures but won't require invasive changes to the
  59. * methods' implementations, potentially under time pressure.
  60. */
  61. #ifndef js_CallArgs_h
  62. #define js_CallArgs_h
  63. #include "mozilla/Assertions.h"
  64. #include "mozilla/Attributes.h"
  65. #include "mozilla/TypeTraits.h"
  66. #include "jstypes.h"
  67. #include "js/RootingAPI.h"
  68. #include "js/Value.h"
  69. /* Typedef for native functions called by the JS VM. */
  70. typedef bool
  71. (* JSNative)(JSContext* cx, unsigned argc, JS::Value* vp);
  72. namespace JS {
  73. extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
  74. namespace detail {
  75. /*
  76. * Compute |this| for the |vp| inside a JSNative, either boxing primitives or
  77. * replacing with the global object as necessary.
  78. */
  79. extern JS_PUBLIC_API(Value)
  80. ComputeThis(JSContext* cx, JS::Value* vp);
  81. #ifdef JS_DEBUG
  82. extern JS_PUBLIC_API(void)
  83. CheckIsValidConstructible(const Value& v);
  84. #endif
  85. class MOZ_STACK_CLASS IncludeUsedRval
  86. {
  87. protected:
  88. #ifdef JS_DEBUG
  89. mutable bool usedRval_;
  90. void setUsedRval() const { usedRval_ = true; }
  91. void clearUsedRval() const { usedRval_ = false; }
  92. void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); }
  93. #else
  94. void setUsedRval() const {}
  95. void clearUsedRval() const {}
  96. void assertUnusedRval() const {}
  97. #endif
  98. };
  99. class MOZ_STACK_CLASS NoUsedRval
  100. {
  101. protected:
  102. void setUsedRval() const {}
  103. void clearUsedRval() const {}
  104. void assertUnusedRval() const {}
  105. };
  106. template<class WantUsedRval>
  107. class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval
  108. {
  109. static_assert(mozilla::IsSame<WantUsedRval, IncludeUsedRval>::value ||
  110. mozilla::IsSame<WantUsedRval, NoUsedRval>::value,
  111. "WantUsedRval can only be IncludeUsedRval or NoUsedRval");
  112. protected:
  113. Value* argv_;
  114. unsigned argc_;
  115. bool constructing_:1;
  116. // True if the caller does not use the return value.
  117. bool ignoresReturnValue_:1;
  118. public:
  119. // CALLEE ACCESS
  120. /*
  121. * Returns the function being called, as a value. Must not be called after
  122. * rval() has been used!
  123. */
  124. HandleValue calleev() const {
  125. this->assertUnusedRval();
  126. return HandleValue::fromMarkedLocation(&argv_[-2]);
  127. }
  128. /*
  129. * Returns the function being called, as an object. Must not be called
  130. * after rval() has been used!
  131. */
  132. JSObject& callee() const {
  133. return calleev().toObject();
  134. }
  135. // CALLING/CONSTRUCTING-DIFFERENTIATIONS
  136. bool isConstructing() const {
  137. if (!argv_[-1].isMagic())
  138. return false;
  139. #ifdef JS_DEBUG
  140. if (!this->usedRval_)
  141. CheckIsValidConstructible(calleev());
  142. #endif
  143. return true;
  144. }
  145. bool ignoresReturnValue() const {
  146. return ignoresReturnValue_;
  147. }
  148. MutableHandleValue newTarget() const {
  149. MOZ_ASSERT(constructing_);
  150. return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
  151. }
  152. /*
  153. * Returns the |this| value passed to the function. This method must not
  154. * be called when the function is being called as a constructor via |new|.
  155. * The value may or may not be an object: it is the individual function's
  156. * responsibility to box the value if needed.
  157. */
  158. HandleValue thisv() const {
  159. // Some internal code uses thisv() in constructing cases, so don't do
  160. // this yet.
  161. // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING));
  162. return HandleValue::fromMarkedLocation(&argv_[-1]);
  163. }
  164. Value computeThis(JSContext* cx) const {
  165. if (thisv().isObject())
  166. return thisv();
  167. return ComputeThis(cx, base());
  168. }
  169. // ARGUMENTS
  170. /* Returns the number of arguments. */
  171. unsigned length() const { return argc_; }
  172. /* Returns the i-th zero-indexed argument. */
  173. MutableHandleValue operator[](unsigned i) const {
  174. MOZ_ASSERT(i < argc_);
  175. return MutableHandleValue::fromMarkedLocation(&this->argv_[i]);
  176. }
  177. /*
  178. * Returns the i-th zero-indexed argument, or |undefined| if there's no
  179. * such argument.
  180. */
  181. HandleValue get(unsigned i) const {
  182. return i < length()
  183. ? HandleValue::fromMarkedLocation(&this->argv_[i])
  184. : UndefinedHandleValue;
  185. }
  186. /*
  187. * Returns true if the i-th zero-indexed argument is present and is not
  188. * |undefined|.
  189. */
  190. bool hasDefined(unsigned i) const {
  191. return i < argc_ && !this->argv_[i].isUndefined();
  192. }
  193. // RETURN VALUE
  194. /*
  195. * Returns the currently-set return value. The initial contents of this
  196. * value are unspecified. Once this method has been called, callee() and
  197. * calleev() can no longer be used. (If you're compiling against a debug
  198. * build of SpiderMonkey, these methods will assert to aid debugging.)
  199. *
  200. * If the method you're implementing succeeds by returning true, you *must*
  201. * set this. (SpiderMonkey doesn't currently assert this, but it will do
  202. * so eventually.) You don't need to use or change this if your method
  203. * fails.
  204. */
  205. MutableHandleValue rval() const {
  206. this->setUsedRval();
  207. return MutableHandleValue::fromMarkedLocation(&argv_[-2]);
  208. }
  209. public:
  210. // These methods are publicly exposed, but they are *not* to be used when
  211. // implementing a JSNative method and encapsulating access to |vp| within
  212. // it. You probably don't want to use these!
  213. void setCallee(const Value& aCalleev) const {
  214. this->clearUsedRval();
  215. argv_[-2] = aCalleev;
  216. }
  217. void setThis(const Value& aThisv) const {
  218. argv_[-1] = aThisv;
  219. }
  220. MutableHandleValue mutableThisv() const {
  221. return MutableHandleValue::fromMarkedLocation(&argv_[-1]);
  222. }
  223. public:
  224. // These methods are publicly exposed, but we're unsure of the interfaces
  225. // (because they're hackish and drop assertions). Avoid using these if you
  226. // can.
  227. Value* array() const { return argv_; }
  228. Value* end() const { return argv_ + argc_ + constructing_; }
  229. public:
  230. // These methods are only intended for internal use. Embedders shouldn't
  231. // use them!
  232. Value* base() const { return argv_ - 2; }
  233. Value* spAfterCall() const {
  234. this->setUsedRval();
  235. return argv_ - 1;
  236. }
  237. };
  238. } // namespace detail
  239. class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval>
  240. {
  241. private:
  242. friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
  243. friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing,
  244. bool ignoresReturnValue);
  245. static CallArgs create(unsigned argc, Value* argv, bool constructing,
  246. bool ignoresReturnValue = false) {
  247. CallArgs args;
  248. args.clearUsedRval();
  249. args.argv_ = argv;
  250. args.argc_ = argc;
  251. args.constructing_ = constructing;
  252. args.ignoresReturnValue_ = ignoresReturnValue;
  253. #ifdef DEBUG
  254. for (unsigned i = 0; i < argc; ++i)
  255. MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
  256. #endif
  257. return args;
  258. }
  259. public:
  260. /*
  261. * Returns true if there are at least |required| arguments passed in. If
  262. * false, it reports an error message on the context.
  263. */
  264. JS_PUBLIC_API(bool) requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const;
  265. };
  266. MOZ_ALWAYS_INLINE CallArgs
  267. CallArgsFromVp(unsigned argc, Value* vp)
  268. {
  269. return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING));
  270. }
  271. // This method is only intended for internal use in SpiderMonkey. We may
  272. // eventually move it to an internal header. Embedders should use
  273. // JS::CallArgsFromVp!
  274. MOZ_ALWAYS_INLINE CallArgs
  275. CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false,
  276. bool ignoresReturnValue = false)
  277. {
  278. return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing,
  279. ignoresReturnValue);
  280. }
  281. } // namespace JS
  282. /*
  283. * Macros to hide interpreter stack layout details from a JSNative using its
  284. * JS::Value* vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and
  285. * friends, above. These macros will be removed when we change JSNative to
  286. * take a const JS::CallArgs&.
  287. */
  288. /*
  289. * Return |this| if |this| is an object. Otherwise, return the global object
  290. * if |this| is null or undefined, and finally return a boxed version of any
  291. * other primitive.
  292. *
  293. * Note: if this method returns null, an error has occurred and must be
  294. * propagated or caught.
  295. */
  296. MOZ_ALWAYS_INLINE JS::Value
  297. JS_THIS(JSContext* cx, JS::Value* vp)
  298. {
  299. return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1];
  300. }
  301. /*
  302. * A note on JS_THIS_OBJECT: no equivalent method is part of the CallArgs
  303. * interface, and we're unlikely to add one (functions shouldn't be implicitly
  304. * exposing the global object to arbitrary callers). Continue using |vp|
  305. * directly for this case, but be aware this API will eventually be replaced
  306. * with a function that operates directly upon |args.thisv()|.
  307. */
  308. #define JS_THIS_OBJECT(cx,vp) (JS_THIS(cx,vp).toObjectOrNull())
  309. /*
  310. * |this| is passed to functions in ES5 without change. Functions themselves
  311. * do any post-processing they desire to box |this|, compute the global object,
  312. * &c. This macro retrieves a function's unboxed |this| value.
  313. *
  314. * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT,
  315. * or vice versa. Either use the provided this value with this macro, or
  316. * compute the boxed |this| value using those. JS_THIS_VALUE must not be used
  317. * if the function is being called as a constructor.
  318. *
  319. * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above.
  320. *
  321. */
  322. #define JS_THIS_VALUE(cx,vp) ((vp)[1])
  323. #endif /* js_CallArgs_h */