Coverage Report

Created: 2018-09-25 14:53

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