LCOV - code coverage report
Current view: top level - js/ipc - WrapperOwner.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 76 584 13.0 %
Date: 2017-07-14 16:53:18 Functions: 11 80 13.8 %
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=4 sw=4 et tw=80:
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       7             : 
       8             : #include "WrapperOwner.h"
       9             : #include "JavaScriptLogging.h"
      10             : #include "mozilla/Unused.h"
      11             : #include "mozilla/dom/BindingUtils.h"
      12             : #include "jsfriendapi.h"
      13             : #include "js/CharacterEncoding.h"
      14             : #include "xpcprivate.h"
      15             : #include "CPOWTimer.h"
      16             : #include "WrapperFactory.h"
      17             : 
      18             : #include "nsIDocShellTreeItem.h"
      19             : #include "nsIDOMDocument.h"
      20             : 
      21             : using namespace js;
      22             : using namespace JS;
      23             : using namespace mozilla;
      24             : using namespace mozilla::jsipc;
      25             : 
      26           0 : struct AuxCPOWData
      27             : {
      28             :     ObjectId id;
      29             :     bool isCallable;
      30             :     bool isConstructor;
      31             :     bool isDOMObject;
      32             : 
      33             :     // The object tag is just some auxilliary information that clients can use
      34             :     // however they see fit.
      35             :     nsCString objectTag;
      36             : 
      37             :     // The class name for WrapperOwner::className, below.
      38             :     nsCString className;
      39             : 
      40           5 :     AuxCPOWData(ObjectId id,
      41             :                 bool isCallable,
      42             :                 bool isConstructor,
      43             :                 bool isDOMObject,
      44             :                 const nsACString& objectTag)
      45           5 :       : id(id),
      46             :         isCallable(isCallable),
      47             :         isConstructor(isConstructor),
      48             :         isDOMObject(isDOMObject),
      49           5 :         objectTag(objectTag)
      50           5 :     {}
      51             : };
      52             : 
      53           3 : WrapperOwner::WrapperOwner()
      54           3 :   : inactive_(false)
      55             : {
      56           3 : }
      57             : 
      58             : static inline AuxCPOWData*
      59           0 : AuxCPOWDataOf(JSObject* obj)
      60             : {
      61           0 :     MOZ_ASSERT(IsCPOW(obj));
      62           0 :     return static_cast<AuxCPOWData*>(GetProxyReservedSlot(obj, 1).toPrivate());
      63             : }
      64             : 
      65             : static inline WrapperOwner*
      66           0 : OwnerOf(JSObject* obj)
      67             : {
      68           0 :     MOZ_ASSERT(IsCPOW(obj));
      69           0 :     return reinterpret_cast<WrapperOwner*>(GetProxyReservedSlot(obj, 0).toPrivate());
      70             : }
      71             : 
      72             : ObjectId
      73           0 : WrapperOwner::idOfUnchecked(JSObject* obj)
      74             : {
      75           0 :     MOZ_ASSERT(IsCPOW(obj));
      76             : 
      77           0 :     AuxCPOWData* aux = AuxCPOWDataOf(obj);
      78           0 :     MOZ_ASSERT(!aux->id.isNull());
      79           0 :     return aux->id;
      80             : }
      81             : 
      82             : ObjectId
      83           0 : WrapperOwner::idOf(JSObject* obj)
      84             : {
      85           0 :     ObjectId objId = idOfUnchecked(obj);
      86           0 :     MOZ_ASSERT(hasCPOW(objId, obj));
      87           0 :     return objId;
      88             : }
      89             : 
      90             : class CPOWProxyHandler : public BaseProxyHandler
      91             : {
      92             :   public:
      93             :     constexpr CPOWProxyHandler()
      94             :       : BaseProxyHandler(&family) {}
      95             : 
      96           5 :     virtual bool finalizeInBackground(const Value& priv) const override {
      97           5 :         return false;
      98             :     }
      99             : 
     100             :     virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     101             :                                           MutableHandle<PropertyDescriptor> desc) const override;
     102             :     virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
     103             :                                 Handle<PropertyDescriptor> desc,
     104             :                                 ObjectOpResult& result) const override;
     105             :     virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
     106             :                                  AutoIdVector& props) const override;
     107             :     virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
     108             :                          ObjectOpResult& result) const override;
     109             :     virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const override;
     110             :     virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
     111             :                                    ObjectOpResult& result) const override;
     112             :     virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
     113             :     virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
     114             :     virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
     115             :                      HandleId id, MutableHandleValue vp) const override;
     116             :     virtual bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
     117             :                      JS::HandleValue receiver, JS::ObjectOpResult& result) const override;
     118             :     virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
     119             :     virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
     120             : 
     121             :     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     122             :                                        MutableHandle<PropertyDescriptor> desc) const override;
     123             :     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
     124             :     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
     125             :                                               AutoIdVector& props) const override;
     126             :     virtual bool hasInstance(JSContext* cx, HandleObject proxy,
     127             :                              MutableHandleValue v, bool* bp) const override;
     128             :     virtual bool getBuiltinClass(JSContext* cx, HandleObject obj, js::ESClass* cls) const override;
     129             :     virtual bool isArray(JSContext* cx, HandleObject obj,
     130             :                          IsArrayAnswer* answer) const override;
     131             :     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     132             :     virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     133             :     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const override;
     134             :     virtual void objectMoved(JSObject* proxy, const JSObject* old) const override;
     135             :     virtual bool isCallable(JSObject* obj) const override;
     136             :     virtual bool isConstructor(JSObject* obj) const override;
     137             :     virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const override;
     138             :     virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
     139             :                                         MutableHandleObject protop) const override;
     140             : 
     141             :     static const char family;
     142             :     static const CPOWProxyHandler singleton;
     143             : };
     144             : 
     145             : const char CPOWProxyHandler::family = 0;
     146             : const CPOWProxyHandler CPOWProxyHandler::singleton;
     147             : 
     148             : #define FORWARD(call, args, failRetVal)                                 \
     149             :     AUTO_PROFILER_LABEL(__func__, JS);                                  \
     150             :     WrapperOwner* owner = OwnerOf(proxy);                               \
     151             :     if (!owner->active()) {                                             \
     152             :         JS_ReportErrorASCII(cx, "cannot use a CPOW whose process is gone"); \
     153             :         return failRetVal;                                              \
     154             :     }                                                                   \
     155             :     if (!owner->allowMessage(cx)) {                                     \
     156             :         return failRetVal;                                              \
     157             :     }                                                                   \
     158             :     {                                                                   \
     159             :         CPOWTimer timer(cx);                                            \
     160             :         return owner->call args;                                        \
     161             :     }
     162             : 
     163             : bool
     164           0 : CPOWProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     165             :                                         MutableHandle<PropertyDescriptor> desc) const
     166             : {
     167           0 :     FORWARD(getPropertyDescriptor, (cx, proxy, id, desc), false);
     168             : }
     169             : 
     170             : bool
     171           0 : WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     172             :                                     MutableHandle<PropertyDescriptor> desc)
     173             : {
     174           0 :     ObjectId objId = idOf(proxy);
     175             : 
     176           0 :     JSIDVariant idVar;
     177           0 :     if (!toJSIDVariant(cx, id, &idVar))
     178           0 :         return false;
     179             : 
     180           0 :     ReturnStatus status;
     181           0 :     PPropertyDescriptor result;
     182           0 :     if (!SendGetPropertyDescriptor(objId, idVar, &status, &result))
     183           0 :         return ipcfail(cx);
     184             : 
     185           0 :     LOG_STACK();
     186             : 
     187           0 :     if (!ok(cx, status))
     188           0 :         return false;
     189             : 
     190           0 :     return toDescriptor(cx, result, desc);
     191             : }
     192             : 
     193             : bool
     194           0 : CPOWProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     195             :                                            MutableHandle<PropertyDescriptor> desc) const
     196             : {
     197           0 :     FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc), false);
     198             : }
     199             : 
     200             : bool
     201           0 : WrapperOwner::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     202             :                                        MutableHandle<PropertyDescriptor> desc)
     203             : {
     204           0 :     ObjectId objId = idOf(proxy);
     205             : 
     206           0 :     JSIDVariant idVar;
     207           0 :     if (!toJSIDVariant(cx, id, &idVar))
     208           0 :         return false;
     209             : 
     210           0 :     ReturnStatus status;
     211           0 :     PPropertyDescriptor result;
     212           0 :     if (!SendGetOwnPropertyDescriptor(objId, idVar, &status, &result))
     213           0 :         return ipcfail(cx);
     214             : 
     215           0 :     LOG_STACK();
     216             : 
     217           0 :     if (!ok(cx, status))
     218           0 :         return false;
     219             : 
     220           0 :     return toDescriptor(cx, result, desc);
     221             : }
     222             : 
     223             : bool
     224           0 : CPOWProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
     225             :                                  Handle<PropertyDescriptor> desc,
     226             :                                  ObjectOpResult& result) const
     227             : {
     228           0 :     FORWARD(defineProperty, (cx, proxy, id, desc, result), false);
     229             : }
     230             : 
     231             : bool
     232           0 : WrapperOwner::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
     233             :                              Handle<PropertyDescriptor> desc,
     234             :                              ObjectOpResult& result)
     235             : {
     236           0 :     ObjectId objId = idOf(proxy);
     237             : 
     238           0 :     JSIDVariant idVar;
     239           0 :     if (!toJSIDVariant(cx, id, &idVar))
     240           0 :         return false;
     241             : 
     242           0 :     PPropertyDescriptor descriptor;
     243           0 :     if (!fromDescriptor(cx, desc, &descriptor))
     244           0 :         return false;
     245             : 
     246           0 :     ReturnStatus status;
     247           0 :     if (!SendDefineProperty(objId, idVar, descriptor, &status))
     248           0 :         return ipcfail(cx);
     249             : 
     250           0 :     LOG_STACK();
     251             : 
     252           0 :     return ok(cx, status, result);
     253             : }
     254             : 
     255             : bool
     256           0 : CPOWProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
     257             :                                   AutoIdVector& props) const
     258             : {
     259           0 :     FORWARD(ownPropertyKeys, (cx, proxy, props), false);
     260             : }
     261             : 
     262             : bool
     263           0 : WrapperOwner::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
     264             : {
     265           0 :     return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
     266             : }
     267             : 
     268             : bool
     269           0 : CPOWProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
     270             :                           ObjectOpResult& result) const
     271             : {
     272           0 :     FORWARD(delete_, (cx, proxy, id, result), false);
     273             : }
     274             : 
     275             : bool
     276           0 : WrapperOwner::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result)
     277             : {
     278           0 :     ObjectId objId = idOf(proxy);
     279             : 
     280           0 :     JSIDVariant idVar;
     281           0 :     if (!toJSIDVariant(cx, id, &idVar))
     282           0 :         return false;
     283             : 
     284           0 :     ReturnStatus status;
     285           0 :     if (!SendDelete(objId, idVar, &status))
     286           0 :         return ipcfail(cx);
     287             : 
     288           0 :     LOG_STACK();
     289             : 
     290           0 :     return ok(cx, status, result);
     291             : }
     292             : 
     293             : JSObject*
     294           0 : CPOWProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const
     295             : {
     296             :     // Using a CPOW for the Iterator would slow down for .. in performance, instead
     297             :     // call the base hook, that will use our implementation of getOwnEnumerablePropertyKeys
     298             :     // and follow the proto chain.
     299           0 :     return BaseProxyHandler::enumerate(cx, proxy);
     300             : }
     301             : 
     302             : bool
     303           0 : CPOWProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
     304             : {
     305           0 :     FORWARD(has, (cx, proxy, id, bp), false);
     306             : }
     307             : 
     308             : bool
     309           0 : WrapperOwner::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
     310             : {
     311           0 :     ObjectId objId = idOf(proxy);
     312             : 
     313           0 :     JSIDVariant idVar;
     314           0 :     if (!toJSIDVariant(cx, id, &idVar))
     315           0 :         return false;
     316             : 
     317           0 :     ReturnStatus status;
     318           0 :     if (!SendHas(objId, idVar, &status, bp))
     319           0 :         return ipcfail(cx);
     320             : 
     321           0 :     LOG_STACK();
     322             : 
     323           0 :     return ok(cx, status);
     324             : }
     325             : 
     326             : bool
     327           0 : CPOWProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
     328             : {
     329           0 :     FORWARD(hasOwn, (cx, proxy, id, bp), false);
     330             : }
     331             : 
     332             : bool
     333           0 : WrapperOwner::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
     334             : {
     335           0 :     ObjectId objId = idOf(proxy);
     336             : 
     337           0 :     JSIDVariant idVar;
     338           0 :     if (!toJSIDVariant(cx, id, &idVar))
     339           0 :         return false;
     340             : 
     341           0 :     ReturnStatus status;
     342           0 :     if (!SendHasOwn(objId, idVar, &status, bp))
     343           0 :         return ipcfail(cx);
     344             : 
     345           0 :     LOG_STACK();
     346             : 
     347           0 :     return !!ok(cx, status);
     348             : }
     349             : 
     350             : bool
     351           0 : CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
     352             :                       HandleId id, MutableHandleValue vp) const
     353             : {
     354           0 :     FORWARD(get, (cx, proxy, receiver, id, vp), false);
     355             : }
     356             : 
     357             : static bool
     358           0 : CPOWDOMQI(JSContext* cx, unsigned argc, Value* vp)
     359             : {
     360           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     361           0 :     if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) {
     362           0 :         JS_ReportErrorASCII(cx, "bad this object passed to special QI");
     363           0 :         return false;
     364             :     }
     365             : 
     366           0 :     RootedObject proxy(cx, &args.thisv().toObject());
     367           0 :     FORWARD(DOMQI, (cx, proxy, args), false);
     368             : }
     369             : 
     370             : static bool
     371           0 : CPOWToString(JSContext* cx, unsigned argc, Value* vp)
     372             : {
     373           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     374           0 :     RootedObject callee(cx, &args.callee());
     375           0 :     RootedValue cpowValue(cx);
     376           0 :     if (!JS_GetProperty(cx, callee, "__cpow__", &cpowValue))
     377           0 :         return false;
     378             : 
     379           0 :     if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) {
     380           0 :         JS_ReportErrorASCII(cx, "CPOWToString called on an incompatible object");
     381           0 :         return false;
     382             :     }
     383             : 
     384           0 :     RootedObject proxy(cx, &cpowValue.toObject());
     385           0 :     FORWARD(toString, (cx, proxy, args), false);
     386             : }
     387             : 
     388             : bool
     389           0 : WrapperOwner::toString(JSContext* cx, HandleObject cpow, JS::CallArgs& args)
     390             : {
     391             :     // Ask the other side to call its toString method. Update the callee so that
     392             :     // it points to the CPOW and not to the synthesized CPOWToString function.
     393           0 :     args.setCallee(ObjectValue(*cpow));
     394           0 :     if (!callOrConstruct(cx, cpow, args, false))
     395           0 :         return false;
     396             : 
     397           0 :     if (!args.rval().isString())
     398           0 :         return true;
     399             : 
     400           0 :     RootedString cpowResult(cx, args.rval().toString());
     401           0 :     nsAutoJSString toStringResult;
     402           0 :     if (!toStringResult.init(cx, cpowResult))
     403           0 :         return false;
     404             : 
     405             :     // We don't want to wrap toString() results for things like the location
     406             :     // object, where toString() is supposed to return a URL and nothing else.
     407           0 :     nsAutoString result;
     408           0 :     if (toStringResult[0] == '[') {
     409           0 :         result.AppendLiteral("[object CPOW ");
     410           0 :         result += toStringResult;
     411           0 :         result.AppendLiteral("]");
     412             :     } else {
     413           0 :         result += toStringResult;
     414             :     }
     415             : 
     416           0 :     JSString* str = JS_NewUCStringCopyN(cx, result.get(), result.Length());
     417           0 :     if (!str)
     418           0 :         return false;
     419             : 
     420           0 :     args.rval().setString(str);
     421           0 :     return true;
     422             : }
     423             : 
     424             : bool
     425           0 : WrapperOwner::DOMQI(JSContext* cx, JS::HandleObject proxy, JS::CallArgs& args)
     426             : {
     427             :     // Someone's calling us, handle nsISupports specially to avoid unnecessary
     428             :     // CPOW traffic.
     429           0 :     HandleValue id = args[0];
     430           0 :     if (id.isObject()) {
     431           0 :         RootedObject idobj(cx, &id.toObject());
     432           0 :         nsCOMPtr<nsIJSID> jsid;
     433             : 
     434           0 :         nsresult rv = UnwrapArg<nsIJSID>(cx, idobj, getter_AddRefs(jsid));
     435           0 :         if (NS_SUCCEEDED(rv)) {
     436           0 :             MOZ_ASSERT(jsid, "bad wrapJS");
     437           0 :             const nsID* idptr = jsid->GetID();
     438           0 :             if (idptr->Equals(NS_GET_IID(nsISupports))) {
     439           0 :                 args.rval().set(args.thisv());
     440           0 :                 return true;
     441             :             }
     442             : 
     443             :             // Webidl-implemented DOM objects never have nsIClassInfo.
     444           0 :             if (idptr->Equals(NS_GET_IID(nsIClassInfo)))
     445           0 :                 return Throw(cx, NS_ERROR_NO_INTERFACE);
     446             :         }
     447             :     }
     448             : 
     449             :     // It wasn't nsISupports, call into the other process to do the QI for us
     450             :     // (since we don't know what other interfaces our object supports). Note
     451             :     // that we have to use JS_GetPropertyDescriptor here to avoid infinite
     452             :     // recursion back into CPOWDOMQI via WrapperOwner::get().
     453             :     // We could stash the actual QI function on our own function object to avoid
     454             :     // if we're called multiple times, but since we're transient, there's no
     455             :     // point right now.
     456           0 :     JS::Rooted<PropertyDescriptor> propDesc(cx);
     457           0 :     if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc))
     458           0 :         return false;
     459             : 
     460           0 :     if (!propDesc.value().isObject()) {
     461           0 :         MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node");
     462             :         return Throw(cx, NS_ERROR_UNEXPECTED);
     463             :     }
     464           0 :     return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval());
     465             : }
     466             : 
     467             : bool
     468           0 : WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
     469             :                   HandleId id, MutableHandleValue vp)
     470             : {
     471           0 :     ObjectId objId = idOf(proxy);
     472             : 
     473           0 :     JSVariant receiverVar;
     474           0 :     if (!toVariant(cx, receiver, &receiverVar))
     475           0 :         return false;
     476             : 
     477           0 :     JSIDVariant idVar;
     478           0 :     if (!toJSIDVariant(cx, id, &idVar))
     479           0 :         return false;
     480             : 
     481           0 :     AuxCPOWData* data = AuxCPOWDataOf(proxy);
     482           0 :     if (data->isDOMObject &&
     483           0 :         idVar.type() == JSIDVariant::TnsString &&
     484           0 :         idVar.get_nsString().EqualsLiteral("QueryInterface"))
     485             :     {
     486             :         // Handle QueryInterface on DOM Objects specially since we can assume
     487             :         // certain things about their implementation.
     488           0 :         RootedFunction qi(cx, JS_NewFunction(cx, CPOWDOMQI, 1, 0,
     489           0 :                                              "QueryInterface"));
     490           0 :         if (!qi)
     491           0 :             return false;
     492             : 
     493           0 :         vp.set(ObjectValue(*JS_GetFunctionObject(qi)));
     494           0 :         return true;
     495             :     }
     496             : 
     497           0 :     JSVariant val;
     498           0 :     ReturnStatus status;
     499           0 :     if (!SendGet(objId, receiverVar, idVar, &status, &val))
     500           0 :         return ipcfail(cx);
     501             : 
     502           0 :     LOG_STACK();
     503             : 
     504           0 :     if (!ok(cx, status))
     505           0 :         return false;
     506             : 
     507           0 :     if (!fromVariant(cx, val, vp))
     508           0 :         return false;
     509             : 
     510           0 :     if (idVar.type() == JSIDVariant::TnsString &&
     511           0 :         idVar.get_nsString().EqualsLiteral("toString")) {
     512           0 :         RootedFunction toString(cx, JS_NewFunction(cx, CPOWToString, 0, 0,
     513           0 :                                                    "toString"));
     514           0 :         if (!toString)
     515           0 :             return false;
     516             : 
     517           0 :         RootedObject toStringObj(cx, JS_GetFunctionObject(toString));
     518             : 
     519           0 :         if (!JS_DefineProperty(cx, toStringObj, "__cpow__", vp, JSPROP_PERMANENT | JSPROP_READONLY))
     520           0 :             return false;
     521             : 
     522           0 :         vp.set(ObjectValue(*toStringObj));
     523             :     }
     524             : 
     525           0 :     return true;
     526             : }
     527             : 
     528             : bool
     529           0 : CPOWProxyHandler::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
     530             :                       JS::HandleValue receiver, JS::ObjectOpResult& result) const
     531             : {
     532           0 :     FORWARD(set, (cx, proxy, id, v, receiver, result), false);
     533             : }
     534             : 
     535             : bool
     536           0 : WrapperOwner::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
     537             :                   JS::HandleValue receiver, JS::ObjectOpResult& result)
     538             : {
     539           0 :     ObjectId objId = idOf(proxy);
     540             : 
     541           0 :     JSIDVariant idVar;
     542           0 :     if (!toJSIDVariant(cx, id, &idVar))
     543           0 :         return false;
     544             : 
     545           0 :     JSVariant val;
     546           0 :     if (!toVariant(cx, v, &val))
     547           0 :         return false;
     548             : 
     549           0 :     JSVariant receiverVar;
     550           0 :     if (!toVariant(cx, receiver, &receiverVar))
     551           0 :         return false;
     552             : 
     553           0 :     ReturnStatus status;
     554           0 :     if (!SendSet(objId, idVar, val, receiverVar, &status))
     555           0 :         return ipcfail(cx);
     556             : 
     557           0 :     LOG_STACK();
     558             : 
     559           0 :     return ok(cx, status, result);
     560             : }
     561             : 
     562             : bool
     563           0 : CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
     564             :                                                AutoIdVector& props) const
     565             : {
     566           0 :     FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props), false);
     567             : }
     568             : 
     569             : bool
     570           0 : WrapperOwner::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
     571             : {
     572           0 :     return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
     573             : }
     574             : 
     575             : bool
     576           0 : CPOWProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const
     577             : {
     578           0 :     FORWARD(preventExtensions, (cx, proxy, result), false);
     579             : }
     580             : 
     581             : bool
     582           0 : WrapperOwner::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result)
     583             : {
     584           0 :     ObjectId objId = idOf(proxy);
     585             : 
     586           0 :     ReturnStatus status;
     587           0 :     if (!SendPreventExtensions(objId, &status))
     588           0 :         return ipcfail(cx);
     589             : 
     590           0 :     LOG_STACK();
     591             : 
     592           0 :     return ok(cx, status, result);
     593             : }
     594             : 
     595             : bool
     596           0 : CPOWProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
     597             : {
     598           0 :     FORWARD(isExtensible, (cx, proxy, extensible), false);
     599             : }
     600             : 
     601             : bool
     602           0 : WrapperOwner::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible)
     603             : {
     604           0 :     ObjectId objId = idOf(proxy);
     605             : 
     606           0 :     ReturnStatus status;
     607           0 :     if (!SendIsExtensible(objId, &status, extensible))
     608           0 :         return ipcfail(cx);
     609             : 
     610           0 :     LOG_STACK();
     611             : 
     612           0 :     return ok(cx, status);
     613             : }
     614             : 
     615             : bool
     616           0 : CPOWProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
     617             : {
     618           0 :     FORWARD(callOrConstruct, (cx, proxy, args, false), false);
     619             : }
     620             : 
     621             : bool
     622           0 : CPOWProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
     623             : {
     624           0 :     FORWARD(callOrConstruct, (cx, proxy, args, true), false);
     625             : }
     626             : 
     627             : bool
     628           0 : WrapperOwner::callOrConstruct(JSContext* cx, HandleObject proxy, const CallArgs& args,
     629             :                               bool construct)
     630             : {
     631           0 :     ObjectId objId = idOf(proxy);
     632             : 
     633           0 :     InfallibleTArray<JSParam> vals;
     634           0 :     AutoValueVector outobjects(cx);
     635             : 
     636           0 :     RootedValue v(cx);
     637           0 :     for (size_t i = 0; i < args.length() + 2; i++) {
     638             :         // The |this| value for constructors is a magic value that we won't be
     639             :         // able to convert, so skip it.
     640           0 :         if (i == 1 && construct)
     641           0 :             v = UndefinedValue();
     642             :         else
     643           0 :             v = args.base()[i];
     644           0 :         if (v.isObject()) {
     645           0 :             RootedObject obj(cx, &v.toObject());
     646           0 :             if (xpc::IsOutObject(cx, obj)) {
     647             :                 // Make sure it is not an in-out object.
     648             :                 bool found;
     649           0 :                 if (!JS_HasProperty(cx, obj, "value", &found))
     650           0 :                     return false;
     651           0 :                 if (found) {
     652           0 :                     JS_ReportErrorASCII(cx, "in-out objects cannot be sent via CPOWs yet");
     653           0 :                     return false;
     654             :                 }
     655             : 
     656           0 :                 vals.AppendElement(JSParam(void_t()));
     657           0 :                 if (!outobjects.append(ObjectValue(*obj)))
     658           0 :                     return false;
     659           0 :                 continue;
     660             :             }
     661             :         }
     662           0 :         JSVariant val;
     663           0 :         if (!toVariant(cx, v, &val))
     664           0 :             return false;
     665           0 :         vals.AppendElement(JSParam(val));
     666             :     }
     667             : 
     668           0 :     JSVariant result;
     669           0 :     ReturnStatus status;
     670           0 :     InfallibleTArray<JSParam> outparams;
     671           0 :     if (!SendCallOrConstruct(objId, vals, construct, &status, &result, &outparams))
     672           0 :         return ipcfail(cx);
     673             : 
     674           0 :     LOG_STACK();
     675             : 
     676           0 :     if (!ok(cx, status))
     677           0 :         return false;
     678             : 
     679           0 :     if (outparams.Length() != outobjects.length())
     680           0 :         return ipcfail(cx);
     681             : 
     682           0 :     RootedObject obj(cx);
     683           0 :     for (size_t i = 0; i < outparams.Length(); i++) {
     684             :         // Don't bother doing anything for outparams that weren't set.
     685           0 :         if (outparams[i].type() == JSParam::Tvoid_t)
     686           0 :             continue;
     687             : 
     688             :         // Take the value the child process returned, and set it on the XPC
     689             :         // object.
     690           0 :         if (!fromVariant(cx, outparams[i], &v))
     691           0 :             return false;
     692             : 
     693           0 :         obj = &outobjects[i].toObject();
     694           0 :         if (!JS_SetProperty(cx, obj, "value", v))
     695           0 :             return false;
     696             :     }
     697             : 
     698           0 :     if (!fromVariant(cx, result, args.rval()))
     699           0 :         return false;
     700             : 
     701           0 :     return true;
     702             : }
     703             : 
     704             : bool
     705           0 : CPOWProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const
     706             : {
     707           0 :     FORWARD(hasInstance, (cx, proxy, v, bp), false);
     708             : }
     709             : 
     710             : bool
     711           0 : WrapperOwner::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp)
     712             : {
     713           0 :     ObjectId objId = idOf(proxy);
     714             : 
     715           0 :     JSVariant vVar;
     716           0 :     if (!toVariant(cx, v, &vVar))
     717           0 :         return false;
     718             : 
     719           0 :     ReturnStatus status;
     720           0 :     if (!SendHasInstance(objId, vVar, &status, bp))
     721           0 :         return ipcfail(cx);
     722             : 
     723           0 :     LOG_STACK();
     724             : 
     725           0 :     return ok(cx, status);
     726             : }
     727             : 
     728             : bool
     729           0 : CPOWProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
     730             : {
     731           0 :     FORWARD(getBuiltinClass, (cx, proxy, cls), false);
     732             : }
     733             : 
     734             : bool
     735           0 : WrapperOwner::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls)
     736             : {
     737           0 :     ObjectId objId = idOf(proxy);
     738             : 
     739           0 :     uint32_t classValue = uint32_t(ESClass::Other);
     740           0 :     ReturnStatus status;
     741           0 :     if (!SendGetBuiltinClass(objId, &status, &classValue))
     742           0 :         return ipcfail(cx);
     743           0 :     *cls = ESClass(classValue);
     744             : 
     745           0 :     LOG_STACK();
     746             : 
     747           0 :     return ok(cx, status);
     748             : }
     749             : 
     750             : bool
     751           0 : CPOWProxyHandler::isArray(JSContext* cx, HandleObject proxy,
     752             :                           IsArrayAnswer* answer) const
     753             : {
     754           0 :     FORWARD(isArray, (cx, proxy, answer), false);
     755             : }
     756             : 
     757             : bool
     758           0 : WrapperOwner::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer)
     759             : {
     760           0 :     ObjectId objId = idOf(proxy);
     761             : 
     762             :     uint32_t ans;
     763           0 :     ReturnStatus status;
     764           0 :     if (!SendIsArray(objId, &status, &ans))
     765           0 :         return ipcfail(cx);
     766             : 
     767           0 :     LOG_STACK();
     768             : 
     769           0 :     *answer = IsArrayAnswer(ans);
     770           0 :     MOZ_ASSERT(*answer == IsArrayAnswer::Array ||
     771             :                *answer == IsArrayAnswer::NotArray ||
     772             :                *answer == IsArrayAnswer::RevokedProxy);
     773             : 
     774           0 :     return ok(cx, status);
     775             : }
     776             : 
     777             : const char*
     778           0 : CPOWProxyHandler::className(JSContext* cx, HandleObject proxy) const
     779             : {
     780           0 :     WrapperOwner* parent = OwnerOf(proxy);
     781           0 :     if (!parent->active())
     782           0 :         return "<dead CPOW>";
     783           0 :     return parent->className(cx, proxy);
     784             : }
     785             : 
     786             : const char*
     787           0 : WrapperOwner::className(JSContext* cx, HandleObject proxy)
     788             : {
     789           0 :     AuxCPOWData* data = AuxCPOWDataOf(proxy);
     790           0 :     if (data->className.IsEmpty()) {
     791           0 :         ObjectId objId = idOf(proxy);
     792             : 
     793           0 :         if (!SendClassName(objId, &data->className))
     794           0 :             return "<error>";
     795             : 
     796           0 :         LOG_STACK();
     797             :     }
     798             : 
     799           0 :     return data->className.get();
     800             : }
     801             : 
     802             : bool
     803           0 : CPOWProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const
     804             : {
     805           0 :     FORWARD(getPrototype, (cx, proxy, objp), false);
     806             : }
     807             : 
     808             : bool
     809           0 : WrapperOwner::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp)
     810             : {
     811           0 :     ObjectId objId = idOf(proxy);
     812             : 
     813           0 :     ObjectOrNullVariant val;
     814           0 :     ReturnStatus status;
     815           0 :     if (!SendGetPrototype(objId, &status, &val))
     816           0 :         return ipcfail(cx);
     817             : 
     818           0 :     LOG_STACK();
     819             : 
     820           0 :     if (!ok(cx, status))
     821           0 :         return false;
     822             : 
     823           0 :     objp.set(fromObjectOrNullVariant(cx, val));
     824             : 
     825           0 :     return true;
     826             : }
     827             : 
     828             : bool
     829           0 : CPOWProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
     830             :                                          MutableHandleObject objp) const
     831             : {
     832           0 :     FORWARD(getPrototypeIfOrdinary, (cx, proxy, isOrdinary, objp), false);
     833             : }
     834             : 
     835             : bool
     836           0 : WrapperOwner::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
     837             :                                      MutableHandleObject objp)
     838             : {
     839           0 :     ObjectId objId = idOf(proxy);
     840             : 
     841           0 :     ObjectOrNullVariant val;
     842           0 :     ReturnStatus status;
     843           0 :     if (!SendGetPrototypeIfOrdinary(objId, &status, isOrdinary, &val))
     844           0 :         return ipcfail(cx);
     845             : 
     846           0 :     LOG_STACK();
     847             : 
     848           0 :     if (!ok(cx, status))
     849           0 :         return false;
     850             : 
     851           0 :     objp.set(fromObjectOrNullVariant(cx, val));
     852             : 
     853           0 :     return true;
     854             : }
     855             : 
     856             : RegExpShared*
     857           0 : CPOWProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
     858             : {
     859           0 :     FORWARD(regexp_toShared, (cx, proxy), nullptr);
     860             : }
     861             : 
     862             : RegExpShared*
     863           0 : WrapperOwner::regexp_toShared(JSContext* cx, HandleObject proxy)
     864             : {
     865           0 :     ObjectId objId = idOf(proxy);
     866             : 
     867           0 :     ReturnStatus status;
     868           0 :     nsString source;
     869           0 :     unsigned flags = 0;
     870           0 :     if (!SendRegExpToShared(objId, &status, &source, &flags)) {
     871           0 :         MOZ_ALWAYS_FALSE(ipcfail(cx));
     872           0 :         return nullptr;
     873             :     }
     874           0 :     LOG_STACK();
     875             : 
     876           0 :     if (!ok(cx, status))
     877           0 :         return nullptr;
     878             : 
     879           0 :     RootedObject regexp(cx);
     880           0 :     regexp = JS_NewUCRegExpObject(cx, source.get(), source.Length(), flags);
     881           0 :     if (!regexp)
     882           0 :         return nullptr;
     883             : 
     884           0 :     return js::RegExpToSharedNonInline(cx, regexp);
     885             : }
     886             : 
     887             : void
     888           0 : CPOWProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
     889             : {
     890           0 :     AuxCPOWData* aux = AuxCPOWDataOf(proxy);
     891             : 
     892           0 :     OwnerOf(proxy)->drop(proxy);
     893             : 
     894           0 :     if (aux)
     895           0 :         delete aux;
     896           0 : }
     897             : 
     898             : void
     899           0 : CPOWProxyHandler::objectMoved(JSObject* proxy, const JSObject* old) const
     900             : {
     901           0 :     OwnerOf(proxy)->updatePointer(proxy, old);
     902           0 : }
     903             : 
     904             : bool
     905           0 : CPOWProxyHandler::isCallable(JSObject* proxy) const
     906             : {
     907           0 :     AuxCPOWData* aux = AuxCPOWDataOf(proxy);
     908           0 :     return aux->isCallable;
     909             : }
     910             : 
     911             : bool
     912           0 : CPOWProxyHandler::isConstructor(JSObject* proxy) const
     913             : {
     914           0 :     AuxCPOWData* aux = AuxCPOWDataOf(proxy);
     915           0 :     return aux->isConstructor;
     916             : }
     917             : 
     918             : void
     919           0 : WrapperOwner::drop(JSObject* obj)
     920             : {
     921             :     // The association may have already been swept from the table but if it's
     922             :     // there then remove it.
     923           0 :     ObjectId objId = idOfUnchecked(obj);
     924           0 :     if (cpows_.findPreserveColor(objId) == obj)
     925           0 :         cpows_.remove(objId);
     926             : 
     927           0 :     if (active())
     928           0 :         Unused << SendDropObject(objId);
     929           0 :     decref();
     930           0 : }
     931             : 
     932             : void
     933           0 : WrapperOwner::updatePointer(JSObject* obj, const JSObject* old)
     934             : {
     935           0 :     ObjectId objId = idOfUnchecked(obj);
     936           0 :     MOZ_ASSERT(hasCPOW(objId, old));
     937           0 :     cpows_.add(objId, obj);
     938           0 : }
     939             : 
     940             : bool
     941           3 : WrapperOwner::init()
     942             : {
     943           3 :     if (!JavaScriptShared::init())
     944           0 :         return false;
     945             : 
     946           3 :     return true;
     947             : }
     948             : 
     949             : bool
     950           0 : WrapperOwner::getPropertyKeys(JSContext* cx, HandleObject proxy, uint32_t flags, AutoIdVector& props)
     951             : {
     952           0 :     ObjectId objId = idOf(proxy);
     953             : 
     954           0 :     ReturnStatus status;
     955           0 :     InfallibleTArray<JSIDVariant> ids;
     956           0 :     if (!SendGetPropertyKeys(objId, flags, &status, &ids))
     957           0 :         return ipcfail(cx);
     958             : 
     959           0 :     LOG_STACK();
     960             : 
     961           0 :     if (!ok(cx, status))
     962           0 :         return false;
     963             : 
     964           0 :     for (size_t i = 0; i < ids.Length(); i++) {
     965           0 :         RootedId id(cx);
     966           0 :         if (!fromJSIDVariant(cx, ids[i], &id))
     967           0 :             return false;
     968           0 :         if (!props.append(id))
     969           0 :             return false;
     970             :     }
     971             : 
     972           0 :     return true;
     973             : }
     974             : 
     975             : namespace mozilla {
     976             : namespace jsipc {
     977             : 
     978             : bool
     979        7837 : IsCPOW(JSObject* obj)
     980             : {
     981        7837 :     return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
     982             : }
     983             : 
     984             : bool
     985        7669 : IsWrappedCPOW(JSObject* obj)
     986             : {
     987        7669 :     JSObject* unwrapped = js::UncheckedUnwrap(obj, true);
     988        7669 :     if (!unwrapped)
     989           0 :         return false;
     990        7669 :     return IsCPOW(unwrapped);
     991             : }
     992             : 
     993             : void
     994           0 : GetWrappedCPOWTag(JSObject* obj, nsACString& out)
     995             : {
     996           0 :     JSObject* unwrapped = js::UncheckedUnwrap(obj, true);
     997           0 :     MOZ_ASSERT(IsCPOW(unwrapped));
     998             : 
     999           0 :     AuxCPOWData* aux = AuxCPOWDataOf(unwrapped);
    1000           0 :     if (aux)
    1001           0 :         out = aux->objectTag;
    1002           0 : }
    1003             : 
    1004             : nsresult
    1005           0 : InstanceOf(JSObject* proxy, const nsID* id, bool* bp)
    1006             : {
    1007           0 :     WrapperOwner* parent = OwnerOf(proxy);
    1008           0 :     if (!parent->active())
    1009           0 :         return NS_ERROR_UNEXPECTED;
    1010           0 :     return parent->instanceOf(proxy, id, bp);
    1011             : }
    1012             : 
    1013             : bool
    1014           0 : DOMInstanceOf(JSContext* cx, JSObject* proxyArg, int prototypeID, int depth, bool* bp)
    1015             : {
    1016           0 :     RootedObject proxy(cx, proxyArg);
    1017           0 :     FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp), false);
    1018             : }
    1019             : 
    1020             : } /* namespace jsipc */
    1021             : } /* namespace mozilla */
    1022             : 
    1023             : nsresult
    1024           0 : WrapperOwner::instanceOf(JSObject* obj, const nsID* id, bool* bp)
    1025             : {
    1026           0 :     ObjectId objId = idOf(obj);
    1027             : 
    1028           0 :     JSIID iid;
    1029           0 :     ConvertID(*id, &iid);
    1030             : 
    1031           0 :     ReturnStatus status;
    1032           0 :     if (!SendInstanceOf(objId, iid, &status, bp))
    1033           0 :         return NS_ERROR_UNEXPECTED;
    1034             : 
    1035           0 :     if (status.type() != ReturnStatus::TReturnSuccess)
    1036           0 :         return NS_ERROR_UNEXPECTED;
    1037             : 
    1038           0 :     return NS_OK;
    1039             : }
    1040             : 
    1041             : bool
    1042           0 : WrapperOwner::domInstanceOf(JSContext* cx, JSObject* obj, int prototypeID, int depth, bool* bp)
    1043             : {
    1044           0 :     ObjectId objId = idOf(obj);
    1045             : 
    1046           0 :     ReturnStatus status;
    1047           0 :     if (!SendDOMInstanceOf(objId, prototypeID, depth, &status, bp))
    1048           0 :         return ipcfail(cx);
    1049             : 
    1050           0 :     LOG_STACK();
    1051             : 
    1052           0 :     return ok(cx, status);
    1053             : }
    1054             : 
    1055             : void
    1056           0 : WrapperOwner::ActorDestroy(ActorDestroyReason why)
    1057             : {
    1058           0 :     inactive_ = true;
    1059             : 
    1060           0 :     objects_.clear();
    1061           0 :     unwaivedObjectIds_.clear();
    1062           0 :     waivedObjectIds_.clear();
    1063           0 : }
    1064             : 
    1065             : bool
    1066           0 : WrapperOwner::ipcfail(JSContext* cx)
    1067             : {
    1068           0 :     JS_ReportErrorASCII(cx, "cross-process JS call failed");
    1069           0 :     return false;
    1070             : }
    1071             : 
    1072             : bool
    1073           0 : WrapperOwner::ok(JSContext* cx, const ReturnStatus& status)
    1074             : {
    1075           0 :     if (status.type() == ReturnStatus::TReturnSuccess)
    1076           0 :         return true;
    1077             : 
    1078           0 :     if (status.type() == ReturnStatus::TReturnStopIteration)
    1079           0 :         return JS_ThrowStopIteration(cx);
    1080             : 
    1081           0 :     if (status.type() == ReturnStatus::TReturnDeadCPOW) {
    1082           0 :         JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
    1083           0 :         return false;
    1084             :     }
    1085             : 
    1086           0 :     RootedValue exn(cx);
    1087           0 :     if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
    1088           0 :         return false;
    1089             : 
    1090           0 :     JS_SetPendingException(cx, exn);
    1091           0 :     return false;
    1092             : }
    1093             : 
    1094             : bool
    1095           0 : WrapperOwner::ok(JSContext* cx, const ReturnStatus& status, ObjectOpResult& result)
    1096             : {
    1097           0 :     if (status.type() == ReturnStatus::TReturnObjectOpResult)
    1098           0 :         return result.fail(status.get_ReturnObjectOpResult().code());
    1099           0 :     if (!ok(cx, status))
    1100           0 :         return false;
    1101           0 :     return result.succeed();
    1102             : }
    1103             : 
    1104             : // CPOWs can have a tag string attached to them, originating in the local
    1105             : // process from this function.  It's sent with the CPOW to the remote process,
    1106             : // where it can be fetched with Components.utils.getCrossProcessWrapperTag.
    1107             : static nsCString
    1108          29 : GetRemoteObjectTag(JS::Handle<JSObject*> obj)
    1109             : {
    1110          52 :     if (nsCOMPtr<nsISupports> supports = xpc::UnwrapReflectorToISupports(obj)) {
    1111          52 :         nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(supports));
    1112          29 :         if (treeItem)
    1113           6 :             return NS_LITERAL_CSTRING("ContentDocShellTreeItem");
    1114             : 
    1115          46 :         nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(supports));
    1116          23 :         if (doc)
    1117           0 :             return NS_LITERAL_CSTRING("ContentDocument");
    1118             :     }
    1119             : 
    1120          23 :     return NS_LITERAL_CSTRING("generic");
    1121             : }
    1122             : 
    1123             : static RemoteObject
    1124          29 : MakeRemoteObject(JSContext* cx, ObjectId id, HandleObject obj)
    1125             : {
    1126          58 :     return RemoteObject(id.serialize(),
    1127          58 :                         JS::IsCallable(obj),
    1128          58 :                         JS::IsConstructor(obj),
    1129          58 :                         dom::IsDOMObject(obj),
    1130          87 :                         GetRemoteObjectTag(obj));
    1131             : }
    1132             : 
    1133             : bool
    1134          29 : WrapperOwner::toObjectVariant(JSContext* cx, JSObject* objArg, ObjectVariant* objVarp)
    1135             : {
    1136          58 :     RootedObject obj(cx, objArg);
    1137          29 :     MOZ_ASSERT(obj);
    1138             : 
    1139             :     // We always save objects unwrapped in the CPOW table. If we stored
    1140             :     // wrappers, then the wrapper might be GCed while the target remained alive.
    1141             :     // Whenever operating on an object that comes from the table, we wrap it
    1142             :     // in findObjectById.
    1143          29 :     unsigned wrapperFlags = 0;
    1144          29 :     obj = js::UncheckedUnwrap(obj, true, &wrapperFlags);
    1145          29 :     if (obj && IsCPOW(obj) && OwnerOf(obj) == this) {
    1146           0 :         *objVarp = LocalObject(idOf(obj).serialize());
    1147           0 :         return true;
    1148             :     }
    1149          29 :     bool waiveXray = wrapperFlags & xpc::WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG;
    1150             : 
    1151          29 :     ObjectId id = objectIdMap(waiveXray).find(obj);
    1152          29 :     if (!id.isNull()) {
    1153          24 :         MOZ_ASSERT(id.hasXrayWaiver() == waiveXray);
    1154          24 :         *objVarp = MakeRemoteObject(cx, id, obj);
    1155          24 :         return true;
    1156             :     }
    1157             : 
    1158             :     // Need to call PreserveWrapper on |obj| in case it's a reflector.
    1159             :     // FIXME: What if it's an XPCWrappedNative?
    1160           5 :     if (mozilla::dom::IsDOMObject(obj))
    1161           0 :         mozilla::dom::TryPreserveWrapper(obj);
    1162             : 
    1163           5 :     id = ObjectId(nextSerialNumber_++, waiveXray);
    1164           5 :     if (!objects_.add(id, obj))
    1165           0 :         return false;
    1166           5 :     if (!objectIdMap(waiveXray).add(cx, obj, id))
    1167           0 :         return false;
    1168             : 
    1169           5 :     *objVarp = MakeRemoteObject(cx, id, obj);
    1170           5 :     return true;
    1171             : }
    1172             : 
    1173             : JSObject*
    1174          29 : WrapperOwner::fromObjectVariant(JSContext* cx, const ObjectVariant& objVar)
    1175             : {
    1176          29 :     if (objVar.type() == ObjectVariant::TRemoteObject) {
    1177          29 :         return fromRemoteObjectVariant(cx, objVar.get_RemoteObject());
    1178             :     } else {
    1179           0 :         return fromLocalObjectVariant(cx, objVar.get_LocalObject());
    1180             :     }
    1181             : }
    1182             : 
    1183             : JSObject*
    1184          29 : WrapperOwner::fromRemoteObjectVariant(JSContext* cx, const RemoteObject& objVar)
    1185             : {
    1186          29 :     ObjectId objId = ObjectId::deserialize(objVar.serializedId());
    1187          58 :     RootedObject obj(cx, findCPOWById(objId));
    1188          29 :     if (!obj) {
    1189             : 
    1190             :         // All CPOWs live in the privileged junk scope.
    1191          10 :         RootedObject junkScope(cx, xpc::PrivilegedJunkScope());
    1192          10 :         JSAutoCompartment ac(cx, junkScope);
    1193          10 :         RootedValue v(cx, UndefinedValue());
    1194             :         // We need to setLazyProto for the getPrototype/getPrototypeIfOrdinary
    1195             :         // hooks.
    1196           5 :         ProxyOptions options;
    1197           5 :         options.setLazyProto(true);
    1198          10 :         obj = NewProxyObject(cx,
    1199             :                              &CPOWProxyHandler::singleton,
    1200             :                              v,
    1201             :                              nullptr,
    1202           5 :                              options);
    1203           5 :         if (!obj)
    1204           0 :             return nullptr;
    1205             : 
    1206           5 :         if (!cpows_.add(objId, obj))
    1207           0 :             return nullptr;
    1208             : 
    1209           5 :         nextCPOWNumber_ = objId.serialNumber() + 1;
    1210             : 
    1211             :         // Incref once we know the decref will be called.
    1212           5 :         incref();
    1213             : 
    1214             :         AuxCPOWData* aux = new AuxCPOWData(objId,
    1215           5 :                                            objVar.isCallable(),
    1216           5 :                                            objVar.isConstructor(),
    1217           5 :                                            objVar.isDOMObject(),
    1218          15 :                                            objVar.objectTag());
    1219             : 
    1220           5 :         SetProxyReservedSlot(obj, 0, PrivateValue(this));
    1221           5 :         SetProxyReservedSlot(obj, 1, PrivateValue(aux));
    1222             :     }
    1223             : 
    1224          29 :     if (!JS_WrapObject(cx, &obj))
    1225           0 :         return nullptr;
    1226          29 :     return obj;
    1227             : }
    1228             : 
    1229             : JSObject*
    1230           0 : WrapperOwner::fromLocalObjectVariant(JSContext* cx, const LocalObject& objVar)
    1231             : {
    1232           0 :     ObjectId id = ObjectId::deserialize(objVar.serializedId());
    1233           0 :     Rooted<JSObject*> obj(cx, findObjectById(cx, id));
    1234           0 :     if (!obj)
    1235           0 :         return nullptr;
    1236           0 :     if (!JS_WrapObject(cx, &obj))
    1237           0 :         return nullptr;
    1238           0 :     return obj;
    1239             : }

Generated by: LCOV version 1.13