xpcomproxy-gcalloc.patch
author Benjamin Smedberg <benjamin@smedbergs.us>
Sat, 26 Jul 2008 22:49:39 -0400
changeset 167 a4da40849f5436e629c5732f4368c6c48189637f
parent 123 55f4c3203c4f384a083cc87cccea108f7db740b9
permissions -rw-r--r--
State as of now

* * *
* * *
* * *

diff --git a/xpcom/proxy/src/nsProxyEvent.cpp b/xpcom/proxy/src/nsProxyEvent.cpp
--- a/xpcom/proxy/src/nsProxyEvent.cpp
+++ b/xpcom/proxy/src/nsProxyEvent.cpp
@@ -109,7 +109,6 @@ nsProxyCallCompletedEvent::QueryInterfac
     // needs to be allowed through during a synchronous proxy call.
     if (aIID.Equals(kFilterIID)) {
         *aResult = mInfo;
-        mInfo->AddRef();
         return NS_OK;
     }
     return nsRunnable::QueryInterface(aIID, aResult);
@@ -154,7 +153,7 @@ nsProxyObjectCallInfo::~nsProxyObjectCal
     mOwner = nsnull;
     
     if (mParameterList)  
-        free(mParameterList);
+        NS_GetGC()->Free(mParameterList);
 }
 
 NS_IMETHODIMP
@@ -162,7 +161,6 @@ nsProxyObjectCallInfo::QueryInterface(RE
 {
     if (aIID.Equals(kFilterIID)) {
         *aResult = this;
-        AddRef();
         return NS_OK;
     }
     return nsRunnable::QueryInterface(aIID, aResult);
@@ -279,7 +277,7 @@ nsProxyObjectCallInfo::PostCompleted()
     PROXY_LOG(("PROXY(%p): PostCompleted\n", this));
 
     if (mCallersTarget) {
-        nsCOMPtr<nsIRunnable> event =
+        nsIRunnable* event =
                 new nsProxyCallCompletedEvent(this);
         if (event &&
             NS_SUCCEEDED(mCallersTarget->Dispatch(event, NS_DISPATCH_NORMAL)))
@@ -303,31 +301,18 @@ nsProxyObjectCallInfo::SetCallersTarget(
     mCallersTarget = target;
 }   
 
-nsProxyObject::nsProxyObject(nsIEventTarget *target, PRInt32 proxyType,
-                             nsISupports *realObject) :
-  mProxyType(proxyType),
-  mTarget(target),
-  mRealObject(realObject),
-  mFirst(nsnull)
+nsProxyObject::nsProxyObject(nsISupports *realObject, nsIEventTarget *target,
+                             PRInt32 proxyType)
+    : nsProxyBase(realObject, target, proxyType)
+    , mFirst(nsnull)
 {
     MOZ_COUNT_CTOR(nsProxyObject);
 
 #ifdef DEBUG
-    nsCOMPtr<nsISupports> canonicalTarget = do_QueryInterface(target);
+    nsISupports* canonicalTarget = do_QueryInterface(target);
     NS_ASSERTION(target == canonicalTarget,
                  "Non-canonical nsISupports passed to nsProxyObject constructor");
 #endif
-
-    nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
-    NS_ASSERTION(pom, "Creating a proxy without a global proxy-object-manager.");
-    pom->AddRef();
-}
-
-nsProxyObject::~nsProxyObject()
-{
-    nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
-    nsAutoLock lock(pom->GetLock());
-    pom->LockedRemove(this);
 }
 
 NS_IMETHODIMP
@@ -335,13 +320,11 @@ nsProxyObject::QueryInterface(REFNSIID a
 {
     if (aIID.Equals(GetIID())) {
         *aResult = this;
-        AddRef();
         return NS_OK;
     }
 
     if (aIID.Equals(NS_GET_IID(nsISupports))) {
         *aResult = static_cast<nsISupports*>(this);
-        AddRef();
         return NS_OK;
     }
 
@@ -415,14 +398,18 @@ nsProxyObject::LockedFind(REFNSIID aIID,
 }
 
 void
-nsProxyObject::LockedRemove(nsProxyEventObject *peo)
+nsProxyObject::SweepDyingMembers()
 {
-    nsProxyEventObject **i;
-    for (i = &mFirst; *i; i = &((*i)->mNext)) {
-        if (*i == peo) {
-            *i = peo->mNext;
-            return;
+    nsProxyEventObject **peo = &mFirst;
+    while (*peo) {
+        if (!NS_GetGC()->GetMark(*peo)) {
+            // If this member isn't marked, remove it from the list
+            *peo = (*peo)->mNext;
+        }
+        else {
+            // otherwise keep walking through the list
+            peo = &(*peo)->mNext;
         }
     }
-    NS_ERROR("Didn't find nsProxyEventObject in nsProxyObject chain!");
 }
+
diff --git a/xpcom/proxy/src/nsProxyEventClass.cpp b/xpcom/proxy/src/nsProxyEventClass.cpp
--- a/xpcom/proxy/src/nsProxyEventClass.cpp
+++ b/xpcom/proxy/src/nsProxyEventClass.cpp
@@ -70,10 +70,9 @@ nsProxyEventClass::nsProxyEventClass(REF
         if(methodCount)
         {
             int wordCount = (methodCount/32)+1;
-            if(NULL != (mDescriptors = new uint32[wordCount]))
-            {
-                memset(mDescriptors, 0, wordCount * sizeof(uint32));
-            }
+            mDescriptors = (uint32*)
+                NS_GetGC()->Alloc(wordCount * sizeof(uint32),
+                                  MMgc::GC::kZero);
         }
         else
         {
@@ -84,6 +83,4 @@ nsProxyEventClass::nsProxyEventClass(REF
 
 nsProxyEventClass::~nsProxyEventClass()
 {
-    if (mDescriptors && mDescriptors != &zero_methods_descriptor)
-        delete [] mDescriptors;
 }
diff --git a/xpcom/proxy/src/nsProxyEventObject.cpp b/xpcom/proxy/src/nsProxyEventObject.cpp
--- a/xpcom/proxy/src/nsProxyEventObject.cpp
+++ b/xpcom/proxy/src/nsProxyEventObject.cpp
@@ -65,12 +65,6 @@ nsProxyEventObject::nsProxyEventObject(n
     *rv = InitStub(aClass->GetProxiedIID());
 }
 
-nsProxyEventObject::~nsProxyEventObject()
-{
-    nsAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
-    mProxyObject->LockedRemove(this);
-}
-
 //
 // nsISupports implementation...
 //
@@ -81,7 +75,6 @@ nsProxyEventObject::QueryInterface(REFNS
     if( aIID.Equals(GetClass()->GetProxiedIID()) )
     {
         *aInstancePtr = static_cast<nsISupports*>(mXPTCStub);
-        NS_ADDREF_THIS();
         return NS_OK;
     }
         
@@ -104,7 +97,9 @@ nsProxyEventObject::convertMiniVariantTo
 
     if (!paramCount) return NS_OK;
         
-    *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount);
+    *fullParam = static_cast<nsXPTCVariant*>(
+        NS_GetGC()->Alloc(sizeof(nsXPTCVariant) * paramCount,
+                          MMgc::GC::kContainsPointers));
     
     if (*fullParam == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -116,7 +111,6 @@ nsProxyEventObject::convertMiniVariantTo
             (paramInfo.IsOut() || paramInfo.IsDipper()))
         {
             NS_WARNING("Async proxying of out parameters is not supported"); 
-            free(*fullParam);
             return NS_ERROR_PROXY_INVALID_OUT_PARAMETER;
         }
         uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0;
@@ -126,7 +120,7 @@ nsProxyEventObject::convertMiniVariantTo
     return NS_OK;
 }
 
-class nsProxyThreadFilter : public nsIThreadEventFilter
+class nsProxyThreadFilter : public XPCOMGCFinalizedObject, public nsIThreadEventFilter
 {
 public:
     NS_DECL_ISUPPORTS
@@ -147,8 +141,8 @@ nsProxyThreadFilter::AcceptEvent(nsIRunn
     // we want to allow the event to be dispatched to the thread's event queue
     // for processing later once we complete the current sync method call.
     
-    nsRefPtr<nsProxyObjectCallInfo> poci;
-    event->QueryInterface(kFilterIID, getter_AddRefs(poci));
+    nsProxyObjectCallInfo* poci = nsnull;
+    event->QueryInterface(kFilterIID, (void**)&poci);
     return poci && poci->IsSync();
 }
 
@@ -181,12 +175,12 @@ nsProxyEventObject::CallMethod(PRUint16 
                               paramCount, fullParam);
 
         if (fullParam)
-            free(fullParam);
+            NS_GetGC()->Free(fullParam);
 
         return rv;
     }
 
-    nsRefPtr<nsProxyObjectCallInfo> proxyInfo =
+    nsProxyObjectCallInfo* proxyInfo =
         new nsProxyObjectCallInfo(this, methodInfo, methodIndex,
                                   fullParam, paramCount);
     if (!proxyInfo)
@@ -199,12 +193,12 @@ nsProxyEventObject::CallMethod(PRUint16 
     // Post synchronously
 
     nsIThread *thread = NS_GetCurrentThread();
-    nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread);
+    nsIThreadInternal* threadInt = do_QueryInterface(thread);
     NS_ENSURE_STATE(threadInt);
 
     // Install  thread filter to limit event processing only to 
     // nsProxyObjectCallInfo instances.  XXX Add support for sequencing?
-    nsRefPtr<nsProxyThreadFilter> filter = new nsProxyThreadFilter();
+    nsProxyThreadFilter* filter = new nsProxyThreadFilter();
     if (!filter)
         return NS_ERROR_OUT_OF_MEMORY;
     threadInt->PushEventQueue(filter);
diff --git a/xpcom/proxy/src/nsProxyEventPrivate.h b/xpcom/proxy/src/nsProxyEventPrivate.h
--- a/xpcom/proxy/src/nsProxyEventPrivate.h
+++ b/xpcom/proxy/src/nsProxyEventPrivate.h
@@ -51,7 +51,7 @@
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
 
-#include "nsClassHashtable.h"
+#include "nsDataHashtable.h"
 #include "nsHashtable.h"
 
 #include "prmon.h"
@@ -81,7 +81,7 @@ typedef nsISupports nsISomeInterface;
  * An object representing an IID and its associated interfaceinfo. Instances
  * of this class are obtained via nsProxyObjectManager::GetClass.
  */
-class nsProxyEventClass
+class nsProxyEventClass : public XPCOMGCObject
 {
 public:
     nsIInterfaceInfo*        GetInterfaceInfo() const {return mInfo;}
@@ -92,7 +92,7 @@ public:
 
     nsIID                      mIID;
     nsCOMPtr<nsIInterfaceInfo> mInfo;
-    uint32*                    mDescriptors;
+    uint32*                    mDescriptors; // GC-allocated
 };
 
 /**
@@ -100,15 +100,32 @@ public:
  * Instances of this class are obtained from the POM, and are uniquely
  * hashed on a proxytype/eventtarget/realobject key.
  */
-class nsProxyObject : public nsISupports
+struct nsProxyBase
+{
+    nsProxyBase(nsISupports* realObject, nsIEventTarget* target,
+                PRInt32 proxyType)
+        : mProxyType(proxyType)
+        , mTarget(target)
+        , mRealObject(realObject)
+    { }
+
+    const PRInt32          mProxyType;
+    nsIEventTarget *const  mTarget;
+    nsISupports *const     mRealObject;
+};
+
+class nsProxyObject
+    : private nsProxyBase
+    , public XPCOMGCObject
+    , public nsISupports
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYOBJECT_CLASS_IID)
 
-    nsProxyObject(nsIEventTarget *destQueue, PRInt32 proxyType,
-                  nsISupports *realObject);
+    nsProxyObject(nsISupports *realObject, nsIEventTarget *destQueue,
+                  PRInt32 proxyType);
  
     nsISupports*        GetRealObject() const { return mRealObject; }
     nsIEventTarget*     GetTarget() const { return mTarget; }
@@ -118,16 +135,11 @@ public:
     // temporarily unlock the lock during execution.
     nsresult LockedFind(REFNSIID iid, void **aResult);
 
-    void LockedRemove(nsProxyEventObject* aObject);
+    void SweepDyingMembers();
 
     friend class nsProxyObjectManager;
+    friend class nsProxyObjectKey;
 private:
-    ~nsProxyObject();
-
-    PRInt32                   mProxyType;
-    nsCOMPtr<nsIEventTarget>  mTarget;           /* event target */
-    nsCOMPtr<nsISupports>     mRealObject;       /* the non-proxy object that this object is proxying
-                                                    This is a strong ref. */
     nsProxyEventObject       *mFirst;
 
     class nsProxyObjectDestructorEvent : public nsRunnable
@@ -148,12 +160,57 @@ private:
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyObject, NS_PROXYOBJECT_CLASS_IID)
 
+class nsProxyObjectKey : public PLDHashEntryHdr
+{
+public:
+    typedef nsProxyBase *KeyType;
+    typedef const nsProxyBase *KeyTypePointer;
+
+    nsProxyObjectKey(const nsProxyBase *key, char *entryStore)
+        : mProxy(NULL)
+    { }
+
+    ~nsProxyObjectKey() { }
+
+    void SetProxy(nsProxyObject *proxy)
+    {
+        mProxy = proxy;
+    }
+    
+    nsProxyObject* GetProxy() const
+    {
+        return mProxy;
+    }
+
+    PRBool KeyEquals(const nsProxyBase *other) const
+    {
+        return mProxy->mRealObject == other->mRealObject &&
+            mProxy->mTarget == other->mTarget &&
+            mProxy->mProxyType == other->mProxyType;
+    }
+
+    static const nsProxyBase* KeyToPointer(const nsProxyBase *key)
+    {
+        return key;
+    }
+
+    static PLDHashNumber HashKey(const nsProxyBase *key)
+    {
+        return NS_PTR_TO_INT32(key->mRealObject) ^
+            NS_PTR_TO_INT32(key->mTarget) ^
+            key->mProxyType;
+    }
+
+private:
+    nsProxyObject *mProxy;
+};
+
 /**
  * Object representing a single interface implemented on a proxied object.
  * This object is maintained in a singly-linked list from the associated
  * "parent" nsProxyObject.
  */
-class nsProxyEventObject : protected nsAutoXPTCStub
+class nsProxyEventObject : public XPCOMGCObject, protected nsAutoXPTCStub
 {
 public:
 
@@ -182,8 +239,6 @@ public:
     friend class nsProxyObject;
 
 private:
-    ~nsProxyEventObject();
-
     // Member ordering is important: See note in the destructor.
     nsProxyEventClass          *mClass;
     nsCOMPtr<nsProxyObject>     mProxyObject;
@@ -263,7 +318,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyObj
 // nsProxyObjectManager
 ////////////////////////////////////////////////////////////////////////////////
 
-class nsProxyObjectManager: public nsIProxyObjectManager
+class nsProxyObjectManager
+    : public XPCOMGCFinalizedObject
+    , public nsIProxyObjectManager
+    , public MMgc::GCCallback
 {
 public:
     NS_DECL_ISUPPORTS
@@ -282,6 +340,8 @@ public:
 
     void LockedRemove(nsProxyObject* aProxy);
 
+    void presweep();
+
     PRLock* GetLock() const { return mProxyCreationLock; }
 
 #ifdef PR_LOGGING
@@ -292,8 +352,9 @@ private:
     ~nsProxyObjectManager();
 
     static nsProxyObjectManager* mInstance;
-    nsHashtable  mProxyObjectMap;
-    nsClassHashtable<nsIDHashKey, nsProxyEventClass> mProxyClassMap;
+    nsTHashtable<nsProxyObjectKey> mProxyObjectMap;
+    
+    nsDataHashtable<nsIDHashKey, nsProxyEventClass*> mProxyClassMap;
     PRLock *mProxyCreationLock;
 };
 
diff --git a/xpcom/proxy/src/nsProxyObjectManager.cpp b/xpcom/proxy/src/nsProxyObjectManager.cpp
--- a/xpcom/proxy/src/nsProxyObjectManager.cpp
+++ b/xpcom/proxy/src/nsProxyObjectManager.cpp
@@ -63,35 +63,6 @@ PRLogModuleInfo *nsProxyObjectManager::s
 PRLogModuleInfo *nsProxyObjectManager::sLog = PR_NewLogModule("xpcomproxy");
 #endif
 
-class nsProxyEventKey : public nsHashKey
-{
-public:
-    nsProxyEventKey(void* rootObjectKey, void* targetKey, PRInt32 proxyType)
-        : mRootObjectKey(rootObjectKey), mTargetKey(targetKey), mProxyType(proxyType) {
-    }
-  
-    PRUint32 HashCode(void) const {
-        return NS_PTR_TO_INT32(mRootObjectKey) ^ 
-            NS_PTR_TO_INT32(mTargetKey) ^ mProxyType;
-    }
-
-    PRBool Equals(const nsHashKey *aKey) const {
-        const nsProxyEventKey* other = (const nsProxyEventKey*)aKey;
-        return mRootObjectKey == other->mRootObjectKey
-            && mTargetKey == other->mTargetKey
-            && mProxyType == other->mProxyType;
-    }
-
-    nsHashKey *Clone() const {
-        return new nsProxyEventKey(mRootObjectKey, mTargetKey, mProxyType);
-    }
-
-protected:
-    void*       mRootObjectKey;
-    void*       mTargetKey;
-    PRInt32     mProxyType;
-};
-
 /////////////////////////////////////////////////////////////////////////
 // nsProxyObjectManager
 /////////////////////////////////////////////////////////////////////////
@@ -101,16 +72,47 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObj
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObjectManager, nsIProxyObjectManager)
 
 nsProxyObjectManager::nsProxyObjectManager()
-    : mProxyObjectMap(256, PR_FALSE)
+    : MMgc::GCCallback(NS_GetGC())
 {
     mProxyCreationLock = PR_NewLock();
     mProxyClassMap.Init(256);
+    mProxyObjectMap.Init(256);
+}
+
+static PLDHashOperator
+SweepDyingClasses(const nsID& aID, nsProxyEventClass *&aEntry, void *userArg)
+{
+    NS_ASSERTION(aEntry, "Horked table.");
+
+    if (NS_GetGC()->GetMark(aEntry))
+        return PL_DHASH_NEXT;
+
+    return PL_DHASH_REMOVE;
+}
+
+static PLDHashOperator
+SweepDyingProxies(nsProxyObjectKey *key, void *userArg)
+{
+    nsProxyObject *proxy = key->GetProxy();
+
+    NS_ASSERTION(proxy, "Horked table.");
+
+    if (NS_GetGC()->GetMark(proxy)) {
+        proxy->SweepDyingMembers();
+        return PL_DHASH_NEXT;
+    }
+    return PL_DHASH_REMOVE;
+}
+
+void
+nsProxyObjectManager::presweep()
+{
+    mProxyClassMap.Enumerate(SweepDyingClasses, NULL);
+    mProxyObjectMap.EnumerateEntries(SweepDyingProxies, NULL);
 }
 
 nsProxyObjectManager::~nsProxyObjectManager()
 {
-    mProxyClassMap.Clear();
-
     if (mProxyCreationLock)
         PR_DestroyLock(mProxyCreationLock);
 
@@ -189,44 +191,26 @@ nsProxyObjectManager::GetProxyForObject(
         realObj = po->GetRealObject();
     }
 
-    nsProxyEventKey rootKey(realObj, aTarget, proxyType);
-
+    nsProxyBase rootKey(realObj, aTarget, proxyType);
     {
         nsAutoLock lock(mProxyCreationLock);
-        nsProxyObject *root =
-            (nsProxyObject*) mProxyObjectMap.Get(&rootKey);
-        if (root)
-            return root->LockedFind(aIID, aProxyObject);
+        nsProxyObjectKey *entry = mProxyObjectMap.GetEntry(&rootKey);
+        if (entry)
+            return entry->GetProxy()->LockedFind(aIID, aProxyObject);
     }
 
     // don't lock while creating the nsProxyObject
-    nsProxyObject *newRoot = new nsProxyObject(aTarget, proxyType, realObj);
-    if (!newRoot)
-        return NS_ERROR_OUT_OF_MEMORY;
+    nsProxyObject *newRoot = new nsProxyObject(realObj, aTarget, proxyType);
 
     // lock again, and check for a race putting into mProxyObjectMap
     {
         nsAutoLock lock(mProxyCreationLock);
-        nsProxyObject *root = 
-            (nsProxyObject*) mProxyObjectMap.Get(&rootKey);
-        if (root) {
-            delete newRoot;
-            return root->LockedFind(aIID, aProxyObject);
-        }
+        nsProxyObjectKey *entry = mProxyObjectMap.PutEntry(&rootKey);
 
-        mProxyObjectMap.Put(&rootKey, newRoot);
+        if (!entry->GetProxy())
+            entry->SetProxy(newRoot);
 
-        return newRoot->LockedFind(aIID, aProxyObject);
-    }
-}
-
-void
-nsProxyObjectManager::LockedRemove(nsProxyObject *aProxy)
-{
-    nsProxyEventKey rootKey(aProxy->GetRealObject(), aProxy->GetTarget(), aProxy->GetProxyType());
-
-    if (!mProxyObjectMap.Remove(&rootKey)) {
-        NS_ERROR("nsProxyObject not found in global hash.");
+        return entry->GetProxy()->LockedFind(aIID, aProxyObject);
     }
 }