forked from mirrors/gecko-dev
		
	 4babb2b5ab
			
		
	
	
		4babb2b5ab
		
	
	
	
	
		
			
			Patch by bhackett and jlaster. Also reviewed by mccr8. Differential Revision: https://phabricator.services.mozilla.com/D60197 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			697 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			697 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 | |
|  * vim: set ts=4 sw=2 et tw=80:
 | |
|  *
 | |
|  * This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "JavaScriptShared.h"
 | |
| #include "mozilla/dom/BindingUtils.h"
 | |
| #include "mozilla/dom/CPOWManagerGetter.h"
 | |
| #include "mozilla/dom/BrowserChild.h"
 | |
| #include "jsfriendapi.h"
 | |
| #include "js/Symbol.h"
 | |
| #include "xpcprivate.h"
 | |
| #include "WrapperFactory.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| 
 | |
| using namespace js;
 | |
| using namespace JS;
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::jsipc;
 | |
| 
 | |
| IdToObjectMap::IdToObjectMap() : table_(SystemAllocPolicy(), 32) {}
 | |
| 
 | |
| void IdToObjectMap::trace(JSTracer* trc, uint64_t minimumId) {
 | |
|   for (Table::Range r(table_.all()); !r.empty(); r.popFront()) {
 | |
|     if (r.front().key().serialNumber() >= minimumId) {
 | |
|       JS::TraceEdge(trc, &r.front().value(), "ipc-object");
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void IdToObjectMap::sweep() {
 | |
|   for (Table::Enum e(table_); !e.empty(); e.popFront()) {
 | |
|     JS::Heap<JSObject*>* objp = &e.front().value();
 | |
|     JS_UpdateWeakPointerAfterGC(objp);
 | |
|     if (!*objp) {
 | |
|       e.removeFront();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| JSObject* IdToObjectMap::find(ObjectId id) {
 | |
|   Table::Ptr p = table_.lookup(id);
 | |
|   if (!p) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return p->value();
 | |
| }
 | |
| 
 | |
| JSObject* IdToObjectMap::findPreserveColor(ObjectId id) {
 | |
|   Table::Ptr p = table_.lookup(id);
 | |
|   if (!p) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return p->value().unbarrieredGet();
 | |
| }
 | |
| 
 | |
| bool IdToObjectMap::add(ObjectId id, JSObject* obj) {
 | |
|   return table_.put(id, obj);
 | |
| }
 | |
| 
 | |
| void IdToObjectMap::remove(ObjectId id) { table_.remove(id); }
 | |
| 
 | |
| void IdToObjectMap::clear() { table_.clear(); }
 | |
| 
 | |
| bool IdToObjectMap::empty() const { return table_.empty(); }
 | |
| 
 | |
| #ifdef DEBUG
 | |
| bool IdToObjectMap::has(const ObjectId& id, const JSObject* obj) const {
 | |
|   auto p = table_.lookup(id);
 | |
|   if (!p) {
 | |
|     return false;
 | |
|   }
 | |
|   return p->value() == obj;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| ObjectToIdMap::ObjectToIdMap() : table_(SystemAllocPolicy(), 32) {}
 | |
| 
 | |
| void ObjectToIdMap::trace(JSTracer* trc) { table_.trace(trc); }
 | |
| 
 | |
| void ObjectToIdMap::sweep() { table_.sweep(); }
 | |
| 
 | |
| ObjectId ObjectToIdMap::find(JSObject* obj) {
 | |
|   Table::Ptr p = table_.lookup(obj);
 | |
|   if (!p) {
 | |
|     return ObjectId::nullId();
 | |
|   }
 | |
|   return p->value();
 | |
| }
 | |
| 
 | |
| bool ObjectToIdMap::add(JSContext* cx, JSObject* obj, ObjectId id) {
 | |
|   return table_.put(obj, id);
 | |
| }
 | |
| 
 | |
| void ObjectToIdMap::remove(JSObject* obj) { table_.remove(obj); }
 | |
| 
 | |
| void ObjectToIdMap::clear() { table_.clear(); }
 | |
| 
 | |
| bool JavaScriptShared::sLoggingInitialized;
 | |
| bool JavaScriptShared::sLoggingEnabledByEnvVar;
 | |
| bool JavaScriptShared::sStackLoggingEnabledByEnvVar;
 | |
| 
 | |
| JavaScriptShared::JavaScriptShared()
 | |
|     : refcount_(1), nextSerialNumber_(1), nextCPOWNumber_(1) {
 | |
|   if (!sLoggingInitialized) {
 | |
|     sLoggingInitialized = true;
 | |
| 
 | |
|     if (PR_GetEnv("MOZ_CPOW_LOG")) {
 | |
|       sLoggingEnabledByEnvVar = true;
 | |
|       sStackLoggingEnabledByEnvVar =
 | |
|           !!strstr(PR_GetEnv("MOZ_CPOW_LOG"), "stacks");
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| JavaScriptShared::~JavaScriptShared() { MOZ_RELEASE_ASSERT(cpows_.empty()); }
 | |
| 
 | |
| void JavaScriptShared::decref() {
 | |
|   refcount_--;
 | |
|   if (!refcount_) {
 | |
|     delete this;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void JavaScriptShared::incref() { refcount_++; }
 | |
| 
 | |
| bool JavaScriptShared::convertIdToGeckoString(JSContext* cx, JS::HandleId id,
 | |
|                                               nsString* to) {
 | |
|   RootedValue idval(cx);
 | |
|   if (!JS_IdToValue(cx, id, &idval)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   RootedString str(cx, ToString(cx, idval));
 | |
|   if (!str) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return AssignJSString(cx, *to, str);
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::convertGeckoStringToId(JSContext* cx,
 | |
|                                               const nsString& from,
 | |
|                                               JS::MutableHandleId to) {
 | |
|   RootedString str(cx,
 | |
|                    JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
 | |
|   if (!str) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return JS_StringToId(cx, str, to);
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::toVariant(JSContext* cx, JS::HandleValue from,
 | |
|                                  JSVariant* to) {
 | |
|   switch (JS_TypeOfValue(cx, from)) {
 | |
|     case JSTYPE_UNDEFINED:
 | |
|       *to = UndefinedVariant();
 | |
|       return true;
 | |
| 
 | |
|     case JSTYPE_OBJECT:
 | |
|     case JSTYPE_FUNCTION: {
 | |
|       RootedObject obj(cx, from.toObjectOrNull());
 | |
|       if (!obj) {
 | |
|         MOZ_ASSERT(from.isNull());
 | |
|         *to = NullVariant();
 | |
|         return true;
 | |
|       }
 | |
| 
 | |
|       Maybe<nsID> id = xpc::JSValue2ID(cx, from);
 | |
|       if (id) {
 | |
|         JSIID iid;
 | |
|         ConvertID(*id, &iid);
 | |
|         *to = iid;
 | |
|         return true;
 | |
|       }
 | |
| 
 | |
|       ObjectVariant objVar;
 | |
|       if (!toObjectVariant(cx, obj, &objVar)) {
 | |
|         return false;
 | |
|       }
 | |
|       *to = objVar;
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSTYPE_SYMBOL: {
 | |
|       RootedSymbol sym(cx, from.toSymbol());
 | |
| 
 | |
|       SymbolVariant symVar;
 | |
|       if (!toSymbolVariant(cx, sym, &symVar)) {
 | |
|         return false;
 | |
|       }
 | |
|       *to = symVar;
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSTYPE_STRING: {
 | |
|       nsAutoJSString autoStr;
 | |
|       if (!autoStr.init(cx, from)) {
 | |
|         return false;
 | |
|       }
 | |
|       *to = autoStr;
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSTYPE_NUMBER:
 | |
|       if (from.isInt32()) {
 | |
|         *to = double(from.toInt32());
 | |
|       } else {
 | |
|         *to = from.toDouble();
 | |
|       }
 | |
|       return true;
 | |
| 
 | |
|     case JSTYPE_BOOLEAN:
 | |
|       *to = from.toBoolean();
 | |
|       return true;
 | |
| 
 | |
|     default:
 | |
|       MOZ_ASSERT(false);
 | |
|       return false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::fromVariant(JSContext* cx, const JSVariant& from,
 | |
|                                    MutableHandleValue to) {
 | |
|   switch (from.type()) {
 | |
|     case JSVariant::TUndefinedVariant:
 | |
|       to.set(UndefinedValue());
 | |
|       return true;
 | |
| 
 | |
|     case JSVariant::TNullVariant:
 | |
|       to.set(NullValue());
 | |
|       return true;
 | |
| 
 | |
|     case JSVariant::TObjectVariant: {
 | |
|       JSObject* obj = fromObjectVariant(cx, from.get_ObjectVariant());
 | |
|       if (!obj) {
 | |
|         return false;
 | |
|       }
 | |
|       to.set(ObjectValue(*obj));
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSVariant::TSymbolVariant: {
 | |
|       Symbol* sym = fromSymbolVariant(cx, from.get_SymbolVariant());
 | |
|       if (!sym) {
 | |
|         return false;
 | |
|       }
 | |
|       to.setSymbol(sym);
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSVariant::Tdouble:
 | |
|       to.set(JS_NumberValue(from.get_double()));
 | |
|       return true;
 | |
| 
 | |
|     case JSVariant::Tbool:
 | |
|       to.setBoolean(from.get_bool());
 | |
|       return true;
 | |
| 
 | |
|     case JSVariant::TnsString: {
 | |
|       const nsString& old = from.get_nsString();
 | |
|       JSString* str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length());
 | |
|       if (!str) {
 | |
|         return false;
 | |
|       }
 | |
|       to.set(StringValue(str));
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSVariant::TJSIID: {
 | |
|       nsID iid;
 | |
|       const JSIID& id = from.get_JSIID();
 | |
|       ConvertID(id, &iid);
 | |
|       return xpc::ID2JSValue(cx, iid, to);
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       MOZ_CRASH("NYI");
 | |
|       return false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::toJSIDVariant(JSContext* cx, HandleId from,
 | |
|                                      JSIDVariant* to) {
 | |
|   if (JSID_IS_STRING(from)) {
 | |
|     nsAutoJSString autoStr;
 | |
|     if (!autoStr.init(cx, JSID_TO_STRING(from))) {
 | |
|       return false;
 | |
|     }
 | |
|     *to = autoStr;
 | |
|     return true;
 | |
|   }
 | |
|   if (JSID_IS_INT(from)) {
 | |
|     *to = JSID_TO_INT(from);
 | |
|     return true;
 | |
|   }
 | |
|   if (JSID_IS_SYMBOL(from)) {
 | |
|     SymbolVariant symVar;
 | |
|     if (!toSymbolVariant(cx, JSID_TO_SYMBOL(from), &symVar)) {
 | |
|       return false;
 | |
|     }
 | |
|     *to = symVar;
 | |
|     return true;
 | |
|   }
 | |
|   MOZ_ASSERT(false);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::fromJSIDVariant(JSContext* cx, const JSIDVariant& from,
 | |
|                                        MutableHandleId to) {
 | |
|   switch (from.type()) {
 | |
|     case JSIDVariant::TSymbolVariant: {
 | |
|       Symbol* sym = fromSymbolVariant(cx, from.get_SymbolVariant());
 | |
|       if (!sym) {
 | |
|         return false;
 | |
|       }
 | |
|       to.set(SYMBOL_TO_JSID(sym));
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     case JSIDVariant::TnsString:
 | |
|       return convertGeckoStringToId(cx, from.get_nsString(), to);
 | |
| 
 | |
|     case JSIDVariant::Tint32_t:
 | |
|       to.set(INT_TO_JSID(from.get_int32_t()));
 | |
|       return true;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::toSymbolVariant(JSContext* cx, JS::Symbol* symArg,
 | |
|                                        SymbolVariant* symVarp) {
 | |
|   RootedSymbol sym(cx, symArg);
 | |
|   MOZ_ASSERT(sym);
 | |
| 
 | |
|   SymbolCode code = GetSymbolCode(sym);
 | |
|   if (static_cast<uint32_t>(code) < WellKnownSymbolLimit) {
 | |
|     *symVarp = WellKnownSymbol(static_cast<uint32_t>(code));
 | |
|     return true;
 | |
|   }
 | |
|   if (code == SymbolCode::InSymbolRegistry) {
 | |
|     nsAutoJSString autoStr;
 | |
|     if (!autoStr.init(cx, GetSymbolDescription(sym))) {
 | |
|       return false;
 | |
|     }
 | |
|     *symVarp = RegisteredSymbol(autoStr);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   JS_ReportErrorASCII(cx, "unique symbol can't be used with CPOW");
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| JS::Symbol* JavaScriptShared::fromSymbolVariant(JSContext* cx,
 | |
|                                                 const SymbolVariant& symVar) {
 | |
|   switch (symVar.type()) {
 | |
|     case SymbolVariant::TWellKnownSymbol: {
 | |
|       uint32_t which = symVar.get_WellKnownSymbol().which();
 | |
|       if (which < WellKnownSymbolLimit) {
 | |
|         return GetWellKnownSymbol(cx, static_cast<SymbolCode>(which));
 | |
|       }
 | |
|       MOZ_ASSERT(false, "bad child data");
 | |
|       return nullptr;
 | |
|     }
 | |
| 
 | |
|     case SymbolVariant::TRegisteredSymbol: {
 | |
|       nsString key = symVar.get_RegisteredSymbol().key();
 | |
|       RootedString str(cx, JS_NewUCStringCopyN(cx, key.get(), key.Length()));
 | |
|       if (!str) {
 | |
|         return nullptr;
 | |
|       }
 | |
|       return GetSymbolFor(cx, str);
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       return nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void JavaScriptShared::ConvertID(const nsID& from, JSIID* to) {
 | |
|   to->m0() = from.m0;
 | |
|   to->m1() = from.m1;
 | |
|   to->m2() = from.m2;
 | |
|   to->m3_0() = from.m3[0];
 | |
|   to->m3_1() = from.m3[1];
 | |
|   to->m3_2() = from.m3[2];
 | |
|   to->m3_3() = from.m3[3];
 | |
|   to->m3_4() = from.m3[4];
 | |
|   to->m3_5() = from.m3[5];
 | |
|   to->m3_6() = from.m3[6];
 | |
|   to->m3_7() = from.m3[7];
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void JavaScriptShared::ConvertID(const JSIID& from, nsID* to) {
 | |
|   to->m0 = from.m0();
 | |
|   to->m1 = from.m1();
 | |
|   to->m2 = from.m2();
 | |
|   to->m3[0] = from.m3_0();
 | |
|   to->m3[1] = from.m3_1();
 | |
|   to->m3[2] = from.m3_2();
 | |
|   to->m3[3] = from.m3_3();
 | |
|   to->m3[4] = from.m3_4();
 | |
|   to->m3[5] = from.m3_5();
 | |
|   to->m3[6] = from.m3_6();
 | |
|   to->m3[7] = from.m3_7();
 | |
| }
 | |
| 
 | |
| JSObject* JavaScriptShared::findCPOWById(const ObjectId& objId) {
 | |
|   JSObject* obj = findCPOWByIdPreserveColor(objId);
 | |
|   if (obj) {
 | |
|     JS::ExposeObjectToActiveJS(obj);
 | |
|   }
 | |
|   return obj;
 | |
| }
 | |
| 
 | |
| JSObject* JavaScriptShared::findCPOWByIdPreserveColor(const ObjectId& objId) {
 | |
|   JSObject* obj = cpows_.findPreserveColor(objId);
 | |
|   if (!obj) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   if (js::gc::EdgeNeedsSweepUnbarriered(&obj)) {
 | |
|     cpows_.remove(objId);
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return obj;
 | |
| }
 | |
| 
 | |
| JSObject* JavaScriptShared::findObjectById(JSContext* cx,
 | |
|                                            const ObjectId& objId) {
 | |
|   RootedObject obj(cx, objects_.find(objId));
 | |
|   if (!obj) {
 | |
|     JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // Each process has a dedicated compartment for CPOW targets. All CPOWs
 | |
|   // from the other process point to objects in this scope. From there, they
 | |
|   // can access objects in other compartments using cross-compartment
 | |
|   // wrappers.
 | |
|   JSAutoRealm ar(cx, scopeForTargetObjects());
 | |
|   if (objId.hasXrayWaiver()) {
 | |
|     obj = js::ToWindowProxyIfWindow(obj);
 | |
|     MOZ_ASSERT(obj);
 | |
|     if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &obj)) {
 | |
|       return nullptr;
 | |
|     }
 | |
|   } else {
 | |
|     if (!JS_WrapObject(cx, &obj)) {
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
|   return obj;
 | |
| }
 | |
| 
 | |
| static const uint64_t UnknownPropertyOp = 1;
 | |
| 
 | |
| bool JavaScriptShared::fromDescriptor(JSContext* cx,
 | |
|                                       Handle<PropertyDescriptor> desc,
 | |
|                                       PPropertyDescriptor* out) {
 | |
|   out->attrs() = desc.attributes();
 | |
|   if (!toVariant(cx, desc.value(), &out->value())) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!toObjectOrNullVariant(cx, desc.object(), &out->obj())) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!desc.getter()) {
 | |
|     out->getter() = 0;
 | |
|   } else if (desc.hasGetterObject()) {
 | |
|     JSObject* getter = desc.getterObject();
 | |
|     ObjectVariant objVar;
 | |
|     if (!toObjectVariant(cx, getter, &objVar)) {
 | |
|       return false;
 | |
|     }
 | |
|     out->getter() = objVar;
 | |
|   } else {
 | |
|     out->getter() = UnknownPropertyOp;
 | |
|   }
 | |
| 
 | |
|   if (!desc.setter()) {
 | |
|     out->setter() = 0;
 | |
|   } else if (desc.hasSetterObject()) {
 | |
|     JSObject* setter = desc.setterObject();
 | |
|     ObjectVariant objVar;
 | |
|     if (!toObjectVariant(cx, setter, &objVar)) {
 | |
|       return false;
 | |
|     }
 | |
|     out->setter() = objVar;
 | |
|   } else {
 | |
|     out->setter() = UnknownPropertyOp;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool UnknownPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
 | |
|                          MutableHandleValue vp) {
 | |
|   JS_ReportErrorASCII(cx, "getter could not be wrapped via CPOWs");
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool UnknownStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
 | |
|                                HandleValue v, ObjectOpResult& result) {
 | |
|   JS_ReportErrorASCII(cx, "setter could not be wrapped via CPOWs");
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::toDescriptor(JSContext* cx,
 | |
|                                     const PPropertyDescriptor& in,
 | |
|                                     MutableHandle<PropertyDescriptor> out) {
 | |
|   out.setAttributes(in.attrs());
 | |
|   if (!fromVariant(cx, in.value(), out.value())) {
 | |
|     return false;
 | |
|   }
 | |
|   out.object().set(fromObjectOrNullVariant(cx, in.obj()));
 | |
| 
 | |
|   if (in.getter().type() == GetterSetter::Tuint64_t &&
 | |
|       !in.getter().get_uint64_t()) {
 | |
|     out.setGetter(nullptr);
 | |
|   } else if (in.attrs() & JSPROP_GETTER) {
 | |
|     Rooted<JSObject*> getter(cx);
 | |
|     getter = fromObjectVariant(cx, in.getter().get_ObjectVariant());
 | |
|     if (!getter) {
 | |
|       return false;
 | |
|     }
 | |
|     out.setGetter(JS_DATA_TO_FUNC_PTR(JSGetterOp, getter.get()));
 | |
|   } else {
 | |
|     out.setGetter(UnknownPropertyStub);
 | |
|   }
 | |
| 
 | |
|   if (in.setter().type() == GetterSetter::Tuint64_t &&
 | |
|       !in.setter().get_uint64_t()) {
 | |
|     out.setSetter(nullptr);
 | |
|   } else if (in.attrs() & JSPROP_SETTER) {
 | |
|     Rooted<JSObject*> setter(cx);
 | |
|     setter = fromObjectVariant(cx, in.setter().get_ObjectVariant());
 | |
|     if (!setter) {
 | |
|       return false;
 | |
|     }
 | |
|     out.setSetter(JS_DATA_TO_FUNC_PTR(JSSetterOp, setter.get()));
 | |
|   } else {
 | |
|     out.setSetter(UnknownStrictPropertyStub);
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::toObjectOrNullVariant(JSContext* cx, JSObject* obj,
 | |
|                                              ObjectOrNullVariant* objVarp) {
 | |
|   if (!obj) {
 | |
|     *objVarp = NullVariant();
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   ObjectVariant objVar;
 | |
|   if (!toObjectVariant(cx, obj, &objVar)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   *objVarp = objVar;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| JSObject* JavaScriptShared::fromObjectOrNullVariant(
 | |
|     JSContext* cx, const ObjectOrNullVariant& objVar) {
 | |
|   if (objVar.type() == ObjectOrNullVariant::TNullVariant) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return fromObjectVariant(cx, objVar.get_ObjectVariant());
 | |
| }
 | |
| 
 | |
| CrossProcessCpowHolder::CrossProcessCpowHolder(
 | |
|     dom::CPOWManagerGetter* managerGetter, const nsTArray<CpowEntry>& cpows)
 | |
|     : js_(nullptr), cpows_(cpows), unwrapped_(false) {
 | |
|   // Only instantiate the CPOW manager if we might need it later.
 | |
|   if (cpows.Length()) {
 | |
|     js_ = managerGetter->GetCPOWManager();
 | |
|   }
 | |
| }
 | |
| 
 | |
| CrossProcessCpowHolder::~CrossProcessCpowHolder() {
 | |
|   if (cpows_.Length() && !unwrapped_) {
 | |
|     // This should only happen if a message manager message
 | |
|     // containing CPOWs gets ignored for some reason. We need to
 | |
|     // unwrap every incoming CPOW in this process to ensure that
 | |
|     // the corresponding part of the CPOW in the other process
 | |
|     // will eventually be collected. The scope for this object
 | |
|     // doesn't really matter, because it immediately becomes
 | |
|     // garbage.
 | |
|     AutoJSAPI jsapi;
 | |
|     if (!jsapi.Init(xpc::PrivilegedJunkScope())) {
 | |
|       return;
 | |
|     }
 | |
|     JSContext* cx = jsapi.cx();
 | |
|     JS::Rooted<JSObject*> cpows(cx);
 | |
|     js_->Unwrap(cx, cpows_, &cpows);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool CrossProcessCpowHolder::ToObject(JSContext* cx,
 | |
|                                       JS::MutableHandleObject objp) {
 | |
|   unwrapped_ = true;
 | |
| 
 | |
|   if (!cpows_.Length()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return js_->Unwrap(cx, cpows_, objp);
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::Unwrap(JSContext* cx, const nsTArray<CpowEntry>& aCpows,
 | |
|                               JS::MutableHandleObject objp) {
 | |
|   objp.set(nullptr);
 | |
| 
 | |
|   if (!aCpows.Length()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   RootedObject obj(cx, JS_NewPlainObject(cx));
 | |
|   if (!obj) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   RootedValue v(cx);
 | |
|   RootedString str(cx);
 | |
|   for (size_t i = 0; i < aCpows.Length(); i++) {
 | |
|     const nsString& name = aCpows[i].name();
 | |
| 
 | |
|     if (!fromVariant(cx, aCpows[i].value(), &v)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (!JS_DefineUCProperty(cx, obj, name.BeginReading(), name.Length(), v,
 | |
|                              JSPROP_ENUMERATE)) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   objp.set(obj);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool JavaScriptShared::Wrap(JSContext* cx, HandleObject aObj,
 | |
|                             nsTArray<CpowEntry>* outCpows) {
 | |
|   if (!aObj) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   Rooted<IdVector> ids(cx, IdVector(cx));
 | |
|   if (!JS_Enumerate(cx, aObj, &ids)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   RootedId id(cx);
 | |
|   RootedValue v(cx);
 | |
|   for (size_t i = 0; i < ids.length(); i++) {
 | |
|     id = ids[i];
 | |
| 
 | |
|     nsString str;
 | |
|     if (!convertIdToGeckoString(cx, id, &str)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (!JS_GetPropertyById(cx, aObj, id, &v)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     JSVariant var;
 | |
|     if (!toVariant(cx, v, &var)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     outCpows->AppendElement(CpowEntry(str, var));
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| CPOWManager* mozilla::jsipc::CPOWManagerFor(PJavaScriptParent* aParent) {
 | |
|   return static_cast<JavaScriptParent*>(aParent);
 | |
| }
 | |
| 
 | |
| CPOWManager* mozilla::jsipc::CPOWManagerFor(PJavaScriptChild* aChild) {
 | |
|   return static_cast<JavaScriptChild*>(aChild);
 | |
| }
 |