js/public/CallArgs.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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.

     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/. */
     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  */
    29 #ifndef js_CallArgs_h
    30 #define js_CallArgs_h
    32 #include "mozilla/Assertions.h"
    33 #include "mozilla/Attributes.h"
    34 #include "mozilla/TypeTraits.h"
    36 #include "jstypes.h"
    38 #include "js/RootingAPI.h"
    39 #include "js/Value.h"
    41 /* Typedef for native functions called by the JS VM. */
    42 typedef bool
    43 (* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp);
    45 /* Typedef for native functions that may be called in parallel. */
    46 typedef bool
    47 (* JSParallelNative)(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp);
    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);
    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);
    64 template <JSThreadSafeNative threadSafeNative>
    65 inline bool
    66 JSParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp);
    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);
    80 namespace JS {
    82 extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
    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  */
   119 namespace detail {
   121 #ifdef JS_DEBUG
   122 extern JS_PUBLIC_API(void)
   123 CheckIsValidConstructible(Value v);
   124 #endif
   126 enum UsedRval { IncludeUsedRval, NoUsedRval };
   128 template<UsedRval WantUsedRval>
   129 class MOZ_STACK_CLASS UsedRvalBase;
   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 };
   140 template<>
   141 class MOZ_STACK_CLASS UsedRvalBase<NoUsedRval>
   142 {
   143   protected:
   144     void setUsedRval() const {}
   145     void clearUsedRval() const {}
   146 };
   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_;
   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     }
   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     }
   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     }
   192     Value computeThis(JSContext *cx) const {
   193         if (thisv().isObject())
   194             return thisv();
   196         return JS_ComputeThis(cx, base());
   197     }
   199     bool isConstructing() const {
   200 #ifdef JS_DEBUG
   201         if (this->usedRval_)
   202             CheckIsValidConstructible(calleev());
   203 #endif
   204         return argv_[-1].isMagic();
   205     }
   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     }
   223   public:
   224     // These methods are only intended for internal use.  Embedders shouldn't
   225     // use them!
   227     Value *base() const { return argv_ - 2; }
   229     Value *spAfterCall() const {
   230         this->setUsedRval();
   231         return argv_ - 1;
   232     }
   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!
   239     void setCallee(Value aCalleev) const {
   240         this->clearUsedRval();
   241         argv_[-2] = aCalleev;
   242     }
   244     void setThis(Value aThisv) const {
   245         argv_[-1] = aThisv;
   246     }
   248     MutableHandleValue mutableThisv() const {
   249         return MutableHandleValue::fromMarkedLocation(&argv_[-1]);
   250     }
   251 };
   253 } // namespace detail
   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 };
   262 MOZ_ALWAYS_INLINE CallReceiver
   263 CallReceiverFromArgv(Value *argv)
   264 {
   265     CallReceiver receiver;
   266     receiver.clearUsedRval();
   267     receiver.argv_ = argv;
   268     return receiver;
   269 }
   271 MOZ_ALWAYS_INLINE CallReceiver
   272 CallReceiverFromVp(Value *vp)
   273 {
   274     return CallReceiverFromArgv(vp + 2);
   275 }
   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 {
   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_;
   312   public:
   313     /* Returns the number of arguments. */
   314     unsigned length() const { return argc_; }
   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     }
   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     }
   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     }
   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.
   345     Value *array() const { return this->argv_; }
   346     Value *end() const { return this->argv_ + argc_; }
   347 };
   349 } // namespace detail
   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);
   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     }
   365 };
   367 MOZ_ALWAYS_INLINE CallArgs
   368 CallArgsFromVp(unsigned argc, Value *vp)
   369 {
   370     return CallArgs::create(argc, vp + 2);
   371 }
   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 }
   382 } // namespace JS
   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  */
   391 #define JS_THIS_OBJECT(cx,vp)   (JSVAL_TO_OBJECT(JS_THIS(cx,vp)))
   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 }
   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])
   418 #endif /* js_CallArgs_h */

mercurial