mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-04 11:26:09 +00:00
18fae65f38
This requires replacing inclusions of it with inclusions of more specific prefs files. The exception is that StaticPrefsAll.h, which is equivalent to StaticPrefs.h, and is used in `Codegen.py` because doing something smarter is tricky and suitable for a follow-up. As a result, any change to StaticPrefList.yaml will still trigger recompilation of all the generated DOM bindings files, but that's still a big improvement over trigger recompilation of every file that uses static prefs. Most of the changes in this commit are very boring. The only changes that are not boring are modules/libpref/*, Codegen.py, and ServoBindings.toml. Differential Revision: https://phabricator.services.mozilla.com/D39138 --HG-- extra : moz-landing-system : lando
256 lines
8.0 KiB
C++
256 lines
8.0 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vim: set ts=8 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/. */
|
|
|
|
#ifndef mozilla_jsipc_JavaScriptShared_h__
|
|
#define mozilla_jsipc_JavaScriptShared_h__
|
|
|
|
#include "mozilla/HashFunctions.h"
|
|
#include "mozilla/dom/DOMTypes.h"
|
|
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
|
#include "mozilla/jsipc/PJavaScript.h"
|
|
#include "mozilla/StaticPrefs_dom.h"
|
|
#include "js/GCHashTable.h"
|
|
#include "nsJSUtils.h"
|
|
|
|
namespace mozilla {
|
|
namespace jsipc {
|
|
|
|
class ObjectId {
|
|
public:
|
|
// Use 47 bits at most, to be safe, since jsval privates are encoded as
|
|
// doubles. See bug 1065811 comment 12 for an explanation.
|
|
static const size_t SERIAL_NUMBER_BITS = 47;
|
|
static const size_t FLAG_BITS = 1;
|
|
static const uint64_t SERIAL_NUMBER_MAX =
|
|
(uint64_t(1) << SERIAL_NUMBER_BITS) - 1;
|
|
|
|
explicit ObjectId(uint64_t serialNumber, bool hasXrayWaiver)
|
|
: serialNumber_(serialNumber), hasXrayWaiver_(hasXrayWaiver) {
|
|
if (isInvalidSerialNumber(serialNumber)) {
|
|
MOZ_CRASH("Bad CPOW Id");
|
|
}
|
|
}
|
|
|
|
bool operator==(const ObjectId& other) const {
|
|
bool equal = serialNumber() == other.serialNumber();
|
|
MOZ_ASSERT_IF(equal, hasXrayWaiver() == other.hasXrayWaiver());
|
|
return equal;
|
|
}
|
|
|
|
bool isNull() { return !serialNumber_; }
|
|
|
|
uint64_t serialNumber() const { return serialNumber_; }
|
|
bool hasXrayWaiver() const { return hasXrayWaiver_; }
|
|
uint64_t serialize() const {
|
|
MOZ_ASSERT(serialNumber(), "Don't send a null ObjectId over IPC");
|
|
return uint64_t((serialNumber() << FLAG_BITS) |
|
|
((hasXrayWaiver() ? 1 : 0) << 0));
|
|
}
|
|
|
|
static ObjectId nullId() { return ObjectId(); }
|
|
static Maybe<ObjectId> deserialize(uint64_t data) {
|
|
if (isInvalidSerialNumber(data >> FLAG_BITS)) {
|
|
return Nothing();
|
|
}
|
|
return Some(ObjectId(data >> FLAG_BITS, data & 1));
|
|
}
|
|
|
|
// For use with StructGCPolicy.
|
|
void trace(JSTracer*) const {}
|
|
bool needsSweep() const { return false; }
|
|
|
|
private:
|
|
ObjectId() : serialNumber_(0), hasXrayWaiver_(false) {}
|
|
|
|
static bool isInvalidSerialNumber(uint64_t aSerialNumber) {
|
|
return aSerialNumber == 0 || aSerialNumber > SERIAL_NUMBER_MAX;
|
|
}
|
|
|
|
uint64_t serialNumber_ : SERIAL_NUMBER_BITS;
|
|
bool hasXrayWaiver_ : 1;
|
|
};
|
|
|
|
class JavaScriptShared;
|
|
|
|
// DefaultHasher<T> requires that T coerce to an integral type. We could make
|
|
// ObjectId do that, but doing so would weaken our type invariants, so we just
|
|
// reimplement it manually.
|
|
struct ObjectIdHasher {
|
|
typedef ObjectId Lookup;
|
|
static js::HashNumber hash(const Lookup& l) {
|
|
return mozilla::HashGeneric(l.serialize());
|
|
}
|
|
static bool match(const ObjectId& k, const ObjectId& l) { return k == l; }
|
|
static void rekey(ObjectId& k, const ObjectId& newKey) { k = newKey; }
|
|
};
|
|
|
|
// Map ids -> JSObjects
|
|
class IdToObjectMap {
|
|
typedef js::HashMap<ObjectId, JS::Heap<JSObject*>, ObjectIdHasher,
|
|
js::SystemAllocPolicy>
|
|
Table;
|
|
|
|
public:
|
|
IdToObjectMap();
|
|
|
|
void trace(JSTracer* trc, uint64_t minimumId = 0);
|
|
void sweep();
|
|
|
|
bool add(ObjectId id, JSObject* obj);
|
|
JSObject* find(ObjectId id);
|
|
JSObject* findPreserveColor(ObjectId id);
|
|
void remove(ObjectId id);
|
|
|
|
void clear();
|
|
bool empty() const;
|
|
|
|
#ifdef DEBUG
|
|
bool has(const ObjectId& id, const JSObject* obj) const;
|
|
#endif
|
|
|
|
private:
|
|
Table table_;
|
|
};
|
|
|
|
// Map JSObjects -> ids
|
|
class ObjectToIdMap {
|
|
using Hasher = js::MovableCellHasher<JS::Heap<JSObject*>>;
|
|
using Table = JS::GCHashMap<JS::Heap<JSObject*>, ObjectId, Hasher,
|
|
js::SystemAllocPolicy>;
|
|
|
|
public:
|
|
ObjectToIdMap();
|
|
|
|
void trace(JSTracer* trc);
|
|
void sweep();
|
|
|
|
bool add(JSContext* cx, JSObject* obj, ObjectId id);
|
|
ObjectId find(JSObject* obj);
|
|
void remove(JSObject* obj);
|
|
void clear();
|
|
|
|
private:
|
|
Table table_;
|
|
};
|
|
|
|
class Logging;
|
|
|
|
class JavaScriptShared : public CPOWManager {
|
|
public:
|
|
JavaScriptShared();
|
|
virtual ~JavaScriptShared();
|
|
|
|
void decref();
|
|
void incref();
|
|
|
|
bool Unwrap(JSContext* cx, const nsTArray<CpowEntry>& aCpows,
|
|
JS::MutableHandleObject objp) override;
|
|
bool Wrap(JSContext* cx, JS::HandleObject aObj,
|
|
nsTArray<CpowEntry>* outCpows) override;
|
|
|
|
protected:
|
|
bool toVariant(JSContext* cx, JS::HandleValue from, JSVariant* to);
|
|
bool fromVariant(JSContext* cx, const JSVariant& from,
|
|
JS::MutableHandleValue to);
|
|
|
|
bool toJSIDVariant(JSContext* cx, JS::HandleId from, JSIDVariant* to);
|
|
bool fromJSIDVariant(JSContext* cx, const JSIDVariant& from,
|
|
JS::MutableHandleId to);
|
|
|
|
bool toSymbolVariant(JSContext* cx, JS::Symbol* sym, SymbolVariant* symVarp);
|
|
JS::Symbol* fromSymbolVariant(JSContext* cx, const SymbolVariant& symVar);
|
|
|
|
bool fromDescriptor(JSContext* cx, JS::Handle<JS::PropertyDescriptor> desc,
|
|
PPropertyDescriptor* out);
|
|
bool toDescriptor(JSContext* cx, const PPropertyDescriptor& in,
|
|
JS::MutableHandle<JS::PropertyDescriptor> out);
|
|
|
|
bool toObjectOrNullVariant(JSContext* cx, JSObject* obj,
|
|
ObjectOrNullVariant* objVarp);
|
|
JSObject* fromObjectOrNullVariant(JSContext* cx,
|
|
const ObjectOrNullVariant& objVar);
|
|
|
|
bool convertIdToGeckoString(JSContext* cx, JS::HandleId id, nsString* to);
|
|
bool convertGeckoStringToId(JSContext* cx, const nsString& from,
|
|
JS::MutableHandleId id);
|
|
|
|
virtual bool toObjectVariant(JSContext* cx, JSObject* obj,
|
|
ObjectVariant* objVarp) = 0;
|
|
virtual JSObject* fromObjectVariant(JSContext* cx,
|
|
const ObjectVariant& objVar) = 0;
|
|
|
|
static void ConvertID(const nsID& from, JSIID* to);
|
|
static void ConvertID(const JSIID& from, nsID* to);
|
|
|
|
JSObject* findCPOWById(const ObjectId& objId);
|
|
JSObject* findCPOWByIdPreserveColor(const ObjectId& objId);
|
|
JSObject* findObjectById(JSContext* cx, const ObjectId& objId);
|
|
|
|
#ifdef DEBUG
|
|
bool hasCPOW(const ObjectId& objId, const JSObject* obj) {
|
|
MOZ_ASSERT(obj);
|
|
return findCPOWByIdPreserveColor(objId) == obj;
|
|
}
|
|
#endif
|
|
|
|
static bool LoggingEnabled() {
|
|
return sLoggingEnabledByEnvVar || StaticPrefs::dom_ipc_cpows_log_enabled();
|
|
}
|
|
static bool StackLoggingEnabled() {
|
|
return sStackLoggingEnabledByEnvVar ||
|
|
StaticPrefs::dom_ipc_cpows_log_stack();
|
|
}
|
|
|
|
friend class Logging;
|
|
|
|
virtual bool isParent() = 0;
|
|
|
|
virtual JSObject* scopeForTargetObjects() = 0;
|
|
|
|
protected:
|
|
uintptr_t refcount_;
|
|
|
|
IdToObjectMap objects_;
|
|
IdToObjectMap cpows_;
|
|
|
|
uint64_t nextSerialNumber_;
|
|
|
|
// nextCPOWNumber_ should be the value of nextSerialNumber_ in the other
|
|
// process. The next new CPOW we get should have this serial number.
|
|
uint64_t nextCPOWNumber_;
|
|
|
|
// CPOW references can be weak, and any object we store in a map may be
|
|
// GCed (at which point the CPOW will report itself "dead" to the owner).
|
|
// This means that we don't want to store any js::Wrappers in the CPOW map,
|
|
// because CPOW will die if the wrapper is GCed, even if the underlying
|
|
// object is still alive.
|
|
//
|
|
// This presents a tricky situation for Xray waivers, since they're normally
|
|
// represented as a special same-compartment wrapper. We have to strip them
|
|
// off before putting them in the id-to-object and object-to-id maps, so we
|
|
// need a way of distinguishing them at lookup-time.
|
|
//
|
|
// For the id-to-object map, we encode waiver-or-not information into the id
|
|
// itself, which lets us do the right thing when accessing the object.
|
|
//
|
|
// For the object-to-id map, we just keep two maps, one for each type.
|
|
ObjectToIdMap unwaivedObjectIds_;
|
|
ObjectToIdMap waivedObjectIds_;
|
|
ObjectToIdMap& objectIdMap(bool waiver) {
|
|
return waiver ? waivedObjectIds_ : unwaivedObjectIds_;
|
|
}
|
|
|
|
static bool sLoggingInitialized;
|
|
static bool sLoggingEnabledByEnvVar;
|
|
static bool sStackLoggingEnabledByEnvVar;
|
|
};
|
|
|
|
} // namespace jsipc
|
|
} // namespace mozilla
|
|
|
|
#endif
|