Backed out 2 changesets (bug 915757, bug 919885) for xpcshell bustage
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 13 Oct 2013 21:59:58 -0700
changeset 164426 e8bb002bc13ab3149a4b5e9462e275f2fd0e1161
parent 164425 d4e5777ad39d34d75c9684604b348eaa78a4b558
child 164437 4c4dec8506ab4cecbe730b7add710bbf5b3b74fa
child 164467 230e0dbeff0d5998e5bb5394c4f66dfb375e49af
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs915757, 919885
milestone27.0a1
backs out5d17d90b838d71bce624c60ae74e4b98b268b4cb
91495d3a91c8e90d0e06c9deafed658f9bd00b81
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 2 changesets (bug 915757, bug 919885) for xpcshell bustage Backed out changeset 5d17d90b838d (bug 915757) Backed out changeset 91495d3a91c8 (bug 919885)
accessible/src/base/DocManager.cpp
accessible/src/base/nsCoreUtils.cpp
content/base/public/nsContentUtils.h
content/base/public/nsINode.h
content/base/src/Element.cpp
content/base/src/FragmentOrElement.cpp
content/base/src/nsCCUncollectableMarker.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsINode.cpp
content/base/src/nsNodeUtils.cpp
content/base/src/nsXMLHttpRequest.cpp
content/events/public/EventTarget.h
content/events/src/EventTarget.cpp
content/events/src/nsDOMEventTargetHelper.cpp
content/events/src/nsDOMEventTargetHelper.h
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventListenerManager.h
content/events/src/nsEventListenerService.cpp
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsTextEditorState.cpp
content/smil/nsSMILTimeValueSpec.cpp
content/svg/content/src/nsSVGElement.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLService.cpp
content/xul/content/src/nsXULElement.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsWindowRoot.cpp
dom/base/nsWindowRoot.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/test/TestBindingHeader.h
dom/devicestorage/DeviceStorage.h
dom/devicestorage/nsDeviceStorage.cpp
dom/interfaces/events/nsIDOMEventTarget.idl
dom/ipc/TabChild.cpp
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/Worker.webidl
dom/webidl/moz.build
dom/workers/RuntimeService.cpp
dom/workers/RuntimeService.h
dom/workers/SharedWorker.cpp
dom/workers/SharedWorker.h
dom/workers/Worker.cpp
dom/workers/Worker.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.cpp
dom/workers/moz.build
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorEventListener.cpp
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/text/nsPlaintextEditor.cpp
editor/libeditor/text/nsPlaintextEditor.h
embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
layout/base/PositionedEventTargeting.cpp
layout/base/nsPresContext.cpp
--- a/accessible/src/base/DocManager.cpp
+++ b/accessible/src/base/DocManager.cpp
@@ -324,17 +324,17 @@ DocManager::HandleDOMDocumentLoad(nsIDoc
 }
 
 void
 DocManager::AddListeners(nsIDocument* aDocument,
                          bool aAddDOMContentLoadedListener)
 {
   nsPIDOMWindow* window = aDocument->GetWindow();
   EventTarget* target = window->GetChromeEventHandler();
-  nsEventListenerManager* elm = target->GetOrCreateListenerManager();
+  nsEventListenerManager* elm = target->GetListenerManager(true);
   elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
                               dom::TrustedEventsAtCapture());
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate))
     logging::Text("added 'pagehide' listener");
 #endif
 
@@ -354,17 +354,17 @@ DocManager::RemoveListeners(nsIDocument*
   nsPIDOMWindow* window = aDocument->GetWindow();
   if (!window)
     return;
 
   EventTarget* target = window->GetChromeEventHandler();
   if (!target)
     return;
 
-  nsEventListenerManager* elm = target->GetOrCreateListenerManager();
+  nsEventListenerManager* elm = target->GetListenerManager(true);
   elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
                                  dom::TrustedEventsAtCapture());
 
   elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
                                  dom::TrustedEventsAtCapture());
 }
 
 DocAccessible*
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -41,17 +41,17 @@ using namespace mozilla;
 // nsCoreUtils
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
 nsCoreUtils::HasClickListener(nsIContent *aContent)
 {
   NS_ENSURE_TRUE(aContent, false);
   nsEventListenerManager* listenerManager =
-    aContent->GetExistingListenerManager();
+    aContent->GetListenerManager(false);
 
   return listenerManager &&
     (listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
      listenerManager->HasListenersFor(nsGkAtoms::onmousedown) ||
      listenerManager->HasListenersFor(nsGkAtoms::onmouseup));
 }
 
 void
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1055,29 +1055,25 @@ public:
    *
    * @param aNode The node to traverse.
    * @param children The buffer to push a listener manager pointer into.
    */
   static void TraverseListenerManager(nsINode *aNode,
                                       nsCycleCollectionTraversalCallback &cb);
 
   /**
-   * Get the eventlistener manager for aNode, creating it if it does not
-   * already exist.
+   * Get the eventlistener manager for aNode. If a new eventlistener manager
+   * was created, aCreated is set to true.
    *
    * @param aNode The node for which to get the eventlistener manager.
+   * @param aCreateIfNotFound If false, returns a listener manager only if
+   *                          one already exists.
    */
-  static nsEventListenerManager* GetListenerManagerForNode(nsINode* aNode);
-  /**
-   * Get the eventlistener manager for aNode, returning null if it does not
-   * already exist.
-   *
-   * @param aNode The node for which to get the eventlistener manager.
-   */
-  static nsEventListenerManager* GetExistingListenerManagerForNode(const nsINode* aNode);
+  static nsEventListenerManager* GetListenerManager(nsINode* aNode,
+                                                    bool aCreateIfNotFound);
 
   static void UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration);
 
   /**
    * Remove the eventlistener manager for aNode.
    *
    * @param aNode The node for which to remove the eventlistener manager.
    */
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -795,22 +795,16 @@ public:
 #endif
     return node;
   }
 
   /**
    * See nsIDOMEventTarget
    */
   NS_DECL_NSIDOMEVENTTARGET
-
-  virtual nsEventListenerManager*
-  GetExistingListenerManager() const MOZ_OVERRIDE;
-  virtual nsEventListenerManager*
-  GetOrCreateListenerManager() MOZ_OVERRIDE;
-
   using mozilla::dom::EventTarget::RemoveEventListener;
   using nsIDOMEventTarget::AddEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
   using nsIDOMEventTarget::AddSystemEventListener;
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -1805,17 +1805,17 @@ Element::SetMappedAttribute(nsIDocument*
   return false;
 }
 
 nsEventListenerManager*
 Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
                                         bool* aDefer)
 {
   *aDefer = true;
-  return GetOrCreateListenerManager();
+  return GetListenerManager(true);
 }
 
 Element::nsAttrInfo
 Element::GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const
 {
   NS_ASSERTION(nullptr != aName, "must have attribute name");
   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
                "must have a real namespace ID!");
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -1220,17 +1220,17 @@ FragmentOrElement::MarkUserDataHandler(v
 void
 FragmentOrElement::MarkNodeChildren(nsINode* aNode)
 {
   JSObject* o = GetJSObjectChild(aNode);
   if (o) {
     JS::ExposeObjectToActiveJS(o);
   }
 
-  nsEventListenerManager* elm = aNode->GetExistingListenerManager();
+  nsEventListenerManager* elm = aNode->GetListenerManager(false);
   if (elm) {
     elm->MarkForCC();
   }
 
   if (aNode->HasProperties()) {
     nsIDocument* ownerDoc = aNode->OwnerDoc();
     ownerDoc->PropertyTable(DOM_USER_DATA)->
       Enumerate(aNode, FragmentOrElement::MarkUserData,
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -139,17 +139,17 @@ MarkMessageManagers()
         static_cast<nsFrameMessageManager*>(tabMM)->GetCallback();
       if (cb) {
         nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
         EventTarget* et = fl->GetTabChildGlobalAsEventTarget();
         if (!et) {
           continue;
         }
         static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
-        nsEventListenerManager* elm = et->GetExistingListenerManager();
+        nsEventListenerManager* elm = et->GetListenerManager(false);
         if (elm) {
           elm->MarkForCC();
         }
       }
     }
   }
   if (nsFrameMessageManager::sParentProcessManager) {
     nsFrameMessageManager::sParentProcessManager->MarkForCC();
@@ -183,23 +183,23 @@ MarkContentViewer(nsIContentViewer* aVie
     return;
   }
 
   nsIDocument *doc = aViewer->GetDocument();
   if (doc &&
       doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
     doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     if (aCleanupJS) {
-      nsEventListenerManager* elm = doc->GetExistingListenerManager();
+      nsEventListenerManager* elm = doc->GetListenerManager(false);
       if (elm) {
         elm->MarkForCC();
       }
       nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow());
       if (win) {
-        elm = win->GetExistingListenerManager();
+        elm = win->GetListenerManager(false);
         if (elm) {
           elm->MarkForCC();
         }
         static_cast<nsGlobalWindow*>(win.get())->UnmarkGrayTimers();
       }
 
       doc->PropertyTable(DOM_USER_DATA_HANDLER)->
         EnumerateAll(MarkUserDataHandler, &nsCCUncollectableMarker::sGeneration);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3625,28 +3625,28 @@ nsContentUtils::HasMutationListeners(nsI
   }
 
   doc->MayDispatchMutationEvent(aTargetForSubtreeModified);
 
   // If we have a window, we can check it for mutation listeners now.
   if (aNode->IsInDoc()) {
     nsCOMPtr<EventTarget> piTarget(do_QueryInterface(window));
     if (piTarget) {
-      nsEventListenerManager* manager = piTarget->GetExistingListenerManager();
+      nsEventListenerManager* manager = piTarget->GetListenerManager(false);
       if (manager && manager->HasMutationListeners()) {
         return true;
       }
     }
   }
 
   // If we have a window, we know a mutation listener is registered, but it
   // might not be in our chain.  If we don't have a window, we might have a
   // mutation listener.  Check quickly to see.
   while (aNode) {
-    nsEventListenerManager* manager = aNode->GetExistingListenerManager();
+    nsEventListenerManager* manager = aNode->GetListenerManager(false);
     if (manager && manager->HasMutationListeners()) {
       return true;
     }
 
     if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
       nsIContent* content = static_cast<nsIContent*>(aNode);
       nsIContent* insertionParent = content->GetXBLInsertionParent();
       if (insertionParent) {
@@ -3758,25 +3758,41 @@ nsContentUtils::TraverseListenerManager(
                                         PL_DHASH_LOOKUP));
   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     CycleCollectionNoteChild(cb, entry->mListenerManager.get(),
                              "[via hash] mListenerManager");
   }
 }
 
 nsEventListenerManager*
-nsContentUtils::GetListenerManagerForNode(nsINode *aNode)
-{
+nsContentUtils::GetListenerManager(nsINode *aNode,
+                                   bool aCreateIfNotFound)
+{
+  if (!aCreateIfNotFound && !aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
+    return nullptr;
+  }
+  
   if (!sEventListenerManagersHash.ops) {
     // We're already shut down, don't bother creating an event listener
     // manager.
 
     return nullptr;
   }
 
+  if (!aCreateIfNotFound) {
+    EventListenerManagerMapEntry *entry =
+      static_cast<EventListenerManagerMapEntry *>
+                 (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
+                                          PL_DHASH_LOOKUP));
+    if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
+      return entry->mListenerManager;
+    }
+    return nullptr;
+  }
+
   EventListenerManagerMapEntry *entry =
     static_cast<EventListenerManagerMapEntry *>
                (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
                                         PL_DHASH_ADD));
 
   if (!entry) {
     return nullptr;
   }
@@ -3785,41 +3801,16 @@ nsContentUtils::GetListenerManagerForNod
     entry->mListenerManager = new nsEventListenerManager(aNode);
 
     aNode->SetFlags(NODE_HAS_LISTENERMANAGER);
   }
 
   return entry->mListenerManager;
 }
 
-nsEventListenerManager*
-nsContentUtils::GetExistingListenerManagerForNode(const nsINode *aNode)
-{
-  if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
-    return nullptr;
-  }
-  
-  if (!sEventListenerManagersHash.ops) {
-    // We're already shut down, don't bother creating an event listener
-    // manager.
-
-    return nullptr;
-  }
-
-  EventListenerManagerMapEntry *entry =
-    static_cast<EventListenerManagerMapEntry *>
-               (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
-                                        PL_DHASH_LOOKUP));
-  if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
-    return entry->mListenerManager;
-  }
-
-  return nullptr;
-}
-
 /* static */
 void
 nsContentUtils::RemoveListenerManager(nsINode *aNode)
 {
   if (sEventListenerManagersHash.ops) {
     EventListenerManagerMapEntry *entry =
       static_cast<EventListenerManagerMapEntry *>
                  (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1654,17 +1654,17 @@ nsDocument::Release()
 NS_IMETHODIMP_(void)
 nsDocument::DeleteCycleCollectable()
 {
   delete this;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
   if (Element::CanSkip(tmp, aRemovingAllowed)) {
-    nsEventListenerManager* elm = tmp->GetExistingListenerManager();
+    nsEventListenerManager* elm = tmp->GetListenerManager(false);
     if (elm) {
       elm->MarkForCC();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument)
@@ -6961,33 +6961,27 @@ nsDocument::GetViewportInfo(const Screen
     }
 
     return nsViewportInfo(scaleFloat, scaleMinFloat, scaleMaxFloat, size,
                           mAutoSize, mAllowZoom);
   }
 }
 
 nsEventListenerManager*
-nsDocument::GetOrCreateListenerManager()
-{
-  if (!mListenerManager) {
+nsDocument::GetListenerManager(bool aCreateIfNotFound)
+{
+  if (!mListenerManager && aCreateIfNotFound) {
     mListenerManager =
       new nsEventListenerManager(static_cast<EventTarget*>(this));
     SetFlags(NODE_HAS_LISTENERMANAGER);
   }
 
   return mListenerManager;
 }
 
-nsEventListenerManager*
-nsDocument::GetExistingListenerManager() const
-{
-  return mListenerManager;
-}
-
 nsresult
 nsDocument::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
    // FIXME! This is a hack to make middle mouse paste working also in Editor.
    // Bug 329119
   aVisitor.mForceContentDispatch = true;
 
@@ -7671,17 +7665,18 @@ nsDocument::CanSavePresentation(nsIReque
   nsPIDOMWindow* win = GetInnerWindow();
   if (win && win->TimeoutSuspendCount()) {
     return false;
   }
 
   // Check our event listener manager for unload/beforeunload listeners.
   nsCOMPtr<EventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
   if (piTarget) {
-    nsEventListenerManager* manager = piTarget->GetExistingListenerManager();
+    nsEventListenerManager* manager =
+      piTarget->GetListenerManager(false);
     if (manager && manager->HasUnloadListeners()) {
       return false;
     }
   }
 
   // Check if we have pending network requests
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
   if (loadGroup) {
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -768,18 +768,18 @@ public:
   // nsIDOMXMLDocument
   NS_DECL_NSIDOMXMLDOCUMENT
 
   // nsIDOMDocumentXBL
   NS_DECL_NSIDOMDOCUMENTXBL
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
-  virtual nsEventListenerManager* GetOrCreateListenerManager() MOZ_OVERRIDE;
-  virtual nsEventListenerManager* GetExistingListenerManager() const MOZ_OVERRIDE;
+  virtual nsEventListenerManager*
+    GetListenerManager(bool aCreateIfNotFound) MOZ_OVERRIDE;
 
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal() MOZ_OVERRIDE;
 
   // nsIApplicationCacheContainer
   NS_DECL_NSIAPPLICATIONCACHECONTAINER
 
   // nsIObserver
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -1033,17 +1033,17 @@ nsINode::AddEventListener(const nsAStrin
                "explicit by making aOptionalArgc non-zero.");
 
   if (!aWantsUntrusted &&
       (aOptionalArgc < 2 &&
        !nsContentUtils::IsChromeDoc(OwnerDoc()))) {
     aWantsUntrusted = true;
   }
 
-  nsEventListenerManager* listener_manager = GetOrCreateListenerManager();
+  nsEventListenerManager* listener_manager = GetListenerManager(true);
   NS_ENSURE_STATE(listener_manager);
   listener_manager->AddEventListener(aType, aListener, aUseCapture,
                                      aWantsUntrusted);
   return NS_OK;
 }
 
 void
 nsINode::AddEventListener(const nsAString& aType,
@@ -1054,17 +1054,17 @@ nsINode::AddEventListener(const nsAStrin
 {
   bool wantsUntrusted;
   if (aWantsUntrusted.IsNull()) {
     wantsUntrusted = !nsContentUtils::IsChromeDoc(OwnerDoc());
   } else {
     wantsUntrusted = aWantsUntrusted.Value();
   }
 
-  nsEventListenerManager* listener_manager = GetOrCreateListenerManager();
+  nsEventListenerManager* listener_manager = GetListenerManager(true);
   if (!listener_manager) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   listener_manager->AddEventListener(aType, aListener, aUseCapture,
                                      wantsUntrusted);
 }
 
@@ -1090,17 +1090,17 @@ nsINode::AddSystemEventListener(const ns
                                    aWantsUntrusted);
 }
 
 NS_IMETHODIMP
 nsINode::RemoveEventListener(const nsAString& aType,
                              nsIDOMEventListener* aListener,
                              bool aUseCapture)
 {
-  nsEventListenerManager* elm = GetExistingListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(false);
   if (elm) {
     elm->RemoveEventListener(aType, aListener, aUseCapture);
   }
   return NS_OK;
 }
 
 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
 
@@ -1152,25 +1152,19 @@ nsINode::DispatchDOMEvent(WidgetEvent* a
                           nsPresContext* aPresContext,
                           nsEventStatus* aEventStatus)
 {
   return nsEventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
                                              aPresContext, aEventStatus);
 }
 
 nsEventListenerManager*
-nsINode::GetOrCreateListenerManager()
+nsINode::GetListenerManager(bool aCreateIfNotFound)
 {
-  return nsContentUtils::GetListenerManagerForNode(this);
-}
-
-nsEventListenerManager*
-nsINode::GetExistingListenerManager() const
-{
-  return nsContentUtils::GetExistingListenerManagerForNode(this);
+  return nsContentUtils::GetListenerManager(this, aCreateIfNotFound);
 }
 
 nsIScriptContext*
 nsINode::GetContextForEventHandlers(nsresult* aRv)
 {
   return nsContentUtils::GetContextForEventHandlers(this, aRv);
 }
 
@@ -2165,17 +2159,18 @@ nsINode::GetBoundMutationObservers(nsTAr
     }
   }
 }
 
 size_t
 nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
-  nsEventListenerManager* elm = GetExistingListenerManager();
+  nsEventListenerManager* elm =
+    const_cast<nsINode*>(this)->GetListenerManager(false);
   if (elm) {
     n += elm->SizeOfIncludingThis(aMallocSizeOf);
   }
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mNodeInfo
   // - mSlots
@@ -2183,23 +2178,23 @@ nsINode::SizeOfExcludingThis(MallocSizeO
   // The following members are not measured:
   // - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're
   //   non-owning
   return n;
 }
 
 #define EVENT(name_, id_, type_, struct_)                                    \
   EventHandlerNonNull* nsINode::GetOn##name_() {                             \
-    nsEventListenerManager *elm = GetExistingListenerManager();              \
+    nsEventListenerManager *elm = GetListenerManager(false);                 \
     return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString())   \
                : nullptr;                                                    \
   }                                                                          \
   void nsINode::SetOn##name_(EventHandlerNonNull* handler)                   \
   {                                                                          \
-    nsEventListenerManager *elm = GetOrCreateListenerManager();              \
+    nsEventListenerManager *elm = GetListenerManager(true);                  \
     if (elm) {                                                               \
       elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler);    \
     }                                                                        \
   }                                                                          \
   NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, JS::Value *vp) {        \
     EventHandlerNonNull* h = GetOn##name_();                                 \
     vp->setObjectOrNull(h ? h->Callable().get() : nullptr);                  \
     return NS_OK;                                                            \
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -226,17 +226,17 @@ nsNodeUtils::LastRelease(nsINode* aNode)
   }
   aNode->UnsetFlags(NODE_HAS_PROPERTIES);
 
   if (aNode->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
       aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
 #ifdef DEBUG
     if (nsContentUtils::IsInitialized()) {
       nsEventListenerManager* manager =
-        nsContentUtils::GetExistingListenerManagerForNode(aNode);
+        nsContentUtils::GetListenerManager(aNode, false);
       if (!manager) {
         NS_ERROR("Huh, our bit says we have a listener manager list, "
                  "but there's nothing in the hash!?!!");
       }
     }
 #endif
 
     nsContentUtils::RemoveListenerManager(aNode);
@@ -475,17 +475,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       // XXX what if oldDoc is null, we don't know if this should be
       // registered or not! Can that really happen?
       if (wasRegistered) {
         newDoc->RegisterFreezableElement(aNode->AsElement());
       }
 
       nsPIDOMWindow* window = newDoc->GetInnerWindow();
       if (window) {
-        nsEventListenerManager* elm = aNode->GetExistingListenerManager();
+        nsEventListenerManager* elm = aNode->GetListenerManager(false);
         if (elm) {
           window->SetMutationListeners(elm->MutationListenerBits());
           if (elm->MayHavePaintEventListener()) {
             window->SetHasPaintEventListeners();
           }
           if (elm->MayHaveAudioAvailableEventListener()) {
             window->SetHasAudioAvailableEventListeners();
           }
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2167,18 +2167,17 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
   if (!mResponseXML) {
     ChangeStateToDone();
     return NS_OK;
   }
   if (mIsHtml) {
     NS_ASSERTION(!(mState & XML_HTTP_REQUEST_SYNCLOOPING),
       "We weren't supposed to support HTML parsing with XHR!");
     nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(mResponseXML);
-    nsEventListenerManager* manager =
-      eventTarget->GetOrCreateListenerManager();
+    nsEventListenerManager* manager = eventTarget->GetListenerManager(true);
     manager->AddEventListenerByType(new nsXHRParseEndListener(this),
                                     NS_LITERAL_STRING("DOMContentLoaded"),
                                     dom::TrustedEventsAtSystemGroupBubble());
     return NS_OK;
   }
   // We might have been sent non-XML data. If that was the case,
   // we should null out the document member. The idea in this
   // check here is that if there is no document element it is not
--- a/content/events/public/EventTarget.h
+++ b/content/events/public/EventTarget.h
@@ -21,18 +21,18 @@ class ErrorResult;
 namespace dom {
 
 class EventListener;
 class EventHandlerNonNull;
 template <class T> struct Nullable;
 
 // IID for the dom::EventTarget interface
 #define NS_EVENTTARGET_IID \
-{ 0xce3817d0, 0x177b, 0x402f, \
- { 0xae, 0x75, 0xf8, 0x4e, 0xbe, 0x5a, 0x07, 0xc3 } }
+{ 0x0a5aed21, 0x0bab, 0x48b3, \
+ { 0xbe, 0x4b, 0xd4, 0xf9, 0xd4, 0xea, 0xc7, 0xdb } }
 
 class EventTarget : public nsIDOMEventTarget,
                     public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_EVENTTARGET_IID)
 
   // WebIDL API
@@ -65,27 +65,16 @@ public:
   virtual void EventListenerAdded(nsIAtom* aType) {}
   virtual void EventListenerRemoved(nsIAtom* aType) {}
 
   // Returns an outer window that corresponds to the inner window this event
   // target is associated with.  Will return null if the inner window is not the
   // current inner or if there is no window around at all.
   virtual nsIDOMWindow* GetOwnerGlobal() = 0;
 
-  /**
-   * Get the event listener manager, creating it if it does not already exist.
-   */
-  virtual nsEventListenerManager* GetOrCreateListenerManager() = 0;
-
-  /**
-   * Get the event listener manager, returning null if it does not already
-   * exist.
-   */
-  virtual nsEventListenerManager* GetExistingListenerManager() const = 0;
-
 protected:
   EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
                                        const nsAString& aTypeString);
   void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
                        EventHandlerNonNull* aHandler);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)
--- a/content/events/src/EventTarget.cpp
+++ b/content/events/src/EventTarget.cpp
@@ -11,26 +11,26 @@ namespace mozilla {
 namespace dom {
 
 void
 EventTarget::RemoveEventListener(const nsAString& aType,
                                  EventListener* aListener,
                                  bool aUseCapture,
                                  ErrorResult& aRv)
 {
-  nsEventListenerManager* elm = GetExistingListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(false);
   if (elm) {
     elm->RemoveEventListener(aType, aListener, aUseCapture);
   }
 }
 
 EventHandlerNonNull*
 EventTarget::GetEventHandler(nsIAtom* aType, const nsAString& aTypeString)
 {
-  nsEventListenerManager* elm = GetExistingListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(false);
   return elm ? elm->GetEventHandler(aType, aTypeString) : nullptr;
 }
 
 void
 EventTarget::SetEventHandler(const nsAString& aType,
                              EventHandlerNonNull* aHandler,
                              ErrorResult& aRv)
 {
@@ -47,13 +47,13 @@ EventTarget::SetEventHandler(const nsASt
                   Substring(aType, 2), // Remove "on"
                   aHandler);
 }
 
 void
 EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
                              EventHandlerNonNull* aHandler)
 {
-  GetOrCreateListenerManager()->SetEventHandler(aType, aTypeString, aHandler);
+  GetListenerManager(true)->SetEventHandler(aType, aTypeString, aHandler);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -149,17 +149,17 @@ nsDOMEventTargetHelper::DisconnectFromOw
   }
 }
 
 NS_IMETHODIMP
 nsDOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
                                             nsIDOMEventListener* aListener,
                                             bool aUseCapture)
 {
-  nsEventListenerManager* elm = GetExistingListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(false);
   if (elm) {
     elm->RemoveEventListener(aType, aListener, aUseCapture);
   }
 
   return NS_OK;
 }
 
 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsDOMEventTargetHelper)
@@ -176,17 +176,17 @@ nsDOMEventTargetHelper::AddEventListener
                "aWantsUntrusted to false or make the aWantsUntrusted "
                "explicit by making aOptionalArgc non-zero.");
 
   if (aOptionalArgc < 2) {
     nsresult rv = WantsUntrusted(&aWantsUntrusted);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsEventListenerManager* elm = GetOrCreateListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(true);
   NS_ENSURE_STATE(elm);
   elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
   return NS_OK;
 }
 
 void
 nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
                                          EventListener* aListener,
@@ -200,17 +200,17 @@ nsDOMEventTargetHelper::AddEventListener
     if (NS_FAILED(rv)) {
       aRv.Throw(rv);
       return;
     }
   } else {
     wantsUntrusted = aWantsUntrusted.Value();
   }
 
-  nsEventListenerManager* elm = GetOrCreateListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(true);
   if (!elm) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
 }
 
 NS_IMETHODIMP
@@ -314,31 +314,25 @@ nsDOMEventTargetHelper::DispatchDOMEvent
                                          nsEventStatus* aEventStatus)
 {
   return
     nsEventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent, aPresContext,
                                         aEventStatus);
 }
 
 nsEventListenerManager*
-nsDOMEventTargetHelper::GetOrCreateListenerManager()
+nsDOMEventTargetHelper::GetListenerManager(bool aCreateIfNotFound)
 {
-  if (!mListenerManager) {
+  if (!mListenerManager && aCreateIfNotFound) {
     mListenerManager = new nsEventListenerManager(this);
   }
 
   return mListenerManager;
 }
 
-nsEventListenerManager*
-nsDOMEventTargetHelper::GetExistingListenerManager() const
-{
-  return mListenerManager;
-}
-
 nsIScriptContext*
 nsDOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
 {
   *aRv = CheckInnerWindowCorrectness();
   if (NS_FAILED(*aRv)) {
     return nullptr;
   }
   nsPIDOMWindow* owner = GetOwner();
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -39,22 +39,16 @@ public:
     SetIsDOMBinding();
   }
 
   virtual ~nsDOMEventTargetHelper();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsDOMEventTargetHelper)
 
   NS_DECL_NSIDOMEVENTTARGET
-
-  virtual nsEventListenerManager*
-  GetExistingListenerManager() const MOZ_OVERRIDE;
-  virtual nsEventListenerManager*
-  GetOrCreateListenerManager() MOZ_OVERRIDE;
-
   using mozilla::dom::EventTarget::RemoveEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMEVENTTARGETHELPER_IID)
@@ -220,35 +214,24 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMEvent
     return _to WillHandleEvent(aVisitor); \
   } \
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor & aVisitor) { \
     return _to PostHandleEvent(aVisitor); \
   } \
   virtual nsresult DispatchDOMEvent(mozilla::WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent, nsPresContext* aPresContext, nsEventStatus* aEventStatus) { \
     return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); \
   } \
-  virtual nsEventListenerManager * GetOrCreateListenerManager() { \
-    return _to GetOrCreateListenerManager(); \
-  } \
-  virtual nsEventListenerManager * GetExistingListenerManager() const { \
-    return _to GetExistingListenerManager(); \
+  virtual nsEventListenerManager * GetListenerManager(bool aMayCreate) { \
+    return _to GetListenerManager(aMayCreate); \
   } \
   virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv) { \
     return _to GetContextForEventHandlers(aRv); \
   } \
   virtual JSContext * GetJSContextForEventHandlers(void) { \
     return _to GetJSContextForEventHandlers(); \
   }
 
 #define NS_REALLY_FORWARD_NSIDOMEVENTTARGET(_class) \
   using _class::AddEventListener;                   \
   using _class::RemoveEventListener;                \
-  NS_FORWARD_NSIDOMEVENTTARGET(_class::)            \
-  virtual nsEventListenerManager*                   \
-  GetOrCreateListenerManager() {                    \
-    return _class::GetOrCreateListenerManager();    \
-  }                                                 \
-  virtual nsEventListenerManager*                   \
-  GetExistingListenerManager() const {              \
-    return _class::GetExistingListenerManager();    \
-  }
+  NS_FORWARD_NSIDOMEVENTTARGET(_class::)
 
 #endif // nsDOMEventTargetHelper_h_
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -180,17 +180,18 @@ public:
     }
     if (aVisitor.mEvent->mFlags.mPropagationStopped) {
       return NS_OK;
     }
     if (!mManager) {
       if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
         return NS_OK;
       }
-      mManager = mTarget->GetExistingListenerManager();
+      mManager =
+        static_cast<nsEventListenerManager*>(mTarget->GetListenerManager(false));
     }
     if (mManager) {
       NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
                    "CurrentTarget should be null!");
       mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
                             &aVisitor.mDOMEvent,
                             CurrentTarget(),
                             &aVisitor.mEventStatus,
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -555,18 +555,17 @@ protected:
  */
 inline nsresult
 NS_AddSystemEventListener(mozilla::dom::EventTarget* aTarget,
                           const nsAString& aType,
                           nsIDOMEventListener *aListener,
                           bool aUseCapture,
                           bool aWantsUntrusted)
 {
-  nsEventListenerManager* listenerManager =
-    aTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* listenerManager = aTarget->GetListenerManager(true);
   NS_ENSURE_STATE(listenerManager);
   mozilla::dom::EventListenerFlags flags;
   flags.mInSystemGroup = true;
   flags.mCapture = aUseCapture;
   flags.mAllowUntrustedEvents = aWantsUntrusted;
   listenerManager->AddEventListenerByType(aListener, aType, flags);
   return NS_OK;
 }
--- a/content/events/src/nsEventListenerService.cpp
+++ b/content/events/src/nsEventListenerService.cpp
@@ -157,21 +157,18 @@ NS_IMETHODIMP
 nsEventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
                                            uint32_t* aCount,
                                            nsIEventListenerInfo*** aOutArray)
 {
   NS_ENSURE_ARG_POINTER(aEventTarget);
   *aCount = 0;
   *aOutArray = nullptr;
   nsCOMArray<nsIEventListenerInfo> listenerInfos;
-
-  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget);
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
-
-  nsEventListenerManager* elm = eventTarget->GetExistingListenerManager();
+  nsEventListenerManager* elm =
+    aEventTarget->GetListenerManager(false);
   if (elm) {
     elm->GetListenerInfo(&listenerInfos);
   }
 
   int32_t count = listenerInfos.Count();
   if (count == 0) {
     return NS_OK;
   }
@@ -219,37 +216,31 @@ nsEventListenerService::GetEventTargetCh
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget,
                                         const nsAString& aType,
                                         bool* aRetVal)
 {
-  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget);
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
-
-  nsEventListenerManager* elm = eventTarget->GetExistingListenerManager();
+  nsEventListenerManager* elm = aEventTarget->GetListenerManager(false);
   *aRetVal = elm && elm->HasListenersFor(aType);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget,
                                                const nsAString& aType,
                                                nsIDOMEventListener* aListener,
                                                bool aUseCapture)
 {
   NS_PRECONDITION(aTarget, "Missing target");
   NS_PRECONDITION(aListener, "Missing listener");
 
-  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
-
-  nsEventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* manager = aTarget->GetListenerManager(true);
   NS_ENSURE_STATE(manager);
 
   EventListenerFlags flags =
     aUseCapture ? TrustedEventsAtSystemGroupCapture() :
                   TrustedEventsAtSystemGroupBubble();
   manager->AddEventListenerByType(aListener, aType, flags);
   return NS_OK;
 }
@@ -258,20 +249,17 @@ NS_IMETHODIMP
 nsEventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget,
                                                   const nsAString& aType,
                                                   nsIDOMEventListener* aListener,
                                                   bool aUseCapture)
 {
   NS_PRECONDITION(aTarget, "Missing target");
   NS_PRECONDITION(aListener, "Missing listener");
 
-  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
-
-  nsEventListenerManager* manager = eventTarget->GetExistingListenerManager();
+  nsEventListenerManager* manager = aTarget->GetListenerManager(false);
   if (manager) {
     EventListenerFlags flags =
       aUseCapture ? TrustedEventsAtSystemGroupCapture() :
                     TrustedEventsAtSystemGroupBubble();
     manager->RemoveEventListenerByType(aListener, aType, flags);
   }
 
   return NS_OK;
@@ -280,39 +268,31 @@ nsEventListenerService::RemoveSystemEven
 NS_IMETHODIMP
 nsEventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget,
                                                 nsIDOMEventListener* aListener,
                                                 bool aUseCapture,
                                                 bool aWantsUntrusted,
                                                 bool aSystemEventGroup)
 {
   NS_ENSURE_STATE(aTarget && aListener);
-
-  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
-
-  nsEventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* manager = aTarget->GetListenerManager(true);
   NS_ENSURE_STATE(manager);
   manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted,
                                aSystemEventGroup);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget,
                                                    nsIDOMEventListener* aListener,
                                                    bool aUseCapture,
                                                    bool aSystemEventGroup)
 {
   NS_ENSURE_STATE(aTarget && aListener);
-
-  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
-
-  nsEventListenerManager* manager = eventTarget->GetExistingListenerManager();
+  nsEventListenerManager* manager = aTarget->GetListenerManager(false);
   if (manager) {
     manager->RemoveListenerForAllEvents(aListener, aUseCapture, aSystemEventGroup);
   }
   return NS_OK;
 }
 
 nsresult
 NS_NewEventListenerService(nsIEventListenerService** aResult)
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -837,17 +837,17 @@ nsGenericHTMLElement::GetEventListenerMa
     // XXXbz sXBL/XBL2 issue: should we instead use GetCurrentDoc() here,
     // override BindToTree for those classes and munge event listeners there?
     nsIDocument *document = OwnerDoc();
 
     *aDefer = false;
     if ((win = document->GetInnerWindow())) {
       nsCOMPtr<EventTarget> piTarget(do_QueryInterface(win));
 
-      return piTarget->GetOrCreateListenerManager();
+      return piTarget->GetListenerManager(true);
     }
 
     return nullptr;
   }
 
   return nsGenericHTMLElementBase::GetEventListenerManagerForAttr(aAttrName,
                                                                   aDefer);
 }
@@ -1004,17 +1004,18 @@ nsGenericHTMLElement::UnsetAttr(int32_t 
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else if (aAttribute == nsGkAtoms::accesskey) {
       // Have to unregister before clearing flag. See UnregAccessKey
       UnregAccessKey();
       UnsetFlags(NODE_HAS_ACCESSKEY);
     }
     else if (IsEventAttributeName(aAttribute)) {
-      if (nsEventListenerManager* manager = GetExistingListenerManager()) {
+      nsEventListenerManager* manager = GetListenerManager(false);
+      if (manager) {
         manager->RemoveEventHandler(aAttribute, EmptyString());
       }
     }
   }
 
   nsresult rv = nsGenericHTMLElementBase::UnsetAttr(aNameSpaceID, aAttribute,
                                                     aNotify);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1557,17 +1557,18 @@ nsTextEditorState::UnbindFromFrame(nsTex
     mSelCon = nullptr;
   }
 
   if (mTextListener)
   {
     mTextListener->SetFrame(nullptr);
 
     nsCOMPtr<EventTarget> target = do_QueryInterface(mTextCtrlElement);
-    nsEventListenerManager* manager = target->GetExistingListenerManager();
+    nsEventListenerManager* manager =
+      target->GetListenerManager(false);
     if (manager) {
       manager->RemoveEventListenerByType(mTextListener,
         NS_LITERAL_STRING("keydown"),
         dom::TrustedEventsAtSystemGroupBubble());
       manager->RemoveEventListenerByType(mTextListener,
         NS_LITERAL_STRING("keypress"),
         dom::TrustedEventsAtSystemGroupBubble());
       manager->RemoveEventListenerByType(mTextListener,
@@ -1964,17 +1965,17 @@ nsTextEditorState::SetValue(const nsAStr
   mTextCtrlElement->OnValueChanged(!!mRootNode);
 }
 
 void
 nsTextEditorState::InitializeKeyboardEventListeners()
 {
   //register key listeners
   nsCOMPtr<EventTarget> target = do_QueryInterface(mTextCtrlElement);
-  nsEventListenerManager* manager = target->GetOrCreateListenerManager();
+  nsEventListenerManager* manager = target->GetListenerManager(true);
   if (manager) {
     manager->AddEventListenerByType(mTextListener,
                                     NS_LITERAL_STRING("keydown"),
                                     dom::TrustedEventsAtSystemGroupBubble());
     manager->AddEventListenerByType(mTextListener,
                                     NS_LITERAL_STRING("keypress"),
                                     dom::TrustedEventsAtSystemGroupBubble());
     manager->AddEventListenerByType(mTextListener,
--- a/content/smil/nsSMILTimeValueSpec.cpp
+++ b/content/smil/nsSMILTimeValueSpec.cpp
@@ -367,17 +367,17 @@ nsSMILTimeValueSpec::GetEventListenerMan
       return nullptr;
     target = do_QueryInterface(win);
   } else {
     target = aTarget;
   }
   if (!target)
     return nullptr;
 
-  return target->GetOrCreateListenerManager();
+  return target->GetListenerManager(true);
 }
 
 void
 nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent)
 {
   NS_ABORT_IF_FALSE(mEventListener, "Got event without an event listener");
   NS_ABORT_IF_FALSE(IsEventBased(),
                     "Got event for non-event nsSMILTimeValueSpec");
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -659,17 +659,17 @@ nsSVGElement::UnsetAttrInternal(int32_t 
   // Maybe consolidate?
 
   if (aNamespaceID == kNameSpaceID_None) {
     // If this is an svg presentation attribute, remove rule to force an update
     if (IsAttributeMapped(aName))
       mContentStyleRule = nullptr;
 
     if (IsEventAttributeName(aName)) {
-      nsEventListenerManager* manager = GetExistingListenerManager();
+      nsEventListenerManager* manager = GetListenerManager(false);
       if (manager) {
         nsIAtom* eventName = GetEventNameForAttr(aName);
         manager->RemoveEventHandler(eventName, EmptyString());
       }
       return;
     }
     
     // Check if this is a length attribute going away
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -493,17 +493,18 @@ void
 nsXBLBinding::InstallEventHandlers()
 {
   // Don't install handlers if scripts aren't allowed.
   if (AllowScripts()) {
     // Fetch the handlers prototypes for this binding.
     nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
 
     if (handlerChain) {
-      nsEventListenerManager* manager = mBoundElement->GetOrCreateListenerManager();
+      nsEventListenerManager* manager =
+        mBoundElement->GetListenerManager(true);
       if (!manager)
         return;
 
       bool isChromeDoc =
         nsContentUtils::IsChromeDoc(mBoundElement->OwnerDoc());
       bool isChromeBinding = mPrototypeBinding->IsChrome();
       nsXBLPrototypeHandler* curr;
       for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
@@ -642,17 +643,17 @@ nsXBLBinding::ExecuteDetachedHandler()
 
 void
 nsXBLBinding::UnhookEventHandlers()
 {
   nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
 
   if (handlerChain) {
     nsEventListenerManager* manager =
-      mBoundElement->GetExistingListenerManager();
+      mBoundElement->GetListenerManager(false);
     if (!manager) {
       return;
     }
                                       
     bool isChromeBinding = mPrototypeBinding->IsChrome();
     nsXBLPrototypeHandler* curr;
     for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
       nsXBLEventHandler* handler = curr->GetCachedEventHandler();
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -556,17 +556,17 @@ nsXBLService::AttachGlobalKeyHandler(Eve
   nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
   if (contentNode) {
     // Only attach if we're really in a document
     nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
     if (doc)
       piTarget = doc; // We're a XUL keyset. Attach to our document.
   }
 
-  nsEventListenerManager* manager = piTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* manager = piTarget->GetListenerManager(true);
 
   if (!piTarget || !manager)
     return NS_ERROR_FAILURE;
 
   // the listener already exists, so skip this
   if (contentNode && contentNode->GetProperty(nsGkAtoms::listener))
     return NS_OK;
 
@@ -606,17 +606,17 @@ nsXBLService::DetachGlobalKeyHandler(Eve
   if (!contentNode) // detaching is only supported for content nodes
     return NS_ERROR_FAILURE;
 
   // Only attach if we're really in a document
   nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
   if (doc)
     piTarget = do_QueryInterface(doc);
 
-  nsEventListenerManager* manager = piTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* manager = piTarget->GetListenerManager(true);
 
   if (!piTarget || !manager)
     return NS_ERROR_FAILURE;
 
   nsIDOMEventListener* handler =
     static_cast<nsIDOMEventListener*>(contentNode->GetProperty(nsGkAtoms::listener));
   if (!handler)
     return NS_ERROR_FAILURE;
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -491,17 +491,17 @@ nsXULElement::GetEventListenerManagerFor
     nsPIDOMWindow *window;
     Element *root = doc->GetRootElement();
     if ((!root || root == this) && !mNodeInfo->Equals(nsGkAtoms::overlay) &&
         (window = doc->GetInnerWindow())) {
 
         nsCOMPtr<EventTarget> piTarget = do_QueryInterface(window);
 
         *aDefer = false;
-        return piTarget->GetOrCreateListenerManager();
+        return piTarget->GetListenerManager(true);
     }
 
     return nsStyledElement::GetEventListenerManagerForAttr(aAttrName, aDefer);
 }
 
 // returns true if the element is not a list
 static bool IsNonList(nsINodeInfo* aNodeInfo)
 {
@@ -1666,17 +1666,17 @@ nsXULElement::AddPopupListener(nsIAtom* 
     if (HasFlag(listenerFlag)) {
         return NS_OK;
     }
 
     nsCOMPtr<nsIDOMEventListener> listener =
       new nsXULPopupListener(this, isContext);
 
     // Add the popup as a listener on this element.
-    nsEventListenerManager* manager = GetOrCreateListenerManager();
+    nsEventListenerManager* manager = GetListenerManager(true);
     SetFlags(listenerFlag);
 
     if (isContext) {
       manager->AddEventListenerByType(listener,
                                       NS_LITERAL_STRING("contextmenu"),
                                       dom::TrustedEventsAtSystemGroupBubble());
     } else {
       manager->AddEventListenerByType(listener,
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -136,16 +136,19 @@
 
 // Storage includes
 #include "nsIDOMStorage.h"
 #include "nsPIDOMStorage.h"
 
 // Drag and drop
 #include "nsIDOMDataTransfer.h"
 
+// Workers
+#include "mozilla/dom/workers/Workers.h"
+
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
 
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 #include "nsIDOMMediaQueryList.h"
 
 #include "nsDOMTouchEvent.h"
@@ -186,16 +189,17 @@
 #include "nsIInterfaceInfoManager.h"
 
 #ifdef MOZ_TIME_MANAGER
 #include "TimeManager.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using mozilla::dom::workers::ResolveWorkerClasses;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
 //       are defined in nsIDOMClassInfo.h.
 
 #define WINDOW_SCRIPTABLE_FLAGS                                               \
  (nsIXPCScriptable::WANT_PRECREATE |                                          \
@@ -3596,16 +3600,26 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
                                JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
     *objp = obj;
 
     return NS_OK;
   }
 
+  // Handle resolving if id refers to a name resolved by DOM worker code.
+  JS::RootedObject tmp(cx, NULL);
+  if (!ResolveWorkerClasses(cx, obj, id, flags, &tmp)) {
+    return NS_ERROR_FAILURE;
+  }
+  if (tmp) {
+    *objp = tmp;
+    return NS_OK;
+  }
+
   // Check for names managed by the script namespace manager.  Call
   // GlobalResolve() after we call FindChildWithName() so that named child
   // frames will override external properties which have been registered with
   // the script namespace manager -- pages must be able to depend on frame
   // names working no matter how Gecko's been configured.
   bool did_resolve = false;
   nsresult rv = GlobalResolve(win, cx, obj, id, &did_resolve);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1565,17 +1565,18 @@ MarkXBLHandlers(nsXBLPrototypeHandler* a
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
   if (tmp->IsBlackForCC()) {
     if (tmp->mCachedXBLPrototypeHandlers) {
       tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
     }
-    if (nsEventListenerManager* elm = tmp->GetExistingListenerManager()) {
+    nsEventListenerManager* elm = tmp->GetListenerManager(false);
+    if (elm) {
       elm->MarkForCC();
     }
     tmp->UnmarkGrayTimers();
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
@@ -8059,17 +8060,18 @@ nsGlobalWindow::Btoa(const nsAString& aB
 // nsGlobalWindow::nsIDOMEventTarget
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
                                     nsIDOMEventListener* aListener,
                                     bool aUseCapture)
 {
-  if (nsRefPtr<nsEventListenerManager> elm = GetExistingListenerManager()) {
+  nsRefPtr<nsEventListenerManager> elm = GetListenerManager(false);
+  if (elm) {
     elm->RemoveEventListener(aType, aListener, aUseCapture);
   }
   return NS_OK;
 }
 
 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
 
 NS_IMETHODIMP
@@ -8114,17 +8116,17 @@ nsGlobalWindow::AddEventListener(const n
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   if (!aWantsUntrusted &&
       (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
     aWantsUntrusted = true;
   }
 
-  nsEventListenerManager* manager = GetOrCreateListenerManager();
+  nsEventListenerManager* manager = GetListenerManager(true);
   NS_ENSURE_STATE(manager);
   manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
   return NS_OK;
 }
 
 void
 nsGlobalWindow::AddEventListener(const nsAString& aType,
                                  EventListener* aListener,
@@ -8140,17 +8142,17 @@ nsGlobalWindow::AddEventListener(const n
 
   bool wantsUntrusted;
   if (aWantsUntrusted.IsNull()) {
     wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
   } else {
     wantsUntrusted = aWantsUntrusted.Value();
   }
 
-  nsEventListenerManager* manager = GetOrCreateListenerManager();
+  nsEventListenerManager* manager = GetListenerManager(true);
   if (!manager) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   manager->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
 }
 
 NS_IMETHODIMP
@@ -8175,36 +8177,28 @@ nsGlobalWindow::AddSystemEventListener(c
     aWantsUntrusted = true;
   }
 
   return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
                                    aWantsUntrusted);
 }
 
 nsEventListenerManager*
-nsGlobalWindow::GetOrCreateListenerManager()
-{
-  FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr);
-
-  if (!mListenerManager) {
+nsGlobalWindow::GetListenerManager(bool aCreateIfNotFound)
+{
+  FORWARD_TO_INNER_CREATE(GetListenerManager, (aCreateIfNotFound), nullptr);
+
+  if (!mListenerManager && aCreateIfNotFound) {
     mListenerManager =
       new nsEventListenerManager(static_cast<EventTarget*>(this));
   }
 
   return mListenerManager;
 }
 
-nsEventListenerManager*
-nsGlobalWindow::GetExistingListenerManager() const
-{
-  FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr);
-
-  return mListenerManager;
-}
-
 nsIScriptContext*
 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
 {
   *aRv = NS_ERROR_UNEXPECTED;
   if (IsInnerWindow()) {
     nsPIDOMWindow* outer = GetOuterWindow();
     NS_ENSURE_TRUE(outer && outer->GetCurrentInnerWindow() == this, nullptr);
   }
@@ -11542,17 +11536,18 @@ SizeOfEventTargetObjectsEntryExcludingTh
 }
 
 void
 nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
 {
   aWindowSizes->mDOMOther += aWindowSizes->mMallocSizeOf(this);
 
   if (IsInnerWindow()) {
-    nsEventListenerManager* elm = GetExistingListenerManager();
+    nsEventListenerManager* elm =
+      const_cast<nsGlobalWindow*>(this)->GetListenerManager(false);
     if (elm) {
       aWindowSizes->mDOMOther +=
         elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
     }
     if (mDoc) {
       mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
     }
   }
@@ -12083,61 +12078,61 @@ nsGlobalWindow::DisableNetworkEvent(uint
       handler = new EventHandlerNonNull(callable);                           \
     }                                                                        \
     SetOn##name_(handler);                                                   \
     return NS_OK;                                                            \
   }
 #define ERROR_EVENT(name_, id_, type_, struct_)                              \
   NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
                                              JS::Value *vp) {                \
-    nsEventListenerManager *elm = GetExistingListenerManager();              \
+    nsEventListenerManager *elm = GetListenerManager(false);                 \
     if (elm) {                                                               \
       OnErrorEventHandlerNonNull* h = elm->GetOnErrorEventHandler();         \
       if (h) {                                                               \
         *vp = JS::ObjectValue(*h->Callable());                               \
         return NS_OK;                                                        \
       }                                                                      \
     }                                                                        \
     *vp = JSVAL_NULL;                                                        \
     return NS_OK;                                                            \
   }                                                                          \
   NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
                                              const JS::Value &v) {           \
-    nsEventListenerManager *elm = GetOrCreateListenerManager();              \
+    nsEventListenerManager *elm = GetListenerManager(true);                  \
     if (!elm) {                                                              \
       return NS_ERROR_OUT_OF_MEMORY;                                         \
     }                                                                        \
                                                                              \
     nsRefPtr<OnErrorEventHandlerNonNull> handler;                            \
     JSObject *callable;                                                      \
     if (v.isObject() &&                                                      \
         JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
       handler = new OnErrorEventHandlerNonNull(callable);                    \
     }                                                                        \
     elm->SetEventHandler(handler);                                           \
     return NS_OK;                                                            \
   }
 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                       \
   NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
                                              JS::Value *vp) {                \
-    nsEventListenerManager *elm = GetExistingListenerManager();              \
+    nsEventListenerManager *elm = GetListenerManager(false);                 \
     if (elm) {                                                               \
       BeforeUnloadEventHandlerNonNull* h =                                   \
         elm->GetOnBeforeUnloadEventHandler();                                \
       if (h) {                                                               \
         *vp = JS::ObjectValue(*h->Callable());                               \
         return NS_OK;                                                        \
       }                                                                      \
     }                                                                        \
     *vp = JSVAL_NULL;                                                        \
     return NS_OK;                                                            \
   }                                                                          \
   NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
                                              const JS::Value &v) {           \
-    nsEventListenerManager *elm = GetOrCreateListenerManager();              \
+    nsEventListenerManager *elm = GetListenerManager(true);                  \
     if (!elm) {                                                              \
       return NS_ERROR_OUT_OF_MEMORY;                                         \
     }                                                                        \
                                                                              \
     nsRefPtr<BeforeUnloadEventHandlerNonNull> handler;                       \
     JSObject *callable;                                                      \
     if (v.isObject() &&                                                      \
         JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -366,23 +366,16 @@ public:
   // nsIDOMWindowPerformance
   NS_DECL_NSIDOMWINDOWPERFORMANCE
 
   // nsIDOMJSWindow
   NS_DECL_NSIDOMJSWINDOW
 
   // nsIDOMEventTarget
   NS_DECL_NSIDOMEVENTTARGET
-
-  virtual nsEventListenerManager*
-  GetExistingListenerManager() const MOZ_OVERRIDE;
-
-  virtual nsEventListenerManager*
-  GetOrCreateListenerManager() MOZ_OVERRIDE;
-
   using mozilla::dom::EventTarget::RemoveEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
   virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE
   {
@@ -554,17 +547,17 @@ public:
     return mContext;
   }
 
   nsGlobalWindow *GetOuterWindowInternal()
   {
     return static_cast<nsGlobalWindow *>(GetOuterWindow());
   }
 
-  nsGlobalWindow *GetCurrentInnerWindowInternal() const
+  nsGlobalWindow *GetCurrentInnerWindowInternal()
   {
     return static_cast<nsGlobalWindow *>(mInnerWindow);
   }
 
   nsGlobalWindow *EnsureInnerWindowInternal()
   {
     return static_cast<nsGlobalWindow *>(EnsureInnerWindow());
   }
@@ -710,49 +703,49 @@ public:
   // Enable/disable updates for gamepad input.
   void EnableGamepadUpdates();
   void DisableGamepadUpdates();
 
 
 #define EVENT(name_, id_, type_, struct_)                                     \
   mozilla::dom::EventHandlerNonNull* GetOn##name_()                           \
   {                                                                           \
-    nsEventListenerManager *elm = GetExistingListenerManager();               \
+    nsEventListenerManager *elm = GetListenerManager(false);                  \
     return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString())    \
                : nullptr;                                                     \
   }                                                                           \
   void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler)               \
   {                                                                           \
-    nsEventListenerManager *elm = GetOrCreateListenerManager();               \
+    nsEventListenerManager *elm = GetListenerManager(true);                   \
     if (elm) {                                                                \
       elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler);     \
     }                                                                         \
   }
 #define ERROR_EVENT(name_, id_, type_, struct_)                               \
   mozilla::dom::OnErrorEventHandlerNonNull* GetOn##name_()                    \
   {                                                                           \
-    nsEventListenerManager *elm = GetExistingListenerManager();               \
+    nsEventListenerManager *elm = GetListenerManager(false);                  \
     return elm ? elm->GetOnErrorEventHandler() : nullptr;                     \
   }                                                                           \
   void SetOn##name_(mozilla::dom::OnErrorEventHandlerNonNull* handler)        \
   {                                                                           \
-    nsEventListenerManager *elm = GetOrCreateListenerManager();               \
+    nsEventListenerManager *elm = GetListenerManager(true);                   \
     if (elm) {                                                                \
       elm->SetEventHandler(handler);                                          \
     }                                                                         \
   }
 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                        \
   mozilla::dom::BeforeUnloadEventHandlerNonNull* GetOn##name_()               \
   {                                                                           \
-    nsEventListenerManager *elm = GetExistingListenerManager();               \
+    nsEventListenerManager *elm = GetListenerManager(false);                  \
     return elm ? elm->GetOnBeforeUnloadEventHandler() : nullptr;              \
   }                                                                           \
   void SetOn##name_(mozilla::dom::BeforeUnloadEventHandlerNonNull* handler)   \
   {                                                                           \
-    nsEventListenerManager *elm = GetOrCreateListenerManager();               \
+    nsEventListenerManager *elm = GetListenerManager(true);                   \
     if (elm) {                                                                \
       elm->SetEventHandler(handler);                                          \
     }                                                                         \
   }
 #define WINDOW_ONLY_EVENT EVENT
 #define TOUCH_EVENT EVENT
 #include "nsEventNameList.h"
 #undef TOUCH_EVENT
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -59,17 +59,18 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
 
 NS_IMPL_DOMTARGET_DEFAULTS(nsWindowRoot)
 
 NS_IMETHODIMP
 nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture)
 {
-  if (nsRefPtr<nsEventListenerManager> elm = GetExistingListenerManager()) {
+  nsRefPtr<nsEventListenerManager> elm = GetListenerManager(false);
+  if (elm) {
     elm->RemoveEventListener(aType, aListener, aUseCapture);
   }
   return NS_OK;
 }
 
 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot)
 
 NS_IMETHODIMP
@@ -99,31 +100,31 @@ nsWindowRoot::AddEventListener(const nsA
                                bool aUseCapture, bool aWantsUntrusted,
                                uint8_t aOptionalArgc)
 {
   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
                "Won't check if this is chrome, you want to set "
                "aWantsUntrusted to false or make the aWantsUntrusted "
                "explicit by making optional_argc non-zero.");
 
-  nsEventListenerManager* elm = GetOrCreateListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(true);
   NS_ENSURE_STATE(elm);
   elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
   return NS_OK;
 }
 
 void
 nsWindowRoot::AddEventListener(const nsAString& aType,
                                 EventListener* aListener,
                                 bool aUseCapture,
                                 const Nullable<bool>& aWantsUntrusted,
                                 ErrorResult& aRv)
 {
   bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value();
-  nsEventListenerManager* elm = GetOrCreateListenerManager();
+  nsEventListenerManager* elm = GetListenerManager(true);
   if (!elm) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
 }
 
 
@@ -139,32 +140,26 @@ nsWindowRoot::AddSystemEventListener(con
                "aWantsUntrusted to false or make the aWantsUntrusted "
                "explicit by making optional_argc non-zero.");
 
   return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
                                    aWantsUntrusted);
 }
 
 nsEventListenerManager*
-nsWindowRoot::GetOrCreateListenerManager()
+nsWindowRoot::GetListenerManager(bool aCreateIfNotFound)
 {
-  if (!mListenerManager) {
+  if (!mListenerManager && aCreateIfNotFound) {
     mListenerManager =
       new nsEventListenerManager(static_cast<EventTarget*>(this));
   }
 
   return mListenerManager;
 }
 
-nsEventListenerManager*
-nsWindowRoot::GetExistingListenerManager() const
-{
-  return mListenerManager;
-}
-
 nsIScriptContext*
 nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
 {
   *aRv = NS_OK;
   return nullptr;
 }
 
 nsresult
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -23,22 +23,16 @@ class nsEventChainPostVisitor;
 class nsWindowRoot : public nsPIWindowRoot
 {
 public:
   nsWindowRoot(nsPIDOMWindow* aWindow);
   virtual ~nsWindowRoot();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIDOMEVENTTARGET
-
-  virtual nsEventListenerManager*
-  GetExistingListenerManager() const MOZ_OVERRIDE;
-  virtual nsEventListenerManager*
-  GetOrCreateListenerManager() MOZ_OVERRIDE;
-
   using mozilla::dom::EventTarget::RemoveEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
   // nsPIWindowRoot
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -26,19 +26,16 @@
 #                interfaces.  Defaults to True otherwise.
 #   * workers - Indicates whether the descriptor is intended to be used solely
 #               for worker threads (defaults to false). If true the interface
 #               will not be made available on the main thread.
 #   * customTrace - The native class will use a custom trace hook (defaults to
 #                   true for workers, false otherwise).
 #   * customFinalize - The native class will use a custom finalize hook
 #                      (defaults to true for workers, false otherwise).
-#   * customWrapperManagement - The native class will be responsible for
-#                               preserving its own wrapper (no AddProperty
-#                               hook will be generated, defaults to false).
 #   * notflattened - The native type does not have nsIClassInfo, so when
 #                    wrapping it the right IID needs to be passed in.
 #   * register - True if this binding should be registered.  Defaults to true.
 #   * binaryNames - Dict for mapping method and attribute names to different
 #                   names when calling the native methods (defaults to an empty
 #                   dict). The keys are the property names as they appear in the
 #                   .webidl file and the values are the names as they should be
 #                   in the WebIDL.
@@ -201,23 +198,16 @@ DOMInterfaces = {
     'nativeType': 'nsDOMCaretPosition',
 },
 
 'CharacterData': {
     'nativeType': 'nsGenericDOMDataNode',
     'concrete': False
 },
 
-'ChromeWorker': {
-    'headerFile': 'mozilla/dom/WorkerPrivate.h',
-    'nativeType': 'mozilla::dom::workers::ChromeWorkerPrivate',
-    'customFinalize': True,
-    'customWrapperManagement': True,
-},
-
 'DOMRectList': {
     'headerFile': 'mozilla/dom/DOMRect.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'ClipboardEvent': {
     'nativeType': 'nsDOMClipboardEvent',
 },
@@ -1430,26 +1420,16 @@ DOMInterfaces = {
     'concrete': False
 },
 {
     # We need a worker descriptor for WindowProxy because EventTarget exists in
     # workers.  But it's an external interface, so it'll just map to JSObject*.
     'workers': True
 }],
 
-'Worker': {
-    'headerFile': 'mozilla/dom/WorkerPrivate.h',
-    'nativeType': 'mozilla::dom::workers::WorkerPrivate',
-    'implicitJSContext': [
-        'terminate',
-    ],
-    'customFinalize': True,
-    'customWrapperManagement': True,
-},
-
 'WorkerLocation': {
     'headerFile': 'mozilla/dom/workers/bindings/Location.h',
     'workers': True,
 },
 
 'WorkerMessagePort': [{
     'nativeType': 'mozilla::dom::workers::MessagePort',
     'headerFile': 'mozilla/dom/workers/bindings/MessagePort.h',
@@ -1881,9 +1861,9 @@ addExternalIface('CameraCapabilities', n
 addExternalIface('CameraAutoFocusCallback', nativeType='nsICameraAutoFocusCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraShutterCallback', nativeType='nsICameraShutterCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraClosedCallback', nativeType='nsICameraClosedCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraTakePictureCallback', nativeType='nsICameraTakePictureCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraReleaseCallback', nativeType='nsICameraReleaseCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraStartRecordingCallback', nativeType='nsICameraStartRecordingCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraPreviewStateChange', nativeType='nsICameraPreviewStateChange', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraPreviewStreamCallback', nativeType='nsICameraPreviewStreamCallback', headerFile='nsIDOMCameraManager.h')
-addExternalIface('CameraRecorderStateChange', nativeType='nsICameraRecorderStateChange', headerFile='nsIDOMCameraManager.h')
+addExternalIface('CameraRecorderStateChange', nativeType='nsICameraRecorderStateChange', headerFile='nsIDOMCameraManager.h')
\ No newline at end of file
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -48,20 +48,16 @@ def replaceFileIfChanged(filename, newCo
     return True
 
 def toStringBool(arg):
     return str(not not arg).lower()
 
 def toBindingNamespace(arg):
     return re.sub("((_workers)?$)", "Binding\\1", arg);
 
-def wantsAddProperty(desc):
-    return desc.concrete and not desc.nativeOwnership == 'worker' and \
-           desc.wrapperCache and not desc.customWrapperManagement
-
 class CGThing():
     """
     Abstract base class for things that spit out code.
     """
     def __init__(self):
         pass # Nothing for now
     def declare(self):
         """Produce code for a header file."""
@@ -208,17 +204,17 @@ static const DOMJSClass Class = {
     nullptr,               /* construct */
     %s, /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
 %s
 };
 """ % (self.descriptor.interface.identifier.name,
        classFlags,
-       ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'JS_PropertyStub',
+       ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.nativeOwnership == 'worker' and self.descriptor.wrapperCache else 'JS_PropertyStub',
        enumerateHook, newResolveHook, FINALIZE_HOOK_NAME, callHook, traceHook,
        CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
 def PrototypeIDAndDepth(descriptor):
     prototypeID = "prototypes::id::"
     if descriptor.interface.hasInterfacePrototypeObject():
         prototypeID += descriptor.interface.identifier.name
         if descriptor.workers:
@@ -696,26 +692,19 @@ class CGHeaders(CGWrapper):
                         callbacks))
 
         # Now for non-callback descriptors make sure we include any
         # headers needed by Func declarations.
         for desc in descriptors:
             if desc.interface.isExternal():
                 continue
             def addHeaderForFunc(func):
-                if func is None:
-                    return
                 # Include the right class header, which we can only do
                 # if this is a class member function.
-                if not desc.headerIsDefault:
-                    # An explicit header file was provided, assume that we know
-                    # what we're doing.
-                    return
-
-                if "::" in func:
+                if func is not None and "::" in func:
                     # Strip out the function name and convert "::" to "/"
                     bindingHeaders.add("/".join(func.split("::")[:-1]) + ".h")
             for m in desc.interface.members:
                 addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"))
             # getExtendedAttribute() returns a list, extract the entry.
             funcList = desc.interface.getExtendedAttribute("Func")
             if funcList is not None:
                 addHeaderForFunc(funcList[0])
@@ -8039,17 +8028,17 @@ class CGDescriptor(CGThing):
         if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
                                                              lenientThis=True))
 
         if descriptor.interface.getNavigatorProperty():
             cgThings.append(CGConstructNavigatorObjectHelper(descriptor))
             cgThings.append(CGConstructNavigatorObject(descriptor))
 
         if descriptor.concrete and not descriptor.proxy:
-            if wantsAddProperty(descriptor):
+            if not descriptor.nativeOwnership == 'worker' and descriptor.wrapperCache:
                 cgThings.append(CGAddPropertyHook(descriptor))
 
             # Always have a finalize hook, regardless of whether the class
             # wants a custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
             # Only generate a trace hook if the class wants a custom hook.
             if (descriptor.customTrace):
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -233,17 +233,16 @@ class Descriptor(DescriptorProvider):
             if self.workers:
                 headerDefault = "mozilla/dom/workers/bindings/%s.h" % ifaceName
             elif not self.interface.isExternal() and self.interface.getExtendedAttribute("HeaderFile"):
                 headerDefault = self.interface.getExtendedAttribute("HeaderFile")[0]
             else:
                 headerDefault = self.nativeType
                 headerDefault = headerDefault.replace("::", "/") + ".h"
         self.headerFile = desc.get('headerFile', headerDefault)
-        self.headerIsDefault = self.headerFile == headerDefault
         if self.jsImplParent == self.nativeType:
             self.jsImplParentHeader = self.headerFile
         else:
             self.jsImplParentHeader = self.jsImplParent.replace("::", "/") + ".h"
 
         self.skipGen = desc.get('skipGen', False)
 
         self.notflattened = desc.get('notflattened', False)
@@ -352,27 +351,22 @@ class Descriptor(DescriptorProvider):
         else:
             self.nativeOwnership = desc.get('nativeOwnership', 'refcounted')
             if not self.nativeOwnership in ['owned', 'refcounted']:
                 raise TypeError("Descriptor for %s has unrecognized value (%s) "
                                 "for nativeOwnership" %
                                 (self.interface.identifier.name, self.nativeOwnership))
         self.customTrace = desc.get('customTrace', self.nativeOwnership == 'worker')
         self.customFinalize = desc.get('customFinalize', self.nativeOwnership == 'worker')
-        self.customWrapperManagement = desc.get('customWrapperManagement', False)
         if desc.get('wantsQI', None) != None:
             self._wantsQI = desc.get('wantsQI', None)
         self.wrapperCache = (not self.interface.isCallback() and
                              (self.nativeOwnership == 'worker' or
                               (self.nativeOwnership != 'owned' and
                                desc.get('wrapperCache', True))))
-        if self.customWrapperManagement and not self.wrapperCache:
-            raise TypeError("Descriptor for %s has customWrapperManagement "
-                            "but is not wrapperCached." %
-                            (self.interface.identifier.name))
 
         def make_name(name):
             return name + "_workers" if self.workers else name
         self.name = make_name(interface.identifier.name)
 
         # self.extendedAttributes is a dict of dicts, keyed on
         # all/getterOnly/setterOnly and then on member name. Values are an
         # array of extended attributes.
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -8,17 +8,16 @@
 #define TestBindingHeader_h
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCOMPtr.h"
-#include "nsGenericHTMLElement.h"
 #include "nsWrapperCache.h"
 
 // Forward declare this before we include TestCodeGenBinding.h, because that header relies on including
 // this one for it, for ParentDict. Hopefully it won't begin to rely on it in more fundamental ways.
 namespace mozilla {
 namespace dom {
 class TestExternalInterface;
 } // namespace dom
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -152,21 +152,16 @@ public:
   typedef nsTArray<nsString> VolumeNameArray;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMDEVICESTORAGE
 
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIDOMEVENTTARGET
 
-  virtual nsEventListenerManager*
-  GetExistingListenerManager() const MOZ_OVERRIDE;
-  virtual nsEventListenerManager*
-  GetOrCreateListenerManager() MOZ_OVERRIDE;
-
   virtual void
   AddEventListener(const nsAString& aType,
                    mozilla::dom::EventListener* aListener,
                    bool aUseCapture,
                    const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                    ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual void RemoveEventListener(const nsAString& aType,
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -3474,25 +3474,19 @@ nsDOMDeviceStorage::DispatchDOMEvent(Wid
 {
   return nsDOMEventTargetHelper::DispatchDOMEvent(aEvent,
                                                   aDOMEvent,
                                                   aPresContext,
                                                   aEventStatus);
 }
 
 nsEventListenerManager *
-nsDOMDeviceStorage::GetOrCreateListenerManager()
+nsDOMDeviceStorage::GetListenerManager(bool aMayCreate)
 {
-  return nsDOMEventTargetHelper::GetOrCreateListenerManager();
-}
-
-nsEventListenerManager *
-nsDOMDeviceStorage::GetExistingListenerManager() const
-{
-  return nsDOMEventTargetHelper::GetExistingListenerManager();
+  return nsDOMEventTargetHelper::GetListenerManager(aMayCreate);
 }
 
 nsIScriptContext *
 nsDOMDeviceStorage::GetContextForEventHandlers(nsresult *aRv)
 {
   return nsDOMEventTargetHelper::GetContextForEventHandlers(aRv);
 }
 
--- a/dom/interfaces/events/nsIDOMEventTarget.idl
+++ b/dom/interfaces/events/nsIDOMEventTarget.idl
@@ -40,17 +40,17 @@ class nsEventListenerManager;
 [ptr] native JSContextPtr(JSContext);
 [ptr] native nsEventListenerManagerPtr(nsEventListenerManager);
 [ptr] native EventTargetPtr(mozilla::dom::EventTarget);
 
 interface nsIScriptContext;
 interface nsIDOMEventListener;
 interface nsIDOMEvent;
 
-[scriptable, builtinclass, uuid(b128448c-7b53-4769-92cb-cd6eafee676c)]
+[scriptable, builtinclass, uuid(31e92e56-4d23-4a4a-9cfe-a6d12cf434bc)]
 interface nsIDOMEventTarget : nsISupports
 {
   /**
    * This method allows the registration of event listeners on the event target.
    * If an EventListener is added to an EventTarget while it is processing an
    * event, it will not be triggered by the current actions but may be 
    * triggered during a later stage of event flow, such as the bubbling phase.
    * 
@@ -263,16 +263,25 @@ interface nsIDOMEventTarget : nsISupport
    */
   [noscript, nostdcall]
   void DispatchDOMEvent(in WidgetEventPtr aEvent,
                         in nsIDOMEvent aDOMEvent,
                         in nsPresContextPtr aPresContext,
                         in nsEventStatusPtr aEventStatus);
 
   /**
+   * Get the event listener manager, the guy you talk to to register for events
+   * on this node.
+   * @param aMayCreate If PR_FALSE, returns a listener manager only if
+   *                   one already exists.
+   */
+  [notxpcom, nostdcall]
+  nsEventListenerManagerPtr GetListenerManager(in boolean aMayCreate);
+
+  /**
    * Get the script context in which the event handlers should be run.
    * May return null.
    * @note Caller *must* check the value of aRv.
    */
   [notxpcom, nostdcall]
   nsIScriptContext GetContextForEventHandlers(out nsresult aRv);
 
   /**
@@ -291,17 +300,17 @@ nsresult _class::WillHandleEvent(nsEvent
 JSContext* _class::GetJSContextForEventHandlers() { return nullptr; }
 
 #define NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(aClass) \
 NS_IMETHODIMP \
 aClass::RemoveSystemEventListener(const nsAString& aType, \
                                   nsIDOMEventListener *aListener, \
                                   bool aUseCapture) \
 { \
-  nsEventListenerManager* listenerManager = GetExistingListenerManager(); \
+  nsEventListenerManager* listenerManager = GetListenerManager(false); \
   if (!listenerManager) { \
     return NS_OK; \
   } \
   mozilla::dom::EventListenerFlags flags; \
   flags.mInSystemGroup = true; \
   flags.mCapture = aUseCapture; \
   listenerManager->RemoveEventListenerByType(aListener, aType, flags); \
   return NS_OK; \
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1197,17 +1197,17 @@ TabChild::~TabChild()
 
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(mWebNav);
     if (webBrowser) {
       webBrowser->SetContainerWindow(nullptr);
     }
     mGlobal = nullptr;
 
     if (mTabChildGlobal) {
-      nsEventListenerManager* elm = mTabChildGlobal->GetExistingListenerManager();
+      nsEventListenerManager* elm = mTabChildGlobal->GetListenerManager(false);
       if (elm) {
         elm->Disconnect();
       }
       mTabChildGlobal->mTabChild = nullptr;
     }
 }
 
 void
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -574,17 +574,16 @@ var interfaceNamesInGlobalScope =
     "WebGLShaderPrecisionFormat",
     "WebGLTexture",
     "WebGLUniformLocation",
     "WebGLVertexArray",
     "WebSocket",
     "WheelEvent",
     "Window",
     "WindowUtils",
-    "Worker",
     "XMLDocument",
     "XMLHttpRequest",
     "XMLHttpRequestUpload",
     "XMLSerializer",
     "XMLStylesheetProcessingInstruction",
     "XPathEvaluator",
     "XPathExpression",
     "XPathNamespace",
deleted file mode 100644
--- a/dom/webidl/Worker.webidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * The origin of this IDL file is
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html
- *
- * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera
- * Software ASA.
- * You are granted a license to use, reproduce and create derivative works of
- * this document.
- */
-
-[Constructor(DOMString scriptURL),
- Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable"]
-interface Worker : EventTarget {
-  void terminate();
-
-  [Throws]
-  void postMessage(any message, optional sequence<any> transfer);
-
-  attribute EventHandler onmessage;
-};
-
-Worker implements AbstractWorker;
-
-[Constructor(DOMString scriptURL),
- Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable"]
-interface ChromeWorker : Worker {
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -405,17 +405,16 @@ WEBIDL_FILES = [
     'VideoPlaybackQuality.webidl',
     'VideoStreamTrack.webidl',
     'WaveShaperNode.webidl',
     'WebComponents.webidl',
     'WebSocket.webidl',
     'WheelEvent.webidl',
     'WifiOptions.webidl',
     'Window.webidl',
-    'Worker.webidl',
     'WorkerLocation.webidl',
     'WorkerMessagePort.webidl',
     'WorkerNavigator.webidl',
     'XMLDocument.webidl',
     'XMLHttpRequest.webidl',
     'XMLHttpRequestEventTarget.webidl',
     'XMLHttpRequestUpload.webidl',
     'XMLSerializer.webidl',
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -23,20 +23,17 @@
 
 #include <algorithm>
 #include "GeckoProfiler.h"
 #include "js/OldDebugAPI.h"
 #include "jsfriendapi.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
-#include "mozilla/dom/MessageEventBinding.h"
-#include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Util.h"
 #include <Navigator.h>
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsLayoutStatics.h"
@@ -46,16 +43,17 @@
 #include "nsTraceRefcnt.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "OSFileConstants.h"
 #include "xpcpublic.h"
 
 #include "Events.h"
 #include "SharedWorker.h"
+#include "Worker.h"
 #include "WorkerPrivate.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -91,16 +89,17 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 
 
 // The number of seconds that idle threads can hang around before being killed.
 #define IDLE_THREAD_TIMEOUT_SEC 30
 
 // The maximum number of threads that can be idle at one time.
 #define MAX_IDLE_THREADS 20
 
 #define PREF_WORKERS_PREFIX "dom.workers."
+#define PREF_WORKERS_ENABLED PREF_WORKERS_PREFIX "enabled"
 #define PREF_WORKERS_MAX_PER_DOMAIN PREF_WORKERS_PREFIX "maxPerDomain"
 
 #define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
 
 #define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
 
@@ -157,19 +156,19 @@ enum {
 };
 
 // These are jsids for the main runtime. Only touched on the main thread.
 jsid gStringIDs[ID_COUNT] = { JSID_VOID };
 
 const char* gStringChars[] = {
   "Worker",
   "ChromeWorker",
-  "Event",
-  "MessageEvent",
-  "ErrorEvent"
+  "WorkerEvent",
+  "WorkerMessageEvent",
+  "WorkerErrorEvent"
 
   // XXX Don't care about ProgressEvent since it should never leak to the main
   // thread.
 };
 
 static_assert(NS_ARRAY_LENGTH(gStringChars) == ID_COUNT,
               "gStringChars should have the right length.");
 
@@ -962,60 +961,82 @@ public:
     return NS_OK;
   }
 };
 
 } /* anonymous namespace */
 
 BEGIN_WORKERS_NAMESPACE
 
-// Entry point for main thread non-window globals.
+// Entry point for the DOM.
 bool
 ResolveWorkerClasses(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,
                      unsigned aFlags, JS::MutableHandle<JSObject*> aObjp)
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
 
   // Make sure our strings are interned.
   if (JSID_IS_VOID(gStringIDs[0])) {
     for (uint32_t i = 0; i < ID_COUNT; i++) {
       JSString* str = JS_InternString(aCx, gStringChars[i]);
       if (!str) {
         while (i) {
           gStringIDs[--i] = JSID_VOID;
         }
         return false;
       }
       gStringIDs[i] = INTERNED_STRING_TO_JSID(aCx, str);
     }
   }
 
+  bool isChrome = false;
   bool shouldResolve = false;
 
   for (uint32_t i = 0; i < ID_COUNT; i++) {
     if (gStringIDs[i] == aId) {
-      shouldResolve = true;
+      isChrome = nsContentUtils::IsCallerChrome();
+
+      // Don't resolve if this is ChromeWorker and we're not chrome. Otherwise
+      // always resolve.
+      shouldResolve = gStringIDs[ID_ChromeWorker] == aId ? isChrome : true;
       break;
     }
   }
 
-  if (!shouldResolve) {
-    aObjp.set(nullptr);
+  if (shouldResolve) {
+    // Don't do anything if workers are disabled.
+    if (!isChrome && !Preferences::GetBool(PREF_WORKERS_ENABLED)) {
+      aObjp.set(nullptr);
+      return true;
+    }
+
+    JSObject* eventTarget = EventTargetBinding_workers::GetProtoObject(aCx, aObj);
+    if (!eventTarget) {
+      return false;
+    }
+
+    JSObject* worker = worker::InitClass(aCx, aObj, eventTarget, true);
+    if (!worker) {
+      return false;
+    }
+
+    if (isChrome && !chromeworker::InitClass(aCx, aObj, worker, true)) {
+      return false;
+    }
+
+    if (!events::InitClasses(aCx, aObj, true)) {
+      return false;
+    }
+
+    aObjp.set(aObj);
     return true;
   }
 
-  if (!WorkerBinding::GetConstructorObject(aCx, aObj) ||
-      !ChromeWorkerBinding::GetConstructorObject(aCx, aObj) ||
-      !ErrorEventBinding::GetConstructorObject(aCx, aObj) ||
-      !MessageEventBinding::GetConstructorObject(aCx, aObj)) {
-    return false;
-  }
-
-  aObjp.set(aObj);
+  // Not resolved.
+  aObjp.set(nullptr);
   return true;
 }
 
 void
 CancelWorkersForWindow(nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
@@ -1968,83 +1989,85 @@ RuntimeService::ResumeWorkersForWindow(n
       if (!workers[index]->SynchronizeAndResume(cx, aWindow, scx)) {
         JS_ReportPendingException(cx);
       }
     }
   }
 }
 
 nsresult
-RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal,
+RuntimeService::CreateSharedWorker(JSContext* aCx, nsPIDOMWindow* aWindow,
                                    const nsAString& aScriptURL,
                                    const nsAString& aName,
                                    SharedWorker** aSharedWorker)
 {
   AssertIsOnMainThread();
-
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
-  MOZ_ASSERT(window);
-
-  JSContext* cx = aGlobal.GetContext();
+  MOZ_ASSERT(aCx);
+  MOZ_ASSERT(aWindow);
 
   WorkerPrivate::LoadInfo loadInfo;
-  nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
+  nsresult rv = WorkerPrivate::GetLoadInfo(aCx, aWindow, nullptr, aScriptURL,
                                            false, &loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   MOZ_ASSERT(loadInfo.mResolvedScriptURI);
 
   nsCString scriptSpec;
   rv = loadInfo.mResolvedScriptURI->GetSpec(scriptSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<WorkerPrivate> workerPrivate;
+  WorkerPrivate* workerPrivate = nullptr;
   {
     MutexAutoLock lock(mMutex);
 
     WorkerDomainInfo* domainInfo;
     SharedWorkerInfo* sharedWorkerInfo;
 
     if (mDomainMap.Get(loadInfo.mDomain, &domainInfo) &&
         domainInfo->mSharedWorkerInfos.Get(scriptSpec, &sharedWorkerInfo) &&
         sharedWorkerInfo->mName == aName) {
       workerPrivate = sharedWorkerInfo->mWorkerPrivate;
     }
   }
 
   bool created = false;
 
   if (!workerPrivate) {
-    ErrorResult rv;
-    workerPrivate =
-      WorkerPrivate::Constructor(aGlobal, aScriptURL, false, true, aName,
-                                 &loadInfo, rv);
-    NS_ENSURE_TRUE(workerPrivate, rv.ErrorCode());
+    nsRefPtr<WorkerPrivate> newWorkerPrivate =
+      WorkerPrivate::Create(aCx, JS::NullPtr(), nullptr, aScriptURL, false,
+                            true, aName, &loadInfo);
+    NS_ENSURE_TRUE(newWorkerPrivate, NS_ERROR_FAILURE);
+
+    if (!RegisterWorker(aCx, newWorkerPrivate)) {
+      NS_WARNING("Failed to register worker!");
+      return NS_ERROR_FAILURE;
+    }
 
     created = true;
+    newWorkerPrivate.forget(&workerPrivate);
   }
 
   MOZ_ASSERT(workerPrivate->IsSharedWorker());
 
   nsRefPtr<SharedWorker> sharedWorker =
-    new SharedWorker(window, workerPrivate);
+    new SharedWorker(aWindow, workerPrivate);
 
-  if (!workerPrivate->RegisterSharedWorker(cx, sharedWorker)) {
+  if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker)) {
     NS_WARNING("Worker is unreachable, this shouldn't happen!");
     sharedWorker->Close();
     return NS_ERROR_FAILURE;
   }
 
   // This is normally handled in RegisterWorker, but that wasn't called if the
   // worker already existed.
   if (!created) {
     nsTArray<WorkerPrivate*>* windowArray;
-    if (!mWindowMap.Get(window, &windowArray)) {
+    if (!mWindowMap.Get(aWindow, &windowArray)) {
       windowArray = new nsTArray<WorkerPrivate*>(1);
-      mWindowMap.Put(window, windowArray);
+      mWindowMap.Put(aWindow, windowArray);
     }
 
     if (!windowArray->Contains(workerPrivate)) {
       windowArray->AppendElement(workerPrivate);
     }
   }
 
   sharedWorker.forget(aSharedWorker);
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -140,19 +140,18 @@ public:
 
   void
   SuspendWorkersForWindow(nsPIDOMWindow* aWindow);
 
   void
   ResumeWorkersForWindow(nsPIDOMWindow* aWindow);
 
   nsresult
-  CreateSharedWorker(const GlobalObject& aGlobal,
-                     const nsAString& aScriptURL,
-                     const nsAString& aName,
+  CreateSharedWorker(JSContext* aCx, nsPIDOMWindow* aWindow,
+                     const nsAString& aScriptURL, const nsAString& aName,
                      SharedWorker** aSharedWorker);
 
   void
   ForgetSharedWorker(WorkerPrivate* aWorkerPrivate);
 
   const nsACString&
   GetDetectorName() const
   {
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/SharedWorkerBinding.h"
 #include "nsContentUtils.h"
 #include "nsDOMEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsIClassInfoImpl.h"
 
 #include "MessagePort.h"
 #include "RuntimeService.h"
+#include "Worker.h"
 #include "WorkerPrivate.h"
 
 using mozilla::dom::Optional;
 using mozilla::dom::Sequence;
 
 USING_WORKERS_NAMESPACE
 
 namespace {
@@ -61,29 +62,32 @@ SharedWorker::PrefEnabled()
 already_AddRefed<SharedWorker>
 SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
                           const nsAString& aScriptURL,
                           const mozilla::dom::Optional<nsAString>& aName,
                           ErrorResult& aRv)
 {
   AssertIsOnMainThread();
 
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  MOZ_ASSERT(window);
+
   RuntimeService* rts = RuntimeService::GetOrCreateService();
   if (!rts) {
     aRv = NS_ERROR_NOT_AVAILABLE;
     return nullptr;
   }
 
   nsString name;
   if (aName.WasPassed()) {
     name = aName.Value();
   }
 
   nsRefPtr<SharedWorker> sharedWorker;
-  nsresult rv = rts->CreateSharedWorker(aGlobal, aScriptURL, name,
+  nsresult rv = rts->CreateSharedWorker(aCx, window, aScriptURL, name,
                                         getter_AddRefs(sharedWorker));
   if (NS_FAILED(rv)) {
     aRv = rv;
     return nullptr;
   }
 
   return sharedWorker.forget();
 }
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -23,17 +23,17 @@ class WorkerPrivate;
 class SharedWorker MOZ_FINAL : public nsDOMEventTargetHelper
 {
   friend class MessagePort;
   friend class RuntimeService;
 
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
 
-  nsRefPtr<WorkerPrivate> mWorkerPrivate;
+  WorkerPrivate* mWorkerPrivate;
   nsRefPtr<MessagePort> mMessagePort;
   nsTArray<nsCOMPtr<nsIDOMEvent>> mSuspendedEvents;
   uint64_t mSerial;
   bool mSuspended;
 
 public:
   static bool
   PrefEnabled();
@@ -78,18 +78,17 @@ public:
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::HandleObject aScope) MOZ_OVERRIDE;
 
   virtual nsresult
   PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
 
 private:
   // This class can only be created from the RuntimeService.
-  SharedWorker(nsPIDOMWindow* aWindow,
-               WorkerPrivate* aWorkerPrivate);
+  SharedWorker(nsPIDOMWindow* aWindow, WorkerPrivate* aWorkerPrivate);
 
   // This class is reference-counted and will be destroyed from Release().
   ~SharedWorker();
 
   // Only called by MessagePort.
   void
   PostMessage(JSContext* aCx, JS::HandleValue aMessage,
               const Optional<Sequence<JS::Value>>& aTransferable,
new file mode 100644
--- /dev/null
+++ b/dom/workers/Worker.cpp
@@ -0,0 +1,672 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Worker.h"
+
+#include "mozilla/dom/DOMJSClass.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/EventHandlerBinding.h"
+#include "nsJSUtils.h"
+
+#include "jsapi.h"
+#include "EventTarget.h"
+#include "RuntimeService.h"
+#include "WorkerPrivate.h"
+
+#include "WorkerInlines.h"
+
+#define FUNCTION_FLAGS \
+  JSPROP_ENUMERATE
+
+USING_WORKERS_NAMESPACE
+
+using namespace mozilla::dom;
+using mozilla::ErrorResult;
+
+namespace {
+
+class Worker
+{
+  static const DOMJSClass sClass;
+  static const DOMIfaceAndProtoJSClass sProtoClass;
+  static const JSPropertySpec sProperties[];
+  static const JSFunctionSpec sFunctions[];
+
+protected:
+  enum {
+    // The constructor function holds a WorkerPrivate* in its first reserved
+    // slot.
+    CONSTRUCTOR_SLOT_PARENT = 0
+  };
+
+public:
+  static const JSClass*
+  Class()
+  {
+    return sClass.ToJSClass();
+  }
+
+  static const JSClass*
+  ProtoClass()
+  {
+    return sProtoClass.ToJSClass();
+  }
+
+  static const DOMClass*
+  DOMClassStruct()
+  {
+    return &sClass.mClass;
+  }
+
+  static JSObject*
+  InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
+            bool aMainRuntime)
+  {
+    JS::Rooted<JSObject*> proto(aCx,
+      js::InitClassWithReserved(aCx, aObj, aParentProto, ProtoClass(),
+                                Construct, 0, sProperties, sFunctions,
+                                NULL, NULL));
+    if (!proto) {
+      return NULL;
+    }
+
+    js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
+                        JS::PrivateValue(const_cast<DOMClass *>(DOMClassStruct())));
+
+    if (!aMainRuntime) {
+      WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
+      parent->AssertIsOnWorkerThread();
+
+      JSObject* constructor = JS_GetConstructor(aCx, proto);
+      if (!constructor)
+        return NULL;
+      js::SetFunctionNativeReserved(constructor, CONSTRUCTOR_SLOT_PARENT,
+                                    PRIVATE_TO_JSVAL(parent));
+    }
+
+    return proto;
+  }
+
+  static WorkerPrivate*
+  GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName);
+
+  static JSObject*
+  Create(JSContext* aCx, WorkerPrivate* aParentObj, const nsAString& aScriptURL,
+         bool aIsChromeWorker, bool aIsSharedWorker,
+         const nsAString& aSharedWorkerName);
+
+protected:
+  static bool
+  ConstructInternal(JSContext* aCx, JS::CallArgs aArgs, bool aIsChromeWorker)
+  {
+    if (!aArgs.length()) {
+      JS_ReportError(aCx, "Constructor requires at least one argument!");
+      return false;
+    }
+
+    JS::RootedString scriptURLStr(aCx, JS_ValueToString(aCx, aArgs[0]));
+    if (!scriptURLStr) {
+      return false;
+    }
+
+    nsDependentJSString scriptURL;
+    if (!scriptURL.init(aCx, scriptURLStr)) {
+      return false;
+    }
+
+    JS::Rooted<JS::Value> priv(aCx,
+      js::GetFunctionNativeReserved(&aArgs.callee(), CONSTRUCTOR_SLOT_PARENT));
+
+    WorkerPrivate* parent;
+    if (priv.isUndefined()) {
+      parent = NULL;
+    } else {
+      parent = static_cast<WorkerPrivate*>(priv.get().toPrivate());
+      parent->AssertIsOnWorkerThread();
+    }
+
+    JS::Rooted<JSObject*> obj(aCx,
+      Create(aCx, parent, scriptURL, aIsChromeWorker, false, EmptyString()));
+    if (!obj) {
+      return false;
+    }
+
+    aArgs.rval().setObject(*obj);
+    return true;
+  }
+
+private:
+  // No instance of this class should ever be created so these are explicitly
+  // left without an implementation to prevent linking in case someone tries to
+  // make one.
+  Worker();
+  ~Worker();
+
+  static bool
+  IsWorker(JS::Handle<JS::Value> v)
+  {
+    return v.isObject() && ClassIsWorker(JS_GetClass(&v.toObject()));
+  }
+
+  static bool
+  GetEventListener(JSContext* aCx, const JS::CallArgs aArgs,
+                   const nsAString &aNameStr)
+  {
+    WorkerPrivate* worker =
+      GetInstancePrivate(aCx, &aArgs.thisv().toObject(),
+                         NS_ConvertUTF16toUTF8(aNameStr).get());
+    MOZ_ASSERT(worker);
+
+    ErrorResult rv;
+    nsRefPtr<EventHandlerNonNull> handler =
+      worker->GetEventListener(Substring(aNameStr, 2), rv);
+
+    if (rv.Failed()) {
+      JS_ReportError(aCx, "Failed to get listener!");
+      return false;
+    }
+
+    if (!handler) {
+      aArgs.rval().setNull();
+    } else {
+      aArgs.rval().setObject(*handler->Callable());
+    }
+    return true;
+  }
+
+  static bool
+  GetOnerrorImpl(JSContext* aCx, JS::CallArgs aArgs)
+  {
+    return GetEventListener(aCx, aArgs, NS_LITERAL_STRING("onerror"));
+  }
+
+  static bool
+  GetOnerror(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+  {
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+    return JS::CallNonGenericMethod<IsWorker, GetOnerrorImpl>(aCx, args);
+  }
+
+  static bool
+  GetOnmessageImpl(JSContext* aCx, JS::CallArgs aArgs)
+  {
+    return GetEventListener(aCx, aArgs, NS_LITERAL_STRING("onmessage"));
+  }
+
+  static bool
+  GetOnmessage(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+  {
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+    return JS::CallNonGenericMethod<IsWorker, GetOnmessageImpl>(aCx, args);
+  }
+
+  static bool
+  SetEventListener(JSContext* aCx, JS::CallArgs aArgs,
+                   const nsAString& aNameStr)
+  {
+    WorkerPrivate* worker =
+      GetInstancePrivate(aCx, &aArgs.thisv().toObject(),
+                         NS_ConvertUTF16toUTF8(aNameStr).get());
+    MOZ_ASSERT(worker);
+
+    JS::Rooted<JSObject*> listener(aCx);
+    if (!JS_ValueToObject(aCx, aArgs.get(0), &listener)) {
+      return false;
+    }
+
+    nsRefPtr<EventHandlerNonNull> handler;
+    if (listener && JS_ObjectIsCallable(aCx, listener)) {
+      handler = new EventHandlerNonNull(listener);
+    } else {
+      handler = nullptr;
+    }
+    ErrorResult rv;
+    worker->SetEventListener(Substring(aNameStr, 2), handler, rv);
+
+    if (rv.Failed()) {
+      JS_ReportError(aCx, "Failed to set listener!");
+      return false;
+    }
+
+    aArgs.rval().setUndefined();
+    return true;
+  }
+
+  static bool
+  SetOnerrorImpl(JSContext* aCx, JS::CallArgs aArgs)
+  {
+    return SetEventListener(aCx, aArgs, NS_LITERAL_STRING("onerror"));
+  }
+
+  static bool
+  SetOnerror(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+  {
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+    return JS::CallNonGenericMethod<IsWorker, SetOnerrorImpl>(aCx, args);
+  }
+
+  static bool
+  SetOnmessageImpl(JSContext* aCx, JS::CallArgs aArgs)
+  {
+    return SetEventListener(aCx, aArgs, NS_LITERAL_STRING("onmessage"));
+  }
+
+  static bool
+  SetOnmessage(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+  {
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+    return JS::CallNonGenericMethod<IsWorker, SetOnmessageImpl>(aCx, args);
+  }
+
+  static bool
+  Construct(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+  {
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+    return ConstructInternal(aCx, args, false);
+  }
+
+  static void
+  Finalize(JSFreeOp* aFop, JSObject* aObj)
+  {
+    JS_ASSERT(JS_GetClass(aObj) == Class());
+    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    if (worker) {
+      worker->_finalize(aFop);
+    }
+  }
+
+  static void
+  Trace(JSTracer* aTrc, JSObject* aObj)
+  {
+    JS_ASSERT(JS_GetClass(aObj) == Class());
+    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    if (worker) {
+      worker->_trace(aTrc);
+    }
+  }
+
+  static bool
+  Terminate(JSContext* aCx, unsigned aArgc, jsval* aVp)
+  {
+    JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
+    if (!obj) {
+      return false;
+    }
+
+    const char* name = sFunctions[0].name;
+    WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
+    if (!worker) {
+      return !JS_IsExceptionPending(aCx);
+    }
+
+    if (!worker->Terminate(aCx)) {
+      return false;
+    }
+
+    JS_RVAL(aCx, aVp).setUndefined();
+    return true;
+  }
+
+  static bool
+  PostMessage(JSContext* aCx, unsigned aArgc, jsval* aVp)
+  {
+    JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
+    if (!obj) {
+      return false;
+    }
+
+    const char* name = sFunctions[1].name;
+    WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
+    if (!worker) {
+      return !JS_IsExceptionPending(aCx);
+    }
+
+    JS::Rooted<JS::Value> message(aCx);
+    JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
+    if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/v",
+                             message.address(), transferable.address())) {
+      return false;
+    }
+
+    if (!worker->PostMessage(aCx, message, transferable)) {
+      return false;
+    }
+
+    JS_RVAL(aCx, aVp).setUndefined();
+    return true;
+  }
+};
+
+const DOMJSClass Worker::sClass = {
+  {
+    "Worker",
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3) |
+    JSCLASS_IMPLEMENTS_BARRIERS,
+    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
+    NULL, NULL, NULL, NULL, Trace
+  },
+  {
+    INTERFACE_CHAIN_1(prototypes::id::EventTarget_workers),
+    false,
+    &sWorkerNativePropertyHooks
+  }
+};
+
+const DOMIfaceAndProtoJSClass Worker::sProtoClass = {
+  {
+    // XXXbz we use "Worker" here to match sClass so that we can
+    // js::InitClassWithReserved this JSClass and then call
+    // JS_NewObject with our sClass and have it find the right
+    // prototype.
+    "Worker",
+    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub,       /* addProperty */
+    JS_DeletePropertyStub, /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,               /* finalize */
+    nullptr,               /* checkAccess */
+    nullptr,               /* call */
+    nullptr,               /* hasInstance */
+    nullptr,               /* construct */
+    nullptr,               /* trace */
+    JSCLASS_NO_INTERNAL_MEMBERS
+  },
+  eInterfacePrototype,
+  &sWorkerNativePropertyHooks,
+  "[object Worker]",
+  prototypes::id::_ID_Count,
+  0
+};
+
+const JSPropertySpec Worker::sProperties[] = {
+  JS_PSGS("onerror", GetOnerror, SetOnerror, JSPROP_ENUMERATE),
+  JS_PSGS("onmessage", GetOnmessage, SetOnmessage, JSPROP_ENUMERATE),
+  JS_PS_END
+};
+
+const JSFunctionSpec Worker::sFunctions[] = {
+  JS_FN("terminate", Terminate, 0, FUNCTION_FLAGS),
+  JS_FN("postMessage", PostMessage, 1, FUNCTION_FLAGS),
+  JS_FS_END
+};
+
+class ChromeWorker : public Worker
+{
+  static const DOMJSClass sClass;
+  static const DOMIfaceAndProtoJSClass sProtoClass;
+
+public:
+  static const JSClass*
+  Class()
+  {
+    return sClass.ToJSClass();
+  }
+
+  static const JSClass*
+  ProtoClass()
+  {
+    return sProtoClass.ToJSClass();
+  }
+
+  static const DOMClass*
+  DOMClassStruct()
+  {
+    return &sClass.mClass;
+  }
+
+  static JSObject*
+  InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
+            bool aMainRuntime)
+  {
+    JS::Rooted<JSObject*> proto(aCx,
+      js::InitClassWithReserved(aCx, aObj, aParentProto, ProtoClass(),
+                                Construct, 0, NULL, NULL, NULL, NULL));
+    if (!proto) {
+      return NULL;
+    }
+
+    js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
+                        JS::PrivateValue(const_cast<DOMClass *>(DOMClassStruct())));
+
+    if (!aMainRuntime) {
+      WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
+      parent->AssertIsOnWorkerThread();
+
+      JSObject* constructor = JS_GetConstructor(aCx, proto);
+      if (!constructor)
+        return NULL;
+      js::SetFunctionNativeReserved(constructor, CONSTRUCTOR_SLOT_PARENT,
+                                    PRIVATE_TO_JSVAL(parent));
+    }
+
+    return proto;
+  }
+
+private:
+  // No instance of this class should ever be created so these are explicitly
+  // left without an implementation to prevent linking in case someone tries to
+  // make one.
+  ChromeWorker();
+  ~ChromeWorker();
+
+  static WorkerPrivate*
+  GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
+  {
+    if (aObj) {
+      const JSClass* classPtr = JS_GetClass(aObj);
+      if (classPtr == Class()) {
+        return UnwrapDOMObject<WorkerPrivate>(aObj);
+      }
+    }
+
+    return Worker::GetInstancePrivate(aCx, aObj, aFunctionName);
+  }
+
+  static bool
+  Construct(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+  {
+    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+    return ConstructInternal(aCx, args, true);
+  }
+
+  static void
+  Finalize(JSFreeOp* aFop, JSObject* aObj)
+  {
+    JS_ASSERT(JS_GetClass(aObj) == Class());
+    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    if (worker) {
+      worker->_finalize(aFop);
+    }
+  }
+
+  static void
+  Trace(JSTracer* aTrc, JSObject* aObj)
+  {
+    JS_ASSERT(JS_GetClass(aObj) == Class());
+    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    if (worker) {
+      worker->_trace(aTrc);
+    }
+  }
+};
+
+const DOMJSClass ChromeWorker::sClass = {
+  { "ChromeWorker",
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3) |
+    JSCLASS_IMPLEMENTS_BARRIERS,
+    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
+    NULL, NULL, NULL, NULL, Trace,
+  },
+  {
+    INTERFACE_CHAIN_1(prototypes::id::EventTarget_workers),
+    false,
+    &sWorkerNativePropertyHooks
+  }
+};
+
+const DOMIfaceAndProtoJSClass ChromeWorker::sProtoClass = {
+  {
+    // XXXbz we use "ChromeWorker" here to match sClass so that we can
+    // js::InitClassWithReserved this JSClass and then call
+    // JS_NewObject with our sClass and have it find the right
+    // prototype.
+    "ChromeWorker",
+    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub,       /* addProperty */
+    JS_DeletePropertyStub, /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,               /* finalize */
+    nullptr,               /* checkAccess */
+    nullptr,               /* call */
+    nullptr,               /* hasInstance */
+    nullptr,               /* construct */
+    nullptr,               /* trace */
+    JSCLASS_NO_INTERNAL_MEMBERS
+  },
+  eInterfacePrototype,
+  &sWorkerNativePropertyHooks,
+  "[object ChromeWorker]",
+  prototypes::id::_ID_Count,
+  0
+};
+
+WorkerPrivate*
+Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
+                           const char* aFunctionName)
+{
+  const JSClass* classPtr = JS_GetClass(aObj);
+  if (ClassIsWorker(classPtr)) {
+    return UnwrapDOMObject<WorkerPrivate>(aObj);
+  }
+
+  JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
+                       Class()->name, aFunctionName, classPtr->name);
+  return NULL;
+}
+
+JSObject*
+Worker::Create(JSContext* aCx, WorkerPrivate* aParent,
+               const nsAString& aScriptURL, bool aIsChromeWorker,
+               bool aIsSharedWorker, const nsAString& aSharedWorkerName)
+{
+  MOZ_ASSERT_IF(aIsSharedWorker, !aSharedWorkerName.IsVoid());
+  MOZ_ASSERT_IF(!aIsSharedWorker, aSharedWorkerName.IsEmpty());
+
+  RuntimeService* runtimeService;
+  if (aParent) {
+    runtimeService = RuntimeService::GetService();
+    NS_ASSERTION(runtimeService, "Null runtime service!");
+  }
+  else {
+    runtimeService = RuntimeService::GetOrCreateService();
+    if (!runtimeService) {
+      JS_ReportError(aCx, "Failed to create runtime service!");
+      return nullptr;
+    }
+  }
+
+  const JSClass* classPtr = aIsChromeWorker ? ChromeWorker::Class() : Class();
+
+  JS::Rooted<JSObject*> obj(aCx,
+    JS_NewObject(aCx, const_cast<JSClass*>(classPtr), nullptr, nullptr));
+  if (!obj) {
+    return nullptr;
+  }
+
+  // Ensure that the DOM_OBJECT_SLOT always has a PrivateValue set, as this will
+  // be accessed in the Trace() method if WorkerPrivate::Create() triggers a GC.
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
+
+  nsRefPtr<WorkerPrivate> worker =
+    WorkerPrivate::Create(aCx, obj, aParent, aScriptURL, aIsChromeWorker,
+                          aIsSharedWorker, aSharedWorkerName);
+  if (!worker) {
+    // It'd be better if we could avoid allocating the JSObject until after we
+    // make sure we have a WorkerPrivate, but failing that we should at least
+    // make sure that the DOM_OBJECT_SLOT always has a PrivateValue.
+    return nullptr;
+  }
+
+  // Worker now owned by the JS object.
+  NS_ADDREF(worker.get());
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, JS::PrivateValue(worker));
+
+  if (!runtimeService->RegisterWorker(aCx, worker)) {
+    return nullptr;
+  }
+
+  // Worker now also owned by its thread.
+  NS_ADDREF(worker.get());
+
+  return obj;
+}
+
+} // anonymous namespace
+
+BEGIN_WORKERS_NAMESPACE
+
+namespace worker {
+
+JSObject*
+InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
+          bool aMainRuntime)
+{
+  return Worker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
+}
+
+} // namespace worker
+
+WorkerCrossThreadDispatcher*
+GetWorkerCrossThreadDispatcher(JSContext* aCx, jsval aWorker)
+{
+  if (JSVAL_IS_PRIMITIVE(aWorker)) {
+    return NULL;
+  }
+
+  WorkerPrivate* w =
+      Worker::GetInstancePrivate(aCx, JSVAL_TO_OBJECT(aWorker),
+                                 "GetWorkerCrossThreadDispatcher");
+  if (!w) {
+    return NULL;
+  }
+  return w->GetCrossThreadDispatcher();
+}
+
+
+namespace chromeworker {
+
+bool
+InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
+          bool aMainRuntime)
+{
+  return !!ChromeWorker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
+}
+
+} // namespace chromeworker
+
+bool
+ClassIsWorker(const JSClass* aClass)
+{
+  return Worker::Class() == aClass || ChromeWorker::Class() == aClass;
+}
+
+bool
+GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+{
+    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr, JSMSG_GETTER_ONLY);
+    return false;
+}
+
+END_WORKERS_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/workers/Worker.h
@@ -0,0 +1,35 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_worker_h__
+#define mozilla_dom_workers_worker_h__
+
+#include "Workers.h"
+
+
+BEGIN_WORKERS_NAMESPACE
+
+namespace worker {
+
+JSObject*
+InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
+          bool aMainRuntime);
+
+} // namespace worker
+
+namespace chromeworker {
+
+bool
+InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
+          bool aMainRuntime);
+
+} // namespace chromeworker
+
+bool
+ClassIsWorker(const JSClass* aClass);
+
+END_WORKERS_NAMESPACE
+
+#endif /* mozilla_dom_workers_worker_h__ */
\ No newline at end of file
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -8,17 +8,16 @@
 
 #include "amIAddonManager.h"
 #include "nsIClassInfo.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMDOMException.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMFile.h"
-#include "nsIDOMMessageEvent.h"
 #include "nsIDocument.h"
 #include "nsIDocShell.h"
 #include "nsIMemoryReporter.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPIDOMWindow.h"
@@ -31,27 +30,23 @@
 #include <algorithm>
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEvent.h"
-#include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
-#include "mozilla/dom/WorkerBinding.h"
-#include "mozilla/Preferences.h"
 #include "mozilla/Util.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsError.h"
-#include "nsEventDispatcher.h"
 #include "nsDOMMessageEvent.h"
 #include "nsDOMJSUtils.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
 #include "nsPrintfCString.h"
 #include "nsProxyRelease.h"
@@ -66,28 +61,27 @@
 #include "Events.h"
 #include "mozilla/dom/Exceptions.h"
 #include "File.h"
 #include "MessagePort.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "SharedWorker.h"
+#include "Worker.h"
 #include "WorkerFeature.h"
 #include "WorkerMessagePort.h"
 #include "WorkerScope.h"
 
 // GC will run once every thirty seconds during normal execution.
 #define NORMAL_GC_TIMER_DELAY_MS 30000
 
 // GC will run five seconds after the last event is processed.
 #define IDLE_GC_TIMER_DELAY_MS 5000
 
-#define PREF_WORKERS_ENABLED "dom.workers.enabled"
-
 using mozilla::InternalScriptErrorEvent;
 using mozilla::MutexAutoLock;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 using mozilla::dom::Throw;
 using mozilla::AutoCxPusher;
 using mozilla::AutoPushJSContext;
 using mozilla::AutoSafeJSContext;
@@ -889,90 +883,66 @@ public:
     mClonedObjects.SwapElements(aClonedObjects);
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     MOZ_ASSERT_IF(mToMessagePort, aWorkerPrivate->IsSharedWorker());
 
+    bool mainRuntime;
+    JS::Rooted<JSObject*> target(aCx);
     if (mTarget == ParentThread) {
       // Don't fire this event if the JS object has been disconnected from the
       // private object.
       if (!aWorkerPrivate->IsAcceptingEvents()) {
         return true;
       }
 
       if (mToMessagePort) {
         return
           aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
                                                             mMessagePortSerial,
                                                             mBuffer,
                                                             mClonedObjects);
       }
 
+      mainRuntime = !aWorkerPrivate->GetParent();
+
+      target = aWorkerPrivate->GetJSObject();
+      NS_ASSERTION(target, "Must have a target!");
+
       if (aWorkerPrivate->IsSuspended()) {
         aWorkerPrivate->QueueRunnable(this);
         return true;
       }
 
       aWorkerPrivate->AssertInnerWindowIsCorrect();
-
-      // Release reference to objects that were AddRef'd for
-      // cloning into worker when array goes out of scope.
-      nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
-      clonedObjects.SwapElements(mClonedObjects);
-
-      JS::Rooted<JS::Value> messageData(aCx);
-      if (!mBuffer.read(aCx, messageData.address(),
-                        workers::WorkerStructuredCloneCallbacks(!aWorkerPrivate->GetParent()))) {
-        xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
-        return false;
+    }
+    else {
+      NS_ASSERTION(aWorkerPrivate == GetWorkerPrivateFromContext(aCx),
+                   "Badness!");
+      if (mToMessagePort) {
+        WorkerMessagePort* port =
+          aWorkerPrivate->GetMessagePort(mMessagePortSerial);
+        if (!port) {
+          // Must have been closed already.
+          return true;
+        }
+        return port->MaybeDispatchEvent(aCx, mBuffer, mClonedObjects);
       }
 
-      nsRefPtr<nsDOMMessageEvent> event =
-        new nsDOMMessageEvent(aWorkerPrivate, nullptr, nullptr);
-      nsresult rv =
-        event->InitMessageEvent(NS_LITERAL_STRING("message"),
-                                false /* non-bubbling */,
-                                true /* cancelable */,
-                                messageData,
-                                EmptyString(),
-                                EmptyString(),
-                                nullptr);
-      if (NS_FAILED(rv)) {
-        xpc::Throw(aCx, rv);
-        return false;
-      }
-
-      event->SetTrusted(true);
-
-      nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
-
-      nsEventStatus dummy = nsEventStatus_eIgnore;
-      aWorkerPrivate->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
-      return true;
+      mainRuntime = false;
+      target = JS::CurrentGlobalOrNull(aCx);
     }
 
-    MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
-    if (mToMessagePort) {
-      nsRefPtr<WorkerMessagePort> port =
-        aWorkerPrivate->GetMessagePort(mMessagePortSerial);
-      if (!port) {
-        // Must have been closed already.
-        return true;
-      }
-      return port->MaybeDispatchEvent(aCx, mBuffer, mClonedObjects);
-    }
-
-    JS::Rooted<JSObject*> target(aCx, JS::CurrentGlobalOrNull(aCx));
     NS_ASSERTION(target, "This should never be null!");
 
     JS::Rooted<JSObject*> event(aCx,
-      CreateMessageEvent(aCx, mBuffer, mClonedObjects, false));
+      CreateMessageEvent(aCx, mBuffer, mClonedObjects, mainRuntime));
     if (!event) {
       return false;
     }
 
     bool dummy;
     return DispatchEventToTarget(aCx, target, event, &dummy);
   }
 
@@ -1003,27 +973,16 @@ public:
     return aWorkerPrivate->ModifyBusyCount(aCx, true);
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     return aWorkerPrivate->NotifyInternal(aCx, mStatus);
   }
-
-  void
-  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-               bool aDispatchResult)
-  {
-    if (!aDispatchResult) {
-      // We couldn't dispatch to the worker, which means it's already dead.
-      // Undo the busy count modification.
-      aWorkerPrivate->ModifyBusyCount(aCx, false);
-    }
-  }
 };
 
 class CloseRunnable MOZ_FINAL : public WorkerControlRunnable
 {
 public:
   CloseRunnable(WorkerPrivate* aWorkerPrivate)
   : WorkerControlRunnable(aWorkerPrivate, ParentThread, UnchangedBusyCount)
   { }
@@ -1101,17 +1060,17 @@ public:
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     // Don't fire this event if the JS object has been disconnected from the
     // private object.
     if (!aWorkerPrivate->IsAcceptingEvents()) {
       return true;
     }
 
-    JS::Rooted<JSObject*> target(aCx, aWorkerPrivate->GetWrapper());
+    JS::Rooted<JSObject*> target(aCx, aWorkerPrivate->GetJSObject());
 
     uint64_t innerWindowId;
     bool fireAtScope = true;
 
     WorkerPrivate* parent = aWorkerPrivate->GetParent();
     if (parent) {
       innerWindowId = 0;
     }
@@ -1130,39 +1089,35 @@ public:
         return true;
       }
 
       aWorkerPrivate->AssertInnerWindowIsCorrect();
 
       innerWindowId = aWorkerPrivate->GetInnerWindowId();
     }
 
-    return ReportErrorRunnable::ReportError(aCx, parent, fireAtScope,
-                                            aWorkerPrivate, mMessage,
-                                            mFilename, mLine, mLineNumber,
-                                            mColumnNumber, mFlags,
+    return ReportErrorRunnable::ReportError(aCx, parent, fireAtScope, target,
+                                            mMessage, mFilename, mLine,
+                                            mLineNumber, mColumnNumber, mFlags,
                                             mErrorNumber, innerWindowId);
   }
 
   void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
   {
     WorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
   }
 
-  // aWorkerPrivate is the worker thread we're on (or the main thread, if null)
-  // aTarget is the worker object that we are going to fire an error at
-  // (if any).
   static bool
   ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-              bool aFireAtScope, WorkerPrivate* aTarget,
-              const nsString& aMessage, const nsString& aFilename,
-              const nsString& aLine, uint32_t aLineNumber,
-              uint32_t aColumnNumber, uint32_t aFlags,
+              bool aFireAtScope, JSObject* aTarget, const nsString& aMessage,
+              const nsString& aFilename, const nsString& aLine,
+              uint32_t aLineNumber, uint32_t aColumnNumber, uint32_t aFlags,
               uint32_t aErrorNumber, uint64_t aInnerWindowId)
   {
+    JS::Rooted<JSObject*> target(aCx, aTarget);
     if (aWorkerPrivate) {
       aWorkerPrivate->AssertIsOnWorkerThread();
     }
     else {
       AssertIsOnMainThread();
     }
 
     JS::Rooted<JSString*> message(aCx, JS_NewUCStringCopyN(aCx, aMessage.get(),
@@ -1176,38 +1131,37 @@ public:
     if (!filename) {
       return false;
     }
 
     // We should not fire error events for warnings but instead make sure that
     // they show up in the error console.
     if (!JSREPORT_IS_WARNING(aFlags)) {
       // First fire an ErrorEvent at the worker.
-      if (aTarget) {
-        ErrorEventInit init;
-        init.mMessage = aMessage;
-        init.mFilename = aFilename;
-        init.mLineno = aLineNumber;
-        init.mCancelable = true;
-
-        nsRefPtr<ErrorEvent> event =
-          ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
-
-        nsEventStatus status = nsEventStatus_eIgnore;
-        aTarget->DispatchDOMEvent(nullptr, event, nullptr, &status);
-
-        if (status == nsEventStatus_eConsumeNoDefault) {
+      if (target) {
+        JS::Rooted<JSObject*> event(aCx,
+          CreateErrorEvent(aCx, message, filename, aLineNumber, !aWorkerPrivate));
+        if (!event) {
+          return false;
+        }
+
+        bool preventDefaultCalled;
+        if (!DispatchEventToTarget(aCx, target, event, &preventDefaultCalled)) {
+          return false;
+        }
+
+        if (preventDefaultCalled) {
           return true;
         }
       }
 
       // Now fire an event at the global object, but don't do that if the error
       // code is too much recursion and this is the same script threw the error.
-      if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) {
-        JS::Rooted<JSObject*> target(aCx, JS::CurrentGlobalOrNull(aCx));
+      if (aFireAtScope && (target || aErrorNumber != JSMSG_OVER_RECURSED)) {
+        target = JS::CurrentGlobalOrNull(aCx);
         NS_ASSERTION(target, "This should never be null!");
 
         bool preventDefaultCalled;
         nsIScriptGlobalObject* sgo;
 
         if (aWorkerPrivate ||
             !(sgo = nsJSUtils::GetStaticScriptGlobal(target))) {
           // Fire a normal ErrorEvent if we're running on a worker thread.
@@ -1795,17 +1749,17 @@ WorkerRunnable::Run()
     }
   }
 
   JS::Rooted<JSObject*> targetCompartmentObject(cx);
 
   if (mTarget == WorkerThread) {
     targetCompartmentObject = JS::CurrentGlobalOrNull(cx);
   } else {
-    targetCompartmentObject = mWorkerPrivate->GetWrapper();
+    targetCompartmentObject = mWorkerPrivate->GetJSObject();
   }
 
   NS_ASSERTION(cx, "Must have a context!");
 
   JSAutoRequest ar(cx);
 
   Maybe<JSAutoCompartment> ac;
   if (targetCompartmentObject) {
@@ -2053,43 +2007,40 @@ private:
     mRtPath.Insert(addonId, explicitLength);
   }
 };
 
 NS_IMPL_ISUPPORTS1(WorkerPrivate::MemoryReporter, nsIMemoryReporter)
 
 template <class Derived>
 WorkerPrivateParent<Derived>::WorkerPrivateParent(
-                                             JSContext* aCx,
-                                             WorkerPrivate* aParent,
-                                             const nsAString& aScriptURL,
-                                             bool aIsChromeWorker,
+                                     JSContext* aCx,
+                                             JS::HandleObject aObject,
+                                     WorkerPrivate* aParent,
+                                     const nsAString& aScriptURL,
+                                     bool aIsChromeWorker,
                                              bool aIsSharedWorker,
                                              const nsAString& aSharedWorkerName,
                                              LoadInfo& aLoadInfo)
-: mMutex("WorkerPrivateParent Mutex"),
+: EventTarget(aParent ? aCx : nullptr), mMutex("WorkerPrivateParent Mutex"),
   mCondVar(mMutex, "WorkerPrivateParent CondVar"),
   mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
-  mParent(aParent), mScriptURL(aScriptURL),
+  mJSObject(aObject), mParent(aParent), mScriptURL(aScriptURL),
   mSharedWorkerName(aSharedWorkerName), mBusyCount(0), mMessagePortSerial(0),
-  mParentStatus(Pending), mRooted(false), mParentSuspended(false),
+  mParentStatus(Pending), mJSObjectRooted(false), mParentSuspended(false),
   mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
   mIsSharedWorker(aIsSharedWorker)
 {
-  SetIsDOMBinding();
-
-  MOZ_ASSERT_IF(aIsSharedWorker, !aSharedWorkerName.IsVoid() &&
-                                 NS_IsMainThread());
-  MOZ_ASSERT_IF(!aIsSharedWorker, aSharedWorkerName.IsEmpty());
+  MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivateParent);
+  MOZ_ASSERT_IF(aIsSharedWorker, !aObject && !aSharedWorkerName.IsVoid());
+  MOZ_ASSERT_IF(!aIsSharedWorker, aObject && aSharedWorkerName.IsEmpty());
 
   if (aLoadInfo.mWindow) {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aLoadInfo.mWindow->IsInnerWindow(),
-               "Should have inner window here!");
-    BindToOwner(aLoadInfo.mWindow);
+    NS_ASSERTION(aLoadInfo.mWindow->IsInnerWindow(),
+                 "Should have inner window here!");
   }
 
   mLoadInfo.StealFrom(aLoadInfo);
 
   if (aParent) {
     aParent->AssertIsOnWorkerThread();
 
     aParent->CopyJSSettings(mJSSettings);
@@ -2099,73 +2050,27 @@ WorkerPrivateParent<Derived>::WorkerPriv
                                         mJSSettings.content.options),
                  "Options mismatch!");
   }
   else {
     AssertIsOnMainThread();
 
     RuntimeService::GetDefaultJSSettings(mJSSettings);
   }
+
+  if (!aIsSharedWorker) {
+    SetIsDOMBinding();
+    SetWrapper(aObject);
+  }
 }
 
 template <class Derived>
 WorkerPrivateParent<Derived>::~WorkerPrivateParent()
 {
-  MOZ_ASSERT(!mRooted);
-}
-
-template <class Derived>
-NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, nsDOMEventTargetHelper)
-
-template <class Derived>
-NS_IMPL_RELEASE_INHERITED(WorkerPrivateParent<Derived>, nsDOMEventTargetHelper)
-
-template <class Derived>
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WorkerPrivateParent<Derived>)
-  // No new interfaces, just cycle collection.
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
-
-template <class Derived>
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
-                                                  nsDOMEventTargetHelper)
-  // Nothing else to traverse
-  // The various strong references in LoadInfo are managed manually and cannot
-  // be cycle collected.
-  tmp->AssertIsOnParentThread();
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-template <class Derived>
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
-                                                nsDOMEventTargetHelper)
-  tmp->AssertIsOnParentThread();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-template <class Derived>
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
-                                               nsDOMEventTargetHelper)
-  tmp->AssertIsOnParentThread();
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-template <class Derived>
-JSObject*
-WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx,
-                                         JS::Handle<JSObject*> aScope)
-{
-  MOZ_ASSERT(!mIsSharedWorker,
-             "We should never wrap a WorkerPrivate for a SharedWorker");
-
-  AssertIsOnParentThread();
-
-  JSObject* obj = WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate());
-
-  if (mRooted) {
-    PreserveWrapper(this);
-  }
-
-  return obj;
+  MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerPrivateParent);
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::Start()
 {
   // May be called on any thread!
   {
@@ -2453,31 +2358,62 @@ WorkerPrivateParent<Derived>::Synchroniz
   }
 
   mSynchronizeRunnable = runnable;
   return true;
 }
 
 template <class Derived>
 void
+WorkerPrivateParent<Derived>::_trace(JSTracer* aTrc)
+{
+  // This should only happen on the parent thread but we can't assert that
+  // because it can also happen on the cycle collector thread when this is a
+  // top-level worker.
+  EventTarget::_trace(aTrc);
+}
+
+template <class Derived>
+void
 WorkerPrivateParent<Derived>::_finalize(JSFreeOp* aFop)
 {
   AssertIsOnParentThread();
 
-  MOZ_ASSERT(!mRooted);
-
-  ClearWrapper();
-
-  // Ensure that we're held alive across the TerminatePrivate call, and then
-  // release the reference our wrapper held to us.
-  nsRefPtr<WorkerPrivateParent<Derived> > kungFuDeathGrip = dont_AddRef(this);
+  MOZ_ASSERT(mJSObject);
+  MOZ_ASSERT(!mJSObjectRooted);
+
+  // Clear the JS object.
+  mJSObject = nullptr;
 
   if (!TerminatePrivate(nullptr)) {
     NS_WARNING("Failed to terminate!");
   }
+
+  // Before calling through to the base class we need to grab another reference
+  // if we're on the main thread. Otherwise the base class' _Finalize method
+  // will call Release, and some of our members cannot be released during
+  // finalization. Of course, if those members are already gone then we can skip
+  // this mess...
+  WorkerPrivateParent<Derived>* extraSelfRef = NULL;
+
+  if (!mParent && !mMainThreadObjectsForgotten) {
+    AssertIsOnMainThread();
+    NS_ADDREF(extraSelfRef = this);
+  }
+
+  EventTarget::_finalize(aFop);
+
+  if (extraSelfRef) {
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewNonOwningRunnableMethod(extraSelfRef,
+                                    &WorkerPrivateParent<Derived>::Release);
+    if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
+      NS_WARNING("Failed to proxy release, this will leak!");
+    }
+  }
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::Close(JSContext* aCx)
 {
   AssertIsOnParentThread();
 
@@ -2496,63 +2432,65 @@ template <class Derived>
 bool
 WorkerPrivateParent<Derived>::ModifyBusyCount(JSContext* aCx, bool aIncrease)
 {
   AssertIsOnParentThread();
 
   NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
 
   if (aIncrease) {
-    if (mBusyCount++ == 0) {
-      Root(true);
+    if (mBusyCount++ == 0 && mJSObject) {
+      if (!RootJSObject(aCx, true)) {
+        return false;
+      }
     }
     return true;
   }
 
-  if (--mBusyCount == 0) {
-    Root(false);
+  if (--mBusyCount == 0 && mJSObject) {
+    if (!RootJSObject(aCx, false)) {
+      return false;
+    }
 
     bool shouldCancel;
     {
       MutexAutoLock lock(mMutex);
       shouldCancel = mParentStatus == Terminating;
     }
 
     if (shouldCancel && !Cancel(aCx)) {
       return false;
     }
   }
 
   return true;
 }
 
 template <class Derived>
-void
-WorkerPrivateParent<Derived>::Root(bool aRoot)
+bool
+WorkerPrivateParent<Derived>::RootJSObject(JSContext* aCx, bool aRoot)
 {
   AssertIsOnParentThread();
 
-  if (aRoot == mRooted) {
-    return;
-  }
-
-  if (aRoot) {
-    NS_ADDREF_THIS();
-    if (GetWrapperPreserveColor()) {
-      PreserveWrapper(this);
+  if (aRoot != mJSObjectRooted) {
+    if (aRoot) {
+      NS_ASSERTION(mJSObject, "Nothing to root?");
+      if (!JS_AddNamedObjectRoot(aCx, &mJSObject, "Worker root")) {
+        NS_WARNING("JS_AddNamedObjectRoot failed!");
+        return false;
+      }
     }
-  }
-  else {
-    if (GetWrapperPreserveColor()) {
-      ReleaseWrapper(this);
+    else {
+      JS_RemoveObjectRoot(aCx, &mJSObject);
     }
-    NS_RELEASE_THIS();
-  }
-
-  mRooted = aRoot;
+
+    mJSObjectRooted = aRoot;
+  }
+
+  return true;
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
                                       nsTArray<nsCOMPtr<nsISupports> >& aDoomed)
 {
   AssertIsOnParentThread();
@@ -2572,31 +2510,30 @@ WorkerPrivateParent<Derived>::ForgetMain
   // Before adding anything here update kDoomedCount above!
 
   MOZ_ASSERT(aDoomed.Length() == kDoomedCount);
 
   mMainThreadObjectsForgotten = true;
 }
 
 template <class Derived>
-void
+bool
 WorkerPrivateParent<Derived>::PostMessageInternal(
                                             JSContext* aCx,
-                                            JS::Handle<JS::Value> aMessage,
-                                            const Optional<Sequence<JS::Value> >& aTransferable,
+                                          JS::Handle<JS::Value> aMessage,
+                                            JS::Handle<JS::Value> aTransferable,
                                             bool aToMessagePort,
-                                            uint64_t aMessagePortSerial,
-                                            ErrorResult& aRv)
+                                            uint64_t aMessagePortSerial)
 {
   AssertIsOnParentThread();
 
   {
     MutexAutoLock lock(mMutex);
     if (mParentStatus > Running) {
-      return;
+      return true;
     }
   }
 
   JSStructuredCloneCallbacks* callbacks;
   if (GetParent()) {
     if (IsChromeWorker()) {
       callbacks = &gChromeWorkerStructuredCloneCallbacks;
     }
@@ -2610,59 +2547,58 @@ WorkerPrivateParent<Derived>::PostMessag
     if (IsChromeWorker()) {
       callbacks = &gMainThreadChromeWorkerStructuredCloneCallbacks;
     }
     else {
       callbacks = &gMainThreadWorkerStructuredCloneCallbacks;
     }
   }
 
-  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
-  if (aTransferable.WasPassed()) {
-    const Sequence<JS::Value>& realTransferable = aTransferable.Value();
-    JSObject* array =
-      JS_NewArrayObject(aCx, realTransferable.Length(),
-                        const_cast<JS::Value*>(realTransferable.Elements()));
-    if (!array) {
-      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-      return;
-    }
-    transferable.setObject(*array);
-  }
-
   nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
   JSAutoStructuredCloneBuffer buffer;
-  if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
-    aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
-    return;
+  if (!buffer.write(aCx, aMessage, aTransferable, callbacks, &clonedObjects)) {
+    return false;
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(ParentAsWorkerPrivate(),
                              WorkerRunnable::WorkerThread, buffer,
                              clonedObjects, aToMessagePort, aMessagePortSerial);
-  if (!runnable->Dispatch(aCx)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
+  return runnable->Dispatch(aCx);
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::PostMessageToMessagePort(
                              JSContext* aCx,
                              uint64_t aMessagePortSerial,
                              JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              ErrorResult& aRv)
 {
   AssertIsOnMainThread();
 
-  PostMessageInternal(aCx, aMessage, aTransferable, true, aMessagePortSerial,
-                      aRv);
+  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
+  if (aTransferable.WasPassed()) {
+    const Sequence<JS::Value>& realTransferable = aTransferable.Value();
+    JSObject* array =
+      JS_NewArrayObject(aCx, realTransferable.Length(),
+                        const_cast<jsval*>(realTransferable.Elements()));
+    if (!array) {
+      aRv = NS_ERROR_OUT_OF_MEMORY;
+      return;
+    }
+    transferable.setObject(*array);
+  }
+
+  if (!PostMessageInternal(aCx, aMessage, transferable, true,
+                           aMessagePortSerial)) {
+    aRv = NS_ERROR_FAILURE;
+  }
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
                                 JSContext* aCx, uint64_t aMessagePortSerial,
                                 JSAutoStructuredCloneBuffer& aBuffer,
                                 nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
@@ -3250,162 +3186,80 @@ WorkerPrivateParent<Derived>::ParentJSCo
 
   AssertIsOnMainThread();
 
   return mLoadInfo.mScriptContext ?
          mLoadInfo.mScriptContext->GetNativeContext() :
          nsContentUtils::GetSafeJSContext();
 }
 
-WorkerPrivate::WorkerPrivate(JSContext* aCx,
+WorkerPrivate::WorkerPrivate(JSContext* aCx, JS::HandleObject aObject,
                              WorkerPrivate* aParent,
                              const nsAString& aScriptURL,
                              bool aIsChromeWorker, bool aIsSharedWorker,
                              const nsAString& aSharedWorkerName,
                              LoadInfo& aLoadInfo)
-: WorkerPrivateParent<WorkerPrivate>(aCx, aParent, aScriptURL,
+: WorkerPrivateParent<WorkerPrivate>(aCx, aObject, aParent, aScriptURL,
                                      aIsChromeWorker, aIsSharedWorker,
                                      aSharedWorkerName, aLoadInfo),
   mJSContext(nullptr), mErrorHandlerRecursionCount(0), mNextTimeoutId(1),
   mStatus(Pending), mSuspended(false), mTimerRunning(false),
   mRunningExpiredTimeouts(false), mCloseHandlerStarted(false),
   mCloseHandlerFinished(false), mMemoryReporterRunning(false),
   mBlockedForMemoryReporter(false)
 {
-  MOZ_ASSERT_IF(aIsSharedWorker, !aSharedWorkerName.IsVoid());
-  MOZ_ASSERT_IF(!aIsSharedWorker, aSharedWorkerName.IsEmpty());
+  MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate);
+  MOZ_ASSERT_IF(aIsSharedWorker, !aObject && !aSharedWorkerName.IsVoid());
+  MOZ_ASSERT_IF(!aIsSharedWorker, aObject && aSharedWorkerName.IsEmpty());
 }
 
 WorkerPrivate::~WorkerPrivate()
 {
-}
-
-// static
-already_AddRefed<WorkerPrivate>
-WorkerPrivate::Constructor(const GlobalObject& aGlobal,
-                           const nsAString& aScriptURL,
-                           ErrorResult& aRv)
-{
-  return WorkerPrivate::Constructor(aGlobal, aScriptURL, false, false,
-                                    EmptyString(), nullptr, aRv);
-}
-
-// static
-bool
-WorkerPrivate::WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */)
-{
-  // If we're already on a worker workers are clearly enabled.
-  if (!NS_IsMainThread()) {
-    return true;
-  }
-
-  // If our caller is chrome, workers are always available.
-  if (nsContentUtils::IsCallerChrome()) {
-    return true;
-  }
-
-  // Else check the pref.
-  return Preferences::GetBool(PREF_WORKERS_ENABLED);
-}
-
-// static
-already_AddRefed<ChromeWorkerPrivate>
-ChromeWorkerPrivate::Constructor(const GlobalObject& aGlobal,
-                                 const nsAString& aScriptURL,
-                                 ErrorResult& aRv)
-{
-  return WorkerPrivate::Constructor(aGlobal, aScriptURL, true, false,
-                                    EmptyString(), nullptr, aRv).downcast<ChromeWorkerPrivate>();
-}
-
-// static
-bool
-ChromeWorkerPrivate::WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */)
-{
-  // Chrome is always allowed to use workers, and content is never allowed to
-  // use ChromeWorker, so all we have to check is the caller.
-  return nsContentUtils::ThreadsafeIsCallerChrome();
+  MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerPrivate);
 }
 
 // static
 already_AddRefed<WorkerPrivate>
-WorkerPrivate::Constructor(const GlobalObject& aGlobal,
-                           const nsAString& aScriptURL,
-                           bool aIsChromeWorker, bool aIsSharedWorker,
-                           const nsAString& aSharedWorkerName,
-                           LoadInfo* aLoadInfo, ErrorResult& aRv)
+WorkerPrivate::Create(JSContext* aCx, JS::HandleObject aObject,
+                      WorkerPrivate* aParent, const nsAString& aScriptURL,
+                      bool aIsChromeWorker, bool aIsSharedWorker,
+                      const nsAString& aSharedWorkerName, LoadInfo* aLoadInfo)
 {
-  WorkerPrivate* parent = NS_IsMainThread() ?
-                          nullptr :
-                          GetCurrentThreadWorkerPrivate();
-  if (parent) {
-    parent->AssertIsOnWorkerThread();
+  if (aParent) {
+    aParent->AssertIsOnWorkerThread();
   } else {
     AssertIsOnMainThread();
   }
 
-  JSContext* cx = aGlobal.GetContext();
-
-  MOZ_ASSERT_IF(aIsSharedWorker, !aSharedWorkerName.IsVoid());
-  MOZ_ASSERT_IF(!aIsSharedWorker, aSharedWorkerName.IsEmpty());
+  MOZ_ASSERT_IF(aIsSharedWorker, !aObject && !aSharedWorkerName.IsVoid());
+  MOZ_ASSERT_IF(!aIsSharedWorker, aObject && aSharedWorkerName.IsEmpty());
 
   mozilla::Maybe<LoadInfo> stackLoadInfo;
   if (!aLoadInfo) {
     stackLoadInfo.construct();
 
-    nsresult rv = GetLoadInfo(cx, nullptr, parent, aScriptURL,
+    nsresult rv = GetLoadInfo(aCx, nullptr, aParent, aScriptURL,
                               aIsChromeWorker, stackLoadInfo.addr());
     if (NS_FAILED(rv)) {
-      scriptloader::ReportLoadError(cx, aScriptURL, rv, !parent);
-      aRv.Throw(rv);
+      scriptloader::ReportLoadError(aCx, aScriptURL, rv, !aParent);
       return nullptr;
     }
 
     aLoadInfo = stackLoadInfo.addr();
   }
 
-  // NB: This has to be done before creating the WorkerPrivate, because it will
-  // attempt to use static variables that are initialized in the RuntimeService
-  // constructor.
-  RuntimeService* runtimeService;
-
-  if (!parent) {
-    runtimeService = RuntimeService::GetOrCreateService();
-    if (!runtimeService) {
-      JS_ReportError(cx, "Failed to create runtime service!");
-      aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
-    }
-  }
-  else {
-    runtimeService = RuntimeService::GetService();
-  }
-
-  MOZ_ASSERT(runtimeService);
-
   nsRefPtr<WorkerPrivate> worker =
-    new WorkerPrivate(cx, parent, aScriptURL, aIsChromeWorker,
+    new WorkerPrivate(aCx, aObject, aParent, aScriptURL, aIsChromeWorker,
                       aIsSharedWorker, aSharedWorkerName, *aLoadInfo);
 
   nsRefPtr<CompileScriptRunnable> compiler = new CompileScriptRunnable(worker);
-  if (!compiler->Dispatch(cx)) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
+  if (!compiler->Dispatch(aCx)) {
     return nullptr;
   }
 
-  if (!runtimeService->RegisterWorker(cx, worker)) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-
-  // The worker will be owned by its JSObject (via the reference we return from
-  // this function), but it also needs to be owned by its thread, so AddRef it
-  // again.
-  NS_ADDREF(worker.get());
-
   return worker.forget();
 }
 
 // static
 nsresult
 WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
                            WorkerPrivate* aParent, const nsAString& aScriptURL,
                            bool aIsChromeWorker, LoadInfo* aLoadInfo)
@@ -5150,16 +5004,25 @@ WorkerPrivateParent<Derived>::Unregister
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::StealHostObjectURIs(nsTArray<nsCString>& aArray)
 {
   aArray.SwapElements(mHostObjectURIs);
 }
 
+template <class Derived>
+JSObject*
+WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx,
+                                         JS::HandleObject aScope)
+{
+  MOZ_CRASH("This should never be called!");
+  return nullptr;
+}
+
 WorkerCrossThreadDispatcher*
 WorkerPrivate::GetCrossThreadDispatcher()
 {
   MutexAutoLock lock(mMutex);
 
   if (!mCrossThreadDispatcher && mStatus <= Running) {
     mCrossThreadDispatcher = new WorkerCrossThreadDispatcher(this);
   }
@@ -5305,34 +5168,16 @@ WorkerPrivate::AssertIsOnWorkerThread() 
   bool current;
   MOZ_ASSERT(NS_SUCCEEDED(mThread->IsOnCurrentThread(&current)));
   MOZ_ASSERT(current, "Wrong thread!");
 }
 #endif // DEBUG
 
 BEGIN_WORKERS_NAMESPACE
 
-WorkerCrossThreadDispatcher*
-GetWorkerCrossThreadDispatcher(JSContext* aCx, JS::Value aWorker)
-{
-  if (!aWorker.isObject()) {
-    return nullptr;
-  }
-
-  WorkerPrivate* w = nullptr;
-  UNWRAP_OBJECT(Worker, aCx, &aWorker.toObject(), w);
-  MOZ_ASSERT(w);
-  return w->GetCrossThreadDispatcher();
-}
-
-// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the
-// templates.
-template <>
-WorkerPrivateParent<WorkerPrivate>::cycleCollection WorkerPrivateParent<WorkerPrivate>::_cycleCollectorGlobal = WorkerPrivateParent<WorkerPrivate>::cycleCollection();
-
 // Force instantiation.
 template class WorkerPrivateParent<WorkerPrivate>;
 
 JSStructuredCloneCallbacks*
 WorkerStructuredCloneCallbacks(bool aMainRuntime)
 {
   return aMainRuntime ?
          &gMainThreadWorkerStructuredCloneCallbacks :
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -15,25 +15,25 @@
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
-#include "nsDOMEventTargetHelper.h"
 #include "nsEventQueue.h"
 #include "nsHashKeys.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 #include "nsTPriorityQueue.h"
 #include "StructuredCloneTags.h"
 
+#include "EventTarget.h"
 #include "Queue.h"
 #include "WorkerFeature.h"
 
 class JSAutoStructuredCloneBuffer;
 class nsIChannel;
 class nsIDocument;
 class nsIPrincipal;
 class nsIScriptContext;
@@ -229,17 +229,17 @@ public:
   AssertCurrentThreadOwns() const
   {
     MOZ_ASSERT(mMutex);
     mMutex->AssertCurrentThreadOwns();
   }
 };
 
 template <class Derived>
-class WorkerPrivateParent : public nsDOMEventTargetHelper
+class WorkerPrivateParent : public EventTarget
 {
   class SynchronizeAndResumeRunnable;
 
 public:
   struct LocationInfo
   {
     nsCString mHref;
     nsCString mProtocol;
@@ -295,22 +295,21 @@ public:
 protected:
   typedef mozilla::ErrorResult ErrorResult;
 
   SharedMutex mMutex;
   mozilla::CondVar mCondVar;
   mozilla::CondVar mMemoryReportCondVar;
 
 private:
+  JSObject* mJSObject;
   WorkerPrivate* mParent;
   nsString mScriptURL;
   nsString mSharedWorkerName;
   LocationInfo mLocationInfo;
-  // The lifetime of these objects within LoadInfo is managed explicitly;
-  // they do not need to be cycle collected.
   LoadInfo mLoadInfo;
 
   // Only used for top level workers.
   nsTArray<nsRefPtr<WorkerRunnable> > mQueuedRunnables;
   nsRevocableEventPtr<SynchronizeAndResumeRunnable> mSynchronizeRunnable;
 
   // Only for ChromeWorkers without window and only touched on the main thread.
   nsTArray<nsCString> mHostObjectURIs;
@@ -320,27 +319,27 @@ private:
 
   // Only touched on the parent thread (currently this is always the main
   // thread as SharedWorkers are always top-level).
   nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers;
 
   uint64_t mBusyCount;
   uint64_t mMessagePortSerial;
   Status mParentStatus;
-  bool mRooted;
+  bool mJSObjectRooted;
   bool mParentSuspended;
   bool mIsChromeWorker;
   bool mMainThreadObjectsForgotten;
   bool mIsSharedWorker;
 
 protected:
-  WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
-                      const nsAString& aScriptURL, bool aIsChromeWorker,
-                      bool aIsSharedWorker, const nsAString& aSharedWorkerName,
-                      LoadInfo& aLoadInfo);
+  WorkerPrivateParent(JSContext* aCx, JS::HandleObject aObject,
+                      WorkerPrivate* aParent, const nsAString& aScriptURL,
+                      bool aIsChromeWorker, bool aIsSharedWorker,
+                      const nsAString& aSharedWorkerName, LoadInfo& aLoadInfo);
 
   ~WorkerPrivateParent();
 
 private:
   Derived*
   ParentAsWorkerPrivate() const
   {
     return static_cast<Derived*>(const_cast<WorkerPrivateParent*>(this));
@@ -352,31 +351,22 @@ private:
 
   // aCx is null when called from the finalizer
   bool
   TerminatePrivate(JSContext* aCx)
   {
     return NotifyPrivate(aCx, Terminating);
   }
 
-  void
+  bool
   PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-                      const Optional<Sequence<JS::Value> >& aTransferable,
-                      bool aToMessagePort, uint64_t aMessagePortSerial,
-                      ErrorResult& aRv);
+                      JS::Handle<JS::Value> aTransferable,
+                      bool aToMessagePort, uint64_t aMessagePortSerial);
 
 public:
-
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
-                                                         nsDOMEventTargetHelper)
-
   // May be called on any thread...
   bool
   Start();
 
   // Called on the parent thread.
   bool
   Notify(JSContext* aCx, Status aStatus)
   {
@@ -400,58 +390,60 @@ public:
 
   bool
   Resume(JSContext* aCx, nsPIDOMWindow* aWindow);
 
   bool
   SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow,
                        nsIScriptContext* aScriptContext);
 
-  void
-  _finalize(JSFreeOp* aFop);
+  virtual void
+  _trace(JSTracer* aTrc) MOZ_OVERRIDE;
+
+  virtual void
+  _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
 
   void
   Finish(JSContext* aCx)
   {
-    Root(false);
+    RootJSObject(aCx, false);
   }
 
   bool
   Terminate(JSContext* aCx)
   {
     AssertIsOnParentThread();
-    Root(false);
+    RootJSObject(aCx, false);
     return TerminatePrivate(aCx);
   }
 
   bool
   Close(JSContext* aCx);
 
   bool
   ModifyBusyCount(JSContext* aCx, bool aIncrease);
 
-  void
-  Root(bool aRoot);
+  bool
+  RootJSObject(JSContext* aCx, bool aRoot);
 
   void
   ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
 
-  void
+  bool
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-              const Optional<Sequence<JS::Value> >& aTransferable,
-              ErrorResult& aRv)
+              JS::Handle<JS::Value> aTransferable)
   {
-    PostMessageInternal(aCx, aMessage, aTransferable, false, 0, aRv);
+    return PostMessageInternal(aCx, aMessage, aTransferable, false, 0);
   }
 
   void
   PostMessageToMessagePort(JSContext* aCx,
                            uint64_t aMessagePortSerial,
                            JS::Handle<JS::Value> aMessage,
-                           const Optional<Sequence<JS::Value> >& aTransferable,
+                           const Optional<Sequence<JS::Value > >& aTransferable,
                            ErrorResult& aRv);
 
   bool
   DispatchMessageEventToMessagePort(
                                JSContext* aCx,
                                uint64_t aMessagePortSerial,
                                JSAutoStructuredCloneBuffer& aBuffer,
                                nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
@@ -540,16 +532,22 @@ public:
 
   nsIScriptContext*
   GetScriptContext() const
   {
     AssertIsOnMainThread();
     return mLoadInfo.mScriptContext;
   }
 
+  JSObject*
+  GetJSObject() const
+  {
+    return mJSObject;
+  }
+
   const nsString&
   ScriptURL() const
   {
     return mScriptURL;
   }
 
   const nsCString&
   Domain() const
@@ -703,18 +701,18 @@ public:
   RegisterHostObjectURI(const nsACString& aURI);
 
   void
   UnregisterHostObjectURI(const nsACString& aURI);
 
   void
   StealHostObjectURIs(nsTArray<nsCString>& aArray);
 
-  IMPL_EVENT_HANDLER(message)
-  IMPL_EVENT_HANDLER(error)
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JS::HandleObject aScope) MOZ_OVERRIDE;
 
 #ifdef DEBUG
   void
   AssertIsOnParentThread() const;
 
   void
   AssertInnerWindowIsCorrect() const;
 #else
@@ -788,32 +786,24 @@ class WorkerPrivate : public WorkerPriva
   bool mCloseHandlerFinished;
   bool mMemoryReporterRunning;
   bool mBlockedForMemoryReporter;
 
 #ifdef DEBUG
   nsCOMPtr<nsIThread> mThread;
 #endif
 
-protected:
+public:
   ~WorkerPrivate();
 
-public:
   static already_AddRefed<WorkerPrivate>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              ErrorResult& aRv);
-
-  static already_AddRefed<WorkerPrivate>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              bool aIsChromeWorker, bool aIsSharedWorker,
-              const nsAString& aSharedWorkerName,
-              LoadInfo* aLoadInfo, ErrorResult& aRv);
-
-  static bool
-  WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
+  Create(JSContext* aCx, JS::HandleObject aObject, WorkerPrivate* aParent,
+         const nsAString& aScriptURL, bool aIsChromeWorker,
+         bool aIsSharedWorker, const nsAString& aSharedWorkerName,
+         LoadInfo* aLoadInfo = nullptr);
 
   static nsresult
   GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent,
               const nsAString& aScriptURL, bool aIsChromeWorker,
               LoadInfo* aLoadInfo);
 
   void
   DoRunLoop(JSContext* aCx);
@@ -1023,20 +1013,20 @@ public:
 
   void
   DisconnectMessagePort(uint64_t aMessagePortSerial);
 
   WorkerMessagePort*
   GetMessagePort(uint64_t aMessagePortSerial);
 
 private:
-  WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
-                const nsAString& aScriptURL, bool aIsChromeWorker,
-                bool aIsSharedWorker, const nsAString& aSharedWorkerName,
-                LoadInfo& aLoadInfo);
+  WorkerPrivate(JSContext* aCx, JS::HandleObject aObject,
+                WorkerPrivate* aParent, const nsAString& aScriptURL,
+                bool aIsChromeWorker, bool aIsSharedWorker,
+                const nsAString& aSharedWorkerName, LoadInfo& aLoadInfo);
 
   bool
   Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue);
 
   bool
   DispatchToSyncQueue(WorkerSyncRunnable* aEvent);
 
   void
@@ -1105,41 +1095,19 @@ private:
   bool
   PostMessageToParentInternal(JSContext* aCx,
                               JS::Handle<JS::Value> aMessage,
                               JS::Handle<JS::Value> aTransferable,
                               bool aToMessagePort,
                               uint64_t aMessagePortSerial);
 };
 
-// This class is only used to trick the DOM bindings.  We never create
-// instances of it, and static_casting to it is fine since it doesn't add
-// anything to WorkerPrivate.
-class ChromeWorkerPrivate : public WorkerPrivate
-{
-public:
-  static already_AddRefed<ChromeWorkerPrivate>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              ErrorResult& rv);
-
-  static bool
-  WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
-
-private:
-  ChromeWorkerPrivate() MOZ_DELETE;
-  ChromeWorkerPrivate(const ChromeWorkerPrivate& aRHS) MOZ_DELETE;
-  ChromeWorkerPrivate& operator =(const ChromeWorkerPrivate& aRHS) MOZ_DELETE;
-};
-
 WorkerPrivate*
 GetWorkerPrivateFromContext(JSContext* aCx);
 
-WorkerPrivate*
-GetCurrentThreadWorkerPrivate();
-
 bool
 IsCurrentThreadRunningChromeWorker();
 
 JSContext*
 GetCurrentThreadJSContext();
 
 enum WorkerStructuredDataType
 {
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -18,17 +18,16 @@
 #include "mozilla/dom/FileReaderSyncBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/dom/XMLHttpRequestUploadBinding.h"
 #include "mozilla/dom/URLBinding.h"
-#include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerLocationBinding.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 #include "mozilla/OSFileConstants.h"
 #include "nsIGlobalObject.h"
 #include "nsTraceRefcnt.h"
 #include "xpcpublic.h"
 
 #ifdef ANDROID
@@ -40,16 +39,17 @@
 #include "EventListenerManager.h"
 #include "EventTarget.h"
 #include "File.h"
 #include "FileReaderSync.h"
 #include "Location.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "ScriptLoader.h"
+#include "Worker.h"
 #include "WorkerPrivate.h"
 #include "XMLHttpRequest.h"
 
 #include "WorkerInlines.h"
 
 #define FUNCTION_FLAGS \
   JSPROP_ENUMERATE
 
@@ -1446,20 +1446,26 @@ CreateGlobalScope(JSContext* aCx)
   if (!finalScopeProto) {
     return nullptr;
   }
 
   if (!JS_SetPrototype(aCx, global, finalScopeProto)) {
     return nullptr;
   }
 
+  JS::Rooted<JSObject*> workerProto(aCx,
+    worker::InitClass(aCx, global, eventTargetProto, false));
+  if (!workerProto) {
+    return nullptr;
+  }
+
   if (worker->IsChromeWorker()) {
-    if (!DefineChromeWorkerFunctions(aCx, global) ||
-        !DefineOSFileConstants(aCx, global) ||
-        !ChromeWorkerBinding::GetConstructorObject(aCx, global)) {
+    if (!chromeworker::InitClass(aCx, global, workerProto, false) ||
+        !DefineChromeWorkerFunctions(aCx, global) ||
+        !DefineOSFileConstants(aCx, global)) {
       return nullptr;
     }
   }
 
   // Init other classes we care about.
   if (!events::InitClasses(aCx, global, false) ||
       !file::InitClasses(aCx, global)) {
     return nullptr;
@@ -1470,31 +1476,23 @@ CreateGlobalScope(JSContext* aCx)
       !EventBinding::GetConstructorObject(aCx, global) ||
       !FileReaderSyncBinding_workers::GetConstructorObject(aCx, global) ||
       !ImageDataBinding::GetConstructorObject(aCx, global) ||
       !TextDecoderBinding::GetConstructorObject(aCx, global) ||
       !TextEncoderBinding::GetConstructorObject(aCx, global) ||
       !XMLHttpRequestBinding_workers::GetConstructorObject(aCx, global) ||
       !XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, global) ||
       !URLBinding_workers::GetConstructorObject(aCx, global) ||
-      !WorkerBinding::GetConstructorObject(aCx, global) ||
       !WorkerLocationBinding_workers::GetConstructorObject(aCx, global) ||
       !WorkerNavigatorBinding_workers::GetConstructorObject(aCx, global)) {
     return nullptr;
   }
 
   if (!JS_DefineProfilingFunctions(aCx, global)) {
     return nullptr;
   }
 
   JS_FireOnNewGlobalObject(aCx, global);
 
   return global;
 }
 
-bool
-GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
-  JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr, JSMSG_GETTER_ONLY);
-  return false;
-}
-
 END_WORKERS_NAMESPACE
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -4,20 +4,16 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['test']
 
 MODULE = 'dom'
 
 # Public stuff.
-EXPORTS.mozilla.dom += [
-    'WorkerPrivate.h',
-]
-
 EXPORTS.mozilla.dom.workers += [
     'Workers.h',
 ]
 
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
     'DOMBindingBase.h',
     'EventListenerManager.h',
@@ -46,16 +42,17 @@ CPP_SOURCES += [
     'Location.cpp',
     'MessagePort.cpp',
     'Navigator.cpp',
     'Principal.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
     'SharedWorker.cpp',
     'URL.cpp',
+    'Worker.cpp',
     'WorkerMessagePort.cpp',
     'WorkerPrivate.cpp',
     'WorkerScope.cpp',
     'XMLHttpRequest.cpp',
     'XMLHttpRequestEventTarget.cpp',
     'XMLHttpRequestUpload.cpp',
 ]
 
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -68,17 +68,16 @@ class nsRange;
 class nsString;
 class nsTransactionManager;
 
 namespace mozilla {
 class Selection;
 
 namespace dom {
 class Element;
-class EventTarget;
 }  // namespace dom
 }  // namespace mozilla
 
 namespace mozilla {
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
@@ -659,17 +658,17 @@ public:
                                     nsISelection *aSelection,
                                     nsIDOMNode *previousSelectedNode,
                                     int32_t previousSelectedOffset,
                                     nsIDOMNode *aStartNode,
                                     int32_t aStartOffset,
                                     nsIDOMNode *aEndNode,
                                     int32_t aEndOffset);
 
-  virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget() = 0;
+  virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget() = 0;
 
   // Fast non-refcounting editor root element accessor
   mozilla::dom::Element *GetRoot();
 
   // Likewise, but gets the editor's root instead, which is different for HTML
   // editors
   virtual mozilla::dom::Element* GetEditorRoot();
 
@@ -815,17 +814,17 @@ protected:
   nsCString mContentMIMEType;       // MIME type of the doc we are editing.
 
   nsCOMPtr<nsIInlineSpellChecker> mInlineSpellChecker;
 
   nsRefPtr<nsTransactionManager> mTxnMgr;
   nsCOMPtr<mozilla::dom::Element> mRootElement; // cached root node
   nsCOMPtr<nsIPrivateTextRangeList> mIMETextRangeList; // IME special selection ranges
   nsCOMPtr<nsIDOMCharacterData>     mIMETextNode;      // current IME text node
-  nsCOMPtr<mozilla::dom::EventTarget> mEventTarget; // The form field as an event receiver
+  nsCOMPtr<nsIDOMEventTarget> mEventTarget; // The form field as an event receiver
   nsCOMPtr<nsIDOMEventListener> mEventListener;
   nsWeakPtr        mSelConWeak;          // weak reference to the nsISelectionController
   nsWeakPtr        mPlaceHolderTxn;      // weak reference to placeholder for begin/end batch purposes
   nsWeakPtr        mDocWeak;             // weak reference to the nsIDOMDocument
   nsIAtom          *mPlaceHolderName;    // name of placeholder transaction
   nsSelectionState *mSelState;           // saved selection state for placeholder txn batching
   nsString         *mPhonetic;
 
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=4 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/dom/Element.h"        // for Element
-#include "mozilla/dom/EventTarget.h"    // for EventTarget
 #include "nsAString.h"
 #include "nsCaret.h"                    // for nsCaret
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsEditor.h"                   // for nsEditor, etc
 #include "nsEditorEventListener.h"
 #include "nsEventListenerManager.h"     // for nsEventListenerManager
 #include "nsFocusManager.h"             // for nsFocusManager
 #include "nsGkAtoms.h"                  // for nsGkAtoms, nsGkAtoms::input
@@ -51,17 +50,16 @@
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
 #include "nsContentUtils.h"             // for nsContentUtils, etc
 #include "nsIBidiKeyboard.h"            // for nsIBidiKeyboard
 #endif
 
 class nsPresContext;
 
 using namespace mozilla;
-using mozilla::dom::EventTarget;
 
 nsEditorEventListener::nsEditorEventListener() :
   mEditor(nullptr), mCommitText(false),
   mInTransaction(false)
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   , mHaveBidiKeyboards(false)
   , mShouldSwitchTextDirection(false)
   , mSwitchToRTL(false)
@@ -100,21 +98,21 @@ nsEditorEventListener::Connect(nsEditor*
   return rv;
 }
 
 nsresult
 nsEditorEventListener::InstallToEditor()
 {
   NS_PRECONDITION(mEditor, "The caller must set mEditor");
 
-  nsCOMPtr<EventTarget> piTarget = mEditor->GetDOMEventTarget();
+  nsCOMPtr<nsIDOMEventTarget> piTarget = mEditor->GetDOMEventTarget();
   NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE);
 
   // register the event listeners with the listener manager
-  nsEventListenerManager* elmP = piTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* elmP = piTarget->GetListenerManager(true);
   NS_ENSURE_STATE(elmP);
 
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("keydown"),
                                dom::TrustedEventsAtSystemGroupBubble());
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("keyup"),
@@ -178,22 +176,23 @@ nsEditorEventListener::Disconnect()
   }
   UninstallFromEditor();
   mEditor = nullptr;
 }
 
 void
 nsEditorEventListener::UninstallFromEditor()
 {
-  nsCOMPtr<EventTarget> piTarget = mEditor->GetDOMEventTarget();
+  nsCOMPtr<nsIDOMEventTarget> piTarget = mEditor->GetDOMEventTarget();
   if (!piTarget) {
     return;
   }
 
-  nsEventListenerManager* elmP = piTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* elmP =
+    piTarget->GetListenerManager(true);
   if (!elmP) {
     return;
   }
 
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   elmP->RemoveEventListenerByType(this,
                                   NS_LITERAL_STRING("keydown"),
                                   dom::TrustedEventsAtSystemGroupBubble());
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -65,17 +65,16 @@
 #include "nsWSRunObject.h"
 #include "nsGkAtoms.h"
 #include "nsIWidget.h"
 
 #include "nsIFrame.h"
 #include "nsIParserService.h"
 #include "mozilla/Selection.h"
 #include "mozilla/dom/Element.h"
-#include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "nsTextFragment.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
 // Some utilities to handle annoying overloading of "A" tag for link and named anchor
 static char hrefText[] = "href";
@@ -5213,24 +5212,24 @@ nsHTMLEditor::GetActiveEditingHost()
   // we're not active.
   if (!content->HasFlag(NODE_IS_EDITABLE) ||
       content->HasIndependentSelection()) {
     return nullptr;
   }
   return content->GetEditingHost();
 }
 
-already_AddRefed<mozilla::dom::EventTarget>
+already_AddRefed<nsIDOMEventTarget>
 nsHTMLEditor::GetDOMEventTarget()
 {
   // Don't use getDocument here, because we have no way of knowing
   // whether Init() was ever called.  So we need to get the document
   // ourselves, if it exists.
   NS_PRECONDITION(mDocWeak, "This editor has not been initialized yet");
-  nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryReferent(mDocWeak);
+  nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mDocWeak.get());
   return target.forget();
 }
 
 bool
 nsHTMLEditor::ShouldReplaceRootElement()
 {
   if (!mRootElement) {
     // If we don't know what is our root element, we should find our root.
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -101,17 +101,17 @@ public:
 
   /* ------------ nsPlaintextEditor overrides -------------- */
   NS_IMETHOD GetIsDocumentEditable(bool *aIsDocumentEditable);
   NS_IMETHOD BeginningOfDocument();
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
   virtual already_AddRefed<nsIContent> GetFocusedContent();
   virtual already_AddRefed<nsIContent> GetFocusedContentForIME();
   virtual bool IsActiveInDOMWindow();
-  virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget();
+  virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget();
   virtual mozilla::dom::Element* GetEditorRoot() MOZ_OVERRIDE;
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode *aNode);
   virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
   virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
   virtual bool IsEditable(nsIContent *aNode);
   using nsEditor::IsEditable;
 
   /* ------------ nsStubMutationObserver overrides --------- */
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -1579,20 +1579,20 @@ nsPlaintextEditor::SelectEntireDocument(
     nsCOMPtr<nsIDOMNode> parentNode = GetNodeLocation(childNode, &parentOffset);
 
     return aSelection->Extend(parentNode, parentOffset);
   }
 
   return NS_OK;
 }
 
-already_AddRefed<mozilla::dom::EventTarget>
+already_AddRefed<nsIDOMEventTarget>
 nsPlaintextEditor::GetDOMEventTarget()
 {
-  nsCOMPtr<mozilla::dom::EventTarget> copy = mEventTarget;
+  nsCOMPtr<nsIDOMEventTarget> copy = mEventTarget;
   return copy.forget();
 }
 
 
 nsresult
 nsPlaintextEditor::SetAttributeOrEquivalent(nsIDOMElement * aElement,
                                             const nsAString & aAttribute,
                                             const nsAString & aValue,
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -115,17 +115,17 @@ public:
    *  with a call to EndOperation */
   NS_IMETHOD EndOperation();
 
   /** make the given selection span the entire document */
   NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
 
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
 
-  virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget();
+  virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget();
 
   virtual nsresult BeginIMEComposition();
   virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
                                         nsIPrivateTextRangeList *aTextRange);
 
   virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
 
   /* ------------ Utility Routines, not part of public API -------------- */
--- a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
@@ -860,17 +860,17 @@ nsDocShellTreeOwner::AddChromeListeners(
         rv = NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // register dragover and drop event listeners with the listener manager
   nsCOMPtr<EventTarget> target;
   GetDOMEventTarget(mWebBrowser, getter_AddRefs(target));
 
-  nsEventListenerManager* elmP = target->GetOrCreateListenerManager();
+  nsEventListenerManager* elmP = target->GetListenerManager(true);
   if (elmP) {
     elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"),
                                  dom::TrustedEventsAtSystemGroupBubble());
     elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"),
                                  dom::TrustedEventsAtSystemGroupBubble());
   }
 
   return rv;
@@ -890,17 +890,17 @@ nsDocShellTreeOwner::RemoveChromeListene
     NS_RELEASE(mChromeContextMenuListener);
   }
 
   nsCOMPtr<EventTarget> piTarget;
   GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget));
   if (!piTarget)
     return NS_OK;
 
-  nsEventListenerManager* elmP = piTarget->GetOrCreateListenerManager();
+  nsEventListenerManager* elmP = piTarget->GetListenerManager(true);
   if (elmP)
   {
     elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"),
                                     dom::TrustedEventsAtSystemGroupBubble());
     elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"),
                                     dom::TrustedEventsAtSystemGroupBubble());
   }
 
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -113,23 +113,23 @@ GetPrefsFor(nsEventStructType aEventStru
   }
 
   return prefs;
 }
 
 static bool
 HasMouseListener(nsIContent* aContent)
 {
-  if (nsEventListenerManager* elm = aContent->GetExistingListenerManager()) {
-    return elm->HasListenersFor(nsGkAtoms::onclick) ||
-           elm->HasListenersFor(nsGkAtoms::onmousedown) ||
-           elm->HasListenersFor(nsGkAtoms::onmouseup);
+  nsEventListenerManager* elm = aContent->GetListenerManager(false);
+  if (!elm) {
+    return false;
   }
-
-  return false;
+  return elm->HasListenersFor(nsGkAtoms::onclick) ||
+         elm->HasListenersFor(nsGkAtoms::onmousedown) ||
+         elm->HasListenersFor(nsGkAtoms::onmouseup);
 }
 
 static bool
 IsElementClickable(nsIFrame* aFrame, nsIAtom* stopAt = nullptr)
 {
   // Input events propagate up the content tree so we'll follow the content
   // ancestors to look for elements accepting the click.
   for (nsIContent* content = aFrame->GetContent(); content;
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2203,17 +2203,17 @@ MayHavePaintEventListener(nsPIDOMWindow*
   if (aInnerWindow->HasPaintEventListeners())
     return true;
 
   EventTarget* parentTarget = aInnerWindow->GetParentTarget();
   if (!parentTarget)
     return false;
 
   nsEventListenerManager* manager = nullptr;
-  if ((manager = parentTarget->GetExistingListenerManager()) &&
+  if ((manager = parentTarget->GetListenerManager(false)) &&
       manager->MayHavePaintEventListener()) {
     return true;
   }
 
   nsCOMPtr<nsINode> node;
   if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
     nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
       do_QueryInterface(parentTarget);
@@ -2231,17 +2231,17 @@ MayHavePaintEventListener(nsPIDOMWindow*
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentTarget);
   if (window)
     return MayHavePaintEventListener(window);
 
   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
   EventTarget* tabChildGlobal;
   return root &&
          (tabChildGlobal = root->GetParentTarget()) &&
-         (manager = tabChildGlobal->GetExistingListenerManager()) &&
+         (manager = tabChildGlobal->GetListenerManager(false)) &&
          manager->MayHavePaintEventListener();
 }
 
 bool
 nsPresContext::MayHavePaintEventListener()
 {
   return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
 }