Backing out to fix orange.
authorpeterv@propagandism.org
Fri, 26 Oct 2007 07:15:28 -0700
changeset 7203 27bc05bc1e4371370cb89eb24d01ddac31867cd7
parent 7202 3a36b4660a8f348b0284d9ea0fd86af14cf7d73e
child 7204 c8a35d8d7e5f6101b9956acf9678fda75e1ed67e
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9a9pre
Backing out to fix orange.
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLDocumentInfo.cpp
content/xbl/src/nsXBLDocumentInfo.h
content/xbl/src/nsXBLInsertionPoint.cpp
content/xbl/src/nsXBLProtoImpl.cpp
content/xbl/src/nsXBLProtoImpl.h
content/xbl/src/nsXBLProtoImplMember.h
content/xbl/src/nsXBLProtoImplMethod.cpp
content/xbl/src/nsXBLProtoImplMethod.h
content/xbl/src/nsXBLProtoImplProperty.cpp
content/xbl/src/nsXBLProtoImplProperty.h
content/xbl/src/nsXBLPrototypeBinding.cpp
content/xbl/src/nsXBLPrototypeBinding.h
content/xul/content/src/nsXULElement.cpp
dom/src/base/nsJSEnvironment.cpp
dom/src/base/nsJSTimeoutHandler.cpp
dom/src/events/nsJSEventListener.cpp
dom/src/events/nsJSEventListener.h
js/src/xpconnect/idl/nsIXPCScriptable.idl
js/src/xpconnect/idl/nsIXPConnect.idl
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcwrappedjs.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativejsops.cpp
js/src/xpconnect/src/xpcwrappednativescope.cpp
xpcom/base/nsAgg.h
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -746,16 +746,52 @@ public:
   }
 
   /**
    * Return the content policy service
    */
   static nsIContentPolicy *GetContentPolicy();
 
   /**
+   * Make sure that whatever value *aPtr contains at any given moment is
+   * protected from JS GC until we remove the GC root.  A call to this that
+   * succeeds MUST be matched by a call to RemoveJSGCRoot to avoid leaking.
+   */
+  static nsresult AddJSGCRoot(jsval* aPtr, const char* aName) {
+    return AddJSGCRoot((void*)aPtr, aName);
+  }
+
+  /**
+   * Make sure that whatever object *aPtr is pointing to at any given moment is
+   * protected from JS GC until we remove the GC root.  A call to this that
+   * succeeds MUST be matched by a call to RemoveJSGCRoot to avoid leaking.
+   */
+  static nsresult AddJSGCRoot(JSObject** aPtr, const char* aName) {
+    return AddJSGCRoot((void*)aPtr, aName);
+  }
+
+  /**
+   * Make sure that whatever object *aPtr is pointing to at any given moment is
+   * protected from JS GC until we remove the GC root.  A call to this that
+   * succeeds MUST be matched by a call to RemoveJSGCRoot to avoid leaking.
+   */
+  static nsresult AddJSGCRoot(void* aPtr, const char* aName);  
+
+  /**
+   * Remove aPtr as a JS GC root
+   */
+  static nsresult RemoveJSGCRoot(jsval* aPtr) {
+    return RemoveJSGCRoot((void*)aPtr);
+  }
+  static nsresult RemoveJSGCRoot(JSObject** aPtr) {
+    return RemoveJSGCRoot((void*)aPtr);
+  }
+  static nsresult RemoveJSGCRoot(void* aPtr);
+
+  /**
    * Quick helper to determine whether there are any mutation listeners
    * of a given type that apply to this content or any of its ancestors.
    * The method has the side effect to call document's MayDispatchMutationEvent
    * using aTargetForSubtreeModified as the parameter.
    *
    * @param aNode  The node to search for listeners
    * @param aType  The type of listener (NS_EVENT_BITS_MUTATION_*)
    * @param aTargetForSubtreeModified The node which is the target of the
@@ -959,83 +995,50 @@ public:
     }
   }
 
   /**
    * Unbinds the content from the tree and nulls it out if it's not null.
    */
   static void DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent);
 
-  /**
-   * Keep script object aNewObject, held by aScriptObjectHolder, alive.
-   *
-   * NOTE: This currently only supports objects that hold script objects of one
-   *       scripting language.
-   *
-   * @param aLangID script language ID of aNewObject
-   * @param aScriptObjectHolder the object that holds aNewObject
-   * @param aTracer the tracer for aScriptObject
-   * @param aNewObject the script object to hold
-   * @param aWasHoldingObjects whether aScriptObjectHolder was already holding
-   *                           script objects (ie. HoldScriptObject was called
-   *                           on it before, without a corresponding call to
-   *                           DropScriptObjects)
-   */
-  static nsresult HoldScriptObject(PRUint32 aLangID, void* aScriptObjectHolder,
-                                   nsScriptObjectTracer* aTracer,
-                                   void* aNewObject, PRBool aWasHoldingObjects)
-  {
-    if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
-      return aWasHoldingObjects ? NS_OK :
-                                  HoldJSObjects(aScriptObjectHolder, aTracer);
-    }
-
-    return HoldScriptObject(aLangID, aNewObject);
-  }
+  static nsresult HoldScriptObject(PRUint32 aLangID, void *aObject);
+  static nsresult DropScriptObject(PRUint32 aLangID, void *aObject);
 
-  /**
-   * Drop any script objects that aScriptObjectHolder is holding.
-   *
-   * NOTE: This currently only supports objects that hold script objects of one
-   *       scripting language.
-   *
-   * @param aLangID script language ID of the objects that 
-   * @param aScriptObjectHolder the object that holds script object that we want
-   *                            to drop
-   * @param aTracer the tracer for aScriptObject
-   */
-  static nsresult DropScriptObjects(PRUint32 aLangID, void* aScriptObjectHolder,
-                                    nsScriptObjectTracer* aTracer)
+  class ScriptObjectHolder
   {
-    if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
-      return DropJSObjects(aScriptObjectHolder);
+  public:
+    ScriptObjectHolder(PRUint32 aLangID) : mLangID(aLangID),
+                                           mObject(nsnull)
+    {
+      MOZ_COUNT_CTOR(ScriptObjectHolder);
+    }
+    ~ScriptObjectHolder()
+    {
+      MOZ_COUNT_DTOR(ScriptObjectHolder);
+      if (mObject)
+        DropScriptObject(mLangID, mObject);
     }
-
-    aTracer->Trace(aScriptObjectHolder, DropScriptObject, nsnull);
-
-    return NS_OK;
-  }
-
-  /**
-   * Keep the JS objects held by aScriptObjectHolder alive.
-   *
-   * @param aScriptObjectHolder the object that holds JS objects that we want to
-   *                            keep alive
-   * @param aTracer the tracer for aScriptObject
-   */
-  static nsresult HoldJSObjects(void* aScriptObjectHolder,
-                                nsScriptObjectTracer* aTracer);
-
-  /**
-   * Drop the JS objects held by aScriptObjectHolder.
-   *
-   * @param aScriptObjectHolder the object that holds JS objects that we want to
-   *                            drop
-   */
-  static nsresult DropJSObjects(void* aScriptObjectHolder);
+    nsresult set(void *aObject)
+    {
+      NS_ASSERTION(aObject, "unexpected null object");
+      NS_ASSERTION(!mObject, "already have an object");
+      nsresult rv = HoldScriptObject(mLangID, aObject);
+      if (NS_SUCCEEDED(rv)) {
+        mObject = aObject;
+      }
+      return rv;
+    }
+    void traverse(nsCycleCollectionTraversalCallback &cb)
+    {
+      cb.NoteScriptChild(mLangID, mObject);
+    }
+    PRUint32 mLangID;
+    void *mObject;
+  };
 
   /**
    * Convert nsIContent::IME_STATUS_* to nsIKBStateControll::IME_STATUS_*
    */
   static PRUint32 GetKBStateControlStatusFromIMEStatus(PRUint32 aState);
 
   /*
    * Notify when the first XUL menu is opened and when the all XUL menus are
@@ -1112,20 +1115,16 @@ private:
                                            JSObject *aNewGlobal,
                                            nsIDocument *aOldDocument,
                                            nsIDocument *aNewDocument);
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
 
-  static nsresult HoldScriptObject(PRUint32 aLangID, void* aObject);
-  PR_STATIC_CALLBACK(void) DropScriptObject(PRUint32 aLangID, void *aObject,
-                                            void *aClosure);
-
   static nsIDOMScriptObjectFactory *sDOMScriptObjectFactory;
 
   static nsIXPConnect *sXPConnect;
 
   static nsIScriptSecurityManager *sSecurityManager;
 
   static nsIThreadJSContextStack *sThreadJSContextStack;
 
@@ -1157,36 +1156,33 @@ private:
 
   static nsILineBreaker* sLineBreaker;
   static nsIWordBreaker* sWordBreaker;
   static nsICaseConversion* sCaseConv;
 
   // Holds pointers to nsISupports* that should be released at shutdown
   static nsVoidArray* sPtrsToPtrsToRelease;
 
+  // For now, we don't want to automatically clean this up in Shutdown(), since
+  // consumers might unfortunately end up wanting to use it after that
+  static nsIJSRuntimeService* sJSRuntimeService;
+  static JSRuntime* sJSScriptRuntime;
+  static PRInt32 sJSScriptRootCount;
+
   static nsIScriptRuntime* sScriptRuntimes[NS_STID_ARRAY_UBOUND];
   static PRInt32 sScriptRootCount[NS_STID_ARRAY_UBOUND];
-  static PRUint32 sJSGCThingRootCount;
 
 #ifdef IBMBIDI
   static nsIBidiKeyboard* sBidiKeyboard;
 #endif
 
   static PRBool sInitialized;
 };
 
 
-#define NS_HOLD_JS_OBJECTS(obj, clazz)                                         \
-  nsContentUtils::HoldJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz),        \
-                                &NS_CYCLE_COLLECTION_NAME(clazz))
-
-#define NS_DROP_JS_OBJECTS(obj, clazz)                                         \
-  nsContentUtils::DropJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz))
-
-
 class nsCxPusher
 {
 public:
   nsCxPusher();
   ~nsCxPusher(); // Calls Pop();
 
   // Returns PR_FALSE if something erroneous happened.
   PRBool Push(nsISupports *aCurrentTarget);
@@ -1199,48 +1195,43 @@ private:
 };
 
 class nsAutoGCRoot {
 public:
   // aPtr should be the pointer to the jsval we want to protect
   nsAutoGCRoot(jsval* aPtr, nsresult* aResult) :
     mPtr(aPtr)
   {
-    mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot");
+    mResult = *aResult =
+      nsContentUtils::AddJSGCRoot(aPtr, "nsAutoGCRoot");
   }
 
   // aPtr should be the pointer to the JSObject* we want to protect
   nsAutoGCRoot(JSObject** aPtr, nsresult* aResult) :
     mPtr(aPtr)
   {
-    mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot");
+    mResult = *aResult =
+      nsContentUtils::AddJSGCRoot(aPtr, "nsAutoGCRoot");
   }
 
   // aPtr should be the pointer to the thing we want to protect
   nsAutoGCRoot(void* aPtr, nsresult* aResult) :
     mPtr(aPtr)
   {
-    mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot");
+    mResult = *aResult =
+      nsContentUtils::AddJSGCRoot(aPtr, "nsAutoGCRoot");
   }
 
   ~nsAutoGCRoot() {
     if (NS_SUCCEEDED(mResult)) {
-      RemoveJSGCRoot(mPtr);
+      nsContentUtils::RemoveJSGCRoot(mPtr);
     }
   }
 
-  static void Shutdown();
-
 private:
-  static nsresult AddJSGCRoot(void *aPtr, const char* aName);
-  static nsresult RemoveJSGCRoot(void *aPtr);
-
-  static nsIJSRuntimeService* sJSRuntimeService;
-  static JSRuntime* sJSScriptRuntime;
-
   void* mPtr;
   nsresult mResult;
 };
 
 #define NS_AUTO_GCROOT_PASTE2(tok,line) tok##line
 #define NS_AUTO_GCROOT_PASTE(tok,line) \
   NS_AUTO_GCROOT_PASTE2(tok,line)
 #define NS_AUTO_GCROOT(ptr, result) \ \
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -175,25 +175,25 @@ nsDataHashtable<nsISupportsHashKey, Even
 nsIStringBundleService *nsContentUtils::sStringBundleService;
 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
 nsIContentPolicy *nsContentUtils::sContentPolicyService;
 PRBool nsContentUtils::sTriedToGetContentPolicy = PR_FALSE;
 nsILineBreaker *nsContentUtils::sLineBreaker;
 nsIWordBreaker *nsContentUtils::sWordBreaker;
 nsICaseConversion *nsContentUtils::sCaseConv;
 nsVoidArray *nsContentUtils::sPtrsToPtrsToRelease;
+nsIJSRuntimeService *nsContentUtils::sJSRuntimeService;
+JSRuntime *nsContentUtils::sJSScriptRuntime;
+PRInt32 nsContentUtils::sJSScriptRootCount = 0;
 nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
 PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
-PRUint32 nsContentUtils::sJSGCThingRootCount;
 #ifdef IBMBIDI
 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
 #endif
 
-nsIJSRuntimeService *nsAutoGCRoot::sJSRuntimeService;
-JSRuntime *nsAutoGCRoot::sJSScriptRuntime;
 
 PRBool nsContentUtils::sInitialized = PR_FALSE;
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
 public:
@@ -666,18 +666,17 @@ nsContentUtils::Shutdown()
   NS_IF_RELEASE(sContentPolicyService);
   sTriedToGetContentPolicy = PR_FALSE;
   PRInt32 i;
   for (i = 0; i < PRInt32(PropertiesFile_COUNT); ++i)
     NS_IF_RELEASE(sStringBundles[i]);
   NS_IF_RELEASE(sStringBundleService);
   NS_IF_RELEASE(sConsoleService);
   NS_IF_RELEASE(sDOMScriptObjectFactory);
-  if (sJSGCThingRootCount == 0 && sXPConnect)
-    NS_RELEASE(sXPConnect);
+  NS_IF_RELEASE(sXPConnect);
   NS_IF_RELEASE(sSecurityManager);
   NS_IF_RELEASE(sThreadJSContextStack);
   NS_IF_RELEASE(sNameSpaceManager);
   NS_IF_RELEASE(sParserService);
   NS_IF_RELEASE(sIOService);
   NS_IF_RELEASE(sLineBreaker);
   NS_IF_RELEASE(sWordBreaker);
   NS_IF_RELEASE(sCaseConv);
@@ -717,18 +716,16 @@ nsContentUtils::Shutdown()
     // it could leave dangling references in DOMClassInfo's preserved
     // wrapper table.
 
     if (sEventListenerManagersHash.entryCount == 0) {
       PL_DHashTableFinish(&sEventListenerManagersHash);
       sEventListenerManagersHash.ops = nsnull;
     }
   }
-
-  nsAutoGCRoot::Shutdown();
 }
 
 static PRBool IsCallerTrustedForCapability(const char* aCapability)
 {
   // The secman really should handle UniversalXPConnect case, since that
   // should include UniversalBrowserRead... doesn't right now, though.
   PRBool hasCap;
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
@@ -2667,17 +2664,17 @@ nsContentUtils::GetContentPolicy()
     sTriedToGetContentPolicy = PR_TRUE;
   }
 
   return sContentPolicyService;
 }
 
 // static
 nsresult
-nsAutoGCRoot::AddJSGCRoot(void* aPtr, const char* aName)
+nsContentUtils::AddJSGCRoot(void* aPtr, const char* aName)
 {
   if (!sJSScriptRuntime) {
     nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
                                  &sJSRuntimeService);
     NS_ENSURE_TRUE(sJSRuntimeService, rv);
 
     sJSRuntimeService->GetRuntime(&sJSScriptRuntime);
     if (!sJSScriptRuntime) {
@@ -2685,34 +2682,48 @@ nsAutoGCRoot::AddJSGCRoot(void* aPtr, co
       NS_WARNING("Unable to get JS runtime from JS runtime service");
       return NS_ERROR_FAILURE;
     }
   }
 
   PRBool ok;
   ok = ::JS_AddNamedRootRT(sJSScriptRuntime, aPtr, aName);
   if (!ok) {
+    if (sJSScriptRootCount == 0) {
+      // We just got the runtime... Just null things out, since no
+      // one's expecting us to have a runtime yet
+      NS_RELEASE(sJSRuntimeService);
+      sJSScriptRuntime = nsnull;
+    }
     NS_WARNING("JS_AddNamedRootRT failed");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
+  // We now have one more root we added to the runtime
+  ++sJSScriptRootCount;
+
   return NS_OK;
 }
 
 /* static */
 nsresult
-nsAutoGCRoot::RemoveJSGCRoot(void* aPtr)
+nsContentUtils::RemoveJSGCRoot(void* aPtr)
 {
   if (!sJSScriptRuntime) {
     NS_NOTREACHED("Trying to remove a JS GC root when none were added");
     return NS_ERROR_UNEXPECTED;
   }
 
   ::JS_RemoveRootRT(sJSScriptRuntime, aPtr);
 
+  if (--sJSScriptRootCount == 0) {
+    NS_RELEASE(sJSRuntimeService);
+    sJSScriptRuntime = nsnull;
+  }
+
   return NS_OK;
 }
 
 // static
 PRBool
 nsContentUtils::IsEventAttributeName(nsIAtom* aName, PRInt32 aType)
 {
   const char* name;
@@ -3506,18 +3517,16 @@ nsContentUtils::GetDOMScriptObjectFactor
   return sDOMScriptObjectFactory;
 }
 
 /* static */
 nsresult
 nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject)
 {
   NS_ASSERTION(aObject, "unexpected null object");
-  NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
-               "Should use HoldJSObjects.");
   nsresult rv;
 
   PRUint32 langIndex = NS_STID_INDEX(aLangID);
   nsIScriptRuntime *runtime = sScriptRuntimes[langIndex];
   if (!runtime) {
     nsIDOMScriptObjectFactory *factory = GetDOMScriptObjectFactory();
     NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
 
@@ -3534,57 +3543,27 @@ nsContentUtils::HoldScriptObject(PRUint3
   ++sScriptRootCount[langIndex];
   NS_LOG_ADDREF(sScriptRuntimes[langIndex], sScriptRootCount[langIndex],
                 "HoldScriptObject", sizeof(void*));
 
   return NS_OK;
 }
 
 /* static */
-void
-nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject,
-                                 void *aClosure)
+nsresult
+nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject)
 {
   NS_ASSERTION(aObject, "unexpected null object");
-  NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
-               "Should use DropJSObjects.");
   PRUint32 langIndex = NS_STID_INDEX(aLangID);
   NS_LOG_RELEASE(sScriptRuntimes[langIndex], sScriptRootCount[langIndex] - 1,
                  "HoldScriptObject");
-  sScriptRuntimes[langIndex]->DropScriptObject(aObject);
+  nsresult rv = sScriptRuntimes[langIndex]->DropScriptObject(aObject);
   if (--sScriptRootCount[langIndex] == 0) {
     NS_RELEASE(sScriptRuntimes[langIndex]);
   }
-}
-
-/* static */
-nsresult
-nsContentUtils::HoldJSObjects(void* aScriptObjectHolder,
-                              nsScriptObjectTracer* aTracer)
-{
-  PRBool newHolder;
-  nsresult rv = sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  ++sJSGCThingRootCount;
-  NS_LOG_ADDREF(sXPConnect, sJSGCThingRootCount, "HoldJSObjects",
-                sizeof(void*));
-
-  return NS_OK;
-}
-
-/* static */
-nsresult
-nsContentUtils::DropJSObjects(void* aScriptObjectHolder)
-{
-  NS_LOG_RELEASE(sXPConnect, sJSGCThingRootCount - 1, "HoldJSObjects");
-  nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder);
-  if (--sJSGCThingRootCount == 0 && !sInitialized) {
-    NS_RELEASE(sXPConnect);
-  }
   return rv;
 }
 
 /* static */
 PRUint32
 nsContentUtils::GetKBStateControlStatusFromIMEStatus(PRUint32 aState)
 {
   switch (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
@@ -3730,16 +3709,8 @@ nsContentUtils::IsNativeAnonymous(nsICon
                   aContent->GetParent()->NodeInfo()->
                     Equals(nsGkAtoms::use, kNameSpaceID_SVG)),
                  "Native anonymous node with wrong binding parent");
     aContent = bindingParent;
   }
 
   return PR_FALSE;
 }
-
-/* static */
-void
-nsAutoGCRoot::Shutdown()
-{
-  NS_RELEASE(sJSRuntimeService);
-  sJSScriptRuntime = nsnull;
-}
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -300,17 +300,17 @@ TraverseKey(nsISupports* aKey, nsInserti
 
   cb.NoteXPCOMChild(aKey);
   if (aData) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(*aData, nsXBLInsertionPoint)
   }
   return PL_DHASH_NEXT;
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding)
+NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLBinding)
   // XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because
   //     mPrototypeBinding is weak.
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContent)
   // XXX What about mNextBinding and mInsertionPointTable?
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLBinding)
   cb.NoteXPCOMChild(tmp->mPrototypeBinding->XBLDocumentInfo());
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -447,53 +447,31 @@ TraverseProtos(nsHashKey *aKey, void *aD
 static PRIntn PR_CALLBACK
 UnlinkProtos(nsHashKey *aKey, void *aData, void* aClosure)
 {
   nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
   proto->Unlink();
   return kHashEnumerateNext;
 }
 
-struct ProtoTracer
-{
-  TraceCallback mCallback;
-  void *mClosure;
-};
-
-static PRIntn PR_CALLBACK
-TraceProtos(nsHashKey *aKey, void *aData, void* aClosure)
-{
-  ProtoTracer* closure = static_cast<ProtoTracer*>(aClosure);
-  nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
-  proto->Trace(closure->mCallback, closure->mClosure);
-  return kHashEnumerateNext;
-}
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
   if (tmp->mBindingTable) {
     tmp->mBindingTable->Enumerate(UnlinkProtos, nsnull);
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObject)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
   if (tmp->mBindingTable) {
     tmp->mBindingTable->Enumerate(TraverseProtos, &cb);
   }
   cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObject*>(tmp->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 = { aCallback, aClosure };
-    tmp->mBindingTable->Enumerate(TraceProtos, &closure);
-  }
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLDocumentInfo)
   NS_INTERFACE_MAP_ENTRY(nsIXBLDocumentInfo)
   NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXBLDocumentInfo)
 NS_INTERFACE_MAP_END
 
@@ -524,20 +502,17 @@ nsXBLDocumentInfo::nsXBLDocumentInfo(nsI
 nsXBLDocumentInfo::~nsXBLDocumentInfo()
 {
   /* destructor code */
   if (mGlobalObject) {
     // remove circular reference
     mGlobalObject->SetScriptContext(nsIProgrammingLanguage::JAVASCRIPT, nsnull);
     mGlobalObject->ClearGlobalObjectOwner(); // just in case
   }
-  if (mBindingTable) {
-    NS_DROP_JS_OBJECTS(this, nsXBLDocumentInfo);
-    delete mBindingTable;
-  }
+  delete mBindingTable;
 }
 
 NS_IMETHODIMP
 nsXBLDocumentInfo::GetPrototypeBinding(const nsACString& aRef, nsXBLPrototypeBinding** aResult)
 {
   *aResult = nsnull;
   if (!mBindingTable)
     return NS_OK;
@@ -561,23 +536,18 @@ DeletePrototypeBinding(nsHashKey* aKey, 
   nsXBLPrototypeBinding* binding = static_cast<nsXBLPrototypeBinding*>(aData);
   delete binding;
   return PR_TRUE;
 }
 
 NS_IMETHODIMP
 nsXBLDocumentInfo::SetPrototypeBinding(const nsACString& aRef, nsXBLPrototypeBinding* aBinding)
 {
-  if (!mBindingTable) {
+  if (!mBindingTable)
     mBindingTable = new nsObjectHashtable(nsnull, nsnull, DeletePrototypeBinding, nsnull);
-    if (!mBindingTable)
-      return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_HOLD_JS_OBJECTS(this, nsXBLDocumentInfo);
-  }
 
   const nsPromiseFlatCString& flat = PromiseFlatCString(aRef);
   nsCStringKey key(flat.get());
   mBindingTable->Put(&key, aBinding);
 
   return NS_OK;
 }
 
--- a/content/xbl/src/nsXBLDocumentInfo.h
+++ b/content/xbl/src/nsXBLDocumentInfo.h
@@ -67,18 +67,18 @@ public:
   
   NS_IMETHOD FlushSkinStylesheets();
 
   NS_IMETHOD_(PRBool) IsChrome() { return mIsChrome; }
 
   // nsIScriptGlobalObjectOwner methods
   virtual nsIScriptGlobalObject* GetScriptGlobalObject();
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsXBLDocumentInfo,
-                                                         nsIXBLDocumentInfo)
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXBLDocumentInfo,
+                                           nsIXBLDocumentInfo)
 
 private:
   nsCOMPtr<nsIDocument> mDocument;
   PRPackedBool mScriptAccess;
   PRPackedBool mIsChrome;
   // the binding table owns each nsXBLPrototypeBinding
   nsObjectHashtable* mBindingTable;
   // non-owning pointer to the first binding in the table
--- a/content/xbl/src/nsXBLInsertionPoint.cpp
+++ b/content/xbl/src/nsXBLInsertionPoint.cpp
@@ -59,17 +59,17 @@ nsXBLInsertionPoint::Release()
   if (mRefCnt == 0) {
     mRefCnt = 1;
     delete this;
     return 0;
   }
   return mRefCnt;
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLInsertionPoint)
+NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPoint)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLInsertionPoint)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDefaultContentTemplate)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDefaultContent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLInsertionPoint)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mElements)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDefaultContentTemplate)
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -195,28 +195,28 @@ nsXBLProtoImpl::CompilePrototypeMembers(
       DestroyMembers(curr);
       return rv;
     }
   }
   return NS_OK;
 }
 
 void
-nsXBLProtoImpl::Trace(TraceCallback aCallback, void *aClosure) const
+nsXBLProtoImpl::Traverse(nsCycleCollectionTraversalCallback &cb) const
 {
   // If we don't have a class object then we either didn't compile members
   // or we only have fields, in both cases there are no cycles through our
   // members.
   if (!mClassObject) {
     return;
   }
 
   nsXBLProtoImplMember *member;
   for (member = mMembers; member; member = member->GetNext()) {
-    member->Trace(aCallback, aClosure);
+    member->Traverse(cb);
   }
 }
 
 void
 nsXBLProtoImpl::Unlink()
 {
   if (mClassObject) {
     DestroyMembers(nsnull);
--- a/content/xbl/src/nsXBLProtoImpl.h
+++ b/content/xbl/src/nsXBLProtoImpl.h
@@ -85,17 +85,17 @@ public:
   }
 
   void SetFieldList(nsXBLProtoImplField* aFieldList)
   {
     delete mFields;
     mFields = aFieldList;
   }
 
-  void Trace(TraceCallback aCallback, void *aClosure) const;
+  void Traverse(nsCycleCollectionTraversalCallback &cb) const;
   void Unlink();
 
   nsXBLProtoImplField* FindField(const nsString& aFieldName) const;
 
   // Resolve all the fields for this implementation on the object |obj| False
   // return means a JS exception was set.
   PRBool ResolveAllFields(JSContext *cx, JSObject *obj) const;
 
--- a/content/xbl/src/nsXBLProtoImplMember.h
+++ b/content/xbl/src/nsXBLProtoImplMember.h
@@ -42,21 +42,21 @@
 #include "nsIAtom.h"
 #include "nsString.h"
 #include "jsapi.h"
 #include "nsIContent.h"
 #include "nsString.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIServiceManager.h"
 #include "nsReadableUtils.h"
-#include "nsCycleCollectionParticipant.h"
 
 class nsIScriptContext;
 struct JSRuntime;
 class nsIJSRuntimeService;
+class nsCycleCollectionTraversalCallback;
 
 struct nsXBLTextWithLineNumber
 {
   PRUnichar* mText;
   PRUint32 mLineNumber;
 
   nsXBLTextWithLineNumber() :
     mText(nsnull),
@@ -109,17 +109,17 @@ public:
                                  nsIContent* aBoundElement, 
                                  void* aScriptObject,
                                  void* aTargetClassObject,
                                  const nsCString& aClassStr) = 0;
   virtual nsresult CompileMember(nsIScriptContext* aContext,
                                  const nsCString& aClassStr,
                                  void* aClassObject)=0;
 
-  virtual void Trace(TraceCallback aCallback, void *aClosure) const = 0;
+  virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const = 0;
 
 protected:
   friend class nsAutoGCRoot;
   
   nsXBLProtoImplMember* mNext;  // The members of an implementation are chained.
   PRUnichar* mName;               // The name of the field, method, or property.
 };
 
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -67,16 +67,18 @@ nsXBLProtoImplMethod::~nsXBLProtoImplMet
 }
 
 void
 nsXBLProtoImplMethod::Destroy(PRBool aIsCompiled)
 {
   NS_PRECONDITION(aIsCompiled == mIsCompiled,
                   "Incorrect aIsCompiled in nsXBLProtoImplMethod::Destroy");
   if (aIsCompiled) {
+    if (mJSMethodObject)
+      nsContentUtils::RemoveJSGCRoot(&mJSMethodObject);
     mJSMethodObject = nsnull;
   }
   else {
     delete mUncompiledMethod;
     mUncompiledMethod = nsnull;
   }
 }
 
@@ -256,35 +258,35 @@ nsXBLProtoImplMethod::CompileMember(nsIS
     mUncompiledMethod = nsnull;
     return rv;
   }
 
   mJSMethodObject = methodObject;
 
   if (methodObject) {
     // Root the compiled prototype script object.
+    rv = nsContentUtils::AddJSGCRoot(&mJSMethodObject,
+                                     "nsXBLProtoImplMethod::mJSMethodObject");
     if (NS_FAILED(rv)) {
       mJSMethodObject = nsnull;
     }
   }
   
 #ifdef DEBUG
   mIsCompiled = NS_SUCCEEDED(rv);
 #endif
   return rv;
 }
 
 void
-nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const
+nsXBLProtoImplMethod::Traverse(nsCycleCollectionTraversalCallback &cb) const
 {
   NS_ASSERTION(mIsCompiled, "Shouldn't traverse uncompiled method");
 
-  if (mJSMethodObject) {
-    aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject, aClosure);
-  }
+  cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject);
 }
 
 nsresult
 nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
 {
   NS_PRECONDITION(mIsCompiled, "Can't execute uncompiled method");
   
   if (!mJSMethodObject) {
--- a/content/xbl/src/nsXBLProtoImplMethod.h
+++ b/content/xbl/src/nsXBLProtoImplMethod.h
@@ -124,17 +124,17 @@ public:
                                  nsIContent* aBoundElement, 
                                  void* aScriptObject,
                                  void* aTargetClassObject,
                                  const nsCString& aClassStr);
   virtual nsresult CompileMember(nsIScriptContext* aContext,
                                  const nsCString& aClassStr,
                                  void* aClassObject);
 
-  virtual void Trace(TraceCallback aCallback, void *aClosure) const;
+  virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const;
 
 protected:
   union {
     nsXBLUncompiledMethod* mUncompiledMethod; // An object that represents the method before being compiled.
     JSObject * mJSMethodObject;               // The JS object for the method (after compilation)
   };
 
 #ifdef DEBUG
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -82,24 +82,24 @@ nsXBLProtoImplProperty::~nsXBLProtoImplP
 
 void
 nsXBLProtoImplProperty::Destroy(PRBool aIsCompiled)
 {
   NS_PRECONDITION(aIsCompiled == mIsCompiled,
                   "Incorrect aIsCompiled in nsXBLProtoImplProperty::Destroy");
 
   if ((mJSAttributes & JSPROP_GETTER) && mJSGetterObject) {
-    mJSGetterObject = nsnull;
+    nsContentUtils::RemoveJSGCRoot(&mJSGetterObject);
   }
   else {
     delete mGetterText;
   }
 
   if ((mJSAttributes & JSPROP_SETTER) && mJSSetterObject) {
-    mJSSetterObject = nsnull;
+    nsContentUtils::RemoveJSGCRoot(&mJSSetterObject);
   }
   else {
     delete mSetterText;
   }
 
   mGetterText = mSetterText = nsnull;
 }
 
@@ -263,16 +263,19 @@ nsXBLProtoImplProperty::CompileMember(ns
       // Make sure we free mGetterText here before setting mJSGetterObject, since
       // that'll overwrite mGetterText
       delete mGetterText;
       deletedGetter = PR_TRUE;
       mJSGetterObject = getterObject;
     
       if (mJSGetterObject && NS_SUCCEEDED(rv)) {
         mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
+        // Root the compiled prototype script object.
+        rv = nsContentUtils::AddJSGCRoot(&mJSGetterObject,
+                                         "nsXBLProtoImplProperty::mJSGetterObject");
       }
       if (NS_FAILED(rv)) {
         mJSGetterObject = nsnull;
         mJSAttributes &= ~JSPROP_GETTER;
         /*chaining to return failure*/
       }
     }
   } // if getter is not empty
@@ -312,16 +315,19 @@ nsXBLProtoImplProperty::CompileMember(ns
       // Make sure we free mSetterText here before setting mJSGetterObject, since
       // that'll overwrite mSetterText
       delete mSetterText;
       deletedSetter = PR_TRUE;
       mJSSetterObject = setterObject;
 
       if (mJSSetterObject && NS_SUCCEEDED(rv)) {
         mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
+        // Root the compiled prototype script object.
+        rv = nsContentUtils::AddJSGCRoot(&mJSSetterObject,
+                                         "nsXBLProtoImplProperty::mJSSetterObject");
       }
       if (NS_FAILED(rv)) {
         mJSSetterObject = nsnull;
         mJSAttributes &= ~JSPROP_SETTER;
         /*chaining to return failure*/
       }
     }
   } // if setter wasn't empty....
@@ -334,20 +340,20 @@ nsXBLProtoImplProperty::CompileMember(ns
 #ifdef DEBUG
   mIsCompiled = NS_SUCCEEDED(rv);
 #endif
   
   return rv;
 }
 
 void
-nsXBLProtoImplProperty::Trace(TraceCallback aCallback, void *aClosure) const
+nsXBLProtoImplProperty::Traverse(nsCycleCollectionTraversalCallback &cb) const
 {
   NS_ASSERTION(mIsCompiled, "Shouldn't traverse uncompiled method");
 
-  if ((mJSAttributes & JSPROP_GETTER) && mJSGetterObject) {
-    aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject, aClosure);
+  if (mJSAttributes & JSPROP_GETTER) {
+    cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject);
   }
 
-  if ((mJSAttributes & JSPROP_SETTER) && mJSSetterObject) {
-    aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject, aClosure);
+  if (mJSAttributes & JSPROP_SETTER) {
+    cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject);
   }
 }
--- a/content/xbl/src/nsXBLProtoImplProperty.h
+++ b/content/xbl/src/nsXBLProtoImplProperty.h
@@ -67,17 +67,17 @@ public:
                                  nsIContent* aBoundElement, 
                                  void* aScriptObject,
                                  void* aTargetClassObject,
                                  const nsCString& aClassStr);
   virtual nsresult CompileMember(nsIScriptContext* aContext,
                                  const nsCString& aClassStr,
                                  void* aClassObject);
 
-  virtual void Trace(TraceCallback aCallback, void *aClosure) const;
+  virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const;
 
 protected:
   union {
     // The raw text for the getter (prior to compilation).
     nsXBLTextWithLineNumber* mGetterText;
     // The JS object for the getter (after compilation)
     JSObject *               mJSGetterObject;
   };
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -239,17 +239,17 @@ private:
 
   static nsFixedSizeAllocator* kPool;
   static PRUint32 gRefCnt;
 };
 
 PRUint32 nsXBLInsertionPointEntry::gRefCnt = 0;
 nsFixedSizeAllocator* nsXBLInsertionPointEntry::kPool;
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLInsertionPointEntry)
+NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPointEntry)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLInsertionPointEntry)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInsertionParent)
   if (tmp->mDefaultContent) {
     // mDefaultContent is a sort of anonymous content within the XBL
     // document, and we own and manage it.  Unhook it here, since we're going
     // away.
     tmp->mDefaultContent->UnbindFromTree();
     tmp->mDefaultContent = nsnull;
@@ -350,39 +350,34 @@ TraverseBinding(nsHashKey *aKey, void *a
   cb->NoteXPCOMChild(static_cast<nsISupports*>(aData));
   return kHashEnumerateNext;
 }
 
 void
 nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
 {
   cb.NoteXPCOMChild(mBinding);
+  if (mImplementation)
+    mImplementation->Traverse(cb);
   if (mResources)
     cb.NoteXPCOMChild(mResources->mLoader);
   if (mInsertionPointTable)
     mInsertionPointTable->Enumerate(TraverseInsertionPoint, &cb);
   if (mInterfaceTable)
     mInterfaceTable->Enumerate(TraverseBinding, &cb);
 }
 
 void
 nsXBLPrototypeBinding::Unlink()
 {
   if (mImplementation)
     mImplementation->Unlink();
 }
 
 void
-nsXBLPrototypeBinding::Trace(TraceCallback aCallback, void *aClosure) const
-{
-  if (mImplementation)
-    mImplementation->Trace(aCallback, aClosure);
-}
-
-void
 nsXBLPrototypeBinding::Initialize()
 {
   nsIContent* content = GetImmediateChild(nsGkAtoms::content);
   if (content) {
     // Make sure to construct the attribute table first, since constructing the
     // insertion point table removes some of the subtrees, which makes them
     // unreachable by walking our DOM.
     ConstructAttributeTable(content);
--- a/content/xbl/src/nsXBLPrototypeBinding.h
+++ b/content/xbl/src/nsXBLPrototypeBinding.h
@@ -193,17 +193,16 @@ public:
   // this with the Initialize() method, which must be called after the
   // binding's handlers, properties, etc are all set.
   nsresult Init(const nsACString& aRef,
                 nsIXBLDocumentInfo* aInfo,
                 nsIContent* aElement);
 
   void Traverse(nsCycleCollectionTraversalCallback &cb) const;
   void Unlink();
-  void Trace(TraceCallback aCallback, void *aClosure) const;
 
 // Static members
   static PRUint32 gRefCnt;
  
   static nsFixedSizeAllocator* kAttrPool;
 
 // Internal member functions.
 // XXXbz GetImmediateChild needs to be public to be called by SetAttrs,
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -50,16 +50,17 @@
  * Modifications to Mozilla code or documentation
  * identified per MPL Section 3.3
  *
  * Date         Modified by     Description of modification
  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
  *                               use in OS2
  */
 
+#include "jsapi.h"      // for JS_AddNamedRoot and JS_RemoveRootRT
 #include "nsCOMPtr.h"
 #include "nsDOMCID.h"
 #include "nsDOMError.h"
 #include "nsDOMString.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsHashtable.h"
 #include "nsIAtom.h"
@@ -696,18 +697,17 @@ nsScriptEventHandlerOwnerTearoff::Compil
     nsresult rv;
 
     XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
 
     // XXX sXBL/XBL2 issue! Owner or current document?
     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mElement->GetOwnerDoc());
 
     nsIScriptContext *context;
-    nsXULPrototypeElement *elem = mElement->mPrototype;
-    if (elem && xuldoc) {
+    if (mElement->mPrototype && xuldoc) {
         // It'll be shared among the instances of the prototype.
 
         // Use the prototype document's special context.  Because
         // scopeObject is null, the JS engine has no other source of
         // <the-new-shared-event-handler>.__proto__ than to look in
         // cx->globalObject for Function.prototype.  That prototype
         // keeps the global object alive, so if we use this document's
         // global object, we'll be putting something in the prototype
@@ -750,26 +750,19 @@ nsScriptEventHandlerOwnerTearoff::Compil
     if (NS_FAILED(rv)) return rv;
 
     nsXULPrototypeAttribute *attr =
         mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
     if (attr) {
         XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
         // take a copy of the event handler, and tell the language about it.
         if (aHandler) {
-            NS_ASSERTION(!attr->mEventHandler, "Leaking handler.");
-
             rv = nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(),
-                                                  elem,
-                                                  &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode),
-                                                  aHandler,
-                                                  elem->mHoldsScriptObject);
+                                                  aHandler);
             if (NS_FAILED(rv)) return rv;
-
-            elem->mHoldsScriptObject = PR_TRUE;
         }
         attr->mEventHandler = (void *)aHandler;
     }
 
     return NS_OK;
 }
 
 void
@@ -2353,61 +2346,58 @@ nsXULElement::RecompileScriptEventListen
 
             nsAutoString value;
             GetAttr(kNameSpaceID_None, attr, value);
             AddScriptEventListener(attr, value, PR_TRUE);
         }
     }
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode)
+NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXULPrototypeNode)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsXULPrototypeNode)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXULPrototypeNode)
     if (tmp->mType == nsXULPrototypeNode::eType_Element) {
         nsXULPrototypeElement *elem =
             static_cast<nsXULPrototypeElement*>(tmp);
         PRUint32 i;
+        for (i = 0; i < elem->mNumAttributes; ++i) {
+            cb.NoteScriptChild(elem->mScriptTypeID,
+                               elem->mAttributes[i].mEventHandler);
+        }
         for (i = 0; i < elem->mNumChildren; ++i) {
             NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(elem->mChildren[i],
                                                          nsXULPrototypeNode)
         }
     }
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+    else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
+        static_cast<nsXULPrototypeScript*>(tmp)->mScriptObject.traverse(cb);
+    }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(nsXULPrototypeNode)
-    if (tmp->mType == nsXULPrototypeNode::eType_Element) {
-        nsXULPrototypeElement *elem =
-            static_cast<nsXULPrototypeElement*>(tmp);
-        if (elem->mHoldsScriptObject) {
-            PRUint32 i;
-            for (i = 0; i < elem->mNumAttributes; ++i) {
-                void *handler = elem->mAttributes[i].mEventHandler;
-                NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(elem->mScriptTypeID,
-                                                        handler)
-            }
-        }
-    }
-    else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
-        nsXULPrototypeScript *script =
-            static_cast<nsXULPrototypeScript*>(tmp);
-        NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(script->mScriptObject.mLangID,
-                                                script->mScriptObject.mObject)
-    }
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release)
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeAttribute
 //
 
 nsXULPrototypeAttribute::~nsXULPrototypeAttribute()
 {
     MOZ_COUNT_DTOR(nsXULPrototypeAttribute);
+    NS_ASSERTION(!mEventHandler, "Finalize not called - language object leak!");
+}
+
+void
+nsXULPrototypeAttribute::Finalize(PRUint32 aLangID)
+{
+    if (mEventHandler) {
+        if (NS_FAILED(nsContentUtils::DropScriptObject(aLangID, mEventHandler)))
+            NS_ERROR("Failed to drop script object");
+        mEventHandler = nsnull;
+    }
 }
 
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeElement
 //
 
@@ -2684,29 +2674,16 @@ nsXULPrototypeElement::SetAttrAt(PRUint3
         // Don't abort if parsing failed, it could just be malformed css.
     }
 
     mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
 
     return NS_OK;
 }
 
-void
-nsXULPrototypeElement::Unlink()
-{
-    if (mHoldsScriptObject) {
-        nsContentUtils::DropScriptObjects(mScriptTypeID, this,
-                                          &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
-        mHoldsScriptObject = PR_FALSE;
-    }
-    mNumAttributes = 0;
-    delete[] mAttributes;
-    mAttributes = nsnull;
-}
-
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeScript
 //
 
 nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, PRUint32 aVersion)
     : nsXULPrototypeNode(eType_Script),
       mLineNo(aLineNo),
@@ -2719,17 +2696,16 @@ nsXULPrototypeScript::nsXULPrototypeScri
     NS_LOG_ADDREF(this, 1, ClassName(), ClassSize());
     NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
                  "The language ID must be known and constant");
 }
 
 
 nsXULPrototypeScript::~nsXULPrototypeScript()
 {
-    Unlink();
 }
 
 nsresult
 nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
                                 nsIScriptGlobalObject* aGlobal,
                                 const nsCOMArray<nsINodeInfo> *aNodeInfos)
 {
     nsIScriptContext *context = aGlobal->GetScriptContext(
@@ -2837,17 +2813,17 @@ nsXULPrototypeScript::Deserialize(nsIObj
     NS_ASSERTION(context != nsnull, "Have no context for deserialization");
     NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
     nsScriptObjectHolder newScriptObject(context);
     rv = context->Deserialize(aStream, newScriptObject);
     if (NS_FAILED(rv)) {
         NS_WARNING("Language deseralization failed");
         return rv;
     }
-    Set(newScriptObject);
+    mScriptObject.set(newScriptObject);
     return NS_OK;
 }
 
 
 nsresult
 nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
                                            nsIScriptGlobalObject* aGlobal)
 {
@@ -2890,17 +2866,17 @@ nsXULPrototypeScript::DeserializeOutOfLi
                     // setting langID to UNKNOWN in the nsXULPrototypeScript
                     // ctor and not setting it until the scriptObject is set -
                     // code that pre-fetches these globals will then start
                     // asserting.)
                     if (mScriptObject.mLangID != newLangID) {
                         NS_ERROR("XUL cache gave different language?");
                         return NS_ERROR_UNEXPECTED;
                     }
-                    Set(newScriptObject);
+                    mScriptObject.set(newScriptObject);
                 }
             }
         }
 
         if (! mScriptObject.mObject) {
             nsCOMPtr<nsIURI> oldURI;
 
             if (mSrcURI) {
@@ -3016,17 +2992,17 @@ nsXULPrototypeScript::Compile(const PRUn
                                 aDocument->NodePrincipal(),
                                 urlspec.get(),
                                 aLineNo,
                                 mLangVersion,
                                 newScriptObject);
     if (NS_FAILED(rv))
         return rv;
 
-    Set(newScriptObject);
+    mScriptObject.set(newScriptObject);
     return rv;
 }
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeText
 //
 
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -3724,18 +3724,17 @@ nsresult NS_CreateJSRuntime(nsIScriptRun
 // When consumed by non-JS (eg, another script language), conversion is done
 // on-the-fly.
 class nsJSArgArray : public nsIJSArgArray, public nsIArray {
 public:
   nsJSArgArray(JSContext *aContext, PRUint32 argc, jsval *argv, nsresult *prv);
   ~nsJSArgArray();
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray,
-                                                         nsIJSArgArray)
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsJSArgArray, nsIJSArgArray)
 
   // nsIArray
   NS_DECL_NSIARRAY
 
   // nsIJSArgArray
   nsresult GetArgs(PRUint32 *argc, void **argv);
 
   void ReleaseJSObjects();
@@ -3755,62 +3754,65 @@ nsJSArgArray::nsJSArgArray(JSContext *aC
   // copy the array - we don't know its lifetime, and ours is tied to xpcom
   // refcounting.  Alloc zero'd array so cleanup etc is safe.
   mArgv = (jsval *) PR_CALLOC(argc * sizeof(jsval));
   if (!mArgv) {
     *prv = NS_ERROR_OUT_OF_MEMORY;
     return;
   }
 
-  // Callers are allowed to pass in a nutll argv even for argc > 0. They can
-  // then use GetArgs to initialized the values.
-  if (argv) {
-    for (PRUint32 i = 0; i < argc; ++i)
+  JSAutoRequest ar(aContext);
+  for (PRUint32 i = 0; i < argc; ++i) {
+    if (argv)
       mArgv[i] = argv[i];
+    if (!::JS_AddNamedRoot(aContext, &mArgv[i], "nsJSArgArray.mArgv[i]")) {
+      *prv = NS_ERROR_UNEXPECTED;
+      return;
+    }
   }
-  if (argc > 0)
-    *prv = NS_HOLD_JS_OBJECTS(this, nsJSArgArray);
+  *prv = NS_OK;
 }
 
 nsJSArgArray::~nsJSArgArray()
 {
   ReleaseJSObjects();
 }
 
 void
 nsJSArgArray::ReleaseJSObjects()
 {
-  if (mArgc > 0)
-    NS_DROP_JS_OBJECTS(this, nsJSArgArray);
   if (mArgv) {
+    NS_ASSERTION(nsJSRuntime::sRuntime, "Where's the runtime gone?");
+    if (nsJSRuntime::sRuntime) {
+      for (PRUint32 i = 0; i < mArgc; ++i) {
+        ::JS_RemoveRootRT(nsJSRuntime::sRuntime, &mArgv[i]);
+      }
+    }
     PR_DELETE(mArgv);
   }
   mArgc = 0;
 }
 
 // QueryInterface implementation for nsJSArgArray
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray)
   tmp->ReleaseJSObjects();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray)
-  jsval *argv = tmp->mArgv;
-  if (argv) {
-    jsval *end;
-    for (end = argv + tmp->mArgc; argv < end; ++argv) {
-	    if (JSVAL_IS_GCTHING(*argv))
-        NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT,
-                                                JSVAL_TO_GCTHING(*argv))
+  {
+    jsval *argv = tmp->mArgv;
+    if (argv) {
+      jsval *end;
+      for (end = argv + tmp->mArgc; argv < end; ++argv) {
+        if (JSVAL_IS_OBJECT(*argv))
+          cb.NoteScriptChild(JAVASCRIPT, JSVAL_TO_OBJECT(*argv));
+      }
     }
   }
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray)
   NS_INTERFACE_MAP_ENTRY(nsIArray)
   NS_INTERFACE_MAP_ENTRY(nsIJSArgArray)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSArgArray)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSArgArray, nsIJSArgArray)
--- a/dom/src/base/nsJSTimeoutHandler.cpp
+++ b/dom/src/base/nsJSTimeoutHandler.cpp
@@ -54,17 +54,17 @@ static const char kSetIntervalStr[] = "s
 static const char kSetTimeoutStr[] = "setTimeout";
 
 // Our JS nsIScriptTimeoutHandler implementation.
 class nsJSScriptTimeoutHandler: public nsIScriptTimeoutHandler
 {
 public:
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSScriptTimeoutHandler)
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler)
 
   nsJSScriptTimeoutHandler();
   ~nsJSScriptTimeoutHandler();
 
   virtual const PRUnichar *GetHandlerText();
   virtual void *GetScriptObject() {
     return mFunObj;
   }
@@ -113,24 +113,19 @@ private:
 // QueryInterface implementation for nsJSScriptTimeoutHandler
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSScriptTimeoutHandler)
   tmp->ReleaseJSObjects();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSScriptTimeoutHandler)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgv)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, tmp->mFunObj);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSScriptTimeoutHandler)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpr)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mFunObj)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSScriptTimeoutHandler)
   NS_INTERFACE_MAP_ENTRY(nsIScriptTimeoutHandler)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSScriptTimeoutHandler)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSScriptTimeoutHandler)
 
@@ -146,21 +141,59 @@ nsJSScriptTimeoutHandler::~nsJSScriptTim
 {
   ReleaseJSObjects();
 }
 
 void
 nsJSScriptTimeoutHandler::ReleaseJSObjects()
 {
   if (mExpr || mFunObj) {
+    nsCOMPtr<nsIScriptContext> scx = mContext;
+    JSRuntime *rt = nsnull;
+
+    if (scx) {
+      JSContext *cx;
+      cx = (JSContext *)scx->GetNativeContext();
+      rt = ::JS_GetRuntime(cx);
+      mContext = nsnull;
+    } else {
+      // XXX The timeout *must* be unrooted, even if !scx. This can be
+      // done without a JS context using the JSRuntime. This is safe
+      // enough, but it would be better to drop all a window's
+      // timeouts before its context is cleared. Bug 50705 describes a
+      // situation where we're not. In that case, at the time the
+      // context is cleared, a timeout (actually an Interval) is still
+      // active, but temporarily removed from the window's list of
+      // timers (placed instead on the timer manager's list). This
+      // makes the nearly handy ClearAllTimeouts routine useless, so
+      // we settled on using the JSRuntime rather than relying on the
+      // window having a context. It would be good to remedy this
+      // workable but clumsy situation someday.
+
+      nsCOMPtr<nsIJSRuntimeService> rtsvc =
+        do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+
+      if (rtsvc) {
+        rtsvc->GetRuntime(&rt);
+      }
+    }
+
+    if (!rt) {
+      // most unexpected. not much choice but to bail.
+
+      NS_ERROR("nsTimeout::Release() with no JSRuntime. eek!");
+
+      return;
+    }
+
     if (mExpr) {
-      NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
+      ::JS_RemoveRootRT(rt, &mExpr);
       mExpr = nsnull;
     } else if (mFunObj) {
-      NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
+      ::JS_RemoveRootRT(rt, &mFunObj);
       mFunObj = nsnull;
     } else {
       NS_WARNING("No func and no expr - roots may not have been removed");
     }
   }
 }
 
 nsresult
@@ -242,29 +275,31 @@ nsJSScriptTimeoutHandler::Init(nsIScript
                      *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 
     // Return an error that nsGlobalWindow can recognize and turn into NS_OK.
     ncc->SetExceptionWasThrown(PR_TRUE);
     return NS_ERROR_DOM_TYPE_ERR;
   }
 
   if (expr) {
-    rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (!::JS_AddNamedRoot(cx, &mExpr, "timeout.mExpr")) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
 
     mExpr = expr;
 
     // Get the calling location.
     const char *filename;
     if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
       mFileName.Assign(filename);
     }
   } else if (funobj) {
-    rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (!::JS_AddNamedRoot(cx, &mFunObj, "timeout.mFunObj")) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
 
     mFunObj = funobj;
 
     // Create our arg array - leave an extra slot for a secret final argument
     // that indicates to the called function how "late" the timeout is.  We
     // will fill that in when SetLateness is called.
     nsCOMPtr<nsIArray> array;
     rv = NS_CreateJSArgv(cx, (argc > 1) ? argc - 1 : argc, nsnull,
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -76,40 +76,34 @@ nsJSEventListener::nsJSEventListener(nsI
                                      nsISupports *aTarget)
   : nsIJSEventListener(aContext, aScopeObject, aTarget),
     mReturnResult(nsReturnResult_eNotSet)
 {
   // aScopeObject is the inner window's JS object, which we need to lock
   // until we are done with it.
   NS_ASSERTION(aScopeObject && aContext,
                "EventListener with no context or scope?");
-  NS_HOLD_JS_OBJECTS(this, nsJSEventListener);
+  aContext->HoldScriptObject(aScopeObject);
 }
 
 nsJSEventListener::~nsJSEventListener() 
 {
-  if (mContext)
-    NS_DROP_JS_OBJECTS(this, nsJSEventListener);
+  mContext->DropScriptObject(mScopeObject);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTarget)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, tmp->mScopeObject);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
-                                                 mScopeObject)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSEventListener)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
   NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener)
--- a/dom/src/events/nsJSEventListener.h
+++ b/dom/src/events/nsJSEventListener.h
@@ -60,18 +60,18 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   // nsIDOMEventListener interface
   NS_DECL_NSIDOMEVENTLISTENER
 
   // nsIJSEventListener interface
   virtual void SetEventName(nsIAtom* aName);
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSEventListener,
-                                                         nsIDOMEventListener)
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsJSEventListener,
+                                           nsIDOMEventListener)
 protected:
   nsCOMPtr<nsIAtom> mEventName;
   
   enum nsReturnResult {
      nsReturnResult_eNotSet,
      nsReturnResult_eReverseReturnResult,
      nsReturnResult_eDoNotReverseReturnResult
   };
--- a/js/src/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl
@@ -36,18 +36,16 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIXPConnect.idl"
 
-[ptr] native JSTracerPtr(JSTracer);
-
 %{ C++
 #define NS_SUCCESS_I_DID_SOMETHING \
    (NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,1))
 %}
 
 /**
  * Note: This is not really an XPCOM interface.  For example, callers must
  * guarantee that they set the *_retval of the various methods that return a
--- a/js/src/xpconnect/idl/nsIXPConnect.idl
+++ b/js/src/xpconnect/idl/nsIXPConnect.idl
@@ -59,17 +59,17 @@
 /***************************************************************************/
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSObjectPtr(JSObject);
 [ptr] native JSValPtr(jsval);
       native JSVal(jsval);
       native JSID(jsid);
 [ptr] native voidPtrPtr(void*);
-[ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
+[ptr] native JSTracerPtr(JSTracer);
 
 /***************************************************************************/
 
 %{ C++
 /***************************************************************************/
 #define GENERATE_XPC_FAILURE(x) \
             (NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCONNECT,x))
 
@@ -145,17 +145,17 @@
 interface nsIXPCScriptable;
 interface nsIXPConnect;
 interface nsIXPConnectWrappedNative;
 interface nsIInterfaceInfo;
 interface nsIXPCSecurityManager;
 interface nsIPrincipal;
 
 %{C++
-class nsScriptObjectTracer;
+class nsCycleCollectionTraversalCallback;
 %}
 
 /***************************************************************************/
 [uuid(8916a320-d118-11d3-8f3a-0010a4e73d9a)]
 interface nsIXPConnectJSObjectHolder : nsISupports
 {
     readonly attribute JSObjectPtr      JSObject;
 };
@@ -722,23 +722,9 @@ interface nsIXPConnect : nsISupports
      * Wrap a jsval in a cross origin wrapper.
      * @param aJSContext A context to use to create objects.
      * @param aParent The parent to create the wrapper with.
      * @param aWrappedObj The object to wrap.
      */
     [noscript] JSVal getCrossOriginWrapperForObject(in JSContextPtr aJSContext,
                                                     in JSObjectPtr aParent,
                                                     in JSObjectPtr aWrappedObj);
-
-    /**
-     * Root JS objects held by aHolder.
-     * @param aHolder The object that hold the JS objects that should be rooted.
-     * @param aTrace The tracer for aHolder.
-     */
-    [noscript] void addJSHolder(in voidPtr aHolder,
-                                in nsScriptObjectTracerPtr aTracer);
-
-    /**
-     * Stop rooting the JS objects held by aHolder.
-     * @param aHolder The object that hold the rooted JS objects.
-     */
-    [noscript] void removeJSHolder(in voidPtr aHolder);
 };
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -690,53 +690,38 @@ NoteJSChild(JSTracer *trc, void *thing, 
     {
         ContextCallbackItem *item = static_cast<ContextCallbackItem*>(trc);
         item->cb->NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, thing);
     }
 }
 
 static uint8 GCTypeToTraceKindMap[GCX_NTYPES] = {
     JSTRACE_OBJECT,     /* GCX_OBJECT */
-    JSTRACE_STRING,     /* GCX_STRING */
-    JSTRACE_DOUBLE,     /* GCX_DOUBLE */
-    JSTRACE_FUNCTION,   /* GCX_FUNCTION */
+    JSTRACE_STRING,     /* GCX_STRING (unused) */
+    JSTRACE_DOUBLE,     /* GCX_DOUBLE (unused) */
+    JSTRACE_STRING,     /* GCX_MUTABLE_STRING (unused) */
+    JSTRACE_FUNCTION,   /* GCX_FUNCTION (unused) */
     JSTRACE_NAMESPACE,  /* GCX_NAMESPACE */
     JSTRACE_QNAME,      /* GCX_QNAME */
-    JSTRACE_XML,        /* GCX_XML */
-    (uint8)-1,         /* unused */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 0 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 1 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 2 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 3 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 4 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 5 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 6 */
-    JSTRACE_STRING,     /* GCX_EXTERNAL_STRING + 7 */
+    JSTRACE_XML         /* GCX_XML */
+    // We don't care about JSTRACE_STRING, so stop here
 };
 
-// static
-uint8
-nsXPConnect::GetTraceKind(void *thing)
-{
-    uint8 type = *js_GetGCThingFlags(thing) & GCF_TYPEMASK;
-    return GCTypeToTraceKindMap[type];
-}
-
 NS_IMETHODIMP
 nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
 {
     if(!mCycleCollectionContext)
         return NS_ERROR_FAILURE;
 
     JSContext *cx = mCycleCollectionContext->GetJSContext();
 
     PRUint32 refcount = mObjRefcounts->Get(p);
     NS_ASSERTION(refcount > 0, "JS object but unknown to the JS GC?");
 
-    uint8 ty = GetTraceKind(p);
+    uint8 ty = *js_GetGCThingFlags(p) & GCF_TYPEMASK;
     if(ty != GCX_OBJECT && ty != GCX_NAMESPACE && ty != GCX_QNAME &&
        ty != GCX_XML)
         return NS_OK;
 
 #ifdef DEBUG_CC
     if(ty == GCX_OBJECT)
     {
         JSObject *obj = static_cast<JSObject*>(p);
@@ -2107,28 +2092,16 @@ nsXPConnect::AfterProcessNextEvent(nsITh
 
 NS_IMETHODIMP
 nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
 {
     NS_NOTREACHED("Why tell us?");
     return NS_ERROR_UNEXPECTED;
 }
 
-NS_IMETHODIMP
-nsXPConnect::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
-{
-    return mRuntime->AddJSHolder(aHolder, aTracer);
-}
-
-NS_IMETHODIMP
-nsXPConnect::RemoveJSHolder(void* aHolder)
-{
-    return mRuntime->RemoveJSHolder(aHolder);
-}
-
 #ifdef DEBUG
 /* These are here to be callable from a debugger */
 JS_BEGIN_EXTERN_C
 void DumpJSStack()
 {
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if(NS_SUCCEEDED(rv) && xpc)
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -246,52 +246,16 @@ ContextCallback(JSContext *cx, uintN ope
         }
     }
 
     return gOldJSContextCallback
            ? gOldJSContextCallback(cx, operation)
            : JS_TRUE;
 }
 
-struct ObjectHolder : public JSDHashEntryHdr
-{
-    void *holder;
-    nsScriptObjectTracer* tracer;
-};
-
-nsresult
-XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
-{
-    if(!mJSHolders.ops)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    ObjectHolder *entry =
-        reinterpret_cast<ObjectHolder*>(JS_DHashTableOperate(&mJSHolders,
-                                                             aHolder,
-                                                             JS_DHASH_ADD));
-    if(!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    entry->holder = aHolder;
-    entry->tracer = aTracer;
-
-    return NS_OK;
-}
-
-nsresult
-XPCJSRuntime::RemoveJSHolder(void* aHolder)
-{
-    if(!mJSHolders.ops)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    JS_DHashTableOperate(&mJSHolders, aHolder, JS_DHASH_REMOVE);
-
-    return NS_OK;
-}
-
 // static
 void XPCJSRuntime::TraceJS(JSTracer* trc, void* data)
 {
     XPCJSRuntime* self = (XPCJSRuntime*)data;
 
     // Skip this part if XPConnect is shutting down. We get into
     // bad locking problems with the thread iteration otherwise.
     if(!self->GetXPConnect()->IsShuttingDown())
@@ -308,58 +272,26 @@ void XPCJSRuntime::TraceJS(JSTracer* trc
                              XPCPerThreadData::IterateThreads(&iterp)))
             {
                 // Trace those AutoMarkingPtr lists!
                 thread->TraceJS(trc);
             }
         }
     }
 
-    // XPCJSObjectHolders don't participate in cycle collection, so always trace
-    // them here.
-    for(XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot())
-        static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
-        
-    self->TraceXPConnectRoots(trc);
-}
+    XPCWrappedNativeScope::TraceJS(trc, self);
 
-PR_STATIC_CALLBACK(void)
-TraceJSObject(PRUint32 aLangID, void *aScriptThing, void *aClosure)
-{
-    if(aLangID == nsIProgrammingLanguage::JAVASCRIPT)
-    {
-        JS_CALL_TRACER(static_cast<JSTracer*>(aClosure), aScriptThing,
-                       nsXPConnect::GetXPConnect()->GetTraceKind(aScriptThing),
-                       "JSObjectHolder");
-    }
-}
-
-JS_STATIC_DLL_CALLBACK(JSDHashOperator)
-TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
-              void *arg)
-{
-    ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
-
-    entry->tracer->Trace(entry->holder, TraceJSObject, arg);
-
-    return JS_DHASH_NEXT;
-}
-
-void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
-{
-    XPCWrappedNativeScope::TraceJS(trc, this);
-
-    for(XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
+    for (XPCRootSetElem *e = self->mVariantRoots; e ; e = e->GetNextRoot())
         static_cast<XPCTraceableVariant*>(e)->TraceJS(trc);
 
-    for(XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
+    for (XPCRootSetElem *e = self->mWrappedJSRoots; e ; e = e->GetNextRoot())
         static_cast<nsXPCWrappedJS*>(e)->TraceJS(trc);
 
-    if(mJSHolders.ops)
-        JS_DHashTableEnumerate(&mJSHolders, TraceJSHolder, trc);
+    for (XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot())
+        static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
 }
 
 // static
 JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
 {
     nsVoidArray* dyingWrappedJSArray;
 
     XPCJSRuntime* self = nsXPConnect::GetRuntime();
@@ -872,22 +804,16 @@ XPCJSRuntime::~XPCJSRuntime()
 
     // unwire the readable/JSString sharing magic
     XPCStringConvert::ShutdownDOMStringFinalizer();
 
     XPCConvert::RemoveXPCOMUCStringFinalizer();
 
     gOldJSGCCallback = NULL;
     gOldJSContextCallback = NULL;
-
-    if(mJSHolders.ops)
-    {
-        JS_DHashTableFinish(&mJSHolders);
-        mJSHolders.ops = nsnull;
-    }
 }
 
 XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect,
                            nsIJSRuntimeService* aJSRuntimeService)
  : mXPConnect(aXPConnect),
    mJSRuntime(nsnull),
    mJSRuntimeService(aJSRuntimeService),
    mContextMap(JSContext2XPCContextMap::newMap(XPC_CONTEXT_MAP_SIZE)),
@@ -931,20 +857,16 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     if(mJSRuntime)
     {
         gOldJSContextCallback = JS_SetContextCallback(mJSRuntime,
                                                       ContextCallback);
         gOldJSGCCallback = JS_SetGCCallbackRT(mJSRuntime, GCCallback);
         JS_SetExtraGCRoots(mJSRuntime, TraceJS, this);
     }
 
-    if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
-                          sizeof(ObjectHolder), 512))
-        mJSHolders.ops = nsnull;
-
     // Install a JavaScript 'debugger' keyword handler in debug builds only
 #ifdef DEBUG
     if(mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
         xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
 #endif
 }
 
 // static
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -493,19 +493,16 @@ public:
     virtual nsresult FinishCycleCollection();
     virtual nsCycleCollectionParticipant *ToParticipant(void *p);
 #ifdef DEBUG_CC
     virtual void PrintAllReferencesTo(void *p);
     virtual void SuspectExtraPointers();
 #endif
 
     JSObjectRefcounts* GetJSObjectRefcounts() {return mObjRefcounts;}
-
-    static uint8 GetTraceKind(void *thing);
-
 #ifndef XPCONNECT_STANDALONE
     void RecordTraversal(void *p, nsISupports *s);
 #endif
 
 #ifdef XPC_IDISPATCH_SUPPORT
 public:
     static PRBool IsIDispatchEnabled();
 #endif
@@ -674,29 +671,23 @@ public:
     }
     const char* GetStringName(uintN index) const
     {
         NS_ASSERTION(index < IDX_TOTAL_COUNT, "index out of range");
         return mStrings[index];
     }
 
     static void JS_DLL_CALLBACK TraceJS(JSTracer* trc, void* data);
-    void TraceXPConnectRoots(JSTracer *trc);
-    void AddXPConnectRoots(JSContext* cx,
-                           nsCycleCollectionTraversalCallback& cb);
 
     static JSBool JS_DLL_CALLBACK GCCallback(JSContext *cx, JSGCStatus status);
 
     inline void AddVariantRoot(XPCTraceableVariant* variant);
     inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
     inline void AddObjectHolderRoot(XPCJSObjectHolder* holder);
 
-    nsresult AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer);
-    nsresult RemoveJSHolder(void* aHolder);
-
     void DebugDump(PRInt16 depth);
 
     void SystemIsBeingShutDown(JSContext* cx);
 
     PRThread* GetThreadRunningGC() const {return mThreadRunningGC;}
 
     ~XPCJSRuntime();
 
@@ -750,17 +741,16 @@ private:
     nsVoidArray mWrappedJSToReleaseArray;
     nsVoidArray mNativesToReleaseArray;
     JSBool mMainThreadOnlyGC;
     JSBool mDeferReleases;
     JSBool mDoingFinalization;
     XPCRootSetElem *mVariantRoots;
     XPCRootSetElem *mWrappedJSRoots;
     XPCRootSetElem *mObjectHolderRoots;
-    JSDHashTable mJSHolders;
 };
 
 /***************************************************************************/
 /***************************************************************************/
 // XPCContext is mostly a dumb class to hold JSContext specific data and
 // maps that let us find wrappers created for the given JSContext.
 
 // no virtuals
@@ -1196,16 +1186,18 @@ public:
     static JSBool
     IsDyingScope(XPCWrappedNativeScope *scope);
 
     void SetComponents(nsXPCComponents* aComponents);
     void SetGlobal(XPCCallContext& ccx, JSObject* aGlobal);
 
     static void InitStatics() { gScopes = nsnull; gDyingScopes = nsnull; }
 
+    void Traverse(nsCycleCollectionTraversalCallback &cb);
+
 #ifndef XPCONNECT_STANDALONE
     /**
      * Fills the hash mapping global object to principal.
      */
     static void TraverseScopes(XPCCallContext& ccx);
 #endif
 
 protected:
@@ -1934,21 +1926,20 @@ private:
 
 /***************************************************************************/
 // XPCWrappedNative the wrapper around one instance of a native xpcom object
 // to be used from JavaScript.
 
 class XPCWrappedNative : public nsIXPConnectWrappedNative
 {
 public:
-    NS_DECL_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
     NS_DECL_NSIXPCONNECTWRAPPEDNATIVE
     NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
-    NS_DECL_CYCLE_COLLECTION_UNMARK_PURPLE_STUB(XPCWrappedNative)
 
 #ifndef XPCONNECT_STANDALONE
     virtual nsIPrincipal* GetObjectPrincipal() const;
 #endif
 
     JSBool
     IsValid() const {return nsnull != mFlatJSObject;}
 
@@ -2048,17 +2039,17 @@ public:
     static nsresult
     ReparentWrapperIfFound(XPCCallContext& ccx,
                            XPCWrappedNativeScope* aOldScope,
                            XPCWrappedNativeScope* aNewScope,
                            JSObject* aNewParent,
                            nsISupports* aCOMObj,
                            XPCWrappedNative** aWrapper);
 
-    void FlatJSObjectFinalized(JSContext *cx);
+    void FlatJSObjectFinalized(JSContext *cx, JSObject *obj);
 
     void SystemIsBeingShutDown(JSContext* cx);
 
 #ifdef XPC_DETECT_LEADING_UPPERCASE_ACCESS_ERRORS
     // This will try to find a member that is of the form "camelCased"
     // but was accessed from JS using "CamelCased". This is here to catch
     // mistakes caused by the confusion magnet that JS methods are by
     // convention 'foo' while C++ members are by convention 'Foo'.
@@ -2200,20 +2191,18 @@ private:
         XPCWrappedNativeProto*   mMaybeProto;
     };
     XPCNativeSet*                mSet;
     JSObject*                    mFlatJSObject;
     XPCNativeScriptableInfo*     mScriptableInfo;
     XPCWrappedNativeTearOffChunk mFirstChunk;
     JSObject*                    mWrapper;
 
-#ifdef XPC_CHECK_WRAPPER_THREADSAFETY
 public:
     nsCOMPtr<nsIThread>          mThread; // Don't want to overload _mOwningThread
-#endif
 };
 
 /***************************************************************************
 ****************************************************************************
 *
 * Core classes for wrapped JSObject for use from native code...
 *
 ****************************************************************************
@@ -3034,16 +3023,17 @@ private:
     AutoMarkingPtr*      mAutoRoots;
 
     jsuword              mStackLimit;
 
 #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
     JSUint32             mWrappedNativeThreadsafetyReportDepth;
 #endif
     PRThread*            mThread;
+    nsVoidArray          mNativesToReleaseArray;
 
     static PRLock*           gLock;
     static XPCPerThreadData* gThreads;
     static PRUintn           gTLSIndex;
 };
 
 /**************************************************************/
 
--- a/js/src/xpconnect/src/xpcwrappedjs.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjs.cpp
@@ -584,16 +584,20 @@ nsXPCWrappedJS::SystemIsBeingShutDown(JS
     // mJSObj == nsnull is used to indicate that the wrapper is no longer valid
     // 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).
     mJSObj = nsnull;
 
+    // There is no reason to keep this root any longer. Since we've cleared
+    // mJSObj our dtor will not remove the root later. So, we do it now.
+    JS_RemoveRootRT(rt, &mJSObj);
+
     // Notify other wrappers in the chain.
     if(mNext)
         mNext->SystemIsBeingShutDown(rt);
 }
 
 /***************************************************************************/
 
 /* readonly attribute nsISimpleEnumerator enumerator; */
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -956,17 +956,17 @@ NS_IMPL_THREADSAFE_RELEASE(XPCWrappedNat
  *    mJSObject we set it's parent to be mFlatJSObject. This way we know that
  *    when mFlatJSObject get's collected there are no outstanding reachable
  *    tearoff mJSObjects. Note that we must clear the private of any lingering
  *    mJSObjects at this point because we have no guarentee of the *order* of
  *    finalization within a given gc cycle.
  */
 
 void
-XPCWrappedNative::FlatJSObjectFinalized(JSContext *cx)
+XPCWrappedNative::FlatJSObjectFinalized(JSContext *cx, JSObject *obj)
 {
     if(!IsValid())
         return;
 
     // Iterate the tearoffs and null out each of their JSObject's privates.
     // This will keep them from trying to access their pointers to the
     // dying tearoff object. We can safely assume that those remaining
     // JSObjects are about to be finalized too.
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -642,28 +642,28 @@ XPC_WN_Shared_Enumerate(JSContext *cx, J
 /***************************************************************************/
 
 JS_STATIC_DLL_CALLBACK(void)
 XPC_WN_NoHelper_Finalize(JSContext *cx, JSObject *obj)
 {
     XPCWrappedNative* p = (XPCWrappedNative*) JS_GetPrivate(cx, obj);
     if(!p)
         return;
-    p->FlatJSObjectFinalized(cx);
+    p->FlatJSObjectFinalized(cx, obj);
 }
 
 static void
 TraceScopeJSObjects(JSTracer *trc, XPCWrappedNativeScope* scope)
 {
     NS_ASSERTION(scope, "bad scope");
 
     JSObject* obj;
 
     obj = scope->GetGlobalJSObject();
-    NS_ASSERTION(obj, "bad scope JSObject");
+    NS_ASSERTION(scope, "bad scope JSObject");
     JS_CALL_OBJECT_TRACER(trc, obj, "XPCWrappedNativeScope::mGlobalJSObject");
 
     obj = scope->GetPrototypeJSObject();
     if(obj)
     {
         JS_CALL_OBJECT_TRACER(trc, obj,
                               "XPCWrappedNativeScope::mPrototypeJSObject");
     }
@@ -1030,17 +1030,17 @@ XPC_WN_Helper_HasInstance(JSContext *cx,
 
 JS_STATIC_DLL_CALLBACK(void)
 XPC_WN_Helper_Finalize(JSContext *cx, JSObject *obj)
 {
     XPCWrappedNative* wrapper = (XPCWrappedNative*) JS_GetPrivate(cx, obj);
     if(!wrapper)
         return;
     wrapper->GetScriptableCallback()->Finalize(wrapper, cx, obj);
-    wrapper->FlatJSObjectFinalized(cx);
+    wrapper->FlatJSObjectFinalized(cx, obj);
 }
 
 JS_STATIC_DLL_CALLBACK(void)
 XPC_WN_Helper_Trace(JSTracer *trc, JSObject *obj)
 {
     XPCWrappedNative* wrapper =
         XPCWrappedNative::GetWrappedNativeOfJSObject(trc->context, obj);
     if(wrapper && wrapper->IsValid())
--- a/js/src/xpconnect/src/xpcwrappednativescope.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp
@@ -846,16 +846,26 @@ XPCWrappedNativeScope::DebugDump(PRInt16
             XPC_LOG_INDENT();
             mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
     XPC_LOG_OUTDENT();
 #endif
 }
 
+void
+XPCWrappedNativeScope::Traverse(nsCycleCollectionTraversalCallback &cb)
+{
+    // See TraceScopeJSObjects.
+    cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mGlobalJSObject);
+    cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mPrototypeJSObject);
+    cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
+                       mPrototypeJSFunction);
+}
+
 #ifndef XPCONNECT_STANDALONE
 // static
 void
 XPCWrappedNativeScope::TraverseScopes(XPCCallContext& ccx)
 {
     // Hold the lock throughout.
     XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
 
--- a/xpcom/base/nsAgg.h
+++ b/xpcom/base/nsAgg.h
@@ -113,18 +113,17 @@ public:                                 
   static _class* Downcast(nsISupports* s)                                   \
   {                                                                         \
     return (_class*)((char*)(s) - offsetof(_class, fAggregated));           \
   }                                                                         \
   static nsISupports* Upcast(_class *p)                                     \
   {                                                                         \
     return p->InnerObject();                                                \
   }                                                                         \
-};                                                                          \
-NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+};                                                           
 
 // Put this in your class's constructor:
 #define NS_INIT_AGGREGATED(outer)                                           \
   PR_BEGIN_MACRO                                                            \
     fOuter = outer ? outer : &fAggregated;                                  \
   PR_END_MACRO
 
 
--- a/xpcom/glue/nsCycleCollectionParticipant.cpp
+++ b/xpcom/glue/nsCycleCollectionParticipant.cpp
@@ -33,31 +33,16 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 
-PR_STATIC_CALLBACK(void)
-NoteChild(PRUint32 aLangID, void *aScriptThing, void *aClosure)
-{
-  nsCycleCollectionTraversalCallback *cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
-  cb->NoteScriptChild(aLangID, aScriptThing);
-}
-
-void
-nsScriptObjectTracer::TraverseScriptObjects(void *p,
-                                        nsCycleCollectionTraversalCallback &cb)
-{
-  Trace(p, NoteChild, &cb);
-}
-
 nsresult
 nsXPCOMCycleCollectionParticipant::Root(void *p)
 {
     nsISupports *s = static_cast<nsISupports*>(p);
     NS_ADDREF(s);
     return NS_OK;
 }
 
@@ -82,22 +67,16 @@ nsXPCOMCycleCollectionParticipant::Trave
   return NS_OK;
 }
 
 void
 nsXPCOMCycleCollectionParticipant::UnmarkPurple(nsISupports *n)
 {
 }
 
-NS_IMETHODIMP_(void)
-nsXPCOMCycleCollectionParticipant::Trace(void *p, TraceCallback cb,
-                                         void *closure)
-{
-}
-
 PRBool
 nsXPCOMCycleCollectionParticipant::CheckForRightISupports(nsISupports *s)
 {
     nsCOMPtr<nsISupports> foo;
     s->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
                       getter_AddRefs(foo));
     return s == foo;
 }
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -120,39 +120,26 @@ public:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant, 
                               NS_CYCLECOLLECTIONPARTICIPANT_IID)
 
 #undef IMETHOD_VISIBILITY
 #define IMETHOD_VISIBILITY NS_COM_GLUE
 
-typedef void
-(* PR_CALLBACK TraceCallback)(PRUint32 langID, void *p, void *closure);
-
-class NS_NO_VTABLE nsScriptObjectTracer : public nsCycleCollectionParticipant
-{
-public:
-    NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure) = 0;
-    void NS_COM_GLUE TraverseScriptObjects(void *p,
-                                        nsCycleCollectionTraversalCallback &cb);
-};
-
 class NS_COM_GLUE nsXPCOMCycleCollectionParticipant
-    : public nsScriptObjectTracer
+    : public nsCycleCollectionParticipant
 {
 public:
     NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb);
 
     NS_IMETHOD Root(void *p);
     NS_IMETHOD Unlink(void *p);
     NS_IMETHOD Unroot(void *p);
 
-    NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure);
-
     NS_IMETHOD_(void) UnmarkPurple(nsISupports *p);
 
     PRBool CheckForRightISupports(nsISupports *s);
 };
 
 #undef IMETHOD_VISIBILITY
 #define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN
 
@@ -161,21 +148,18 @@ public:
 ///////////////////////////////////////////////////////////////////////////////
 
 #define NS_CYCLE_COLLECTION_INNERCLASS                                         \
         cycleCollection
 
 #define NS_CYCLE_COLLECTION_CLASSNAME(_class)                                  \
         _class::NS_CYCLE_COLLECTION_INNERCLASS
 
-#define NS_CYCLE_COLLECTION_INNERNAME                                          \
-        _cycleCollectorGlobal
-
 #define NS_CYCLE_COLLECTION_NAME(_class)                                       \
-        _class::NS_CYCLE_COLLECTION_INNERNAME
+        _class##_cycleCollectorGlobal
 
 #define NS_IMPL_QUERY_CYCLE_COLLECTION(_class)                                 \
   if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {          \
     *aInstancePtr = & NS_CYCLE_COLLECTION_NAME(_class);                        \
     return NS_OK;                                                              \
   } else
 
 #define NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class)                       \
@@ -212,18 +196,16 @@ public:
     NS_PRECONDITION(aInstancePtr, "null out param");                          \
                                                                               \
     if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {       \
       *aInstancePtr = &NS_CYCLE_COLLECTION_NAME(_class);                      \
       return NS_OK;                                                           \
     }                                                                         \
     nsresult rv;
 
-#define NS_CYCLE_COLLECTION_UPCAST(obj, clazz)                                 \
-  NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj)
 
 ///////////////////////////////////////////////////////////////////////////////
 // Helpers for implementing nsCycleCollectionParticipant::Unlink
 ///////////////////////////////////////////////////////////////////////////////
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                          \
   NS_IMETHODIMP                                                                \
   NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p)                       \
@@ -336,198 +318,133 @@ public:
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(_field)                   \
     {                                                                          \
       PRInt32 i;                                                               \
       for (i = 0; i < tmp->_field.Count(); ++i)                                \
         cb.NoteXPCOMChild(tmp->_field[i]);                                     \
     }
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(_ptr, _ptr_class)         \
-  cb.NoteNativeChild(_ptr, &NS_CYCLE_COLLECTION_NAME(_ptr_class));
+  cb.NoteNativeChild(_ptr, &NS_CYCLE_COLLECTION_NATIVE_NAME(_ptr_class));
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(_field, _field_class)  \
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->_field, _field_class)
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(_array, _element_class)     \
     {                                                                          \
       PRUint32 i, length = (_array).Length();                                  \
       for (i = 0; i < length; ++i)                                             \
         NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR((_array)[i],              \
                                                      _element_class);          \
     }
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(_field,              \
                                                           _element_class)      \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(tmp->_field, _element_class)
 
-#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS                       \
-    TraverseScriptObjects(tmp, cb);
-
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                                  \
     return NS_OK;                                                              \
   }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Helpers for implementing nsScriptObjectTracer::Trace
-///////////////////////////////////////////////////////////////////////////////
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class)                           \
-  void                                                                         \
-  NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p,                        \
-                                               TraceCallback aCallback,        \
-                                               void *aClosure)                 \
-  {                                                                            \
-    nsISupports *s = static_cast<nsISupports*>(p);                             \
-    NS_ASSERTION(CheckForRightISupports(s),                                    \
-                 "not the nsISupports pointer we expect");                     \
-    _class *tmp = Downcast(s);
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(_class)                    \
-  void                                                                         \
-  NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p,                        \
-                                               TraceCallback aCallback,        \
-                                               void *aClosure)                 \
-  {                                                                            \
-    _class *tmp = static_cast<_class*>(p);
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(_langID, _object)              \
-  if (_object)                                                                 \
-    aCallback(_langID, _object, aClosure);
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(_langID, _field)        \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(_langID, tmp->_field)
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(_object)                    \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(nsIProgrammingLanguage::JAVASCRIPT,  \
-                                          _object);
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field)              \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->_field)
-
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_END                                     \
-  }
-
-///////////////////////////////////////////////////////////////////////////////
 // Helpers for implementing a concrete nsCycleCollectionParticipant 
 ///////////////////////////////////////////////////////////////////////////////
 
-#define NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE                               \
-  static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
-
-#define NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base)                     \
+#define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base)                \
+class NS_CYCLE_COLLECTION_INNERCLASS                                           \
+ : public nsXPCOMCycleCollectionParticipant                                    \
+{                                                                              \
 public:                                                                        \
   NS_IMETHOD Unlink(void *p);                                                  \
   NS_IMETHOD Traverse(void *p,                                                 \
                       nsCycleCollectionTraversalCallback &cb);                 \
   NS_IMETHOD_(void) UnmarkPurple(nsISupports *s)                               \
   {                                                                            \
     Downcast(s)->UnmarkPurple();                                               \
   }                                                                            \
   static _class* Downcast(nsISupports* s)                                      \
   {                                                                            \
     return static_cast<_class*>(static_cast<_base*>(s));                       \
   }                                                                            \
   static nsISupports* Upcast(_class *p)                                        \
   {                                                                            \
     return NS_ISUPPORTS_CAST(_base*, p);                                       \
-  }
-
-#define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base)                \
-class NS_CYCLE_COLLECTION_INNERCLASS                                           \
- : public nsXPCOMCycleCollectionParticipant                                    \
-{                                                                              \
-  NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base)                           \
-};                                                                             \
-NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+  }                                                                            \
+};                                                           
 
 #define NS_DECL_CYCLE_COLLECTION_CLASS(_class)                                 \
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _class)
 
-#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base)  \
-class NS_CYCLE_COLLECTION_INNERCLASS                                           \
- : public nsXPCOMCycleCollectionParticipant                                    \
-{                                                                              \
-  NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base)                           \
-  NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure);           \
-};                                                                             \
-NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
-
-#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(_class)  \
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class)
-
 #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(_class, _base_class)          \
 class NS_CYCLE_COLLECTION_INNERCLASS                                           \
  : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class)                           \
 {                                                                              \
 public:                                                                        \
   NS_IMETHOD Unlink(void *p);                                                  \
   NS_IMETHOD Traverse(void *p,                                                 \
                       nsCycleCollectionTraversalCallback &cb);                 \
   static _class* Downcast(nsISupports* s)                                      \
   {                                                                            \
     return static_cast<_class*>(static_cast<_base_class*>(                     \
       NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Downcast(s)));               \
   }                                                                            \
-};                                                                             \
-NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+};
 
 #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(_class,             \
                                                            _base_class)        \
 class NS_CYCLE_COLLECTION_INNERCLASS                                           \
  : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class)                           \
 {                                                                              \
 public:                                                                        \
   NS_IMETHOD Traverse(void *p,                                                 \
                       nsCycleCollectionTraversalCallback &cb);                 \
   static _class* Downcast(nsISupports* s)                                      \
   {                                                                            \
     return static_cast<_class*>(static_cast<_base_class*>(                     \
       NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Downcast(s)));               \
   }                                                                            \
-};                                                                             \
-NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+};
 
 /**
  * This implements a stub UnmarkPurple function for classes that want to be
  * traversed but whose AddRef/Release functions don't add/remove them to/from
  * the purple buffer. If you're just using NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  * then you don't need this.
  */
 #define NS_DECL_CYCLE_COLLECTION_UNMARK_PURPLE_STUB(_class)                    \
   NS_IMETHODIMP_(void) UnmarkPurple()                                          \
   {                                                                            \
   }                                                                            \
 
 #define NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                 \
-  NS_CYCLE_COLLECTION_CLASSNAME(_class) NS_CYCLE_COLLECTION_NAME(_class);
+  static NS_CYCLE_COLLECTION_CLASSNAME(_class)                                 \
+    NS_CYCLE_COLLECTION_NAME(_class);
+
+#define NS_CYCLE_COLLECTION_NATIVE_INNERNAME                                   \
+        _cycleCollectorGlobal
 
-#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY                             \
+#define NS_CYCLE_COLLECTION_NATIVE_NAME(_class)                                \
+        _class::NS_CYCLE_COLLECTION_NATIVE_INNERNAME
+
+#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class)                          \
+  class NS_CYCLE_COLLECTION_INNERCLASS                                         \
+   : public nsCycleCollectionParticipant                                       \
+  {                                                                            \
   public:                                                                      \
     NS_IMETHOD Root(void *n);                                                  \
     NS_IMETHOD Unlink(void *n);                                                \
     NS_IMETHOD Unroot(void *n);                                                \
     NS_IMETHOD Traverse(void *n,                                               \
-                      nsCycleCollectionTraversalCallback &cb);
-
-#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class)                          \
-  class NS_CYCLE_COLLECTION_INNERCLASS                                         \
-   : public nsCycleCollectionParticipant                                       \
-  {                                                                            \
-     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY                                \
+                      nsCycleCollectionTraversalCallback &cb);                 \
   };                                                                           \
-  NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+  static NS_CYCLE_COLLECTION_INNERCLASS                                        \
+      NS_CYCLE_COLLECTION_NATIVE_INNERNAME;
 
-#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(_class)            \
-  class NS_CYCLE_COLLECTION_INNERCLASS                                         \
-   : public nsScriptObjectTracer                                               \
-  {                                                                            \
-    NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY                                 \
-    NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure);         \
-  };                                                                           \
-  NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+#define NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(_class)                          \
+  NS_CYCLE_COLLECTION_CLASSNAME(_class) NS_CYCLE_COLLECTION_NATIVE_NAME(_class);
 
 #define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function)           \
   NS_IMETHODIMP                                                                \
   NS_CYCLE_COLLECTION_CLASSNAME(_class)::Root(void *p)                         \
   {                                                                            \
     _class *tmp = static_cast<_class*>(p);                                     \
     tmp->_root_function();                                                     \
     return NS_OK;                                                              \