Bug 896385 - Use nsInterfaceHashtable for nsXBLPrototypeBinding::mInterfaceTable; r=mrbkap
authorMs2ger <ms2ger@gmail.com>
Wed, 24 Jul 2013 09:39:56 +0200
changeset 151960 3b4ca49280476bc4e976d6a0de68ef09f8aa45b3
parent 151959 c2707e67339cef6a87433b9acad6397f81c000b2
child 151961 a03dad6ac12a8542bf419871604b7e687e498dac
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs896385
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 896385 - Use nsInterfaceHashtable for nsXBLPrototypeBinding::mInterfaceTable; r=mrbkap
content/xbl/src/nsXBLPrototypeBinding.cpp
content/xbl/src/nsXBLPrototypeBinding.h
xpcom/glue/nsInterfaceHashtable.h
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -48,39 +48,16 @@
 #include "nsXULElement.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Helper Classes =====================================================================
 
-// Internal helper class for managing our IID table.
-class nsIIDKey : public nsHashKey {
-  public:
-    nsIID mKey;
-
-  public:
-    nsIIDKey(REFNSIID key) : mKey(key) {}
-    ~nsIIDKey(void) {}
-
-    uint32_t HashCode(void) const {
-      // Just use the 32-bit m0 field.
-      return mKey.m0;
-    }
-
-    bool Equals(const nsHashKey *aKey) const {
-      return mKey.Equals( ((nsIIDKey*) aKey)->mKey);
-    }
-
-    nsHashKey *Clone(void) const {
-      return new nsIIDKey(mKey);
-    }
-};
-
 // nsXBLAttributeEntry and helpers.  This class is used to efficiently handle
 // attribute changes in anonymous content.
 
 class nsXBLAttributeEntry {
 public:
   nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom,
                       int32_t aDstNameSpace, nsIContent* aContent)
     : mElement(aContent),
@@ -120,20 +97,20 @@ nsXBLPrototypeBinding::nsXBLPrototypeBin
 : mImplementation(nullptr),
   mBaseBinding(nullptr),
   mInheritStyle(true),
   mCheckedBaseProto(false),
   mKeyHandlersRegistered(false),
   mChromeOnlyContent(false),
   mResources(nullptr),
   mAttributeTable(nullptr),
-  mInterfaceTable(nullptr),
   mBaseNameSpaceID(kNameSpaceID_None)
 {
   MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
+  mInterfaceTable.Init();
 }
 
 nsresult
 nsXBLPrototypeBinding::Init(const nsACString& aID,
                             nsXBLDocumentInfo* aInfo,
                             nsIContent* aElement,
                             bool aFirstBinding)
 {
@@ -163,37 +140,26 @@ bool nsXBLPrototypeBinding::CompareBindi
   bool equal = false;
   mBindingURI->Equals(aURI, &equal);
   if (!equal && mAlternateBindingURI) {
     mAlternateBindingURI->Equals(aURI, &equal);
   }
   return equal;
 }
 
-static bool
-TraverseBinding(nsHashKey *aKey, void *aData, void* aClosure)
-{
-  nsCycleCollectionTraversalCallback *cb = 
-    static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME((*cb), "proto mInterfaceTable data");
-  cb->NoteXPCOMChild(static_cast<nsISupports*>(aData));
-  return kHashEnumerateNext;
-}
-
 void
 nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mBinding");
   cb.NoteXPCOMChild(mBinding);
   if (mResources) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mResources mLoader");
     cb.NoteXPCOMChild(mResources->mLoader);
   }
-  if (mInterfaceTable)
-    mInterfaceTable->Enumerate(TraverseBinding, &cb);
+  ImplCycleCollectionTraverse(cb, mInterfaceTable, "proto mInterfaceTable");
 }
 
 void
 nsXBLPrototypeBinding::UnlinkJSObjects()
 {
   if (mImplementation)
     mImplementation->UnlinkJSObjects();
 }
@@ -213,17 +179,16 @@ nsXBLPrototypeBinding::Initialize()
     ConstructAttributeTable(content);
   }
 }
 
 nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
 {
   delete mResources;
   delete mAttributeTable;
-  delete mInterfaceTable;
   delete mImplementation;
   MOZ_COUNT_DTOR(nsXBLPrototypeBinding);
 }
 
 void
 nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding)
 {
   if (mBaseBinding == aBinding)
@@ -469,23 +434,17 @@ nsXBLPrototypeBinding::GetBaseTag(int32_
 
   return nullptr;
 }
 
 bool
 nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const
 {
   // Check our IID table.
-  if (mInterfaceTable) {
-    nsIIDKey key(aIID);
-    nsCOMPtr<nsISupports> supports = dont_AddRef(mInterfaceTable->Get(&key));
-    return supports != nullptr;
-  }
-
-  return false;
+  return !!mInterfaceTable.GetWeak(aIID);
 }
 
 // Internal helpers ///////////////////////////////////////////////////////////////////////
 
 nsIContent*
 nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag)
 {
   for (nsIContent* child = mBinding->GetFirstChild();
@@ -798,20 +757,16 @@ nsXBLPrototypeBinding::ConstructInterfac
   if (!aImpls.IsEmpty()) {
     // Obtain the interface info manager that can tell us the IID
     // for a given interface name.
     nsCOMPtr<nsIInterfaceInfoManager>
       infoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
     if (!infoManager)
       return NS_ERROR_FAILURE;
 
-    // Create the table.
-    if (!mInterfaceTable)
-      mInterfaceTable = new nsSupportsHashtable(4);
-
     // The user specified at least one attribute.
     NS_ConvertUTF16toUTF8 utf8impl(aImpls);
     char* str = utf8impl.BeginWriting();
     char* newStr;
     // XXX We should use a strtok function that tokenizes PRUnichars
     // so that we don't have to convert from Unicode to ASCII and then back
 
     char* token = nsCRT::strtok( str, ", ", &newStr );
@@ -822,34 +777,32 @@ nsXBLPrototypeBinding::ConstructInterfac
 
       if (iinfo) {
         // obtain an IID.
         const nsIID* iid = nullptr;
         iinfo->GetIIDShared(&iid);
 
         if (iid) {
           // We found a valid iid.  Add it to our table.
-          nsIIDKey key(*iid);
-          mInterfaceTable->Put(&key, mBinding);
+          mInterfaceTable.Put(*iid, mBinding);
 
           // this block adds the parent interfaces of each interface
           // defined in the xbl definition (implements="nsI...")
           nsCOMPtr<nsIInterfaceInfo> parentInfo;
           // if it has a parent, add it to the table
           while (NS_SUCCEEDED(iinfo->GetParent(getter_AddRefs(parentInfo))) && parentInfo) {
             // get the iid
             parentInfo->GetIIDShared(&iid);
 
             // don't add nsISupports to the table
             if (!iid || iid->Equals(NS_GET_IID(nsISupports)))
               break;
 
             // add the iid to the table
-            nsIIDKey parentKey(*iid);
-            mInterfaceTable->Put(&parentKey, mBinding);
+            mInterfaceTable.Put(*iid, mBinding);
 
             // look for the next parent
             iinfo = parentInfo;
           }
         }
       }
 
       token = nsCRT::strtok( newStr, ", ", &newStr );
@@ -982,27 +935,20 @@ nsXBLPrototypeBinding::Read(nsIObjectInp
   if (child) {
     mBinding->AppendChildTo(child, false);
   }
 
   uint32_t interfaceCount;
   rv = aStream->Read32(&interfaceCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (interfaceCount > 0) {
-    NS_ASSERTION(!mInterfaceTable, "non-null mInterfaceTable");
-    mInterfaceTable = new nsSupportsHashtable(interfaceCount);
-    NS_ENSURE_TRUE(mInterfaceTable, NS_ERROR_OUT_OF_MEMORY);
-
-    for (; interfaceCount > 0; interfaceCount--) {
-      nsIID iid;
-      aStream->ReadID(&iid);
-      nsIIDKey key(iid);
-      mInterfaceTable->Put(&key, mBinding);
-    }
+  for (; interfaceCount > 0; interfaceCount--) {
+    nsIID iid;
+    aStream->ReadID(&iid);
+    mInterfaceTable.Put(iid, mBinding);
   }
 
   nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner(do_QueryObject(aDocInfo));
   nsIScriptGlobalObject* globalObject = globalOwner->GetScriptGlobalObject();
   NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
 
   nsIScriptContext *context = globalObject->GetContext();
   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
@@ -1087,25 +1033,23 @@ nsXBLPrototypeBinding::Read(nsIObjectInp
   if (isFirstBinding) {
     aDocInfo->SetFirstPrototypeBinding(this);
   }
 
   cleanup.Disconnect();
   return NS_OK;
 }
 
-static
-bool
-WriteInterfaceID(nsHashKey *aKey, void *aData, void* aClosure)
+static PLDHashOperator
+WriteInterfaceID(const nsIID& aKey, nsIContent* aData, void* aClosure)
 {
   // We can just write out the ids. The cache will be invalidated when a
   // different build is used, so we don't need to worry about ids changing.
-  nsID iid = ((nsIIDKey *)aKey)->mKey;
-  static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(iid);
-  return kHashEnumerateNext;
+  static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(aKey);
+  return PL_DHASH_NEXT;
 }
 
 nsresult
 nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
 {
   // This writes out the binding. Note that mCheckedBaseProto,
   // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are
   // computed on demand.
@@ -1162,26 +1106,20 @@ nsXBLPrototypeBinding::Write(nsIObjectOu
   }
   else {
     // Write a marker to indicate that there is no content.
     rv = aStream->Write8(XBLBinding_Serialize_NoContent);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Enumerate and write out the implemented interfaces.
-  if (mInterfaceTable) {
-    rv = aStream->Write32(mInterfaceTable->Count());
-    NS_ENSURE_SUCCESS(rv, rv);
+  rv = aStream->Write32(mInterfaceTable.Count());
+  NS_ENSURE_SUCCESS(rv, rv);
 
-    mInterfaceTable->Enumerate(WriteInterfaceID, aStream);
-  }
-  else {
-    rv = aStream->Write32(0);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  mInterfaceTable.EnumerateRead(WriteInterfaceID, aStream);
 
   // Write out the implementation details.
   if (mImplementation) {
     rv = mImplementation->Write(context, aStream, this);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     // Write out an empty classname. This indicates that the binding does not
--- a/content/xbl/src/nsXBLPrototypeBinding.h
+++ b/content/xbl/src/nsXBLPrototypeBinding.h
@@ -1,27 +1,28 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 nsXBLPrototypeBinding_h__
 #define nsXBLPrototypeBinding_h__
 
+#include "nsClassHashtable.h"
+#include "nsCOMArray.h"
 #include "nsCOMPtr.h"
-#include "nsXBLPrototypeResources.h"
-#include "nsXBLPrototypeHandler.h"
-#include "nsXBLProtoImplMethod.h"
+#include "nsHashtable.h"
 #include "nsICSSLoaderObserver.h"
+#include "nsInterfaceHashtable.h"
 #include "nsWeakReference.h"
-#include "nsHashtable.h"
-#include "nsClassHashtable.h"
 #include "nsXBLDocumentInfo.h"
-#include "nsCOMArray.h"
 #include "nsXBLProtoImpl.h"
+#include "nsXBLProtoImplMethod.h"
+#include "nsXBLPrototypeHandler.h"
+#include "nsXBLPrototypeResources.h"
 
 class nsIAtom;
 class nsIContent;
 class nsIDocument;
 class nsIScriptContext;
 class nsSupportsHashtable;
 class nsXBLProtoImplField;
 class nsXBLBinding;
@@ -277,17 +278,56 @@ protected:
   nsXBLPrototypeResources* mResources; // If we have any resources, this will be non-null.
                                       
   nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info.  Weak, since it owns us.
 
   nsObjectHashtable* mAttributeTable; // A table for attribute containers. Namespace IDs are used as
                                       // keys in the table. Containers are nsObjectHashtables.
                                       // This table is used to efficiently handle attribute changes.
 
-  nsSupportsHashtable* mInterfaceTable; // A table of cached interfaces that we support.
+  class IIDHashKey : public PLDHashEntryHdr
+  {
+  public:
+    typedef const nsIID& KeyType;
+    typedef const nsIID* KeyTypePointer;
+
+    IIDHashKey(const nsIID* aKey)
+      : mKey(*aKey)
+    {}
+    IIDHashKey(const IIDHashKey& aOther)
+      : mKey(aOther.GetKey())
+    {}
+    ~IIDHashKey()
+    {}
+
+    KeyType GetKey() const
+    {
+      return mKey;
+    }
+    bool KeyEquals(const KeyTypePointer aKey) const
+    {
+      return mKey.Equals(*aKey);
+    }
+
+    static KeyTypePointer KeyToPointer(KeyType aKey)
+    {
+      return &aKey;
+    }
+    static PLDHashNumber HashKey(const KeyTypePointer aKey)
+    {
+      // Just use the 32-bit m0 field.
+      return aKey->m0;
+    }
+
+    enum { ALLOW_MEMMOVE = true };
+
+  private:
+    nsIID mKey;
+  };
+  nsInterfaceHashtable<IIDHashKey, nsIContent> mInterfaceTable; // A table of cached interfaces that we support.
 
   int32_t mBaseNameSpaceID;    // If we extend a tagname/namespace, then that information will
   nsCOMPtr<nsIAtom> mBaseTag;  // be stored in here.
 
   nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
 };
 
 #endif
--- a/xpcom/glue/nsInterfaceHashtable.h
+++ b/xpcom/glue/nsInterfaceHashtable.h
@@ -54,17 +54,17 @@ inline void
 ImplCycleCollectionUnlink(nsInterfaceHashtable<K, T>& aField)
 {
   aField.Clear();
 }
 
 template <typename K, typename T>
 inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            nsInterfaceHashtable<K, T>& aField,
+                            const nsInterfaceHashtable<K, T>& aField,
                             const char* aName,
                             uint32_t aFlags = 0)
 {
   nsBaseHashtableCCTraversalData userData(aCallback, aName, aFlags);
 
   aField.EnumerateRead(ImplCycleCollectionTraverse_EnumFunc<typename K::KeyType,T*>,
                        &userData);
 }