Bug 1540301, part 5 - Replace instances of nsXPCWrappedJSClass with nsXPTInterfaceInfo. r=bzbarsky

nsXPCWrappedJSClass now only adds indirections and dynamic
allocations, so eliminate it. The class is kept around as a collection
of static helper functions to avoid needing to move around all of this
code and messing with history. In total, these patches save around 2kb
of dynamic allocations per process.

The major parts of this patch are:
* Dropping indirection for accessing things on nsXPTInterfaceInfo and
  renaming things from class to info.
* Removing the stuff related to instances of nsXPCWrappedJSClass
  existing (ctor, dtor, field, ISupports implementation, getter methods).
* Removing IID2WrappedJSClassMap, because we only need the map from IIDs
  to info.

I dropped the null check in TraverseNative because mInfo is never
cleared, while mClass was.

I dropped the forward declaration of nsXPCWrappedJSClass because no
instances of that class exist, so no function will take or return a
pointer to one.

Differential Revision: https://phabricator.services.mozilla.com/D26218

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrew McCreight 2019-04-06 12:57:02 +00:00
Родитель 8f23fc71ea
Коммит 90abea1653
7 изменённых файлов: 40 добавлений и 171 удалений

Просмотреть файл

@ -9,7 +9,7 @@
#ifndef xpcforwards_h___
#define xpcforwards_h___
// forward declarations of interally used classes...
// forward declarations of internally used classes...
class nsXPConnect;
class XPCJSContext;
@ -20,7 +20,6 @@ class XPCCallContext;
class XPCJSThrower;
class nsXPCWrappedJS;
class nsXPCWrappedJSClass;
class XPCNativeMember;
class XPCNativeInterface;
@ -34,7 +33,6 @@ class XPCTraceableVariant;
class JSObject2WrappedJSMap;
class Native2WrappedNativeMap;
class IID2WrappedJSClassMap;
class IID2NativeInterfaceMap;
class ClassInfo2NativeSetMap;
class ClassInfo2WrappedNativeProtoMap;

Просмотреть файл

@ -1138,9 +1138,6 @@ void XPCJSRuntime::Shutdown(JSContext* cx) {
delete mWrappedJSMap;
mWrappedJSMap = nullptr;
delete mWrappedJSClassMap;
mWrappedJSClassMap = nullptr;
delete mIID2NativeInterfaceMap;
mIID2NativeInterfaceMap = nullptr;
@ -2924,8 +2921,6 @@ static const JSWrapObjectCallbacks WrapObjectCallbacks = {
XPCJSRuntime::XPCJSRuntime(JSContext* aCx)
: CycleCollectedJSRuntime(aCx),
mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH)),
mWrappedJSClassMap(
IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_LENGTH)),
mIID2NativeInterfaceMap(
IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_LENGTH)),
mClassInfo2NativeSetMap(
@ -3148,18 +3143,6 @@ void XPCJSRuntime::DebugDump(int16_t depth) {
XPC_LOG_ALWAYS(("XPCJSRuntime @ %p", this));
XPC_LOG_INDENT();
XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %p with %d wrapperclasses(s)",
mWrappedJSClassMap, mWrappedJSClassMap->Count()));
// iterate wrappersclasses...
if (depth && mWrappedJSClassMap->Count()) {
XPC_LOG_INDENT();
for (auto i = mWrappedJSClassMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<IID2WrappedJSClassMap::Entry*>(i.Get());
nsXPCWrappedJSClass::DebugDump(entry->value->GetInterfaceInfo(), depth);
}
XPC_LOG_OUTDENT();
}
// iterate wrappers...
XPC_LOG_ALWAYS(("mWrappedJSMap @ %p with %d wrappers(s)", mWrappedJSMap,
mWrappedJSMap->Count()));

Просмотреть файл

@ -116,21 +116,6 @@ size_t Native2WrappedNativeMap::SizeOfIncludingThis(
return n;
}
/***************************************************************************/
// implement IID2WrappedJSClassMap...
const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps = {
HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub,
PLDHashTable::ClearEntryStub};
// static
IID2WrappedJSClassMap* IID2WrappedJSClassMap::newMap(int length) {
return new IID2WrappedJSClassMap(length);
}
IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
: mTable(&Entry::sOps, sizeof(Entry), length) {}
/***************************************************************************/
// implement IID2NativeInterfaceMap...

Просмотреть файл

@ -157,58 +157,6 @@ class Native2WrappedNativeMap {
/*************************/
class IID2WrappedJSClassMap {
public:
struct Entry : public PLDHashEntryHdr {
const nsIID* key;
nsXPCWrappedJSClass* value;
static const struct PLDHashTableOps sOps;
};
static IID2WrappedJSClassMap* newMap(int length);
inline nsXPCWrappedJSClass* Find(REFNSIID iid) const {
auto entry = static_cast<Entry*>(mTable.Search(&iid));
return entry ? entry->value : nullptr;
}
inline nsXPCWrappedJSClass* Add(nsXPCWrappedJSClass* clazz) {
MOZ_ASSERT(clazz, "bad param");
const nsIID* iid = &clazz->GetIID();
auto entry = static_cast<Entry*>(mTable.Add(iid, mozilla::fallible));
if (!entry) {
return nullptr;
}
if (entry->key) {
return entry->value;
}
entry->key = iid;
entry->value = clazz;
return clazz;
}
inline void Remove(nsXPCWrappedJSClass* clazz) {
MOZ_ASSERT(clazz, "bad param");
mTable.Remove(&clazz->GetIID());
}
inline uint32_t Count() { return mTable.EntryCount(); }
#ifdef DEBUG
PLDHashTable::Iterator Iter() { return mTable.Iter(); }
#endif
private:
IID2WrappedJSClassMap(); // no implementation
explicit IID2WrappedJSClassMap(int size);
private:
PLDHashTable mTable;
};
/*************************/
class IID2NativeInterfaceMap {
public:
struct Entry : public PLDHashEntryHdr {

Просмотреть файл

@ -103,12 +103,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::TraverseNative(
nsrefcnt refcnt = tmp->mRefCnt.get();
if (cb.WantDebugInfo()) {
char name[72];
if (tmp->GetClass()) {
SprintfLiteral(name, "nsXPCWrappedJS (%s)",
tmp->GetClass()->GetInterfaceName());
} else {
SprintfLiteral(name, "nsXPCWrappedJS");
}
SprintfLiteral(name, "nsXPCWrappedJS (%s)", tmp->mInfo->Name());
cb.DescribeRefCountedNode(refcnt, name);
} else {
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsXPCWrappedJS, refcnt)
@ -334,8 +329,8 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JSContext* cx, JS::HandleObject jsObj,
MOZ_RELEASE_ASSERT(js::GetContextCompartment(cx) ==
js::GetObjectCompartment(jsObj));
RefPtr<nsXPCWrappedJSClass> clasp = nsXPCWrappedJSClass::GetNewOrUsed(aIID);
if (!clasp) {
const nsXPTInterfaceInfo* info = nsXPCWrappedJSClass::GetInterfaceInfo(aIID);
if (!info) {
return NS_ERROR_FAILURE;
}
@ -370,20 +365,20 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JSContext* cx, JS::HandleObject jsObj,
// Make a new root wrapper, because there is no existing
// root wrapper, and the wrapper we are trying to make isn't
// a root.
RefPtr<nsXPCWrappedJSClass> rootClasp =
nsXPCWrappedJSClass::GetNewOrUsed(NS_GET_IID(nsISupports));
if (!rootClasp) {
const nsXPTInterfaceInfo* rootInfo =
nsXPCWrappedJSClass::GetInterfaceInfo(NS_GET_IID(nsISupports));
if (!rootInfo) {
return NS_ERROR_FAILURE;
}
root = new nsXPCWrappedJS(cx, rootJSObj, rootClasp, nullptr, &rv);
root = new nsXPCWrappedJS(cx, rootJSObj, rootInfo, nullptr, &rv);
if (NS_FAILED(rv)) {
return rv;
}
}
RefPtr<nsXPCWrappedJS> wrapper =
new nsXPCWrappedJS(cx, jsObj, clasp, root, &rv);
new nsXPCWrappedJS(cx, jsObj, info, root, &rv);
if (NS_FAILED(rv)) {
return rv;
}
@ -392,13 +387,13 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JSContext* cx, JS::HandleObject jsObj,
}
nsXPCWrappedJS::nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj,
nsXPCWrappedJSClass* aClass,
const nsXPTInterfaceInfo* aInfo,
nsXPCWrappedJS* root, nsresult* rv)
: mJSObj(aJSObj),
mClass(aClass),
mInfo(aInfo),
mRoot(root ? root : this),
mNext(nullptr) {
*rv = InitStub(GetClass()->GetIID());
*rv = InitStub(mInfo->IID());
// Continue even in the failure case, so that our refcounting/Destroy
// behavior works correctly.
@ -535,7 +530,6 @@ void nsXPCWrappedJS::Unlink() {
NS_RELEASE(mRoot);
}
mClass = nullptr;
if (mOuter) {
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
if (rt->GCIsRunning()) {
@ -578,7 +572,7 @@ nsXPCWrappedJS* nsXPCWrappedJS::FindInherited(REFNSIID aIID) {
MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports)), "bad call sequence");
for (nsXPCWrappedJS* cur = mRoot; cur; cur = cur->mNext) {
if (cur->GetClass()->GetInterfaceInfo()->HasAncestor(aIID)) {
if (cur->mInfo->HasAncestor(aIID)) {
return cur;
}
}
@ -616,9 +610,6 @@ void nsXPCWrappedJS::SystemIsBeingShutDown() {
// and that calls should fail without trying to use any of the
// xpconnect mechanisms. 'IsValid' is implemented by checking this pointer.
// NOTE: that mClass is retained so that GetInterfaceInfo can continue to
// work (and avoid crashing some platforms).
// Clear the contents of the pointer using unsafeGet() to avoid
// triggering post barriers in shutdown, as this will access the chunk
// containing mJSObj, which may have been freed at this point. This is safe
@ -634,11 +625,10 @@ void nsXPCWrappedJS::SystemIsBeingShutDown() {
size_t nsXPCWrappedJS::SizeOfIncludingThis(
mozilla::MallocSizeOf mallocSizeOf) const {
// mJSObject is a JS pointer, so don't measure the object.
// mClass is not uniquely owned by this WrappedJS. Measure it in
// IID2WrappedJSClassMap. mRoot is not measured because it is either |this| or
// we have already measured it. mOuter is rare and probably not uniquely owned
// by this.
// mJSObject is a JS pointer, so don't measure the object. mInfo is
// not dynamically allocated. mRoot is not measured because it is
// either |this| or we have already measured it. mOuter is rare and
// probably not uniquely owned by this.
size_t n = mallocSizeOf(this);
n += nsAutoXPTCStub::SizeOfExcludingThis(mallocSizeOf);
@ -663,14 +653,14 @@ nsXPCWrappedJS::DebugDump(int16_t depth) {
XPC_LOG_ALWAYS(("%s wrapper around JSObject @ %p",
IsRootWrapper() ? "ROOT" : "non-root", mJSObj.get()));
const char* name = GetClass()->GetInterfaceInfo()->Name();
const char* name = mInfo->Name();
XPC_LOG_ALWAYS(("interface name is %s", name));
char* iid = GetClass()->GetIID().ToString();
char* iid = mInfo->IID().ToString();
XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
if (iid) {
free(iid);
}
XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %p", mClass.get()));
XPC_LOG_ALWAYS(("nsXPTInterfaceInfo @ %p", mInfo));
if (!IsRootWrapper()) {
XPC_LOG_OUTDENT();

Просмотреть файл

@ -31,8 +31,6 @@ using namespace JS;
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_ISUPPORTS(nsXPCWrappedJSClass, nsISupports)
bool AutoScriptEvaluate::StartEvaluating(HandleObject scope) {
MOZ_ASSERT(!mEvaluated,
"AutoScriptEvaluate::Evaluate should only be called once");
@ -98,30 +96,18 @@ class MOZ_STACK_CLASS AutoSavePendingResult {
};
// static
already_AddRefed<nsXPCWrappedJSClass> nsXPCWrappedJSClass::GetNewOrUsed(
REFNSIID aIID) {
XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
IID2WrappedJSClassMap* map = xpcrt->GetWrappedJSClassMap();
RefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
if (!clasp) {
const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(aIID);
if (info) {
if (!info->IsBuiltinClass() && nsXPConnect::IsISupportsDescendant(info)) {
clasp = new nsXPCWrappedJSClass(info);
}
}
const nsXPTInterfaceInfo*
nsXPCWrappedJSClass::GetInterfaceInfo(REFNSIID aIID) {
const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(aIID);
if (!info) {
return nullptr;
}
return clasp.forget();
}
nsXPCWrappedJSClass::nsXPCWrappedJSClass(const nsXPTInterfaceInfo* aInfo)
: mInfo(aInfo) {
XPCJSRuntime::Get()->GetWrappedJSClassMap()->Add(this);
}
if (info->IsBuiltinClass() || !nsXPConnect::IsISupportsDescendant(info)) {
return nullptr;
}
nsXPCWrappedJSClass::~nsXPCWrappedJSClass() {
XPCJSRuntime::Get()->GetWrappedJSClassMap()->Remove(this);
return info;
}
// static
@ -780,8 +766,7 @@ nsresult nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper,
return NS_ERROR_FAILURE;
}
const nsXPTInterfaceInfo* interfaceInfo =
wrapper->GetClass()->GetInterfaceInfo();
const nsXPTInterfaceInfo* interfaceInfo = wrapper->GetInfo();
JS::RootedId id(cx);
const char* name;
nsAutoCString symbolName;
@ -1094,8 +1079,6 @@ pre_call_clean_up:
return retval;
}
const char* nsXPCWrappedJSClass::GetInterfaceName() { return mInfo->Name(); }
static const JSClass XPCOutParamClass = {"XPCOutParam", 0, JS_NULL_CLASS_OPS};
bool xpc::IsOutObject(JSContext* cx, JSObject* obj) {

Просмотреть файл

@ -171,7 +171,6 @@ class Exception;
// default initial sizes for maps (hashtables)
#define XPC_JS_MAP_LENGTH 32
#define XPC_JS_CLASS_MAP_LENGTH 32
#define XPC_NATIVE_MAP_LENGTH 8
#define XPC_NATIVE_PROTO_MAP_LENGTH 8
@ -488,10 +487,6 @@ class XPCJSRuntime final : public mozilla::CycleCollectedJSRuntime {
return mWrappedJSMap;
}
IID2WrappedJSClassMap* GetWrappedJSClassMap() const {
return mWrappedJSClassMap;
}
IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const {
return mIID2NativeInterfaceMap;
}
@ -625,7 +620,6 @@ class XPCJSRuntime final : public mozilla::CycleCollectedJSRuntime {
Principal2JSObjectMap;
JSObject2WrappedJSMap* mWrappedJSMap;
IID2WrappedJSClassMap* mWrappedJSClassMap;
IID2NativeInterfaceMap* mIID2NativeInterfaceMap;
ClassInfo2NativeSetMap* mClassInfo2NativeSetMap;
NativeSetMap* mNativeSetMap;
@ -1596,22 +1590,15 @@ class XPCWrappedNative final : public nsIXPConnectWrappedNative {
***************************************************************************/
/*************************/
// nsXPCWrappedJSClass represents the sharable factored out common code and
// data for nsXPCWrappedJS instances for the same interface type.
// nsXPCWrappedJSClass contains a number of helper methods for using
// nsXPTInterfaceInfo and nsXPCWrappedJS.
class nsXPCWrappedJSClass final : public nsISupports {
// all the interface method declarations...
NS_DECL_ISUPPORTS
class nsXPCWrappedJSClass final {
public:
static const nsXPTInterfaceInfo* GetInterfaceInfo(REFNSIID aIID);
static void DebugDump(const nsXPTInterfaceInfo* aInfo, int16_t depth);
public:
static already_AddRefed<nsXPCWrappedJSClass> GetNewOrUsed(REFNSIID aIID);
REFNSIID GetIID() const { return mInfo->IID(); }
const nsXPTInterfaceInfo* GetInterfaceInfo() const { return mInfo; }
const char* GetInterfaceName();
static nsresult DelegatedQueryInterface(nsXPCWrappedJS* self, REFNSIID aIID,
void** aInstancePtr);
@ -1636,10 +1623,8 @@ class nsXPCWrappedJSClass final : public nsISupports {
JS::HandleObject aObj, const char* aPropertyName,
const char* anInterfaceName,
mozilla::dom::Exception* aSyntheticException = nullptr);
virtual ~nsXPCWrappedJSClass();
nsXPCWrappedJSClass() = delete;
explicit nsXPCWrappedJSClass(const nsXPTInterfaceInfo* aInfo);
~nsXPCWrappedJSClass() = delete;
static bool GetArraySizeFromParam(const nsXPTMethodInfo* method,
const nsXPTType& type,
@ -1654,9 +1639,6 @@ class nsXPCWrappedJSClass final : public nsISupports {
static void CleanupOutparams(const nsXPTMethodInfo* info,
nsXPTCMiniVariant* nativeParams, bool inOutOnly,
uint8_t count);
private:
const nsXPTInterfaceInfo* mInfo;
};
/*************************/
@ -1710,8 +1692,8 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
// on the root wrapper and will assert if not called on a root wrapper.
bool IsMultiCompartment() const;
nsXPCWrappedJSClass* GetClass() const { return mClass; }
REFNSIID GetIID() const { return GetClass()->GetIID(); }
const nsXPTInterfaceInfo* GetInfo() const { return mInfo; }
REFNSIID GetIID() const { return mInfo->IID(); }
nsXPCWrappedJS* GetRootWrapper() const { return mRoot; }
nsXPCWrappedJS* GetNextWrapper() const { return mNext; }
@ -1759,7 +1741,7 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
protected:
nsXPCWrappedJS() = delete;
nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, nsXPCWrappedJSClass* aClass,
nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, const nsXPTInterfaceInfo* aInfo,
nsXPCWrappedJS* root, nsresult* rv);
bool CanSkip();
@ -1772,7 +1754,7 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
}
JS::Heap<JSObject*> mJSObj;
RefPtr<nsXPCWrappedJSClass> mClass;
const nsXPTInterfaceInfo* const mInfo;
nsXPCWrappedJS* mRoot; // If mRoot != this, it is an owning pointer.
nsXPCWrappedJS* mNext;
nsCOMPtr<nsISupports> mOuter; // only set in root