Bug 1550804 - Add color scheme simulation to the inspector. r=pbro
[gecko.git] / js / ipc / JavaScriptShared.h
blobdddf9215feabc30a2f5a97e21ca71c23608ce1c0
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"
19 namespace mozilla {
20 namespace jsipc {
22 class ObjectId {
23 public:
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());
41 return equal;
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)) {
57 return Nothing();
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; }
66 private:
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
92 class IdToObjectMap {
93 typedef js::HashMap<ObjectId, JS::Heap<JSObject*>, ObjectIdHasher,
94 js::SystemAllocPolicy>
95 Table;
97 public:
98 IdToObjectMap();
100 void trace(JSTracer* trc, uint64_t minimumId = 0);
101 void sweep();
103 bool add(ObjectId id, JSObject* obj);
104 JSObject* find(ObjectId id);
105 JSObject* findPreserveColor(ObjectId id);
106 void remove(ObjectId id);
108 void clear();
109 bool empty() const;
111 #ifdef DEBUG
112 bool has(const ObjectId& id, const JSObject* obj) const;
113 #endif
115 private:
116 Table table_;
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>;
125 public:
126 ObjectToIdMap();
128 void trace(JSTracer* trc);
129 void sweep();
131 bool add(JSContext* cx, JSObject* obj, ObjectId id);
132 ObjectId find(JSObject* obj);
133 void remove(JSObject* obj);
134 void clear();
136 private:
137 Table table_;
140 class Logging;
142 class JavaScriptShared : public CPOWManager {
143 public:
144 JavaScriptShared();
145 virtual ~JavaScriptShared();
147 void decref();
148 void incref();
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;
155 protected:
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);
193 #ifdef DEBUG
194 bool hasCPOW(const ObjectId& objId, const JSObject* obj) {
195 MOZ_ASSERT(obj);
196 return findCPOWByIdPreserveColor(objId) == obj;
198 #endif
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;
214 protected:
215 uintptr_t refcount_;
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;
252 } // namespace jsipc
253 } // namespace mozilla
255 #endif