LCOV - code coverage report
Current view: top level - dom/bindings - DOMJSProxyHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 55 127 43.3 %
Date: 2017-07-14 16:53:18 Functions: 8 19 42.1 %
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             : #include "mozilla/dom/DOMJSProxyHandler.h"
       8             : #include "xpcpublic.h"
       9             : #include "xpcprivate.h"
      10             : #include "XPCWrapper.h"
      11             : #include "WrapperFactory.h"
      12             : #include "nsDOMClassInfo.h"
      13             : #include "nsWrapperCacheInlines.h"
      14             : #include "mozilla/dom/BindingUtils.h"
      15             : 
      16             : #include "jsapi.h"
      17             : 
      18             : using namespace JS;
      19             : 
      20             : namespace mozilla {
      21             : namespace dom {
      22             : 
      23           3 : jsid s_length_id = JSID_VOID;
      24             : 
      25             : bool
      26           3 : DefineStaticJSVals(JSContext* cx)
      27             : {
      28           3 :   return AtomizeAndPinJSString(cx, s_length_id, "length");
      29             : }
      30             : 
      31             : const char DOMProxyHandler::family = 0;
      32             : 
      33             : js::DOMProxyShadowsResult
      34           6 : DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id)
      35             : {
      36          12 :   JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
      37           6 :   JS::Value v = js::GetProxyPrivate(proxy);
      38           6 :   bool isOverrideBuiltins = !v.isObject() && !v.isUndefined();
      39           6 :   if (expando) {
      40             :     bool hasOwn;
      41           0 :     if (!JS_AlreadyHasOwnPropertyById(cx, expando, id, &hasOwn))
      42           0 :       return js::ShadowCheckFailed;
      43             : 
      44           0 :     if (hasOwn) {
      45           0 :       return isOverrideBuiltins ?
      46           0 :         js::ShadowsViaIndirectExpando : js::ShadowsViaDirectExpando;
      47             :     }
      48             :   }
      49             : 
      50           6 :   if (!isOverrideBuiltins) {
      51             :     // Our expando, if any, didn't shadow, so we're not shadowing at all.
      52           6 :     return js::DoesntShadow;
      53             :   }
      54             : 
      55             :   bool hasOwn;
      56           0 :   if (!GetProxyHandler(proxy)->hasOwn(cx, proxy, id, &hasOwn))
      57           0 :     return js::ShadowCheckFailed;
      58             : 
      59           0 :   return hasOwn ? js::Shadows : js::DoesntShadowUnique;
      60             : }
      61             : 
      62             : // Store the information for the specialized ICs.
      63             : struct SetDOMProxyInformation
      64             : {
      65           3 :   SetDOMProxyInformation() {
      66             :     js::SetDOMProxyInformation((const void*) &DOMProxyHandler::family,
      67           3 :                                DOMProxyShadows);
      68           3 :   }
      69             : };
      70             : 
      71           3 : SetDOMProxyInformation gSetDOMProxyInformation;
      72             : 
      73             : // static
      74             : JSObject*
      75           0 : DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
      76             : {
      77           0 :   MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
      78           0 :   JS::Value v = js::GetProxyPrivate(obj);
      79           0 :   if (v.isUndefined()) {
      80           0 :     return nullptr;
      81             :   }
      82             : 
      83           0 :   if (v.isObject()) {
      84           0 :     js::SetProxyPrivate(obj, UndefinedValue());
      85             :   } else {
      86             :     js::ExpandoAndGeneration* expandoAndGeneration =
      87           0 :       static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
      88           0 :     v = expandoAndGeneration->expando;
      89           0 :     if (v.isUndefined()) {
      90           0 :       return nullptr;
      91             :     }
      92             :     // We have to expose v to active JS here.  The reason for that is that we
      93             :     // might be in the middle of a GC right now.  If our proxy hasn't been
      94             :     // traced yet, when it _does_ get traced it won't trace the expando, since
      95             :     // we're breaking that link.  But the Rooted we're presumably being placed
      96             :     // into is also not going to trace us, because Rooted marking is done at
      97             :     // the very beginning of the GC.  In that situation, we need to manually
      98             :     // mark the expando as live here.  JS::ExposeValueToActiveJS will do just
      99             :     // that for us.
     100             :     //
     101             :     // We don't need to do this in the non-expandoAndGeneration case, because
     102             :     // in that case our value is stored in a slot and slots will already mark
     103             :     // the old thing live when the value in the slot changes.
     104           0 :     JS::ExposeValueToActiveJS(v);
     105           0 :     expandoAndGeneration->expando = UndefinedValue();
     106             :   }
     107             : 
     108             : 
     109           0 :   return &v.toObject();
     110             : }
     111             : 
     112             : // static
     113             : JSObject*
     114          10 : DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
     115             : {
     116          10 :   NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
     117          10 :   JS::Value v = js::GetProxyPrivate(obj);
     118          10 :   if (v.isObject()) {
     119           0 :     return &v.toObject();
     120             :   }
     121             : 
     122             :   js::ExpandoAndGeneration* expandoAndGeneration;
     123          10 :   if (!v.isUndefined()) {
     124           7 :     expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
     125           7 :     if (expandoAndGeneration->expando.isObject()) {
     126           0 :       return &expandoAndGeneration->expando.toObject();
     127             :     }
     128             :   } else {
     129           3 :     expandoAndGeneration = nullptr;
     130             :   }
     131             : 
     132             :   JS::Rooted<JSObject*> expando(cx,
     133          20 :     JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
     134          10 :   if (!expando) {
     135           0 :     return nullptr;
     136             :   }
     137             : 
     138          10 :   nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
     139             :   nsWrapperCache* cache;
     140          10 :   CallQueryInterface(native, &cache);
     141          10 :   cache->PreserveWrapper(native);
     142             : 
     143          10 :   if (expandoAndGeneration) {
     144           7 :     expandoAndGeneration->expando.setObject(*expando);
     145           7 :     return expando;
     146             :   }
     147             : 
     148           3 :   js::SetProxyPrivate(obj, ObjectValue(*expando));
     149             : 
     150           3 :   return expando;
     151             : }
     152             : 
     153             : bool
     154           0 : DOMProxyHandler::preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
     155             :                                    JS::ObjectOpResult& result) const
     156             : {
     157             :   // always extensible per WebIDL
     158           0 :   return result.failCantPreventExtensions();
     159             : }
     160             : 
     161             : bool
     162           0 : DOMProxyHandler::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) const
     163             : {
     164           0 :   *extensible = true;
     165           0 :   return true;
     166             : }
     167             : 
     168             : bool
     169         481 : BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
     170             :                                               JS::Handle<JSObject*> proxy,
     171             :                                               JS::Handle<jsid> id,
     172             :                                               MutableHandle<PropertyDescriptor> desc) const
     173             : {
     174             :   return getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ false,
     175         481 :                               desc);
     176             : }
     177             : 
     178             : bool
     179           0 : DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     180             :                                 Handle<PropertyDescriptor> desc,
     181             :                                 JS::ObjectOpResult &result, bool *defined) const
     182             : {
     183           0 :   if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) {
     184           0 :     return result.failGetterOnly();
     185             :   }
     186             : 
     187           0 :   if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
     188           0 :     return result.succeed();
     189             :   }
     190             : 
     191           0 :   JS::Rooted<JSObject*> expando(cx, EnsureExpandoObject(cx, proxy));
     192           0 :   if (!expando) {
     193           0 :     return false;
     194             :   }
     195             : 
     196           0 :   if (!JS_DefinePropertyById(cx, expando, id, desc, result)) {
     197           0 :     return false;
     198             :   }
     199           0 :   *defined = true;
     200           0 :   return true;
     201             : }
     202             : 
     203             : bool
     204           9 : DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<jsid> id,
     205             :                      Handle<JS::Value> v, Handle<JS::Value> receiver,
     206             :                      ObjectOpResult &result) const
     207             : {
     208           9 :   MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
     209             :              "Should not have a XrayWrapper here");
     210             :   bool done;
     211           9 :   if (!setCustom(cx, proxy, id, v, &done)) {
     212           0 :     return false;
     213             :   }
     214           9 :   if (done) {
     215           0 :     return result.succeed();
     216             :   }
     217             : 
     218             :   // Make sure to ignore our named properties when checking for own
     219             :   // property descriptors for a set.
     220          18 :   JS::Rooted<PropertyDescriptor> ownDesc(cx);
     221          18 :   if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true,
     222           9 :                             &ownDesc)) {
     223           0 :     return false;
     224             :   }
     225           9 :   return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, ownDesc, result);
     226             : }
     227             : 
     228             : bool
     229           0 : DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
     230             :                          JS::Handle<jsid> id, JS::ObjectOpResult &result) const
     231             : {
     232           0 :   JS::Rooted<JSObject*> expando(cx);
     233           0 :   if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
     234           0 :     return JS_DeletePropertyById(cx, expando, id, result);
     235             :   }
     236             : 
     237           0 :   return result.succeed();
     238             : }
     239             : 
     240             : bool
     241           0 : BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     242             :                            JS::Handle<JSObject*> callable) const
     243             : {
     244           0 :   return js::WatchGuts(cx, proxy, id, callable);
     245             : }
     246             : 
     247             : bool
     248           0 : BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const
     249             : {
     250           0 :   return js::UnwatchGuts(cx, proxy, id);
     251             : }
     252             : 
     253             : bool
     254           0 : BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
     255             :                                      JS::Handle<JSObject*> proxy,
     256             :                                      JS::AutoIdVector& props) const
     257             : {
     258           0 :   return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
     259             : }
     260             : 
     261             : bool
     262           0 : BaseDOMProxyHandler::getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy,
     263             :                                             bool* isOrdinary,
     264             :                                             JS::MutableHandle<JSObject*> proto) const
     265             : {
     266           0 :   *isOrdinary = true;
     267           0 :   proto.set(GetStaticPrototype(proxy));
     268           0 :   return true;
     269             : }
     270             : 
     271             : bool
     272           0 : BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
     273             :                                                   JS::Handle<JSObject*> proxy,
     274             :                                                   JS::AutoIdVector& props) const
     275             : {
     276           0 :   return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
     277             : }
     278             : 
     279             : bool
     280           9 : DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     281             :                            JS::Handle<JS::Value> v, bool *done) const
     282             : {
     283           9 :   *done = false;
     284           9 :   return true;
     285             : }
     286             : 
     287             : //static
     288             : JSObject *
     289          81 : DOMProxyHandler::GetExpandoObject(JSObject *obj)
     290             : {
     291          81 :   MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
     292          81 :   JS::Value v = js::GetProxyPrivate(obj);
     293          81 :   if (v.isObject()) {
     294           2 :     return &v.toObject();
     295             :   }
     296             : 
     297          79 :   if (v.isUndefined()) {
     298          73 :     return nullptr;
     299             :   }
     300             : 
     301             :   js::ExpandoAndGeneration* expandoAndGeneration =
     302           6 :     static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
     303           6 :   v = expandoAndGeneration->expando;
     304           6 :   return v.isUndefined() ? nullptr : &v.toObject();
     305             : }
     306             : 
     307             : void
     308           0 : ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const
     309             : {
     310           0 :   DOMProxyHandler::trace(trc, proxy);
     311             : 
     312           0 :   MOZ_ASSERT(IsDOMProxy(proxy), "expected a DOM proxy object");
     313           0 :   JS::Value v = js::GetProxyPrivate(proxy);
     314           0 :   MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!");
     315             : 
     316             :   // The proxy's private slot is set when we allocate the proxy,
     317             :   // so it cannot be |undefined|.
     318           0 :   MOZ_ASSERT(!v.isUndefined());
     319             : 
     320             :   js::ExpandoAndGeneration* expandoAndGeneration =
     321           0 :     static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
     322           0 :   JS::TraceEdge(trc, &expandoAndGeneration->expando,
     323           0 :                 "Shadowing DOM proxy expando");
     324           0 : }
     325             : 
     326             : } // namespace dom
     327             : } // namespace mozilla

Generated by: LCOV version 1.13