Backout bug 972591, part 3, for a top crash.
authorAndrew McCreight <amccreight@mozilla.com>
Mon, 24 Feb 2014 11:12:54 -0800
changeset 170571 b437275a4a8a35c1874f25c2556582c0ee093fdb
parent 170570 69602085b4f07f234fbb79a0e589ba3f9f460d12
child 170572 afbf1c788adad3bab396fc6e6ac92f0cff101747
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
bugs972591
milestone30.0a1
Backout bug 972591, part 3, for a top crash.
dom/xbl/nsXBLDocumentInfo.cpp
dom/xbl/nsXBLDocumentInfo.h
--- a/dom/xbl/nsXBLDocumentInfo.cpp
+++ b/dom/xbl/nsXBLDocumentInfo.cpp
@@ -218,97 +218,101 @@ nsXBLDocGlobalObject::GetPrincipal()
   if (!document)
     return nullptr;
 
   return document->NodePrincipal();
 }
 
 /* Implementation file */
 
-static PLDHashOperator
-TraverseProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
+static bool
+TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
 {
-  nsCycleCollectionTraversalCallback *cb =
+  nsCycleCollectionTraversalCallback *cb = 
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
-  aProto->Traverse(*cb);
-  return PL_DHASH_NEXT;
+  nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
+  proto->Traverse(*cb);
+  return kHashEnumerateNext;
 }
 
-static PLDHashOperator
-UnlinkProtoJSObjects(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
+static bool
+UnlinkProtoJSObjects(nsHashKey *aKey, void *aData, void* aClosure)
 {
-  aProto->UnlinkJSObjects();
-  return PL_DHASH_NEXT;
+  nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
+  proto->UnlinkJSObjects();
+  return kHashEnumerateNext;
 }
 
 struct ProtoTracer
 {
   const TraceCallbacks &mCallbacks;
   void *mClosure;
 };
 
-static PLDHashOperator
-TraceProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
+static bool
+TraceProtos(nsHashKey *aKey, void *aData, void* aClosure)
 {
   ProtoTracer* closure = static_cast<ProtoTracer*>(aClosure);
-  aProto->Trace(closure->mCallbacks, closure->mClosure);
-  return PL_DHASH_NEXT;
+  nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
+  proto->Trace(closure->mCallbacks, closure->mClosure);
+  return kHashEnumerateNext;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
   if (tmp->mBindingTable) {
-    tmp->mBindingTable->EnumerateRead(UnlinkProtoJSObjects, nullptr);
+    tmp->mBindingTable->Enumerate(UnlinkProtoJSObjects, nullptr);
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObject)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo)
   if (tmp->mDocument &&
       nsCCUncollectableMarker::InGeneration(cb, tmp->mDocument->GetMarkedCCGeneration())) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
   if (tmp->mBindingTable) {
-    tmp->mBindingTable->EnumerateRead(TraverseProtos, &cb);
+    tmp->mBindingTable->Enumerate(TraverseProtos, &cb);
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo)
   if (tmp->mBindingTable) {
     ProtoTracer closure = { aCallbacks, aClosure };
-    tmp->mBindingTable->EnumerateRead(TraceProtos, &closure);
+    tmp->mBindingTable->Enumerate(TraceProtos, &closure);
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 static void
 UnmarkXBLJSObject(void* aP, const char* aName, void* aClosure)
 {
   JS::ExposeObjectToActiveJS(static_cast<JSObject*>(aP));
 }
 
-static PLDHashOperator
-UnmarkProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
+static bool
+UnmarkProtos(nsHashKey* aKey, void* aData, void* aClosure)
 {
-  aProto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
-  return PL_DHASH_NEXT;
+  nsXBLPrototypeBinding* proto = static_cast<nsXBLPrototypeBinding*>(aData);
+  proto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
+  return kHashEnumerateNext;
 }
 
 void
 nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration)
 {
   if (mDocument) {
     mDocument->MarkUncollectableForCCGeneration(aGeneration);
   }
   // Unmark any JS we hold
   if (mBindingTable) {
-    mBindingTable->EnumerateRead(UnmarkProtos, nullptr);
+    mBindingTable->Enumerate(UnmarkProtos, nullptr);
   }
   if (mGlobalObject) {
     mGlobalObject->UnmarkCompilationGlobal();
   }
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLDocumentInfo)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
@@ -317,16 +321,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLDocumentInfo)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLDocumentInfo)
 
 nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
   : mDocument(aDocument),
     mScriptAccess(true),
     mIsChrome(false),
+    mBindingTable(nullptr),
     mFirstBinding(nullptr)
 {
   nsIURI* uri = aDocument->GetDocumentURI();
   if (IsChromeURI(uri)) {
     // Cache whether or not this chrome XBL can execute scripts.
     nsCOMPtr<nsIXULChromeRegistry> reg =
       mozilla::services::GetXULChromeRegistryService();
     if (reg) {
@@ -357,63 +362,84 @@ nsXBLDocumentInfo::nsXBLDocumentInfo(nsI
 }
 
 nsXBLDocumentInfo::~nsXBLDocumentInfo()
 {
   /* destructor code */
   if (mGlobalObject) {
     mGlobalObject->ClearGlobalObjectOwner(); // just in case
   }
-  mozilla::DropJSObjects(this);
+  if (mBindingTable) {
+    delete mBindingTable;
+    mBindingTable = nullptr;
+    mozilla::DropJSObjects(this);
+  }
 }
 
 nsXBLPrototypeBinding*
 nsXBLDocumentInfo::GetPrototypeBinding(const nsACString& aRef)
 {
   if (!mBindingTable)
     return nullptr;
 
   if (aRef.IsEmpty()) {
     // Return our first binding
     return mFirstBinding;
   }
 
-  return mBindingTable->Get(aRef);
+  const nsPromiseFlatCString& flat = PromiseFlatCString(aRef);
+  nsCStringKey key(flat.get());
+  return static_cast<nsXBLPrototypeBinding*>(mBindingTable->Get(&key));
+}
+
+static bool
+DeletePrototypeBinding(nsHashKey* aKey, void* aData, void* aClosure)
+{
+  nsXBLPrototypeBinding* binding = static_cast<nsXBLPrototypeBinding*>(aData);
+  delete binding;
+  return true;
 }
 
 nsresult
 nsXBLDocumentInfo::SetPrototypeBinding(const nsACString& aRef, nsXBLPrototypeBinding* aBinding)
 {
   if (!mBindingTable) {
-    mBindingTable = new nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>();
+    mBindingTable = new nsObjectHashtable(nullptr, nullptr, DeletePrototypeBinding, nullptr);
+
     mozilla::HoldJSObjects(this);
   }
 
-  NS_ENSURE_STATE(!mBindingTable->Get(aRef));
-  mBindingTable->Put(aRef, aBinding);
+  const nsPromiseFlatCString& flat = PromiseFlatCString(aRef);
+  nsCStringKey key(flat.get());
+  NS_ENSURE_STATE(!mBindingTable->Get(&key));
+  mBindingTable->Put(&key, aBinding);
 
   return NS_OK;
 }
 
 void
 nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef)
 {
   if (mBindingTable) {
-    mBindingTable->Remove(aRef);
+    // Use a flat string to avoid making a copy.
+    const nsPromiseFlatCString& flat = PromiseFlatCString(aRef);
+    nsCStringKey key(flat);
+    mBindingTable->Remove(&key);
   }
 }
 
 // Callback to enumerate over the bindings from this document and write them
 // out to the cache.
-static PLDHashOperator
-WriteBinding(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
+bool
+WriteBinding(nsHashKey *aKey, void *aData, void* aClosure)
 {
-  aProto->Write((nsIObjectOutputStream*)aClosure);
+  nsXBLPrototypeBinding* binding = static_cast<nsXBLPrototypeBinding *>(aData);
+  binding->Write((nsIObjectOutputStream*)aClosure);
 
-  return PL_DHASH_NEXT;
+  return kHashEnumerateNext;
 }
 
 // static
 nsresult
 nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocInfo)
 {
   *aDocInfo = nullptr;
 
@@ -499,19 +525,18 @@ nsXBLDocumentInfo::WritePrototypeBinding
   rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(stream),
                                            getter_AddRefs(storageStream),
                                            true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stream->Write32(XBLBinding_Serialize_Version);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (mBindingTable) {
-    mBindingTable->EnumerateRead(WriteBinding, stream);
-  }
+  if (mBindingTable)
+    mBindingTable->Enumerate(WriteBinding, stream);
 
   // write a end marker at the end
   rv = stream->Write8(XBLBinding_Serialize_NoMoreBindings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   stream->Close();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -524,29 +549,28 @@ nsXBLDocumentInfo::WritePrototypeBinding
 }
 
 void
 nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
 {
   mFirstBinding = aBinding;
 }
 
-static PLDHashOperator
-FlushScopedSkinSheets(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
+bool FlushScopedSkinSheets(nsHashKey* aKey, void* aData, void* aClosure)
 {
-  aProto->FlushSkinSheets();
-  return PL_DHASH_NEXT;
+  nsXBLPrototypeBinding* proto = (nsXBLPrototypeBinding*)aData;
+  proto->FlushSkinSheets();
+  return true;
 }
 
 void
 nsXBLDocumentInfo::FlushSkinStylesheets()
 {
-  if (mBindingTable) {
-    mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
-  }
+  if (mBindingTable)
+    mBindingTable->Enumerate(FlushScopedSkinSheets);
 }
 
 JSObject*
 nsXBLDocumentInfo::GetCompilationGlobal()
 {
   EnsureGlobalObject();
   return mGlobalObject->GetCompilationGlobal();
 }
--- a/dom/xbl/nsXBLDocumentInfo.h
+++ b/dom/xbl/nsXBLDocumentInfo.h
@@ -8,16 +8,17 @@
 #include "mozilla/Attributes.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
 #include "nsIDocument.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsXBLPrototypeBinding;
+class nsObjectHashtable;
 class nsXBLDocGlobalObject;
 
 class nsXBLDocumentInfo : public nsSupportsWeakReference
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   nsXBLDocumentInfo(nsIDocument* aDocument);
@@ -35,17 +36,17 @@ public:
                                nsXBLPrototypeBinding* aBinding);
 
   // This removes the binding without deleting it
   void RemovePrototypeBinding(const nsACString& aRef);
 
   nsresult WritePrototypeBindings();
 
   void SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding);
-
+  
   void FlushSkinStylesheets();
 
   bool IsChrome() { return mIsChrome; }
 
   JSObject* GetCompilationGlobal();
 
   void MarkInCCGeneration(uint32_t aGeneration);
 
@@ -54,18 +55,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXBLDocumentInfo)
 
 private:
   void EnsureGlobalObject();
   nsCOMPtr<nsIDocument> mDocument;
   bool mScriptAccess;
   bool mIsChrome;
   // the binding table owns each nsXBLPrototypeBinding
-  nsAutoPtr<nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>> mBindingTable;
-
+  nsObjectHashtable* mBindingTable;
   // non-owning pointer to the first binding in the table
   nsXBLPrototypeBinding* mFirstBinding;
 
   nsRefPtr<nsXBLDocGlobalObject> mGlobalObject;
 };
 
 #ifdef DEBUG
 void AssertInCompilationScope();