Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 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 : #ifndef mozilla_jsipc_JavaScriptShared_h__
9 : #define mozilla_jsipc_JavaScriptShared_h__
10 :
11 : #include "mozilla/dom/DOMTypes.h"
12 : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
13 : #include "mozilla/jsipc/PJavaScript.h"
14 : #include "js/GCHashTable.h"
15 : #include "nsJSUtils.h"
16 :
17 : namespace mozilla {
18 : namespace jsipc {
19 :
20 : class ObjectId {
21 : public:
22 : // Use 47 bits at most, to be safe, since jsval privates are encoded as
23 : // doubles. See bug 1065811 comment 12 for an explanation.
24 : static const size_t SERIAL_NUMBER_BITS = 47;
25 : static const size_t FLAG_BITS = 1;
26 : static const uint64_t SERIAL_NUMBER_MAX = (uint64_t(1) << SERIAL_NUMBER_BITS) - 1;
27 :
28 34 : explicit ObjectId(uint64_t serialNumber, bool hasXrayWaiver)
29 34 : : serialNumber_(serialNumber), hasXrayWaiver_(hasXrayWaiver)
30 : {
31 34 : if (MOZ_UNLIKELY(serialNumber == 0 || serialNumber > SERIAL_NUMBER_MAX))
32 0 : MOZ_CRASH("Bad CPOW Id");
33 34 : }
34 :
35 24 : bool operator==(const ObjectId& other) const {
36 24 : bool equal = serialNumber() == other.serialNumber();
37 24 : MOZ_ASSERT_IF(equal, hasXrayWaiver() == other.hasXrayWaiver());
38 24 : return equal;
39 : }
40 :
41 29 : bool isNull() { return !serialNumber_; }
42 :
43 189 : uint64_t serialNumber() const { return serialNumber_; }
44 140 : bool hasXrayWaiver() const { return hasXrayWaiver_; }
45 68 : uint64_t serialize() const {
46 68 : MOZ_ASSERT(serialNumber(), "Don't send a null ObjectId over IPC");
47 68 : return uint64_t((serialNumber() << FLAG_BITS) | ((hasXrayWaiver() ? 1 : 0) << 0));
48 : }
49 :
50 5 : static ObjectId nullId() { return ObjectId(); }
51 29 : static ObjectId deserialize(uint64_t data) {
52 29 : return ObjectId(data >> FLAG_BITS, data & 1);
53 : }
54 :
55 : // For use with StructGCPolicy.
56 0 : void trace(JSTracer*) const {}
57 0 : bool needsSweep() const { return false; }
58 :
59 : private:
60 5 : ObjectId() : serialNumber_(0), hasXrayWaiver_(false) {}
61 :
62 : uint64_t serialNumber_ : SERIAL_NUMBER_BITS;
63 : bool hasXrayWaiver_ : 1;
64 : };
65 :
66 : class JavaScriptShared;
67 :
68 : // DefaultHasher<T> requires that T coerce to an integral type. We could make
69 : // ObjectId do that, but doing so would weaken our type invariants, so we just
70 : // reimplement it manually.
71 : struct ObjectIdHasher
72 : {
73 : typedef ObjectId Lookup;
74 39 : static js::HashNumber hash(const Lookup& l) {
75 39 : return l.serialize();
76 : }
77 24 : static bool match(const ObjectId& k, const ObjectId& l) {
78 24 : return k == l;
79 : }
80 : static void rekey(ObjectId& k, const ObjectId& newKey) {
81 : k = newKey;
82 : }
83 : };
84 :
85 : // Map ids -> JSObjects
86 0 : class IdToObjectMap
87 : {
88 : typedef js::HashMap<ObjectId, JS::Heap<JSObject*>, ObjectIdHasher, js::SystemAllocPolicy> Table;
89 :
90 : public:
91 : IdToObjectMap();
92 :
93 : bool init();
94 : void trace(JSTracer* trc, uint64_t minimumId = 0);
95 : void sweep();
96 :
97 : bool add(ObjectId id, JSObject* obj);
98 : JSObject* find(ObjectId id);
99 : JSObject* findPreserveColor(ObjectId id);
100 : void remove(ObjectId id);
101 :
102 : void clear();
103 : bool empty() const;
104 :
105 : #ifdef DEBUG
106 : bool has(const ObjectId& id, const JSObject* obj) const;
107 : #endif
108 :
109 : private:
110 : Table table_;
111 : };
112 :
113 : // Map JSObjects -> ids
114 6 : class ObjectToIdMap
115 : {
116 : using Hasher = js::MovableCellHasher<JS::Heap<JSObject*>>;
117 : using Table = JS::GCHashMap<JS::Heap<JSObject*>, ObjectId, Hasher, js::SystemAllocPolicy>;
118 :
119 : public:
120 : bool init();
121 : void trace(JSTracer* trc);
122 : void sweep();
123 :
124 : bool add(JSContext* cx, JSObject* obj, ObjectId id);
125 : ObjectId find(JSObject* obj);
126 : void remove(JSObject* obj);
127 : void clear();
128 :
129 : private:
130 : Table table_;
131 : };
132 :
133 : class Logging;
134 :
135 : class JavaScriptShared : public CPOWManager
136 : {
137 : public:
138 : JavaScriptShared();
139 : virtual ~JavaScriptShared();
140 :
141 : bool init();
142 :
143 : void decref();
144 : void incref();
145 :
146 : bool Unwrap(JSContext* cx, const InfallibleTArray<CpowEntry>& aCpows, JS::MutableHandleObject objp);
147 : bool Wrap(JSContext* cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry>* outCpows);
148 :
149 : protected:
150 : bool toVariant(JSContext* cx, JS::HandleValue from, JSVariant* to);
151 : bool fromVariant(JSContext* cx, const JSVariant& from, JS::MutableHandleValue to);
152 :
153 : bool toJSIDVariant(JSContext* cx, JS::HandleId from, JSIDVariant* to);
154 : bool fromJSIDVariant(JSContext* cx, const JSIDVariant& from, JS::MutableHandleId to);
155 :
156 : bool toSymbolVariant(JSContext* cx, JS::Symbol* sym, SymbolVariant* symVarp);
157 : JS::Symbol* fromSymbolVariant(JSContext* cx, const SymbolVariant& symVar);
158 :
159 : bool fromDescriptor(JSContext* cx, JS::Handle<JS::PropertyDescriptor> desc,
160 : PPropertyDescriptor* out);
161 : bool toDescriptor(JSContext* cx, const PPropertyDescriptor& in,
162 : JS::MutableHandle<JS::PropertyDescriptor> out);
163 :
164 : bool toObjectOrNullVariant(JSContext* cx, JSObject* obj, ObjectOrNullVariant* objVarp);
165 : JSObject* fromObjectOrNullVariant(JSContext* cx, const ObjectOrNullVariant& objVar);
166 :
167 : bool convertIdToGeckoString(JSContext* cx, JS::HandleId id, nsString* to);
168 : bool convertGeckoStringToId(JSContext* cx, const nsString& from, JS::MutableHandleId id);
169 :
170 : virtual bool toObjectVariant(JSContext* cx, JSObject* obj, ObjectVariant* objVarp) = 0;
171 : virtual JSObject* fromObjectVariant(JSContext* cx, const ObjectVariant& objVar) = 0;
172 :
173 : static void ConvertID(const nsID& from, JSIID* to);
174 : static void ConvertID(const JSIID& from, nsID* to);
175 :
176 : JSObject* findCPOWById(const ObjectId& objId);
177 : JSObject* findCPOWByIdPreserveColor(const ObjectId& objId);
178 : JSObject* findObjectById(JSContext* cx, const ObjectId& objId);
179 :
180 : #ifdef DEBUG
181 0 : bool hasCPOW(const ObjectId& objId, const JSObject* obj) {
182 0 : MOZ_ASSERT(obj);
183 0 : return findCPOWByIdPreserveColor(objId) == obj;
184 : }
185 : #endif
186 :
187 0 : static bool LoggingEnabled() { return sLoggingEnabled; }
188 0 : static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
189 :
190 : friend class Logging;
191 :
192 : virtual bool isParent() = 0;
193 :
194 : virtual JSObject* scopeForTargetObjects() = 0;
195 :
196 : protected:
197 : uintptr_t refcount_;
198 :
199 : IdToObjectMap objects_;
200 : IdToObjectMap cpows_;
201 :
202 : uint64_t nextSerialNumber_;
203 :
204 : // nextCPOWNumber_ should be the value of nextSerialNumber_ in the other
205 : // process. The next new CPOW we get should have this serial number.
206 : uint64_t nextCPOWNumber_;
207 :
208 : // CPOW references can be weak, and any object we store in a map may be
209 : // GCed (at which point the CPOW will report itself "dead" to the owner).
210 : // This means that we don't want to store any js::Wrappers in the CPOW map,
211 : // because CPOW will die if the wrapper is GCed, even if the underlying
212 : // object is still alive.
213 : //
214 : // This presents a tricky situation for Xray waivers, since they're normally
215 : // represented as a special same-compartment wrapper. We have to strip them
216 : // off before putting them in the id-to-object and object-to-id maps, so we
217 : // need a way of distinguishing them at lookup-time.
218 : //
219 : // For the id-to-object map, we encode waiver-or-not information into the id
220 : // itself, which lets us do the right thing when accessing the object.
221 : //
222 : // For the object-to-id map, we just keep two maps, one for each type.
223 : ObjectToIdMap unwaivedObjectIds_;
224 : ObjectToIdMap waivedObjectIds_;
225 34 : ObjectToIdMap& objectIdMap(bool waiver) {
226 34 : return waiver ? waivedObjectIds_ : unwaivedObjectIds_;
227 : }
228 :
229 : static bool sLoggingInitialized;
230 : static bool sLoggingEnabled;
231 : static bool sStackLoggingEnabled;
232 : };
233 :
234 : } // namespace jsipc
235 : } // namespace mozilla
236 :
237 : #endif
|