123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/dom/DOMTypes.h"
- #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
- #include "mozilla/jsipc/PJavaScript.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 (MOZ_UNLIKELY(serialNumber == 0 || serialNumber > SERIAL_NUMBER_MAX))
- 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 ObjectId deserialize(uint64_t data) {
- return 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) {}
- 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 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();
- bool init();
- 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:
- bool init();
- 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();
- bool init();
- void decref();
- void incref();
- bool Unwrap(JSContext* cx, const InfallibleTArray<CpowEntry>& aCpows, JS::MutableHandleObject objp);
- bool Wrap(JSContext* cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry>* outCpows);
- 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) {
- return cpows_.find(objId);
- }
- JSObject* findObjectById(JSContext* cx, const ObjectId& objId);
- #ifdef DEBUG
- bool hasCPOW(const ObjectId& objId, const JSObject* obj) {
- return cpows_.has(objId, obj);
- }
- #endif
- static bool LoggingEnabled() { return sLoggingEnabled; }
- static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
- 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 sLoggingEnabled;
- static bool sStackLoggingEnabled;
- };
- } // namespace jsipc
- } // namespace mozilla
- #endif
|