LCOV - code coverage report
Current view: top level - js/src/proxy - BaseProxyHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 55 202 27.2 %
Date: 2017-07-14 16:53:18 Functions: 10 31 32.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             : #include "js/Proxy.h"
       8             : #include "vm/ProxyObject.h"
       9             : 
      10             : #include "jscntxtinlines.h"
      11             : #include "jsobjinlines.h"
      12             : 
      13             : using namespace js;
      14             : 
      15             : using JS::IsArrayAnswer;
      16             : 
      17             : bool
      18           0 : BaseProxyHandler::enter(JSContext* cx, HandleObject wrapper, HandleId id, Action act, bool mayThrow,
      19             :                         bool* bp) const
      20             : {
      21           0 :     *bp = true;
      22           0 :     return true;
      23             : }
      24             : 
      25             : bool
      26           3 : BaseProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
      27             : {
      28           3 :     assertEnteredPolicy(cx, proxy, id, GET);
      29             : 
      30             :     // This method is not covered by any spec, but we follow ES 2016
      31             :     // (February 11, 2016) 9.1.7.1 fairly closely.
      32             : 
      33             :     // Step 2. (Step 1 is a superfluous assertion.)
      34             :     // Non-standard: Use our faster hasOwn trap.
      35           3 :     if (!hasOwn(cx, proxy, id, bp))
      36           0 :         return false;
      37             : 
      38             :     // Step 3.
      39           3 :     if (*bp)
      40           3 :         return true;
      41             : 
      42             :     // The spec calls this variable "parent", but that word has weird
      43             :     // connotations in SpiderMonkey, so let's go with "proto".
      44             :     // Step 4.
      45           0 :     RootedObject proto(cx);
      46           0 :     if (!GetPrototype(cx, proxy, &proto))
      47           0 :         return false;
      48             : 
      49             :     // Step 5.,5.a.
      50           0 :     if (proto)
      51           0 :         return HasProperty(cx, proto, id, bp);
      52             : 
      53             :     // Step 6.
      54           0 :     *bp = false;
      55           0 :     return true;
      56             : }
      57             : 
      58             : bool
      59           0 : BaseProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
      60             :                                         MutableHandle<PropertyDescriptor> desc) const
      61             : {
      62           0 :     assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
      63             : 
      64           0 :     if (!getOwnPropertyDescriptor(cx, proxy, id, desc))
      65           0 :         return false;
      66           0 :     if (desc.object())
      67           0 :         return true;
      68             : 
      69           0 :     RootedObject proto(cx);
      70           0 :     if (!GetPrototype(cx, proxy, &proto))
      71           0 :         return false;
      72           0 :     if (!proto) {
      73           0 :         MOZ_ASSERT(!desc.object());
      74           0 :         return true;
      75             :     }
      76           0 :     return GetPropertyDescriptor(cx, proto, id, desc);
      77             : }
      78             : 
      79             : 
      80             : bool
      81         952 : BaseProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
      82             : {
      83         952 :     assertEnteredPolicy(cx, proxy, id, GET);
      84        1904 :     Rooted<PropertyDescriptor> desc(cx);
      85         952 :     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
      86           0 :         return false;
      87         952 :     *bp = !!desc.object();
      88         952 :     return true;
      89             : }
      90             : 
      91             : bool
      92           0 : BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
      93             :                       HandleId id, MutableHandleValue vp) const
      94             : {
      95           0 :     assertEnteredPolicy(cx, proxy, id, GET);
      96             : 
      97             :     // This method is not covered by any spec, but we follow ES 2016
      98             :     // (January 21, 2016) 9.1.8 fairly closely.
      99             : 
     100             :     // Step 2. (Step 1 is a superfluous assertion.)
     101           0 :     Rooted<PropertyDescriptor> desc(cx);
     102           0 :     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
     103           0 :         return false;
     104           0 :     desc.assertCompleteIfFound();
     105             : 
     106             :     // Step 3.
     107           0 :     if (!desc.object()) {
     108             :         // The spec calls this variable "parent", but that word has weird
     109             :         // connotations in SpiderMonkey, so let's go with "proto".
     110             :         // Step 3.a.
     111           0 :         RootedObject proto(cx);
     112           0 :         if (!GetPrototype(cx, proxy, &proto))
     113           0 :             return false;
     114             : 
     115             :         // Step 3.b.
     116           0 :         if (!proto) {
     117           0 :             vp.setUndefined();
     118           0 :             return true;
     119             :         }
     120             : 
     121             :         // Step 3.c.
     122           0 :         return GetProperty(cx, proto, receiver, id, vp);
     123             :     }
     124             : 
     125             :     // Step 4.
     126           0 :     if (desc.isDataDescriptor()) {
     127           0 :         vp.set(desc.value());
     128           0 :         return true;
     129             :     }
     130             : 
     131             :     // Step 5.
     132           0 :     MOZ_ASSERT(desc.isAccessorDescriptor());
     133           0 :     RootedObject getter(cx, desc.getterObject());
     134             : 
     135             :     // Step 6.
     136           0 :     if (!getter) {
     137           0 :         vp.setUndefined();
     138           0 :         return true;
     139             :     }
     140             : 
     141             :     // Step 7.
     142           0 :     RootedValue getterFunc(cx, ObjectValue(*getter));
     143           0 :     return CallGetter(cx, receiver, getterFunc, vp);
     144             : }
     145             : 
     146             : bool
     147          28 : BaseProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
     148             :                       HandleValue receiver, ObjectOpResult& result) const
     149             : {
     150          28 :     assertEnteredPolicy(cx, proxy, id, SET);
     151             : 
     152             :     // This method is not covered by any spec, but we follow ES6 draft rev 28
     153             :     // (2014 Oct 14) 9.1.9 fairly closely, adapting it slightly for
     154             :     // SpiderMonkey's particular foibles.
     155             : 
     156             :     // Steps 2-3.  (Step 1 is a superfluous assertion.)
     157          56 :     Rooted<PropertyDescriptor> ownDesc(cx);
     158          28 :     if (!getOwnPropertyDescriptor(cx, proxy, id, &ownDesc))
     159           0 :         return false;
     160          28 :     ownDesc.assertCompleteIfFound();
     161             : 
     162             :     // The rest is factored out into a separate function with a weird name.
     163             :     // This algorithm continues just below.
     164          28 :     return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, ownDesc, result);
     165             : }
     166             : 
     167             : bool
     168          37 : js::SetPropertyIgnoringNamedGetter(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
     169             :                                    HandleValue receiver, Handle<PropertyDescriptor> ownDesc_,
     170             :                                    ObjectOpResult& result)
     171             : {
     172          74 :     Rooted<PropertyDescriptor> ownDesc(cx, ownDesc_);
     173             : 
     174             :     // Step 4.
     175          37 :     if (!ownDesc.object()) {
     176             :         // The spec calls this variable "parent", but that word has weird
     177             :         // connotations in SpiderMonkey, so let's go with "proto".
     178          37 :         RootedObject proto(cx);
     179          37 :         if (!GetPrototype(cx, obj, &proto))
     180           0 :             return false;
     181          37 :         if (proto)
     182          37 :             return SetProperty(cx, proto, id, v, receiver, result);
     183             : 
     184             :         // Step 4.d.
     185           0 :         ownDesc.setDataDescriptor(UndefinedHandleValue, JSPROP_ENUMERATE);
     186             :     }
     187             : 
     188             :     // Step 5.
     189           0 :     if (ownDesc.isDataDescriptor()) {
     190             :         // Steps 5.a-b.
     191           0 :         if (!ownDesc.writable())
     192           0 :             return result.fail(JSMSG_READ_ONLY);
     193           0 :         if (!receiver.isObject())
     194           0 :             return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
     195           0 :         RootedObject receiverObj(cx, &receiver.toObject());
     196             : 
     197             :         // Nonstandard SpiderMonkey special case: setter ops.
     198           0 :         SetterOp setter = ownDesc.setter();
     199           0 :         MOZ_ASSERT(setter != JS_StrictPropertyStub);
     200           0 :         if (setter && setter != JS_StrictPropertyStub) {
     201           0 :             RootedValue valCopy(cx, v);
     202           0 :             return CallJSSetterOp(cx, setter, receiverObj, id, &valCopy, result);
     203             :         }
     204             : 
     205             :         // Steps 5.c-d.
     206           0 :         Rooted<PropertyDescriptor> existingDescriptor(cx);
     207           0 :         if (!GetOwnPropertyDescriptor(cx, receiverObj, id, &existingDescriptor))
     208           0 :             return false;
     209             : 
     210             :         // Step 5.e.
     211           0 :         if (existingDescriptor.object()) {
     212             :             // Step 5.e.i.
     213           0 :             if (existingDescriptor.isAccessorDescriptor())
     214           0 :                 return result.fail(JSMSG_OVERWRITING_ACCESSOR);
     215             : 
     216             :             // Step 5.e.ii.
     217           0 :             if (!existingDescriptor.writable())
     218           0 :                 return result.fail(JSMSG_READ_ONLY);
     219             :         }
     220             : 
     221             : 
     222             :         // Steps 5.e.iii-iv. and 5.f.i.
     223             :         unsigned attrs =
     224           0 :             existingDescriptor.object()
     225           0 :             ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT
     226           0 :             : JSPROP_ENUMERATE;
     227             : 
     228             :         // A very old nonstandard SpiderMonkey extension: default to the Class
     229             :         // getter and setter ops.
     230           0 :         const Class* clasp = receiverObj->getClass();
     231           0 :         MOZ_ASSERT(clasp->getGetProperty() != JS_PropertyStub);
     232           0 :         MOZ_ASSERT(clasp->getSetProperty() != JS_StrictPropertyStub);
     233           0 :         return DefineProperty(cx, receiverObj, id, v,
     234           0 :                               clasp->getGetProperty(), clasp->getSetProperty(), attrs, result);
     235             :     }
     236             : 
     237             :     // Step 6.
     238           0 :     MOZ_ASSERT(ownDesc.isAccessorDescriptor());
     239           0 :     RootedObject setter(cx);
     240           0 :     if (ownDesc.hasSetterObject())
     241           0 :         setter = ownDesc.setterObject();
     242           0 :     if (!setter)
     243           0 :         return result.fail(JSMSG_GETTER_ONLY);
     244           0 :     RootedValue setterValue(cx, ObjectValue(*setter));
     245           0 :     if (!CallSetter(cx, receiver, setterValue, v))
     246           0 :         return false;
     247           0 :     return result.succeed();
     248             : }
     249             : 
     250             : bool
     251           2 : BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
     252             :                                                AutoIdVector& props) const
     253             : {
     254           2 :     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     255           2 :     MOZ_ASSERT(props.length() == 0);
     256             : 
     257           2 :     if (!ownPropertyKeys(cx, proxy, props))
     258           0 :         return false;
     259             : 
     260             :     /* Select only the enumerable properties through in-place iteration. */
     261           4 :     RootedId id(cx);
     262           2 :     size_t i = 0;
     263           9 :     for (size_t j = 0, len = props.length(); j < len; j++) {
     264           7 :         MOZ_ASSERT(i <= j);
     265           7 :         id = props[j];
     266           7 :         if (JSID_IS_SYMBOL(id))
     267           0 :             continue;
     268             : 
     269          14 :         AutoWaivePolicy policy(cx, proxy, id, BaseProxyHandler::GET);
     270          14 :         Rooted<PropertyDescriptor> desc(cx);
     271           7 :         if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
     272           0 :             return false;
     273           7 :         desc.assertCompleteIfFound();
     274             : 
     275           7 :         if (desc.object() && desc.enumerable())
     276           7 :             props[i++].set(id);
     277             :     }
     278             : 
     279           2 :     MOZ_ASSERT(i <= props.length());
     280           2 :     if (!props.resize(i))
     281           0 :         return false;
     282             : 
     283           2 :     return true;
     284             : }
     285             : 
     286             : JSObject*
     287           0 : BaseProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const
     288             : {
     289           0 :     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     290             : 
     291             :     // GetPropertyKeys will invoke getOwnEnumerablePropertyKeys along the proto
     292             :     // chain for us.
     293           0 :     AutoIdVector props(cx);
     294           0 :     if (!GetPropertyKeys(cx, proxy, 0, &props))
     295           0 :         return nullptr;
     296             : 
     297           0 :     return EnumeratedIdVectorToIterator(cx, proxy, 0, props);
     298             : }
     299             : 
     300             : bool
     301           0 : BaseProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
     302             : {
     303           0 :     MOZ_CRASH("callable proxies should implement call trap");
     304             : }
     305             : 
     306             : bool
     307           0 : BaseProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
     308             : {
     309           0 :     MOZ_CRASH("callable proxies should implement construct trap");
     310             : }
     311             : 
     312             : const char*
     313           0 : BaseProxyHandler::className(JSContext* cx, HandleObject proxy) const
     314             : {
     315           0 :     return proxy->isCallable() ? "Function" : "Object";
     316             : }
     317             : 
     318             : JSString*
     319           0 : BaseProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
     320             : {
     321           0 :     if (proxy->isCallable())
     322           0 :         return JS_NewStringCopyZ(cx, "function () {\n    [native code]\n}");
     323           0 :     RootedValue v(cx, ObjectValue(*proxy));
     324           0 :     ReportIsNotFunction(cx, v);
     325           0 :     return nullptr;
     326             : }
     327             : 
     328             : RegExpShared*
     329           0 : BaseProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
     330             : {
     331           0 :     MOZ_CRASH("This should have been a wrapped regexp");
     332             : }
     333             : 
     334             : bool
     335           0 : BaseProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
     336             : {
     337           0 :     vp.setUndefined();
     338           0 :     return true;
     339             : }
     340             : 
     341             : bool
     342           0 : BaseProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
     343             :                              const CallArgs& args) const
     344             : {
     345           0 :     ReportIncompatible(cx, args);
     346           0 :     return false;
     347             : }
     348             : 
     349             : bool
     350           0 : BaseProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
     351             :                               bool* bp) const
     352             : {
     353           0 :     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     354           0 :     RootedValue val(cx, ObjectValue(*proxy.get()));
     355           0 :     ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
     356           0 :                      JSDVG_SEARCH_STACK, val, nullptr);
     357           0 :     return false;
     358             : }
     359             : 
     360             : bool
     361           0 : BaseProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
     362             : {
     363           0 :     *cls = ESClass::Other;
     364           0 :     return true;
     365             : }
     366             : 
     367             : bool
     368           4 : BaseProxyHandler::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer) const
     369             : {
     370           4 :     *answer = IsArrayAnswer::NotArray;
     371           4 :     return true;
     372             : }
     373             : 
     374             : void
     375        2112 : BaseProxyHandler::trace(JSTracer* trc, JSObject* proxy) const
     376             : {
     377        2112 : }
     378             : 
     379             : void
     380           0 : BaseProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
     381             : {
     382           0 : }
     383             : 
     384             : void
     385        2101 : BaseProxyHandler::objectMoved(JSObject* proxy, const JSObject* old) const
     386             : {
     387        2101 : }
     388             : 
     389             : JSObject*
     390           0 : BaseProxyHandler::weakmapKeyDelegate(JSObject* proxy) const
     391             : {
     392           0 :     return nullptr;
     393             : }
     394             : 
     395             : bool
     396           0 : BaseProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const
     397             : {
     398           0 :     MOZ_CRASH("must override getPrototype with dynamic prototype");
     399             : }
     400             : 
     401             : bool
     402           0 : BaseProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
     403             :                                ObjectOpResult& result) const
     404             : {
     405             :     // Disallow sets of protos on proxies with dynamic prototypes but no hook.
     406             :     // This keeps us away from the footgun of having the first proto set opt
     407             :     // you out of having dynamic protos altogether.
     408             :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_PROTO_OF,
     409           0 :                               "incompatible Proxy");
     410           0 :     return false;
     411             : }
     412             : 
     413             : bool
     414           0 : BaseProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const
     415             : {
     416           0 :     *succeeded = false;
     417           0 :     return true;
     418             : }
     419             : 
     420             : bool
     421           0 : BaseProxyHandler::watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable) const
     422             : {
     423             :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
     424           0 :                               proxy->getClass()->name);
     425           0 :     return false;
     426             : }
     427             : 
     428             : bool
     429           0 : BaseProxyHandler::unwatch(JSContext* cx, HandleObject proxy, HandleId id) const
     430             : {
     431           0 :     return true;
     432             : }
     433             : 
     434             : bool
     435          35 : BaseProxyHandler::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
     436             :                               ElementAdder* adder) const
     437             : {
     438          35 :     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     439             : 
     440          35 :     return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder);
     441             : }
     442             : 
     443             : bool
     444          18 : BaseProxyHandler::isCallable(JSObject* obj) const
     445             : {
     446          18 :     return false;
     447             : }
     448             : 
     449             : bool
     450           0 : BaseProxyHandler::isConstructor(JSObject* obj) const
     451             : {
     452           0 :     return false;
     453             : }

Generated by: LCOV version 1.13