LCOV - code coverage report
Current view: top level - dom/bindings - DOMJSProxyHandler.h (source / functions) Hit Total Coverage
Test: output.info Lines: 38 44 86.4 %
Date: 2017-07-14 16:53:18 Functions: 6 8 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_dom_DOMJSProxyHandler_h
       8             : #define mozilla_dom_DOMJSProxyHandler_h
       9             : 
      10             : #include "mozilla/Attributes.h"
      11             : #include "mozilla/Likely.h"
      12             : 
      13             : #include "jsapi.h"
      14             : #include "js/Proxy.h"
      15             : #include "nsString.h"
      16             : 
      17             : namespace mozilla {
      18             : namespace dom {
      19             : 
      20             : /**
      21             :  * DOM proxies store the expando object in the private slot.
      22             :  *
      23             :  * The expando object is a plain JSObject whose properties correspond to
      24             :  * "expandos" (custom properties set by the script author).
      25             :  *
      26             :  * The exact value stored in the proxy's private slot depends on whether the
      27             :  * interface is annotated with the [OverrideBuiltins] extended attribute.
      28             :  *
      29             :  * If it is, the proxy is initialized with a PrivateValue, which contains a
      30             :  * pointer to a js::ExpandoAndGeneration object; this contains a pointer to
      31             :  * the actual expando object as well as the "generation" of the object.  The
      32             :  * proxy handler will trace the expando object stored in the
      33             :  * js::ExpandoAndGeneration while the proxy itself is alive.
      34             :  *
      35             :  * If it is not, the proxy is initialized with an UndefinedValue. In
      36             :  * EnsureExpandoObject, it is set to an ObjectValue that points to the
      37             :  * expando object directly. (It is set back to an UndefinedValue only when
      38             :  * the object is about to die.)
      39             :  */
      40             : 
      41             : template<typename T> struct Prefable;
      42             : 
      43             : class BaseDOMProxyHandler : public js::BaseProxyHandler
      44             : {
      45             : public:
      46             :   explicit constexpr BaseDOMProxyHandler(const void* aProxyFamily, bool aHasPrototype = false)
      47             :     : js::BaseProxyHandler(aProxyFamily, aHasPrototype)
      48             :   {}
      49             : 
      50             :   // Implementations of methods that can be implemented in terms of
      51             :   // other lower-level methods.
      52             :   bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
      53             :                                 JS::Handle<jsid> id,
      54             :                                 JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
      55             :   virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
      56             :                                JS::AutoIdVector &props) const override;
      57             : 
      58             :   virtual bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy,
      59             :                                       bool* isOrdinary,
      60             :                                       JS::MutableHandle<JSObject*> proto) const override;
      61             : 
      62             :   // We override getOwnEnumerablePropertyKeys() and implement it directly
      63             :   // instead of using the default implementation, which would call
      64             :   // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
      65             :   // unnecessary work during enumeration.
      66             :   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
      67             :                                             JS::AutoIdVector &props) const override;
      68             : 
      69             :   bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
      70             :              JS::Handle<JSObject*> callable) const override;
      71             :   bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
      72             :                JS::Handle<jsid> id) const override;
      73             : 
      74             : protected:
      75             :   // Hook for subclasses to implement shared ownPropertyKeys()/keys()
      76             :   // functionality.  The "flags" argument is either JSITER_OWNONLY (for keys())
      77             :   // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for
      78             :   // ownPropertyKeys()).
      79             :   virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
      80             :                             unsigned flags,
      81             :                             JS::AutoIdVector& props) const = 0;
      82             : 
      83             :   // Hook for subclasses to allow set() to ignore named props while other things
      84             :   // that look at property descriptors see them.  This is intentionally not
      85             :   // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
      86             :   // our public getOwnPropertyDescriptor.
      87             :   virtual bool getOwnPropDescriptor(JSContext* cx,
      88             :                                     JS::Handle<JSObject*> proxy,
      89             :                                     JS::Handle<jsid> id,
      90             :                                     bool ignoreNamedProps,
      91             :                                     JS::MutableHandle<JS::PropertyDescriptor> desc) const = 0;
      92             : };
      93             : 
      94             : class DOMProxyHandler : public BaseDOMProxyHandler
      95             : {
      96             : public:
      97             :   constexpr DOMProxyHandler()
      98             :     : BaseDOMProxyHandler(&family)
      99             :   {}
     100             : 
     101           0 :   bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     102             :                       JS::Handle<JS::PropertyDescriptor> desc,
     103             :                       JS::ObjectOpResult &result) const override
     104             :   {
     105             :     bool unused;
     106           0 :     return defineProperty(cx, proxy, id, desc, result, &unused);
     107             :   }
     108             :   virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     109             :                               JS::Handle<JS::PropertyDescriptor> desc,
     110             :                               JS::ObjectOpResult &result, bool *defined) const;
     111             :   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     112             :                JS::ObjectOpResult &result) const override;
     113             :   bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
     114             :                          JS::ObjectOpResult& result) const override;
     115             :   bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
     116             :                     const override;
     117             :   bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     118             :            JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, JS::ObjectOpResult &result)
     119             :            const override;
     120             : 
     121             :   /*
     122             :    * If assigning to proxy[id] hits a named setter with OverrideBuiltins or
     123             :    * an indexed setter, call it and set *done to true on success. Otherwise, set
     124             :    * *done to false.
     125             :    */
     126             :   virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     127             :                          JS::Handle<JS::Value> v, bool *done) const;
     128             : 
     129             :   /*
     130             :    * Get the expando object for the given DOM proxy.
     131             :    */
     132             :   static JSObject* GetExpandoObject(JSObject* obj);
     133             : 
     134             :   /*
     135             :    * Clear the expando object for the given DOM proxy and return it.  This
     136             :    * function will ensure that the returned object is exposed to active JS if
     137             :    * the given object is exposed.
     138             :    *
     139             :    * GetAndClearExpandoObject does not DROP or clear the preserving wrapper
     140             :    * flag.
     141             :    */
     142             :   static JSObject* GetAndClearExpandoObject(JSObject* obj);
     143             : 
     144             :   /*
     145             :    * Ensure that the given proxy (obj) has an expando object, and return it.
     146             :    * Returns null on failure.
     147             :    */
     148             :   static JSObject* EnsureExpandoObject(JSContext* cx,
     149             :                                        JS::Handle<JSObject*> obj);
     150             : 
     151             :   static const char family;
     152             : };
     153             : 
     154             : // Class used by shadowing handlers (the ones that have [OverrideBuiltins].
     155             : // This handles tracing the expando in ExpandoAndGeneration.
     156             : class ShadowingDOMProxyHandler : public DOMProxyHandler
     157             : {
     158             :   virtual void trace(JSTracer* trc, JSObject* proxy) const override;
     159             : };
     160             : 
     161          91 : inline bool IsDOMProxy(JSObject *obj)
     162             : {
     163          91 :     const js::Class* clasp = js::GetObjectClass(obj);
     164         182 :     return clasp->isProxy() &&
     165         182 :            js::GetProxyHandler(obj)->family() == &DOMProxyHandler::family;
     166             : }
     167             : 
     168             : inline const DOMProxyHandler*
     169           0 : GetDOMProxyHandler(JSObject* obj)
     170             : {
     171           0 :   MOZ_ASSERT(IsDOMProxy(obj));
     172           0 :   return static_cast<const DOMProxyHandler*>(js::GetProxyHandler(obj));
     173             : }
     174             : 
     175             : extern jsid s_length_id;
     176             : 
     177             : // A return value of UINT32_MAX indicates "not an array index".  Note, in
     178             : // particular, that UINT32_MAX itself is not a valid array index in general.
     179             : inline uint32_t
     180        1447 : GetArrayIndexFromId(JSContext* cx, JS::Handle<jsid> id)
     181             : {
     182             :   // Much like js::IdIsIndex, except with a fast path for "length" and another
     183             :   // fast path for starting with a lowercase ascii char.  Is that second one
     184             :   // really needed?  I guess it is because StringIsArrayIndex is out of line...
     185        1447 :   if (MOZ_LIKELY(JSID_IS_INT(id))) {
     186          76 :     return JSID_TO_INT(id);
     187             :   }
     188        1371 :   if (MOZ_LIKELY(id == s_length_id)) {
     189          54 :     return UINT32_MAX;
     190             :   }
     191        1317 :   if (MOZ_UNLIKELY(!JSID_IS_ATOM(id))) {
     192          14 :     return UINT32_MAX;
     193             :   }
     194             : 
     195        1303 :   JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
     196             :   char16_t s;
     197             :   {
     198        2606 :     JS::AutoCheckCannotGC nogc;
     199        1303 :     if (js::LinearStringHasLatin1Chars(str)) {
     200        1303 :       s = *js::GetLatin1LinearStringChars(nogc, str);
     201             :     } else {
     202           0 :       s = *js::GetTwoByteLinearStringChars(nogc, str);
     203             :     }
     204             :   }
     205        1303 :   if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
     206         966 :     return UINT32_MAX;
     207             : 
     208             :   uint32_t i;
     209         337 :   return js::StringIsArrayIndex(str, &i) ? i : UINT32_MAX;
     210             : }
     211             : 
     212             : inline bool
     213        1448 : IsArrayIndex(uint32_t index)
     214             : {
     215        1448 :   return index < UINT32_MAX;
     216             : }
     217             : 
     218             : inline void
     219          14 : FillPropertyDescriptor(JS::MutableHandle<JS::PropertyDescriptor> desc,
     220             :                        JSObject* obj, bool readonly, bool enumerable = true)
     221             : {
     222          14 :   desc.object().set(obj);
     223          28 :   desc.setAttributes((readonly ? JSPROP_READONLY : 0) |
     224          28 :                      (enumerable ? JSPROP_ENUMERATE : 0));
     225          14 :   desc.setGetter(nullptr);
     226          14 :   desc.setSetter(nullptr);
     227          14 : }
     228             : 
     229             : inline void
     230          14 : FillPropertyDescriptor(JS::MutableHandle<JS::PropertyDescriptor> desc,
     231             :                        JSObject* obj, const JS::Value& v,
     232             :                        bool readonly, bool enumerable = true)
     233             : {
     234          14 :   desc.value().set(v);
     235          14 :   FillPropertyDescriptor(desc, obj, readonly, enumerable);
     236          14 : }
     237             : 
     238             : inline void
     239           8 : FillPropertyDescriptor(JS::MutableHandle<JS::PropertyDescriptor> desc,
     240             :                        JSObject* obj, unsigned attributes, const JS::Value& v)
     241             : {
     242           8 :   desc.object().set(obj);
     243           8 :   desc.value().set(v);
     244           8 :   desc.setAttributes(attributes);
     245           8 :   desc.setGetter(nullptr);
     246           8 :   desc.setSetter(nullptr);
     247           8 : }
     248             : 
     249             : } // namespace dom
     250             : } // namespace mozilla
     251             : 
     252             : #endif /* mozilla_dom_DOMProxyHandler_h */

Generated by: LCOV version 1.13