LCOV - code coverage report
Current view: top level - js/public - CallNonGenericMethod.h (source / functions) Hit Total Coverage
Test: output.info Lines: 8 10 80.0 %
Date: 2017-07-14 16:53:18 Functions: 25 163 15.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #ifndef js_CallNonGenericMethod_h
       8             : #define js_CallNonGenericMethod_h
       9             : 
      10             : #include "jstypes.h"
      11             : 
      12             : #include "js/CallArgs.h"
      13             : 
      14             : namespace JS {
      15             : 
      16             : // Returns true if |v| is considered an acceptable this-value.
      17             : typedef bool (*IsAcceptableThis)(HandleValue v);
      18             : 
      19             : // Implements the guts of a method; guaranteed to be provided an acceptable
      20             : // this-value, as determined by a corresponding IsAcceptableThis method.
      21             : typedef bool (*NativeImpl)(JSContext* cx, const CallArgs& args);
      22             : 
      23             : namespace detail {
      24             : 
      25             : // DON'T CALL THIS DIRECTLY.  It's for use only by CallNonGenericMethod!
      26             : extern JS_PUBLIC_API(bool)
      27             : CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args);
      28             : 
      29             : } // namespace detail
      30             : 
      31             : // Methods usually act upon |this| objects only from a single global object and
      32             : // compartment.  Sometimes, however, a method must act upon |this| values from
      33             : // multiple global objects or compartments.  In such cases the |this| value a
      34             : // method might see will be wrapped, such that various access to the object --
      35             : // to its class, its private data, its reserved slots, and so on -- will not
      36             : // work properly without entering that object's compartment.  This method
      37             : // implements a solution to this problem.
      38             : //
      39             : // To implement a method that accepts |this| values from multiple compartments,
      40             : // define two functions.  The first function matches the IsAcceptableThis type
      41             : // and indicates whether the provided value is an acceptable |this| for the
      42             : // method; it must be a pure function only of its argument.
      43             : //
      44             : //   static const JSClass AnswerClass = { ... };
      45             : //
      46             : //   static bool
      47             : //   IsAnswerObject(const Value& v)
      48             : //   {
      49             : //       if (!v.isObject())
      50             : //           return false;
      51             : //       return JS_GetClass(&v.toObject()) == &AnswerClass;
      52             : //   }
      53             : //
      54             : // The second function implements the NativeImpl signature and defines the
      55             : // behavior of the method when it is provided an acceptable |this| value.
      56             : // Aside from some typing niceties -- see the CallArgs interface for details --
      57             : // its interface is the same as that of JSNative.
      58             : //
      59             : //   static bool
      60             : //   answer_getAnswer_impl(JSContext* cx, JS::CallArgs args)
      61             : //   {
      62             : //       args.rval().setInt32(42);
      63             : //       return true;
      64             : //   }
      65             : //
      66             : // The implementation function is guaranteed to be called *only* with a |this|
      67             : // value which is considered acceptable.
      68             : //
      69             : // Now to implement the actual method, write a JSNative that calls the method
      70             : // declared below, passing the appropriate template and runtime arguments.
      71             : //
      72             : //   static bool
      73             : //   answer_getAnswer(JSContext* cx, unsigned argc, JS::Value* vp)
      74             : //   {
      75             : //       JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
      76             : //       return JS::CallNonGenericMethod<IsAnswerObject, answer_getAnswer_impl>(cx, args);
      77             : //   }
      78             : //
      79             : // Note that, because they are used as template arguments, the predicate
      80             : // and implementation functions must have external linkage. (This is
      81             : // unfortunate, but GCC wasn't inlining things as one would hope when we
      82             : // passed them as function arguments.)
      83             : //
      84             : // JS::CallNonGenericMethod will test whether |args.thisv()| is acceptable.  If
      85             : // it is, it will call the provided implementation function, which will return
      86             : // a value and indicate success.  If it is not, it will attempt to unwrap
      87             : // |this| and call the implementation function on the unwrapped |this|.  If
      88             : // that succeeds, all well and good.  If it doesn't succeed, a TypeError will
      89             : // be thrown.
      90             : //
      91             : // Note: JS::CallNonGenericMethod will only work correctly if it's called in
      92             : //       tail position in a JSNative.  Do not call it from any other place.
      93             : //
      94             : template<IsAcceptableThis Test, NativeImpl Impl>
      95             : MOZ_ALWAYS_INLINE bool
      96        2482 : CallNonGenericMethod(JSContext* cx, const CallArgs& args)
      97             : {
      98        2482 :     HandleValue thisv = args.thisv();
      99        2482 :     if (Test(thisv))
     100        2482 :         return Impl(cx, args);
     101             : 
     102           0 :     return detail::CallMethodIfWrapped(cx, Test, Impl, args);
     103             : }
     104             : 
     105             : MOZ_ALWAYS_INLINE bool
     106         297 : CallNonGenericMethod(JSContext* cx, IsAcceptableThis Test, NativeImpl Impl, const CallArgs& args)
     107             : {
     108         297 :     HandleValue thisv = args.thisv();
     109         297 :     if (Test(thisv))
     110         297 :         return Impl(cx, args);
     111             : 
     112           0 :     return detail::CallMethodIfWrapped(cx, Test, Impl, args);
     113             : }
     114             : 
     115             : } // namespace JS
     116             : 
     117             : #endif /* js_CallNonGenericMethod_h */

Generated by: LCOV version 1.13