LCOV - code coverage report
Current view: top level - js/src/proxy - Wrapper.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 140 203 69.0 %
Date: 2017-07-14 16:53:18 Functions: 29 42 69.0 %
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 "jscntxt.h"
       8             : #include "jscompartment.h"
       9             : #include "jsexn.h"
      10             : #include "jswrapper.h"
      11             : 
      12             : #include "js/Proxy.h"
      13             : #include "vm/ErrorObject.h"
      14             : #include "vm/ProxyObject.h"
      15             : #include "vm/RegExpObject.h"
      16             : #include "vm/WrapperObject.h"
      17             : 
      18             : #include "jsobjinlines.h"
      19             : 
      20             : #include "vm/NativeObject-inl.h"
      21             : 
      22             : using namespace js;
      23             : 
      24             : bool
      25       11358 : Wrapper::finalizeInBackground(const Value& priv) const
      26             : {
      27       11358 :     if (!priv.isObject())
      28           0 :         return true;
      29             : 
      30             :     /*
      31             :      * Make the 'background-finalized-ness' of the wrapper the same as the
      32             :      * wrapped object, to allow transplanting between them.
      33             :      */
      34       11358 :     JSObject* wrapped = MaybeForwarded(&priv.toObject());
      35             :     gc::AllocKind wrappedKind;
      36       11358 :     if (IsInsideNursery(wrapped)) {
      37        4969 :         JSRuntime *rt = wrapped->runtimeFromActiveCooperatingThread();
      38        4969 :         wrappedKind = wrapped->allocKindForTenure(rt->gc.nursery());
      39             :     } else {
      40        6389 :         wrappedKind = wrapped->asTenured().getAllocKind();
      41             :     }
      42       11358 :     return IsBackgroundFinalized(wrappedKind);
      43             : }
      44             : 
      45             : bool
      46         127 : Wrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
      47             :                                   MutableHandle<PropertyDescriptor> desc) const
      48             : {
      49         127 :     assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
      50         254 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
      51         254 :     return GetOwnPropertyDescriptor(cx, target, id, desc);
      52             : }
      53             : 
      54             : bool
      55        2003 : Wrapper::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
      56             :                         Handle<PropertyDescriptor> desc, ObjectOpResult& result) const
      57             : {
      58        2003 :     assertEnteredPolicy(cx, proxy, id, SET);
      59        4006 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
      60        4006 :     return DefineProperty(cx, target, id, desc, result);
      61             : }
      62             : 
      63             : bool
      64           8 : Wrapper::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const
      65             : {
      66           8 :     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
      67          16 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
      68          16 :     return GetPropertyKeys(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
      69             : }
      70             : 
      71             : bool
      72         414 : Wrapper::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) const
      73             : {
      74         414 :     assertEnteredPolicy(cx, proxy, id, SET);
      75         828 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
      76         828 :     return DeleteProperty(cx, target, id, result);
      77             : }
      78             : 
      79             : JSObject*
      80           5 : Wrapper::enumerate(JSContext* cx, HandleObject proxy) const
      81             : {
      82           5 :     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
      83           5 :     MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
      84          10 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
      85          10 :     return GetIterator(cx, target, 0);
      86             : }
      87             : 
      88             : bool
      89           7 : Wrapper::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const
      90             : {
      91          14 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
      92          14 :     return GetPrototype(cx, target, protop);
      93             : }
      94             : 
      95             : bool
      96           0 : Wrapper::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
      97             :                                  ObjectOpResult& result) const
      98             : {
      99           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     100           0 :     return SetPrototype(cx, target, proto, result);
     101             : }
     102             : 
     103             : bool
     104           0 : Wrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
     105             :                                            bool* isOrdinary, MutableHandleObject protop) const
     106             : {
     107           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     108           0 :     return GetPrototypeIfOrdinary(cx, target, isOrdinary, protop);
     109             : }
     110             : 
     111             : bool
     112           0 : Wrapper::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const
     113             : {
     114           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     115           0 :     return SetImmutablePrototype(cx, target, succeeded);
     116             : }
     117             : 
     118             : bool
     119           1 : Wrapper::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const
     120             : {
     121           2 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     122           2 :     return PreventExtensions(cx, target, result);
     123             : }
     124             : 
     125             : bool
     126           0 : Wrapper::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
     127             : {
     128           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     129           0 :     return IsExtensible(cx, target, extensible);
     130             : }
     131             : 
     132             : bool
     133         355 : Wrapper::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
     134             : {
     135         355 :     assertEnteredPolicy(cx, proxy, id, GET);
     136         355 :     MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     137         710 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     138         710 :     return HasProperty(cx, target, id, bp);
     139             : }
     140             : 
     141             : bool
     142        9599 : Wrapper::get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
     143             :              MutableHandleValue vp) const
     144             : {
     145        9599 :     assertEnteredPolicy(cx, proxy, id, GET);
     146       19198 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     147       19198 :     return GetProperty(cx, target, receiver, id, vp);
     148             : }
     149             : 
     150             : bool
     151         367 : Wrapper::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
     152             :              ObjectOpResult& result) const
     153             : {
     154         367 :     assertEnteredPolicy(cx, proxy, id, SET);
     155         734 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     156         734 :     return SetProperty(cx, target, id, v, receiver, result);
     157             : }
     158             : 
     159             : bool
     160        4925 : Wrapper::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
     161             : {
     162        4925 :     assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
     163        9850 :     RootedValue target(cx, proxy->as<ProxyObject>().private_());
     164             : 
     165        9850 :     InvokeArgs iargs(cx);
     166        4925 :     if (!FillArgumentsFromArraylike(cx, iargs, args))
     167           0 :         return false;
     168             : 
     169        4925 :     return js::Call(cx, target, args.thisv(), iargs, args.rval());
     170             : }
     171             : 
     172             : bool
     173         175 : Wrapper::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
     174             : {
     175         175 :     assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
     176             : 
     177         350 :     RootedValue target(cx, proxy->as<ProxyObject>().private_());
     178         175 :     if (!IsConstructor(target)) {
     179           0 :         ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, target, nullptr);
     180           0 :         return false;
     181             :     }
     182             : 
     183         350 :     ConstructArgs cargs(cx);
     184         175 :     if (!FillArgumentsFromArraylike(cx, cargs, args))
     185           0 :         return false;
     186             : 
     187         350 :     RootedObject obj(cx);
     188         175 :     if (!Construct(cx, target, cargs, args.newTarget(), &obj))
     189           0 :         return false;
     190             : 
     191         175 :     args.rval().setObject(*obj);
     192         175 :     return true;
     193             : }
     194             : 
     195             : bool
     196           0 : Wrapper::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     197             :                                MutableHandle<PropertyDescriptor> desc) const
     198             : {
     199           0 :     assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
     200           0 :     MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     201           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     202           0 :     return GetPropertyDescriptor(cx, target, id, desc);
     203             : }
     204             : 
     205             : bool
     206          45 : Wrapper::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
     207             : {
     208          45 :     assertEnteredPolicy(cx, proxy, id, GET);
     209          90 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     210          90 :     return HasOwnProperty(cx, target, id, bp);
     211             : }
     212             : 
     213             : bool
     214          47 : Wrapper::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
     215             :                                                  AutoIdVector& props) const
     216             : {
     217          47 :     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     218          94 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     219          94 :     return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
     220             : }
     221             : 
     222             : bool
     223           0 : Wrapper::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
     224             :                                const CallArgs& args) const
     225             : {
     226           0 :     args.setThis(ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
     227           0 :     if (!test(args.thisv())) {
     228           0 :         ReportIncompatible(cx, args);
     229           0 :         return false;
     230             :     }
     231             : 
     232           0 :     return CallNativeImpl(cx, impl, args);
     233             : }
     234             : 
     235             : bool
     236          24 : Wrapper::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
     237             :                                 bool* bp) const
     238             : {
     239          24 :     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     240          48 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     241          48 :     return HasInstance(cx, target, v, bp);
     242             : }
     243             : 
     244             : bool
     245         115 : Wrapper::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
     246             : {
     247         230 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     248         230 :     return GetBuiltinClass(cx, target, cls);
     249             : }
     250             : 
     251             : bool
     252          51 : Wrapper::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const
     253             : {
     254         102 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     255         102 :     return IsArray(cx, target, answer);
     256             : }
     257             : 
     258             : const char*
     259           0 : Wrapper::className(JSContext* cx, HandleObject proxy) const
     260             : {
     261           0 :     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     262           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     263           0 :     return GetObjectClassName(cx, target);
     264             : }
     265             : 
     266             : JSString*
     267           0 : Wrapper::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
     268             : {
     269           0 :     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     270           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     271           0 :     return fun_toStringHelper(cx, target, indent);
     272             : }
     273             : 
     274             : RegExpShared*
     275           0 : Wrapper::regexp_toShared(JSContext* cx, HandleObject proxy) const
     276             : {
     277           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     278           0 :     return RegExpToShared(cx, target);
     279             : }
     280             : 
     281             : bool
     282           0 : Wrapper::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
     283             : {
     284           0 :     RootedObject target(cx, proxy->as<ProxyObject>().target());
     285           0 :     return Unbox(cx, target, vp);
     286             : }
     287             : 
     288             : bool
     289        6419 : Wrapper::isCallable(JSObject* obj) const
     290             : {
     291        6419 :     JSObject * target = obj->as<ProxyObject>().target();
     292        6419 :     return target->isCallable();
     293             : }
     294             : 
     295             : bool
     296         927 : Wrapper::isConstructor(JSObject* obj) const
     297             : {
     298             :     // For now, all wrappers are constructable if they are callable. We will want to eventually
     299             :     // decouple this behavior, but none of the Wrapper infrastructure is currently prepared for
     300             :     // that.
     301         927 :     return isCallable(obj);
     302             : }
     303             : 
     304             : JSObject*
     305          12 : Wrapper::weakmapKeyDelegate(JSObject* proxy) const
     306             : {
     307             :     // This may be called during GC.
     308          12 :     return UncheckedUnwrapWithoutExpose(proxy);
     309             : }
     310             : 
     311             : JSObject*
     312        9264 : Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler,
     313             :              const WrapperOptions& options)
     314             : {
     315       18528 :     RootedValue priv(cx, ObjectValue(*obj));
     316       18528 :     return NewProxyObject(cx, handler, priv, options.proto(), options);
     317             : }
     318             : 
     319             : JSObject*
     320          10 : Wrapper::Renew(JSObject* existing, JSObject* obj, const Wrapper* handler)
     321             : {
     322          10 :     existing->as<ProxyObject>().renew(handler, ObjectValue(*obj));
     323          10 :     return existing;
     324             : }
     325             : 
     326             : const Wrapper*
     327       40916 : Wrapper::wrapperHandler(JSObject* wrapper)
     328             : {
     329       40916 :     MOZ_ASSERT(wrapper->is<WrapperObject>());
     330       40916 :     return static_cast<const Wrapper*>(wrapper->as<ProxyObject>().handler());
     331             : }
     332             : 
     333             : JSObject*
     334       49503 : Wrapper::wrappedObject(JSObject* wrapper)
     335             : {
     336       49503 :     MOZ_ASSERT(wrapper->is<WrapperObject>());
     337       49503 :     JSObject* target = wrapper->as<ProxyObject>().target();
     338             : 
     339             :     // Eagerly unmark gray wrapper targets so we can assert that we don't create
     340             :     // black to gray edges. An incremental GC will eventually mark the targets
     341             :     // of black wrappers black but while it is in progress we can observe gray
     342             :     // targets. Expose rather than returning a gray object in this case.
     343       49503 :     if (target) {
     344       49503 :         if (wrapper->isMarkedBlack())
     345       12618 :             MOZ_ASSERT(JS::ObjectIsNotGray(target));
     346       49503 :         if (!wrapper->isMarkedGray())
     347       49503 :             JS::ExposeObjectToActiveJS(target);
     348             :     }
     349             : 
     350       49503 :     return target;
     351             : }
     352             : 
     353             : JS_FRIEND_API(JSObject*)
     354       50448 : js::UncheckedUnwrapWithoutExpose(JSObject* wrapped)
     355             : {
     356             :     while (true) {
     357       57597 :         if (!wrapped->is<WrapperObject>() || MOZ_UNLIKELY(IsWindowProxy(wrapped)))
     358       43299 :             break;
     359        7149 :         wrapped = wrapped->as<WrapperObject>().target();
     360             : 
     361             :         // This can be called from Wrapper::weakmapKeyDelegate() on a wrapper
     362             :         // whose referent has been moved while it is still unmarked.
     363        7149 :         if (wrapped)
     364        7149 :             wrapped = MaybeForwarded(wrapped);
     365             :     }
     366       43299 :     return wrapped;
     367             : }
     368             : 
     369             : JS_FRIEND_API(JSObject*)
     370       99361 : js::UncheckedUnwrap(JSObject* wrapped, bool stopAtWindowProxy, unsigned* flagsp)
     371             : {
     372       99361 :     MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
     373       99361 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(wrapped->runtimeFromAnyThread()));
     374             : 
     375       99361 :     unsigned flags = 0;
     376             :     while (true) {
     377      143993 :         if (!wrapped->is<WrapperObject>() ||
     378       22832 :             MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(wrapped)))
     379             :         {
     380       99361 :             break;
     381             :         }
     382       10900 :         flags |= Wrapper::wrapperHandler(wrapped)->flags();
     383       10900 :         wrapped = Wrapper::wrappedObject(wrapped);
     384             :     }
     385       99361 :     if (flagsp)
     386       38385 :         *flagsp = flags;
     387       99361 :     return wrapped;
     388             : }
     389             : 
     390             : JS_FRIEND_API(JSObject*)
     391       58141 : js::CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy)
     392             : {
     393             :     while (true) {
     394       58141 :         JSObject* wrapper = obj;
     395       58141 :         obj = UnwrapOneChecked(obj, stopAtWindowProxy);
     396       58141 :         if (!obj || obj == wrapper)
     397      114270 :             return obj;
     398        1006 :     }
     399             : }
     400             : 
     401             : JS_FRIEND_API(JSObject*)
     402       58763 : js::UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy)
     403             : {
     404       58763 :     MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
     405       58763 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(obj->runtimeFromAnyThread()));
     406             : 
     407       61321 :     if (!obj->is<WrapperObject>() ||
     408        2558 :         MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(obj)))
     409             :     {
     410       57135 :         return obj;
     411             :     }
     412             : 
     413        1628 :     const Wrapper* handler = Wrapper::wrapperHandler(obj);
     414        1628 :     return handler->hasSecurityPolicy() ? nullptr : Wrapper::wrappedObject(obj);
     415             : }
     416             : 
     417             : void
     418           0 : js::ReportAccessDenied(JSContext* cx)
     419             : {
     420           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_OBJECT_ACCESS_DENIED);
     421           0 : }
     422             : 
     423             : const char Wrapper::family = 0;
     424             : const Wrapper Wrapper::singleton((unsigned)0);
     425             : const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
     426             : JSObject* Wrapper::defaultProto = TaggedProto::LazyProto;
     427             : 
     428             : /* Compartments. */
     429             : 
     430             : JSObject*
     431           0 : js::TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj)
     432             : {
     433             :     // Allow wrapping outer window proxies.
     434           0 :     MOZ_ASSERT(!obj->is<WrapperObject>() || IsWindowProxy(obj));
     435           0 :     return Wrapper::New(cx, obj, &CrossCompartmentWrapper::singleton);
     436             : }
     437             : 
     438           0 : ErrorCopier::~ErrorCopier()
     439             : {
     440           0 :     JSContext* cx = ac->context();
     441             : 
     442             :     // The provenance of Debugger.DebuggeeWouldRun is the topmost locking
     443             :     // debugger compartment; it should not be copied around.
     444           0 :     if (ac->origin() != cx->compartment() &&
     445           0 :         cx->isExceptionPending() &&
     446           0 :         !cx->isThrowingDebuggeeWouldRun())
     447             :     {
     448           0 :         RootedValue exc(cx);
     449           0 :         if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
     450           0 :             cx->clearPendingException();
     451           0 :             ac.reset();
     452           0 :             Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
     453           0 :             JSObject* copyobj = CopyErrorObject(cx, errObj);
     454           0 :             if (copyobj)
     455           0 :                 cx->setPendingException(ObjectValue(*copyobj));
     456             :         }
     457             :     }
     458           0 : }

Generated by: LCOV version 1.13