1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sw=2 et tw=80:
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/. */
8 #ifndef mozilla_jsipc_JavaScriptShared_h__
9 #define mozilla_jsipc_JavaScriptShared_h__
11 #include "mozilla/HashFunctions.h"
12 #include "mozilla/dom/DOMTypes.h"
13 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
14 #include "mozilla/jsipc/PJavaScript.h"
15 #include "mozilla/StaticPrefs_dom.h"
16 #include "js/GCHashTable.h"
17 #include "nsJSUtils.h"
24 // Use 47 bits at most, to be safe, since jsval privates are encoded as
25 // doubles. See bug 1065811 comment 12 for an explanation.
26 static const size_t SERIAL_NUMBER_BITS
= 47;
27 static const size_t FLAG_BITS
= 1;
28 static const uint64_t SERIAL_NUMBER_MAX
=
29 (uint64_t(1) << SERIAL_NUMBER_BITS
) - 1;
31 explicit ObjectId(uint64_t serialNumber
, bool hasXrayWaiver
)
32 : serialNumber_(serialNumber
), hasXrayWaiver_(hasXrayWaiver
) {
33 if (isInvalidSerialNumber(serialNumber
)) {
34 MOZ_CRASH("Bad CPOW Id");
38 bool operator==(const ObjectId
& other
) const {
39 bool equal
= serialNumber() == other
.serialNumber();
40 MOZ_ASSERT_IF(equal
, hasXrayWaiver() == other
.hasXrayWaiver());
44 bool isNull() { return !serialNumber_
; }
46 uint64_t serialNumber() const { return serialNumber_
; }
47 bool hasXrayWaiver() const { return hasXrayWaiver_
; }
48 uint64_t serialize() const {
49 MOZ_ASSERT(serialNumber(), "Don't send a null ObjectId over IPC");
50 return uint64_t((serialNumber() << FLAG_BITS
) |
51 ((hasXrayWaiver() ? 1 : 0) << 0));
54 static ObjectId
nullId() { return ObjectId(); }
55 static Maybe
<ObjectId
> deserialize(uint64_t data
) {
56 if (isInvalidSerialNumber(data
>> FLAG_BITS
)) {
59 return Some(ObjectId(data
>> FLAG_BITS
, data
& 1));
62 // For use with StructGCPolicy.
63 void trace(JSTracer
*) const {}
64 bool needsSweep() const { return false; }
67 ObjectId() : serialNumber_(0), hasXrayWaiver_(false) {}
69 static bool isInvalidSerialNumber(uint64_t aSerialNumber
) {
70 return aSerialNumber
== 0 || aSerialNumber
> SERIAL_NUMBER_MAX
;
73 uint64_t serialNumber_
: SERIAL_NUMBER_BITS
;
74 bool hasXrayWaiver_
: 1;
77 class JavaScriptShared
;
79 // DefaultHasher<T> requires that T coerce to an integral type. We could make
80 // ObjectId do that, but doing so would weaken our type invariants, so we just
81 // reimplement it manually.
82 struct ObjectIdHasher
{
83 typedef ObjectId Lookup
;
84 static js::HashNumber
hash(const Lookup
& l
) {
85 return mozilla::HashGeneric(l
.serialize());
87 static bool match(const ObjectId
& k
, const ObjectId
& l
) { return k
== l
; }
88 static void rekey(ObjectId
& k
, const ObjectId
& newKey
) { k
= newKey
; }
91 // Map ids -> JSObjects
93 typedef js::HashMap
<ObjectId
, JS::Heap
<JSObject
*>, ObjectIdHasher
,
94 js::SystemAllocPolicy
>
100 void trace(JSTracer
* trc
, uint64_t minimumId
= 0);
103 bool add(ObjectId id
, JSObject
* obj
);
104 JSObject
* find(ObjectId id
);
105 JSObject
* findPreserveColor(ObjectId id
);
106 void remove(ObjectId id
);
112 bool has(const ObjectId
& id
, const JSObject
* obj
) const;
119 // Map JSObjects -> ids
120 class ObjectToIdMap
{
121 using Hasher
= js::MovableCellHasher
<JS::Heap
<JSObject
*>>;
122 using Table
= JS::GCHashMap
<JS::Heap
<JSObject
*>, ObjectId
, Hasher
,
123 js::SystemAllocPolicy
>;
128 void trace(JSTracer
* trc
);
131 bool add(JSContext
* cx
, JSObject
* obj
, ObjectId id
);
132 ObjectId
find(JSObject
* obj
);
133 void remove(JSObject
* obj
);
142 class JavaScriptShared
: public CPOWManager
{
145 virtual ~JavaScriptShared();
150 bool Unwrap(JSContext
* cx
, const nsTArray
<CpowEntry
>& aCpows
,
151 JS::MutableHandleObject objp
) override
;
152 bool Wrap(JSContext
* cx
, JS::HandleObject aObj
,
153 nsTArray
<CpowEntry
>* outCpows
) override
;
156 bool toVariant(JSContext
* cx
, JS::HandleValue from
, JSVariant
* to
);
157 bool fromVariant(JSContext
* cx
, const JSVariant
& from
,
158 JS::MutableHandleValue to
);
160 bool toJSIDVariant(JSContext
* cx
, JS::HandleId from
, JSIDVariant
* to
);
161 bool fromJSIDVariant(JSContext
* cx
, const JSIDVariant
& from
,
162 JS::MutableHandleId to
);
164 bool toSymbolVariant(JSContext
* cx
, JS::Symbol
* sym
, SymbolVariant
* symVarp
);
165 JS::Symbol
* fromSymbolVariant(JSContext
* cx
, const SymbolVariant
& symVar
);
167 bool fromDescriptor(JSContext
* cx
, JS::Handle
<JS::PropertyDescriptor
> desc
,
168 PPropertyDescriptor
* out
);
169 bool toDescriptor(JSContext
* cx
, const PPropertyDescriptor
& in
,
170 JS::MutableHandle
<JS::PropertyDescriptor
> out
);
172 bool toObjectOrNullVariant(JSContext
* cx
, JSObject
* obj
,
173 ObjectOrNullVariant
* objVarp
);
174 JSObject
* fromObjectOrNullVariant(JSContext
* cx
,
175 const ObjectOrNullVariant
& objVar
);
177 bool convertIdToGeckoString(JSContext
* cx
, JS::HandleId id
, nsString
* to
);
178 bool convertGeckoStringToId(JSContext
* cx
, const nsString
& from
,
179 JS::MutableHandleId id
);
181 virtual bool toObjectVariant(JSContext
* cx
, JSObject
* obj
,
182 ObjectVariant
* objVarp
) = 0;
183 virtual JSObject
* fromObjectVariant(JSContext
* cx
,
184 const ObjectVariant
& objVar
) = 0;
186 static void ConvertID(const nsID
& from
, JSIID
* to
);
187 static void ConvertID(const JSIID
& from
, nsID
* to
);
189 JSObject
* findCPOWById(const ObjectId
& objId
);
190 JSObject
* findCPOWByIdPreserveColor(const ObjectId
& objId
);
191 JSObject
* findObjectById(JSContext
* cx
, const ObjectId
& objId
);
194 bool hasCPOW(const ObjectId
& objId
, const JSObject
* obj
) {
196 return findCPOWByIdPreserveColor(objId
) == obj
;
200 static bool LoggingEnabled() {
201 return sLoggingEnabledByEnvVar
|| StaticPrefs::dom_ipc_cpows_log_enabled();
203 static bool StackLoggingEnabled() {
204 return sStackLoggingEnabledByEnvVar
||
205 StaticPrefs::dom_ipc_cpows_log_stack();
208 friend class Logging
;
210 virtual bool isParent() = 0;
212 virtual JSObject
* scopeForTargetObjects() = 0;
217 IdToObjectMap objects_
;
218 IdToObjectMap cpows_
;
220 uint64_t nextSerialNumber_
;
222 // nextCPOWNumber_ should be the value of nextSerialNumber_ in the other
223 // process. The next new CPOW we get should have this serial number.
224 uint64_t nextCPOWNumber_
;
226 // CPOW references can be weak, and any object we store in a map may be
227 // GCed (at which point the CPOW will report itself "dead" to the owner).
228 // This means that we don't want to store any js::Wrappers in the CPOW map,
229 // because CPOW will die if the wrapper is GCed, even if the underlying
230 // object is still alive.
232 // This presents a tricky situation for Xray waivers, since they're normally
233 // represented as a special same-compartment wrapper. We have to strip them
234 // off before putting them in the id-to-object and object-to-id maps, so we
235 // need a way of distinguishing them at lookup-time.
237 // For the id-to-object map, we encode waiver-or-not information into the id
238 // itself, which lets us do the right thing when accessing the object.
240 // For the object-to-id map, we just keep two maps, one for each type.
241 ObjectToIdMap unwaivedObjectIds_
;
242 ObjectToIdMap waivedObjectIds_
;
243 ObjectToIdMap
& objectIdMap(bool waiver
) {
244 return waiver
? waivedObjectIds_
: unwaivedObjectIds_
;
247 static bool sLoggingInitialized
;
248 static bool sLoggingEnabledByEnvVar
;
249 static bool sStackLoggingEnabledByEnvVar
;
253 } // namespace mozilla