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