Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 14 Oct 2013 14:43:11 -0400
changeset 165472 75380019dc499a85552e43097c5a1bf68798b209
parent 165471 fa8afb1865a195058c7755703927466b0e5d4bf0 (current diff)
parent 165442 30afbcdcec4d488a9954b3f269ca04d2101e546e (diff)
child 165473 44024cc4a59f9ca19ad329a5aaa389f406c8b8ae
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound.
dom/bindings/Bindings.conf
dom/webidl/Worker.webidl
dom/webidl/moz.build
--- 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/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "47d1ef9819810cecf9ce8cdcfd7f211530e43668", 
+    "revision": "4cdfe9307db3882da00e49361aa2f6788c9efe54", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/base/content/browser-webrtcUI.js
+++ b/browser/base/content/browser-webrtcUI.js
@@ -19,19 +19,27 @@ let WebrtcIndicator = {
 
   updateButton: function () {
     this.button.hidden = !this.UIModule.showGlobalIndicator;
   },
 
   fillPopup: function (aPopup) {
     this._menuitemData = new WeakMap;
     for (let streamData of this.UIModule.activeStreams) {
+      let pageURI = Services.io.newURI(streamData.uri, null, null);
       let menuitem = document.createElement("menuitem");
-      menuitem.setAttribute("label", streamData.uri);
+      menuitem.setAttribute("class", "menuitem-iconic");
+      menuitem.setAttribute("label", streamData.browser.contentTitle || streamData.uri);
       menuitem.setAttribute("tooltiptext", streamData.uri);
+      PlacesUtils.favicons.getFaviconURLForPage(pageURI, function (aURI) {
+        if (aURI) {
+          let iconURL = PlacesUtils.favicons.getFaviconLinkForIcon(aURI).spec;
+          menuitem.setAttribute("image", iconURL);
+        }
+      });
 
       this._menuitemData.set(menuitem, streamData);
 
       aPopup.appendChild(menuitem);
     }
   },
 
   clearPopup: function (aPopup) {
--- a/browser/devtools/tilt/test/browser_tilt_02_notifications-seq.js
+++ b/browser/devtools/tilt/test/browser_tilt_02_notifications-seq.js
@@ -89,12 +89,13 @@ function cleanup() {
   info("Cleaning up the notifications test.");
 
   Services.obs.removeObserver(finalize, DESTROYED);
   Services.obs.removeObserver(obs_INITIALIZING, INITIALIZING);
   Services.obs.removeObserver(obs_INITIALIZED, INITIALIZED);
   Services.obs.removeObserver(obs_DESTROYING, DESTROYING);
   Services.obs.removeObserver(obs_BEFORE_DESTROYED, BEFORE_DESTROYED);
   Services.obs.removeObserver(obs_DESTROYED, DESTROYED);
+  Services.obs.removeObserver(obs_STARTUP, STARTUP);
 
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/browser/devtools/tilt/test/browser_tilt_02_notifications.js
+++ b/browser/devtools/tilt/test/browser_tilt_02_notifications.js
@@ -113,16 +113,17 @@ function cleanup() {
   tab0 = null;
   tab1 = null;
 
   Services.obs.removeObserver(finalize, DESTROYED);
   Services.obs.removeObserver(tab_INITIALIZING, INITIALIZING);
   Services.obs.removeObserver(tab_DESTROYING, DESTROYING);
   Services.obs.removeObserver(tab_SHOWN, SHOWN);
   Services.obs.removeObserver(tab_HIDDEN, HIDDEN);
+  Services.obs.removeObserver(tab_STARTUP, STARTUP);
 
   gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect);
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function tabSelect() {
   if (testStep !== -1) {
--- 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/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -277,23 +277,16 @@ public:
 
   // event handler
   IMPL_EVENT_HANDLER(readystatechange)
 
   // states
   uint16_t ReadyState();
 
   // request
-  void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
-  {
-    Open(aMethod, aUrl, true,
-         mozilla::dom::Optional<nsAString>(),
-         mozilla::dom::Optional<nsAString>(),
-         aRv);
-  }
   void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
             const mozilla::dom::Optional<nsAString>& aUser,
             const mozilla::dom::Optional<nsAString>& aPassword,
             ErrorResult& aRv)
   {
     aRv = Open(aMethod, NS_ConvertUTF16toUTF8(aUrl),
                aAsync, aUser, aPassword);
   }
--- a/content/base/test/test_createHTMLDocument.html
+++ b/content/base/test/test_createHTMLDocument.html
@@ -22,33 +22,29 @@ function checkDoc(title, expectedtitle, 
   // Opera doesn't have a doctype: DSK-311092
   ok(doc.doctype, "Need a doctype");
   is(doc.doctype.name, "html");
   is(doc.doctype.publicId, "");
   is(doc.doctype.systemId, "");
   is(doc.doctype.internalSubset, null, "internalSubset should be null!");
   isElement(doc.documentElement, "html");
   isElement(doc.documentElement.firstChild, "head");
-  if (title !== undefined) {
-    is(doc.documentElement.firstChild.childNodes.length, 1);
-    isElement(doc.documentElement.firstChild.firstChild, "title");
-    // Doesn't always work out in WebKit.
-    ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
-    is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
-  } else {
-    is(doc.documentElement.firstChild.childNodes.length, 0);
-  }
+  is(doc.documentElement.firstChild.childNodes.length, 1);
+  isElement(doc.documentElement.firstChild.firstChild, "title");
+  // Doesn't always work out in WebKit.
+  ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
+  is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
   isElement(doc.documentElement.lastChild, "body");
   is(doc.documentElement.lastChild.childNodes.length, 0);
   ((!title || title.indexOf("\f") === -1) ? is : todo_is)
     (doc.title, normalizedtitle);
   doc.body.innerHTML = "foo";
   is(doc.body.innerHTML, "foo", "innerHTML should work in HTML data documents!");
 }
 checkDoc("", "", "");
 checkDoc(null, "null", "null");
-checkDoc(undefined, "", "");
+checkDoc(undefined, "undefined", "undefined");
 checkDoc("foo  bar baz", "foo  bar baz", "foo bar baz");
 checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz");
 checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz");
 checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz");
 checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz");
 </script>
--- 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/media/MediaDecoderReader.h
+++ b/content/media/MediaDecoderReader.h
@@ -442,16 +442,18 @@ public:
   virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0;
 
   // True if this reader is waiting media resource allocation
   virtual bool IsWaitingMediaResources() { return false; }
   // True when this reader need to become dormant state
   virtual bool IsDormantNeeded() { return false; }
   // Release media resources they should be released in dormant state
   virtual void ReleaseMediaResources() {};
+  // Release the decoder during shutdown
+  virtual void ReleaseDecoder() {};
 
   // Resets all state related to decoding, emptying all buffers etc.
   virtual nsresult ResetDecode();
 
   // Decodes an unspecified amount of audio data, enqueuing the audio data
   // in mAudioQueue. Returns true when there's more audio to decode,
   // false if the audio is finished, end of file has been reached,
   // or an un-recoverable read error has occured.
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -315,17 +315,23 @@ public:
 
   // Timer function to implement ScheduleStateMachine(aUsecs).
   void TimeoutExpired();
 
   // Set the media fragment end time. aEndTime is in microseconds.
   void SetFragmentEndTime(int64_t aEndTime);
 
   // Drop reference to decoder.  Only called during shutdown dance.
-  void ReleaseDecoder() { mDecoder = nullptr; }
+  void ReleaseDecoder() {
+    MOZ_ASSERT(mReader);
+    if (mReader) {
+      mReader->ReleaseDecoder();
+    }
+    mDecoder = nullptr;
+  }
 
    // Called when a "MozAudioAvailable" event listener is added to the media
    // element. Called on the main thread.
    void NotifyAudioAvailableListener();
 
   // Copy queued audio/video data in the reader to any output MediaStreams that
   // need it.
   void SendStreamData();
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -64,16 +64,23 @@ bool MediaOmxReader::IsDormantNeeded()
 void MediaOmxReader::ReleaseMediaResources()
 {
   ResetDecode();
   if (mOmxDecoder.get()) {
     mOmxDecoder->ReleaseMediaResources();
   }
 }
 
+void MediaOmxReader::ReleaseDecoder()
+{
+  if (mOmxDecoder.get()) {
+    mOmxDecoder->ReleaseDecoder();
+  }
+}
+
 nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
                                       MetadataTags** aTags)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   *aTags = nullptr;
 
   if (!mOmxDecoder.get()) {
--- a/content/media/omx/MediaOmxReader.h
+++ b/content/media/omx/MediaOmxReader.h
@@ -57,16 +57,18 @@ public:
     return mHasVideo;
   }
 
   virtual bool IsWaitingMediaResources();
 
   virtual bool IsDormantNeeded();
   virtual void ReleaseMediaResources();
 
+  virtual void ReleaseDecoder() MOZ_OVERRIDE;
+
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags);
   virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
   virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered, int64_t aStartTime);
 
   virtual void OnDecodeThreadStart() MOZ_OVERRIDE;
 
   virtual void OnDecodeThreadFinish() MOZ_OVERRIDE;
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -57,84 +57,95 @@ public:
   }
 
 private:
   android::sp<android::OmxDecoder> mOmxDecoder;
   int64_t                          mOffset;
 };
 
 // When loading an MP3 stream from a file, we need to parse the file's
-// content to find its duration. Reading files of 100 Mib or more can
-// delay the player app noticably, so the file os read and decoded in
+// content to find its duration. Reading files of 100 MiB or more can
+// delay the player app noticably, so the file is read and decoded in
 // smaller chunks.
 //
 // We first read on the decode thread, but parsing must be done on the
 // main thread. After we read the file's initial MiBs in the decode
 // thread, an instance of this class is scheduled to the main thread for
 // parsing the MP3 stream. The decode thread waits until it has finished.
 //
 // If there is more data available from the file, the runnable dispatches
 // a task to the IO thread for retrieving the next chunk of data, and
 // the IO task dispatches a runnable to the main thread for parsing the
 // data. This goes on until all of the MP3 file has been parsed.
 
 class OmxDecoderNotifyDataArrivedRunnable : public nsRunnable
 {
 public:
-  OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder, const char* aBuffer, uint64_t aLength, int64_t aOffset, uint64_t aFullLength)
+  OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder,
+                                      const char* aBuffer, uint64_t aLength,
+                                      int64_t aOffset, uint64_t aFullLength)
   : mOmxDecoder(aOmxDecoder),
     mBuffer(aBuffer),
     mLength(aLength),
     mOffset(aOffset),
     mFullLength(aFullLength),
     mCompletedMonitor("OmxDecoderNotifyDataArrived.mCompleted"),
     mCompleted(false)
   {
     MOZ_ASSERT(mOmxDecoder.get());
     MOZ_ASSERT(mBuffer.get() || !mLength);
   }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
-    const char* buffer = mBuffer.get();
-
-    while (mLength) {
-      uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
-      mOmxDecoder->NotifyDataArrived(mBuffer.get(), mLength, mOffset);
-
-      buffer  += length;
-      mLength -= length;
-      mOffset += length;
-    }
-
-    if (mOffset < mFullLength) {
-      // We cannot read data in the main thread because it
-      // might block for too long. Instead we post an IO task
-      // to the IO thread if there is more data available.
-      XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
-    }
-
+    NotifyDataArrived();
     Completed();
 
     return NS_OK;
   }
 
   void WaitForCompletion()
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
     MonitorAutoLock mon(mCompletedMonitor);
     if (!mCompleted) {
       mCompletedMonitor.Wait();
     }
   }
 
 private:
+  void NotifyDataArrived()
+  {
+    const char* buffer = mBuffer.get();
+
+    while (mLength) {
+      uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
+      bool success = mOmxDecoder->NotifyDataArrived(buffer, mLength,
+                                                    mOffset);
+      if (!success) {
+        return;
+      }
+
+      buffer  += length;
+      mLength -= length;
+      mOffset += length;
+    }
+
+    if (mOffset < mFullLength) {
+      // We cannot read data in the main thread because it
+      // might block for too long. Instead we post an IO task
+      // to the IO thread if there is more data available.
+      XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+          new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
+    }
+  }
+
   // Call this function at the end of Run() to notify waiting
   // threads.
   void Completed()
   {
     MonitorAutoLock mon(mCompletedMonitor);
     MOZ_ASSERT(!mCompleted);
     mCompleted = true;
     mCompletedMonitor.Notify();
@@ -395,17 +406,17 @@ bool OmxDecoder::TryLoad() {
     if (durationUs > totalDurationUs)
       totalDurationUs = durationUs;
   }
   if (mAudioTrack.get()) {
     durationUs = -1;
     const char* audioMime;
     sp<MetaData> meta = mAudioTrack->getFormat();
 
-    if (meta->findCString(kKeyMIMEType, &audioMime) && !strcasecmp(audioMime, AUDIO_MP3)) {
+    if (mIsMp3) {
       // Feed MP3 parser with cached data. Local files will be fully
       // cached already, network streams will update with sucessive
       // calls to NotifyDataArrived.
       if (ProcessCachedData(0, true)) {
         durationUs = mMP3FrameParser.GetDuration();
         if (durationUs > totalDurationUs) {
           totalDurationUs = durationUs;
         }
@@ -623,33 +634,40 @@ bool OmxDecoder::SetAudioFormat() {
   }
 
   LOG(PR_LOG_DEBUG, "channelCount: %d sampleRate: %d",
       mAudioChannels, mAudioSampleRate);
 
   return true;
 }
 
-void OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+void OmxDecoder::ReleaseDecoder()
 {
-  if (!mAudioTrack.get() || !mIsMp3 || !mMP3FrameParser.IsMP3()) {
-    return;
+  mDecoder = nullptr;
+}
+
+bool OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+{
+  if (!mAudioTrack.get() || !mIsMp3 || !mMP3FrameParser.IsMP3() || !mDecoder) {
+    return false;
   }
 
   mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
 
   int64_t durationUs = mMP3FrameParser.GetDuration();
 
   if (durationUs != mDurationUs) {
     mDurationUs = durationUs;
 
     MOZ_ASSERT(mDecoder);
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mDecoder->UpdateEstimatedMediaDuration(mDurationUs);
   }
+
+  return true;
 }
 
 void OmxDecoder::ReleaseVideoBuffer() {
   if (mVideoBuffer) {
     mVideoBuffer->release();
     mVideoBuffer = nullptr;
   }
 }
--- a/content/media/omx/OmxDecoder.h
+++ b/content/media/omx/OmxDecoder.h
@@ -176,17 +176,19 @@ public:
   bool TryLoad();
   bool IsDormantNeeded();
   bool IsWaitingMediaResources();
   bool AllocateMediaResources();
   void ReleaseMediaResources();
   bool SetVideoFormat();
   bool SetAudioFormat();
 
-  void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+  void ReleaseDecoder();
+
+  bool NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
 
   void GetDuration(int64_t *durationUs) {
     *durationUs = mDurationUs;
   }
 
   void GetVideoParameters(int32_t *width, int32_t *height) {
     *width = mVideoWidth;
     *height = mVideoHeight;
--- 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/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -993,61 +993,35 @@ nsXBLPrototypeBinding::Read(nsIObjectInp
       previousHandler->SetNextHandler(handler);
     }
     else {
       SetPrototypeHandlers(handler);
     }
     previousHandler = handler;
   } while (1);
 
-  if (mBinding) {
-    while (true) {
-      XBLBindingSerializeDetails type;
-      rv = aStream->Read8(&type);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (type != XBLBinding_Serialize_Attribute) {
-        break;
-      }
-
-      int32_t attrNamespace;
-      rv = ReadNamespace(aStream, attrNamespace);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsAutoString attrName, attrValue;
-      rv = aStream->ReadString(attrName);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = aStream->ReadString(attrValue);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCOMPtr<nsIAtom> atomName = do_GetAtom(attrName);
-      mBinding->SetAttr(attrNamespace, atomName, attrValue, false);
-    }
-  }
-
   // Finally, read in the resources.
-  while (true) {
+  do {
     XBLBindingSerializeDetails type;
     rv = aStream->Read8(&type);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (type == XBLBinding_Serialize_NoMoreItems)
       break;
 
     NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Stylesheet ||
                  (type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Image, "invalid resource type");
 
     nsAutoString src;
     rv = aStream->ReadString(src);
     NS_ENSURE_SUCCESS(rv, rv);
 
     AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet :
                                                           nsGkAtoms::image, src);
-  }
+  } while (1);
 
   if (isFirstBinding) {
     aDocInfo->SetFirstPrototypeBinding(this);
   }
 
   cleanup.Disconnect();
   return NS_OK;
 }
@@ -1147,40 +1121,16 @@ nsXBLPrototypeBinding::Write(nsIObjectOu
     NS_ENSURE_SUCCESS(rv, rv);
 
     handler = handler->GetNextHandler();
   }
 
   aStream->Write8(XBLBinding_Serialize_NoMoreItems);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (mBinding) {
-    uint32_t attributes = mBinding->GetAttrCount();
-    nsAutoString attrValue;
-    for (uint32_t i = 0; i < attributes; ++i) {
-      const nsAttrName* attr = mBinding->GetAttrNameAt(i);
-      nsDependentAtomString attrName = attr->Atom();
-      mBinding->GetAttr(attr->NamespaceID(), attr->Atom(), attrValue);
-      rv = aStream->Write8(XBLBinding_Serialize_Attribute);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = WriteNamespace(aStream, attr->NamespaceID());
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = aStream->WriteWStringZ(attrName.get());
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = aStream->WriteWStringZ(attrValue.get());
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-
-  aStream->Write8(XBLBinding_Serialize_NoMoreItems);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Write out the resources
   if (mResources) {
     rv = mResources->Write(aStream);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Write out an end mark at the end.
   return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
--- a/content/xbl/src/nsXBLSerialize.h
+++ b/content/xbl/src/nsXBLSerialize.h
@@ -10,17 +10,17 @@
 #include "nsIObjectOutputStream.h"
 #include "nsINameSpaceManager.h"
 #include "js/TypeDecls.h"
 
 typedef uint8_t XBLBindingSerializeDetails;
 
 // A version number to ensure we don't load cached data in a different
 // file format.
-#define XBLBinding_Serialize_Version 0x00000003
+#define XBLBinding_Serialize_Version 0x00000002
 
 // Set for the first binding in a document
 #define XBLBinding_Serialize_IsFirstBinding 1
 
 // Set to indicate that nsXBLPrototypeBinding::mInheritStyle should be true
 #define XBLBinding_Serialize_InheritStyle 2
 
 // Set to indicate that nsXBLPrototypeBinding::mChromeOnlyContent should be true
@@ -40,17 +40,16 @@ typedef uint8_t XBLBindingSerializeDetai
 #define XBLBinding_Serialize_SetterProperty 3
 #define XBLBinding_Serialize_GetterSetterProperty 4
 #define XBLBinding_Serialize_Method 5
 #define XBLBinding_Serialize_Constructor 6
 #define XBLBinding_Serialize_Destructor 7
 #define XBLBinding_Serialize_Handler 8
 #define XBLBinding_Serialize_Image 9
 #define XBLBinding_Serialize_Stylesheet 10
-#define XBLBinding_Serialize_Attribute 0xA
 #define XBLBinding_Serialize_Mask 0x0F
 #define XBLBinding_Serialize_ReadOnly 0x80
 
 // Appears at the end of the list of insertion points to indicate that there
 // are no more. 
 #define XBLBinding_Serialize_NoMoreInsertionPoints 0xFFFFFFFF
 
 // When serializing content nodes, a single-byte namespace id is written out
--- 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/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -698,18 +698,23 @@ AudioChannelService::Observe(nsISupports
     if (keyStr.EqualsLiteral("audio.volume.content")) {
       audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_CONTENT, index);
     } else if (keyStr.EqualsLiteral("audio.volume.notification")) {
       audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_NOTIFICATION, index);
     } else if (keyStr.EqualsLiteral("audio.volume.alarm")) {
       audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_ALARM, index);
     } else if (keyStr.EqualsLiteral("audio.volume.telephony")) {
       audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_TELEPHONY, index);
-    } else {
-      MOZ_ASSUME_UNREACHABLE("unexpected audio channel for volume control");
+    } else if (!keyStr.EqualsLiteral("audio.volume.bt_sco")) {
+      // bt_sco is not a valid audio channel so we manipulate it in
+      // AudioManager.cpp. And the others should not be used.
+      // We didn't use MOZ_ASSUME_UNREACHABLE here because any web content who
+      // has permission of mozSettings can set any names then it can be easy to
+      // crash the B2G.
+      NS_WARNING("unexpected audio channel for volume control");
     }
   }
 #endif
 
   return NS_OK;
 }
 
 AudioChannelService::AudioChannelInternalType
--- 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',
 },
@@ -1436,26 +1426,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',
@@ -1887,9 +1867,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])
@@ -2709,17 +2698,18 @@ def getJSToNativeConversionInfo(type, de
         if (defaultValue is not None and
             not isinstance(defaultValue, IDLNullValue)):
             raise TypeError("Can't handle non-null default value here")
         return handleDefault(template, codeToSetNull)
 
     # A helper function for wrapping up the template body for
     # possibly-nullable objecty stuff
     def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
-        if isNullOrUndefined and type.nullable():
+        if isNullOrUndefined:
+            assert type.nullable()
             # Just ignore templateBody and set ourselves to null.
             # Note that we don't have to worry about default values
             # here either, since we already examined this value.
             return "%s;" % codeToSetNull
 
         if not isDefinitelyObject:
             # Handle the non-object cases by wrapping up the whole
             # thing in an if cascade.
@@ -3326,16 +3316,19 @@ for (uint32_t i = 0; i < length; ++i) {
 
     if type.isDOMString():
         assert not isEnforceRange and not isClamp
 
         treatAs = {
             "Default": "eStringify",
             "EmptyString": "eEmpty",
             "Null": "eNull",
+            # For Missing it doesn't matter what we use here, since we'll never
+            # call ConvertJSValueToString on undefined in that case.
+            "Missing": "eStringify"
         }
         if type.nullable():
             # For nullable strings null becomes a null string.
             treatNullAs = "Null"
             # For nullable strings undefined becomes a null string unless
             # specified otherwise.
             if treatUndefinedAs == "Default":
                 treatUndefinedAs = "Null"
@@ -3845,18 +3838,21 @@ class CGArgumentConverter(CGThing):
             "declName" : "arg%d" % index,
             "holderName" : ("arg%d" % index) + "_holder",
             "obj" : "obj"
             }
         self.replacementVariables["val"] = string.Template(
             "args[${index}]"
             ).substitute(replacer)
         self.replacementVariables["mutableVal"] = self.replacementVariables["val"]
-        haveValueCheck = string.Template(
-            "args.hasDefined(${index})").substitute(replacer)
+        if argument.treatUndefinedAs == "Missing":
+            haveValueCheck = "args.hasDefined(${index})"
+        else:
+            haveValueCheck = "${index} < args.length()"
+        haveValueCheck = string.Template(haveValueCheck).substitute(replacer)
         self.replacementVariables["haveValue"] = haveValueCheck
         self.descriptorProvider = descriptorProvider
         if self.argument.optional and not self.argument.defaultValue:
             self.argcAndIndex = replacer
         else:
             self.argcAndIndex = None
         self.invalidEnumValueFatal = invalidEnumValueFatal
         self.lenientFloatCode = lenientFloatCode
@@ -4987,16 +4983,25 @@ class CGMethodCall(CGThing):
                 code = (
                     "if (args.length() < %d) {\n"
                     '  return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n'
                     "}" % (requiredArgs, methodName))
                 self.cgRoot.prepend(
                     CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n"))
             return
 
+        # We don't handle [TreatUndefinedAs=Missing] arguments in overload
+        # resolution yet.
+        for (_, sigArgs) in signatures:
+            for arg in sigArgs:
+                if arg.treatUndefinedAs == "Missing":
+                    raise TypeError("No support for [TreatUndefinedAs=Missing] "
+                                    "handling in overload resolution yet: %s" %
+                                    arg.location)
+
         # Need to find the right overload
         maxArgCount = method.maxArgCount
         allowedArgCounts = method.allowedArgCounts
 
         argCountCases = []
         for argCount in allowedArgCounts:
             possibleSignatures = method.signaturesForArgCount(argCount)
             if len(possibleSignatures) == 1:
@@ -5076,119 +5081,59 @@ class CGMethodCall(CGThing):
                         isNullOrUndefined=False):
                 assert not isDefinitelyObject or not isNullOrUndefined
                 assert isDefinitelyObject or isNullOrUndefined
                 if isDefinitelyObject:
                     failureCode = "break;"
                 else:
                     failureCode = None
                 type = distinguishingType(signature)
-                # The argument at index distinguishingIndex can't possibly be
-                # unset here, because we've already checked that argc is large
-                # enough that we can examine this argument.  But note that we
-                # still want to claim that optional arguments are optional, in
-                # case undefined was passed in.
-                argIsOptional = (distinguishingArgument(signature).optional and
-                                 not distinguishingArgument(signature).defaultValue)
+                # The argument at index distinguishingIndex can't possibly
+                # be unset here, because we've already checked that argc is
+                # large enough that we can examine this argument.
                 testCode = instantiateJSToNativeConversion(
                     getJSToNativeConversionInfo(type, descriptor,
                                                 failureCode=failureCode,
                                                 isDefinitelyObject=isDefinitelyObject,
                                                 isNullOrUndefined=isNullOrUndefined,
-                                                isOptional=argIsOptional,
                                                 sourceDescription=(argDesc % (distinguishingIndex + 1))),
                     {
                         "declName" : "arg%d" % distinguishingIndex,
                         "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
                         "val" : distinguishingArg,
                         "mutableVal" : distinguishingArg,
-                        "obj" : "obj",
-                        "haveValue": "args.hasDefined(%d)" % distinguishingIndex
-                        },
-                    checkForValue=argIsOptional
-                    )
+                        "obj" : "obj"
+                        })
                 caseBody.append(CGIndenter(testCode, indent));
                 # If we got this far, we know we unwrapped to the right
                 # C++ type, so just do the call.  Start conversion with
                 # distinguishingIndex + 1, since we already converted
                 # distinguishingIndex.
                 caseBody.append(CGIndenter(
                         getPerSignatureCall(signature, distinguishingIndex + 1),
                         indent))
 
-            def hasConditionalConversion(type):
-                """
-                Return whether the argument conversion for this type will be
-                conditional on the type of incoming JS value.  For example, for
-                interface types the conversion is conditional on the incoming
-                value being isObject().
-
-                For the types for which this returns false, we do not have to
-                output extra isUndefined() or isNullOrUndefined() cases, because
-                null/undefined values will just fall through into our
-                unconditional conversion.
-                """
-                if type.isString() or type.isEnum():
-                    return False
-                if type.isBoolean():
-                    distinguishingTypes = (distinguishingType(s) for s in
-                                           possibleSignatures)
-                    return any(t.isString() or t.isEnum() or t.isNumeric()
-                               for t in distinguishingTypes)
-                if type.isNumeric():
-                    distinguishingTypes = (distinguishingType(s) for s in
-                                           possibleSignatures)
-                    return any(t.isString() or t.isEnum()
-                               for t in distinguishingTypes)
-                return True
-
-            def needsNullOrUndefinedCase(type):
-                """
-                Return true if the type needs a special isNullOrUndefined() case
-                """
-                return ((type.nullable() and
-                        hasConditionalConversion(type)) or
-                        type.isDictionary())
-
-            # First check for undefined and optional distinguishing arguments
-            # and output a special branch for that case.  Note that we don't
-            # use distinguishingArgument here because we actualy want to
-            # exclude variadic arguments.  Also note that we skip this check if
-            # we plan to output a isNullOrUndefined() special case for this
-            # argument anyway, since that will subsume our isUndefined() check.
-            # This is safe, because there can be at most one nullable
-            # distinguishing argument, so if we're it we'll definitely get
-            # picked up by the nullable handling.  Also, we can skip this check
-            # if the argument has an unconditional conversion later on.
-            undefSigs = [s for s in possibleSignatures if
-                         distinguishingIndex < len(s[1]) and
-                         s[1][distinguishingIndex].optional and
-                         hasConditionalConversion(s[1][distinguishingIndex].type) and
-                         not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
-            # Can't have multiple signatures with an optional argument at the
-            # same index.
-            assert len(undefSigs) < 2
-            if len(undefSigs) > 0:
-                caseBody.append(CGGeneric("if (%s.isUndefined()) {" %
-                                          distinguishingArg))
-                tryCall(undefSigs[0], 2, isNullOrUndefined=True)
-                caseBody.append(CGGeneric("}"))
-
-            # Next, check for null or undefined.  That means looking for
+            # First check for null or undefined.  That means looking for
             # nullable arguments at the distinguishing index and outputting a
-            # separate branch for them.  But if the nullable argument has an
-            # unconditional conversion, we don't need to do that.  The reason
+            # separate branch for them.  But if the nullable argument is a
+            # primitive, string, or enum, we don't need to do that.  The reason
             # for that is that at most one argument at the distinguishing index
             # is nullable (since two nullable arguments are not
-            # distinguishable), and null/undefined values will always fall
-            # through to the unconditional conversion we have, if any, since
-            # they will fail whatever the conditions on the input value are for
-            # our other conversions.
+            # distinguishable), and all the argument types other than
+            # primitive/string/enum end up inside isObject() checks.  So if our
+            # nullable is a primitive/string/enum it's safe to not output the
+            # extra branch: we'll fall through to conversion for those types,
+            # which correctly handles null as needed, because isObject() will be
+            # false for null and undefined.
             nullOrUndefSigs = [s for s in possibleSignatures
-                               if needsNullOrUndefinedCase(distinguishingType(s))]
+                               if ((distinguishingType(s).nullable() and not
+                                    distinguishingType(s).isString() and not
+                                    distinguishingType(s).isEnum() and not
+                                   distinguishingType(s).isPrimitive()) or
+                                   distinguishingType(s).isDictionary())]
             # Can't have multiple nullable types here
             assert len(nullOrUndefSigs) < 2
             if len(nullOrUndefSigs) > 0:
                 caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {" %
                                           distinguishingArg))
                 tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
                 caseBody.append(CGGeneric("}"))
 
@@ -8039,17 +7984,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/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -76,16 +76,21 @@ public:
     return Equals(aOtherNullable);
   }
 
   bool operator!=(const Nullable<T>& aOtherNullable) const
   {
     return !Equals(aOtherNullable);
   }
 
+  operator bool() const
+  {
+    return !mIsNull;
+  }
+
   // Make it possible to use a const Nullable of an array type with other
   // array types.
   template<typename U>
   operator const Nullable< nsTArray<U> >&() const {
     // Make sure that T is ok to reinterpret to nsTArray<U>
     const nsTArray<U>& arr = mValue;
     (void)arr;
     return *reinterpret_cast<const Nullable< nsTArray<U> >*>(this);
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -396,17 +396,22 @@ class IDLObjectWithIdentifier(IDLObject)
                     raise WebIDLError("[TreatNullAs] must take the identifier "
                                       "'EmptyString', not '%s'" % value,
                                       [self.location])
                 self.treatNullAs = value
             elif identifier == "TreatUndefinedAs":
                 if isDictionaryMember:
                     raise WebIDLError("[TreatUndefinedAs] is not allowed for "
                                       "dictionary members", [self.location])
-                if value == 'Null':
+                if value == 'Missing':
+                    if not isOptional:
+                        raise WebIDLError("[TreatUndefinedAs=Missing] is only "
+                                          "allowed on optional arguments",
+                                          [self.location])
+                elif value == 'Null':
                     if not self.type.isDOMString():
                         raise WebIDLError("[TreatUndefinedAs=Null] is only "
                                           "allowed on arguments or "
                                           "attributes whose type is "
                                           "DOMString or DOMString?",
                                           [self.location])
                     if not self.type.nullable():
                         raise WebIDLError("[TreatUndefinedAs=Null] is only "
@@ -416,18 +421,18 @@ class IDLObjectWithIdentifier(IDLObject)
                     if not self.type.isDOMString():
                         raise WebIDLError("[TreatUndefinedAs=EmptyString] "
                                           "is only allowed on arguments or "
                                           "attributes whose type is "
                                           "DOMString or DOMString?",
                                           [self.location])
                 else:
                     raise WebIDLError("[TreatUndefinedAs] must take the "
-                                      "identifiers EmptyString or Null",
-                                      [self.location])
+                                      "identifiers EmptyString or Null or "
+                                      "Missing", [self.location])
                 self.treatUndefinedAs = value
             else:
                 unhandledAttrs.append(attr)
 
         return unhandledAttrs
 
 class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
     def __init__(self, location, parentScope, identifier):
@@ -3133,32 +3138,35 @@ class IDLMethod(IDLInterfaceMember, IDLS
         return self
 
     def signatures(self):
         return [(overload.returnType, overload.arguments) for overload in
                 self._overloads]
 
     def finish(self, scope):
         for overload in self._overloads:
+            inOptionalArguments = False
             variadicArgument = None
 
             arguments = overload.arguments
             for (idx, argument) in enumerate(arguments):
-                if not argument.isComplete():
-                    argument.complete(scope)
+                if argument.isComplete():
+                    continue
+
+                argument.complete(scope)
                 assert argument.type.isComplete()
 
                 if (argument.type.isDictionary() or
                     (argument.type.isUnion() and
                      argument.type.unroll().hasDictionaryType)):
                     # Dictionaries and unions containing dictionaries at the
                     # end of the list or followed by optional arguments must be
                     # optional.
                     if (not argument.optional and
-                        all(arg.optional for arg in arguments[idx+1:])):
+                        (idx == len(arguments) - 1 or arguments[idx+1].optional)):
                         raise WebIDLError("Dictionary argument or union "
                                           "argument containing a dictionary "
                                           "not followed by a required argument "
                                           "must be optional",
                                           [argument.location])
 
                     # An argument cannot be a Nullable Dictionary
                     if argument.type.nullable():
@@ -3166,16 +3174,23 @@ class IDLMethod(IDLInterfaceMember, IDLS
                                           "dictionary or nullable union "
                                           "containing a dictionary",
                                           [argument.location])
 
                 # Only the last argument can be variadic
                 if variadicArgument:
                     raise WebIDLError("Variadic argument is not last argument",
                                       [variadicArgument.location])
+                # Once we see an optional argument, there can't be any non-optional
+                # arguments.
+                if inOptionalArguments and not argument.optional:
+                    raise WebIDLError("Non-optional argument after optional "
+                                      "arguments",
+                                      [argument.location])
+                inOptionalArguments = argument.optional
                 if argument.variadic:
                     variadicArgument = argument
 
             returnType = overload.returnType
             if returnType.isComplete():
                 continue
 
             type = returnType.complete(scope)
@@ -3210,17 +3225,17 @@ class IDLMethod(IDLInterfaceMember, IDLS
                             (self.identifier.name, argCount, idx,
                              distinguishingIndex),
                             [self.location, overload.location])
 
     def overloadsForArgCount(self, argc):
         return [overload for overload in self._overloads if
                 len(overload.arguments) == argc or
                 (len(overload.arguments) > argc and
-                 all(arg.optional for arg in overload.arguments[argc:])) or
+                 overload.arguments[argc].optional) or
                 (len(overload.arguments) < argc and
                  len(overload.arguments) > 0 and
                  overload.arguments[-1].variadic)]
 
     def signaturesForArgCount(self, argc):
         return [(overload.returnType, overload.arguments) for overload
                 in self.overloadsForArgCount(argc)]
 
@@ -4040,16 +4055,31 @@ class Parser(Tokenizer):
         if stringifier:
             if len(arguments) != 0:
                 raise WebIDLError("stringifier has wrong number of arguments",
                                   [self.getLocation(p, 2)])
             if not returnType.isDOMString():
                 raise WebIDLError("stringifier must have DOMString return type",
                                   [self.getLocation(p, 2)])
 
+        inOptionalArguments = False
+        variadicArgument = False
+        for argument in arguments:
+            # Only the last argument can be variadic
+            if variadicArgument:
+                raise WebIDLError("Only the last argument can be variadic",
+                                  [variadicArgument.location])
+            # Once we see an optional argument, there can't be any non-optional
+            # arguments.
+            if inOptionalArguments and not argument.optional:
+                raise WebIDLError("Cannot have a non-optional argument following an optional argument",
+                                  [argument.location])
+            inOptionalArguments = argument.optional
+            variadicArgument = argument if argument.variadic else None
+
         # identifier might be None.  This is only permitted for special methods.
         if not identifier:
             if not getter and not setter and not creator and \
                not deleter and not legacycaller and not stringifier:
                 raise WebIDLError("Identifier required for non-special methods",
                                   [self.getLocation(p, 2)])
 
             location = BuiltinLocation("<auto-generated-identifier>")
--- a/dom/bindings/parser/tests/test_dictionary.py
+++ b/dom/bindings/parser/tests/test_dictionary.py
@@ -173,33 +173,16 @@ def WebIDLTest(parser, harness):
 
     parser = parser.reset()
     threw = False
     try:
         parser.parse("""
             dictionary A {
             };
             interface X {
-              void doFoo(A arg1, optional long arg2, long arg3);
-            };
-        """)
-        results = parser.finish()
-    except:
-        threw = True
-
-    harness.ok(not threw,
-               "Dictionary arg followed by non-optional arg doesn't have to be optional")
-
-    parser = parser.reset()
-    threw = False
-    try:
-        parser.parse("""
-            dictionary A {
-            };
-            interface X {
               void doFoo((A or DOMString) arg1, optional long arg2);
             };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw,
--- a/dom/bindings/parser/tests/test_optional_constraints.py
+++ b/dom/bindings/parser/tests/test_optional_constraints.py
@@ -6,19 +6,19 @@ def WebIDLTest(parser, harness):
               void foo(optional byte arg1, byte arg2);
             };
         """)
 
         results = parser.finish()
     except:
         threw = True
 
-    harness.ok(not threw,
-               "Should not have thrown on non-optional argument following "
-               "optional argument.")
+    harness.ok(threw,
+               "Should have thrown on non-optional argument following optional "
+               "argument.")
 
     parser = parser.reset()
     parser.parse("""
         interface OptionalConstraints2 {
           void foo(optional byte arg1 = 1, optional byte arg2 = 2,
                    optional byte arg3, optional byte arg4 = 4,
                    optional byte arg5, optional byte arg6 = 9);
         };
--- a/dom/bindings/parser/tests/test_overload.py
+++ b/dom/bindings/parser/tests/test_overload.py
@@ -6,31 +6,29 @@ def WebIDLTest(parser, harness):
           void basic();
           void basic(long arg1);
           boolean abitharder(TestOverloads foo);
           boolean abitharder(boolean foo);
           void abitharder(ArrayBuffer? foo);
           void withVariadics(long... numbers);
           void withVariadics(TestOverloads iface);
           void withVariadics(long num, TestOverloads iface);
-          void optionalTest();
-          void optionalTest(optional long num1, long num2);
         };
     """)
 
     results = parser.finish()
 
     harness.ok(True, "TestOverloads interface parsed without error.")
     harness.check(len(results), 1, "Should be one production.")
     iface = results[0]
     harness.ok(isinstance(iface, WebIDL.IDLInterface),
                "Should be an IDLInterface")
     harness.check(iface.identifier.QName(), "::TestOverloads", "Interface has the right QName")
     harness.check(iface.identifier.name, "TestOverloads", "Interface has the right name")
-    harness.check(len(iface.members), 4, "Expect %s members" % 4)
+    harness.check(len(iface.members), 3, "Expect %s members" % 3)
 
     member = iface.members[0]
     harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName")
     harness.check(member.identifier.name, "basic", "Method has the right name")
     harness.check(member.hasOverloads(), True, "Method has overloads")
 
     signatures = member.signatures()
     harness.check(len(signatures), 2, "Method should have 2 signatures")
@@ -45,16 +43,8 @@ def WebIDLTest(parser, harness):
     harness.check(len(argumentSet), 1, "Expect an argument set with one argument")
 
     argument = argumentSet[0]
     harness.ok(isinstance(argument, WebIDL.IDLArgument),
                "Should be an IDLArgument")
     harness.check(argument.identifier.QName(), "::TestOverloads::basic::arg1", "Argument has the right QName")
     harness.check(argument.identifier.name, "arg1", "Argument has the right name")
     harness.check(str(argument.type), "Long", "Argument has the right type")
-
-    member = iface.members[3]
-    harness.check(len(member.overloadsForArgCount(0)), 1,
-                  "Only one overload for no args")
-    harness.check(len(member.overloadsForArgCount(1)), 0,
-                  "No overloads for one arg")
-    harness.check(len(member.overloadsForArgCount(2)), 1,
-                  "Only one overload for two args")
--- a/dom/bindings/parser/tests/test_variadic_constraints.py
+++ b/dom/bindings/parser/tests/test_variadic_constraints.py
@@ -1,63 +1,52 @@
 def WebIDLTest(parser, harness):
     threw = False
     try:
-        parser.parse("""
+        results = parser.parse("""
             interface VariadicConstraints1 {
               void foo(byte... arg1, byte arg2);
             };
         """)
-        results = parser.finish()
 
     except:
         threw = True
 
-    harness.ok(threw,
-               "Should have thrown on variadic argument followed by required "
-               "argument.")
+    harness.ok(threw, "Should have thrown.")
 
-    parser = parser.reset()
     threw = False
     try:
-        parser.parse("""
+        results = parser.parse("""
             interface VariadicConstraints2 {
               void foo(byte... arg1, optional byte arg2);
             };
         """)
-        results = parser.finish();
+
     except:
         threw = True
 
-    harness.ok(threw,
-               "Should have thrown on variadic argument followed by optional "
-               "argument.")
+    harness.ok(threw, "Should have thrown.")
 
-    parser = parser.reset()
     threw = False
     try:
-        parser.parse("""
+        results = parser.parse("""
             interface VariadicConstraints3 {
               void foo(optional byte... arg1);
             };
         """)
-        results = parser.finish()
 
     except:
         threw = True
 
-    harness.ok(threw,
-               "Should have thrown on variadic argument explicitly flagged as "
-               "optional.")
+    harness.ok(threw, "Should have thrown.")
 
-    parser = parser.reset()
     threw = False
     try:
-        parser.parse("""
+        results = parser.parse("""
             interface VariadicConstraints4 {
               void foo(byte... arg1 = 0);
             };
         """)
-        results = parser.finish()
+
     except:
         threw = True
 
     harness.ok(threw, "Should have thrown on variadic argument with default value.")
--- 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
@@ -157,19 +156,19 @@ public:
 
   // Integer types
   int8_t ReadonlyByte();
   int8_t WritableByte();
   void SetWritableByte(int8_t);
   void PassByte(int8_t);
   int8_t ReceiveByte();
   void PassOptionalByte(const Optional<int8_t>&);
-  void PassOptionalByteBeforeRequired(const Optional<int8_t>&, int8_t);
+  void PassOptionalUndefinedMissingByte(const Optional<int8_t>&);
   void PassOptionalByteWithDefault(int8_t);
-  void PassOptionalByteWithDefaultBeforeRequired(int8_t, int8_t);
+  void PassOptionalUndefinedMissingByteWithDefault(int8_t);
   void PassNullableByte(const Nullable<int8_t>&);
   void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
   void PassVariadicByte(const Sequence<int8_t>&);
 
   int16_t ReadonlyShort();
   int16_t WritableShort();
   void SetWritableShort(int16_t);
   void PassShort(int16_t);
@@ -406,17 +405,19 @@ public:
   void PassVariadicTypedArray(const Sequence<Float32Array>&);
   void PassVariadicNullableTypedArray(const Sequence<Nullable<Float32Array> >&);
   JSObject* ReceiveUint8Array(JSContext*);
 
   // DOMString types
   void PassString(const nsAString&);
   void PassNullableString(const nsAString&);
   void PassOptionalString(const Optional<nsAString>&);
+  void PassOptionalUndefinedMissingString(const Optional<nsAString>&);
   void PassOptionalStringWithDefaultValue(const nsAString&);
+  void PassOptionalUndefinedMissingStringWithDefaultValue(const nsAString&);
   void PassOptionalNullableString(const Optional<nsAString>&);
   void PassOptionalNullableStringWithDefaultValue(const nsAString&);
   void PassVariadicString(const Sequence<nsString>&);
 
   // ByteString types
   void PassByteString(const nsCString&);
   void PassNullableByteString(const nsCString&);
   void PassOptionalByteString(const Optional<nsCString>&);
@@ -625,32 +626,16 @@ public:
   void Overload5(TestEnum);
   void Overload6(int32_t);
   void Overload6(bool);
   void Overload7(int32_t);
   void Overload7(bool);
   void Overload7(const nsCString&);
   void Overload8(int32_t);
   void Overload8(TestInterface&);
-  void Overload9(const Nullable<int32_t>&);
-  void Overload9(const nsAString&);
-  void Overload10(const Nullable<int32_t>&);
-  void Overload10(JSContext*, JS::Handle<JSObject*>);
-  void Overload11(int32_t);
-  void Overload11(const nsAString&);
-  void Overload12(int32_t);
-  void Overload12(const Nullable<bool>&);
-  void Overload13(const Nullable<int32_t>&);
-  void Overload13(bool);
-  void Overload14(const Optional<int32_t>&);
-  void Overload14(TestInterface&);
-  void Overload15(int32_t);
-  void Overload15(const Optional<NonNull<TestInterface> >&);
-  void Overload16(int32_t);
-  void Overload16(const Optional<TestInterface*>&);
 
   // Variadic handling
   void PassVariadicThirdArg(const nsAString&, int32_t,
                             const Sequence<OwningNonNull<TestInterface> >&);
 
   // Conditionally exposed methods/attributes
   bool Prefable1();
   bool Prefable2();
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -113,19 +113,19 @@ interface OnlyForUseInConstructor {
 interface TestInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
-  void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
+  void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
   void passOptionalByteWithDefault(optional byte arg = 0);
-  void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
+  void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
@@ -360,17 +360,19 @@ interface TestInterface {
   void passVariadicTypedArray(Float32Array... arg);
   void passVariadicNullableTypedArray(Float32Array?... arg);
   Uint8Array receiveUint8Array();
 
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
+  void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
+  void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
@@ -574,32 +576,16 @@ interface TestInterface {
   void overload5(TestEnum arg);
   void overload6(long arg);
   void overload6(boolean arg);
   void overload7(long arg);
   void overload7(boolean arg);
   void overload7(ByteString arg);
   void overload8(long arg);
   void overload8(TestInterface arg);
-  void overload9(long? arg);
-  void overload9(DOMString arg);
-  void overload10(long? arg);
-  void overload10(object arg);
-  void overload11(long arg);
-  void overload11(DOMString? arg);
-  void overload12(long arg);
-  void overload12(boolean? arg);
-  void overload13(long? arg);
-  void overload13(boolean arg);
-  void overload14(optional long arg);
-  void overload14(TestInterface arg);
-  void overload15(long arg);
-  void overload15(optional TestInterface arg);
-  void overload16(long arg);
-  void overload16(optional TestInterface? arg);
 
   // Variadic handling
   void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
 
   // Conditionally exposed methods/attributes
   [Pref="abc.def"]
   readonly attribute boolean prefable1;
   [Pref="abc.def"]
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -18,19 +18,19 @@
 interface TestExampleInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
-  void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
+  void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
   void passOptionalByteWithDefault(optional byte arg = 0);
-  void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
+  void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
@@ -258,17 +258,19 @@ interface TestExampleInterface {
   void passVariadicTypedArray(Float32Array... arg);
   void passVariadicNullableTypedArray(Float32Array?... arg);
   Uint8Array receiveUint8Array();
 
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
+  void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
+  void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
@@ -471,32 +473,16 @@ interface TestExampleInterface {
   void overload5(TestEnum arg);
   void overload6(long arg);
   void overload6(boolean arg);
   void overload7(long arg);
   void overload7(boolean arg);
   void overload7(ByteString arg);
   void overload8(long arg);
   void overload8(TestInterface arg);
-  void overload9(long? arg);
-  void overload9(DOMString arg);
-  void overload10(long? arg);
-  void overload10(object arg);
-  void overload11(long arg);
-  void overload11(DOMString? arg);
-  void overload12(long arg);
-  void overload12(boolean? arg);
-  void overload13(long? arg);
-  void overload13(boolean arg);
-  void overload14(optional long arg);
-  void overload14(TestInterface arg);
-  void overload15(long arg);
-  void overload15(optional TestInterface arg);
-  void overload16(long arg);
-  void overload16(optional TestInterface? arg);
 
   // Variadic handling
   void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
 
   // Conditionally exposed methods/attributes
   [Pref="abc.def"]
   readonly attribute boolean prefable1;
   [Pref="abc.def"]
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -30,19 +30,19 @@ enum MyTestEnum {
 interface TestJSImplInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
-  void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
+  void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
   void passOptionalByteWithDefault(optional byte arg = 0);
-  void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
+  void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
@@ -280,17 +280,19 @@ interface TestJSImplInterface {
   //void passVariadicTypedArray(Float32Array... arg);
   //void passVariadicNullableTypedArray(Float32Array?... arg);
   //Uint8Array receiveUint8Array();
 
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
+  void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
+  void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
@@ -499,32 +501,16 @@ interface TestJSImplInterface {
   void overload5(MyTestEnum arg);
   void overload6(long arg);
   void overload6(boolean arg);
   void overload7(long arg);
   void overload7(boolean arg);
   void overload7(ByteString arg);
   void overload8(long arg);
   void overload8(TestJSImplInterface arg);
-  void overload9(long? arg);
-  void overload9(DOMString arg);
-  void overload10(long? arg);
-  void overload10(object arg);
-  void overload11(long arg);
-  void overload11(DOMString? arg);
-  void overload12(long arg);
-  void overload12(boolean? arg);
-  void overload13(long? arg);
-  void overload13(boolean arg);
-  void overload14(optional long arg);
-  void overload14(TestInterface arg);
-  void overload15(long arg);
-  void overload15(optional TestInterface arg);
-  void overload16(long arg);
-  void overload16(optional TestInterface? arg);
 
   // Variadic handling
   void passVariadicThirdArg(DOMString arg1, long arg2, TestJSImplInterface... arg3);
 
   // Miscellania
   [LenientThis] attribute long attrWithLenientThis;
   // FIXME: Bug 863954 Unforgeable things get all confused when
   // non-JS-implemented interfaces inherit from JS-implemented ones or vice
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -984,28 +984,21 @@ BluetoothHfpManager::Connect(const nsASt
     if (mDeviceAddress == aDeviceAddress) {
       aController->OnConnect(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
     } else {
       aController->OnConnect(NS_LITERAL_STRING(ERR_REACHED_CONNECTION_LIMIT));
     }
     return;
   }
 
-  mNeedsUpdatingSdpRecords = true;
-  mIsHandsfree = !IS_HEADSET(aController->GetCod());
-
   nsString uuid;
-  if (mIsHandsfree) {
-    BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
-  } else {
-    BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, uuid);
-  }
+  BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
 
   if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
-    aController->OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
+    aController->OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
     return;
   }
 
   // Stop listening because currently we only support one connection at a time.
   if (mHandsfreeSocket) {
     mHandsfreeSocket->Disconnect();
     mHandsfreeSocket = nullptr;
   }
@@ -1504,56 +1497,43 @@ BluetoothHfpManager::OnSocketDisconnect(
   OnDisconnect(EmptyString());
 
   Reset();
 }
 
 void
 BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!aDeviceAddress.IsEmpty());
-  MOZ_ASSERT(mRunnable);
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE_VOID(bs);
-
-  nsString uuid;
-  if (mIsHandsfree) {
-    BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
-  } else {
-    BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, uuid);
-  }
-
-  // Since we have updated SDP records of the target device, we should
-  // try to get the channel of target service again.
-  if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
-    OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
-  }
+  // UpdateSdpRecord() is not called so this callback function should not
+  // be invoked.
+  MOZ_ASSUME_UNREACHABLE("UpdateSdpRecords() should be called somewhere");
 }
 
 void
 BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
                                          const nsAString& aServiceUuid,
                                          int aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
-  BluetoothValue v;
+  if (aChannel < 0) {
+    // If we can't find Handsfree server channel number on the remote device,
+    // try to create HSP connection instead.
+    nsString hspUuid;
+    BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, hspUuid);
 
-  if (aChannel < 0) {
-    if (mNeedsUpdatingSdpRecords) {
-      mNeedsUpdatingSdpRecords = false;
-      bs->UpdateSdpRecords(aDeviceAddress, this);
-    } else {
+    if (aServiceUuid.Equals(hspUuid)) {
       OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
+    } else if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress,
+                                               hspUuid, this))) {
+      OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
     }
 
     return;
   }
 
   if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) {
     OnConnect(NS_LITERAL_STRING("SocketConnectionError"));
   }
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -142,18 +142,16 @@ private:
   bool mCCWA;
   bool mCLIP;
   bool mCMEE;
   bool mCMER;
   bool mFirstCKPD;
   int mNetworkSelectionMode;
   bool mReceiveVgsFlag;
   bool mDialingRequestProcessed;
-  bool mIsHandsfree;
-  bool mNeedsUpdatingSdpRecords;
   nsString mDeviceAddress;
   nsString mMsisdn;
   nsString mOperatorName;
 
   nsTArray<Call> mCurrentCallArray;
   nsAutoPtr<BluetoothRilListener> mListener;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
   nsRefPtr<BluetoothProfileController> mController;
--- a/dom/bluetooth/BluetoothProfileController.h
+++ b/dom/bluetooth/BluetoothProfileController.h
@@ -41,21 +41,16 @@ BEGIN_BLUETOOTH_NAMESPACE
 #define HAS_OBJECT_TRANSFER(cod)     (cod & 0x100000)
 
 // Bit 18: Major service class = 0x20, Rendering
 #define HAS_RENDERING(cod)           (cod & 0x40000)
 
 // Major device class = 0xA, Peripheral
 #define IS_PERIPHERAL(cod)           (GET_MAJOR_DEVICE_CLASS(cod) == 0xa)
 
-// Major device class = 0x4, Audio/Video
-// Minor device class = 0x1, Wearable Headset device
-#define IS_HEADSET(cod)              ((GET_MAJOR_DEVICE_CLASS(cod) == 0x4) && \
-                                     (GET_MINOR_DEVICE_CLASS(cod) == 0x1))
-
 class BluetoothProfileManagerBase;
 class BluetoothReplyRunnable;
 typedef void (*BluetoothProfileControllerCallback)();
 
 class BluetoothProfileController : public RefCounted<BluetoothProfileController>
 {
 public:
   BluetoothProfileController(const nsAString& aDeviceAddress,
--- 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/imptests/html/dom/nodes/test_DOMImplementation-createHTMLDocument.html
+++ b/dom/imptests/html/dom/nodes/test_DOMImplementation-createHTMLDocument.html
@@ -13,31 +13,27 @@
 function checkDoc(title, expectedtitle, normalizedtitle) {
   test(function() {
     var doc = document.implementation.createHTMLDocument(title);
     assert_equals(doc.doctype.name, "html")
     assert_equals(doc.doctype.publicId, "")
     assert_equals(doc.doctype.systemId, "")
     assert_equals(doc.documentElement.localName, "html")
     assert_equals(doc.documentElement.firstChild.localName, "head")
-    if (title !== undefined) {
-      assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
-      assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
-      assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
-                    expectedtitle)
-    } else {
-      assert_equals(doc.documentElement.firstChild.childNodes.length, 0)
-    }
+    assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
+    assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
+    assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
+    expectedtitle)
     assert_equals(doc.documentElement.lastChild.localName, "body")
     assert_equals(doc.documentElement.lastChild.childNodes.length, 0)
   })
 }
 checkDoc("", "", "")
 checkDoc(null, "null", "null")
-checkDoc(undefined, "", "")
+checkDoc(undefined, "undefined", "undefined")
 checkDoc("foo  bar baz", "foo  bar baz", "foo bar baz")
 checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
 checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")
 checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz")
 checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz")
 
 test(function() {
   var doc = document.implementation.createHTMLDocument();
--- a/dom/imptests/html/html/dom/documents/dta/test_document.title-07.html
+++ b/dom/imptests/html/html/dom/documents/dta/test_document.title-07.html
@@ -7,15 +7,15 @@
 function checkDoc(title, expectedtitle, normalizedtitle) {
   test(function() {
     var doc = document.implementation.createHTMLDocument(title);
     assert_equals(doc.title, normalizedtitle)
   })
 }
 checkDoc("", "", "")
 checkDoc(null, "null", "null")
-checkDoc(undefined, "", "")
+checkDoc(undefined, "undefined", "undefined")
 checkDoc("foo  bar baz", "foo  bar baz", "foo bar baz")
 checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
 checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")
 checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz")
 checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz")
 </script>
--- 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/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -2797,17 +2797,17 @@ QuotaManager::RunSynchronizedOp(nsIOffli
 SynchronizedOp*
 QuotaManager::FindSynchronizedOp(const nsACString& aPattern,
                                  Nullable<PersistenceType> aPersistenceType,
                                  nsISupports* aId)
 {
   for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
     const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
     if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
-        (currentOp->mPersistenceType.IsNull() ||
+        (!currentOp->mPersistenceType ||
          currentOp->mPersistenceType == aPersistenceType) &&
         (!currentOp->mId || currentOp->mId == aId)) {
       return currentOp;
     }
   }
 
   return nullptr;
 }
@@ -3062,28 +3062,28 @@ QuotaManager::CollectOriginsForEviction(
   // Collect active origins first.
   OriginCollection originCollection;
 
   // Add patterns and origins that have running or pending synchronized ops.
   // (add patterns first to reduce redundancy in the origin collection).
   uint32_t index;
   for (index = 0; index < mSynchronizedOps.Length(); index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-    if (op->mPersistenceType.IsNull() ||
+    if (!op->mPersistenceType ||
         op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
       if (op->mOriginOrPattern.IsPattern() &&
           !originCollection.ContainsPattern(op->mOriginOrPattern)) {
         originCollection.AddPattern(op->mOriginOrPattern);
       }
     }
   }
 
   for (index = 0; index < mSynchronizedOps.Length(); index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-    if (op->mPersistenceType.IsNull() ||
+    if (!op->mPersistenceType ||
         op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
       if (op->mOriginOrPattern.IsOrigin() &&
           !originCollection.ContainsOrigin(op->mOriginOrPattern)) {
         originCollection.AddOrigin(op->mOriginOrPattern);
       }
     }
   }
 
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -133,17 +133,18 @@ public:
     } else if (aName.EqualsLiteral("audio.volume.alarm")) {
       audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_ALARM, volIndex);
     } else if (aName.EqualsLiteral("audio.volume.telephony")) {
       audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_TELEPHONY, volIndex);
     } else if (aName.EqualsLiteral("audio.volume.bt_sco")) {
       static_cast<AudioManager *>(audioManager.get())->SetStreamVolumeIndex(
         AUDIO_STREAM_BLUETOOTH_SCO, volIndex);
     } else {
-      MOZ_ASSUME_UNREACHABLE("unexpected audio channel for volume control");
+      MOZ_ASSUME_UNREACHABLE("unexpected audio channel for initializing "
+                             "volume control");
     }
 
     return NS_OK;
   }
 
   NS_IMETHOD HandleError(const nsAString& aName)
   {
     LOG("AudioChannelVolInitCallback::HandleError: %s\n",
@@ -309,17 +310,17 @@ AudioManager::Observe(nsISupports* aSubj
       return NS_OK;
     }
 
     JS::RootedString jsKey(cx, JS_ValueToString(cx, key));
     if (!jsKey) {
       return NS_OK;
     }
     nsDependentJSString keyStr;
-    if (!keyStr.init(cx, jsKey) || keyStr.EqualsLiteral("audio.volume.bt_sco")) {
+    if (!keyStr.init(cx, jsKey) || !keyStr.EqualsLiteral("audio.volume.bt_sco")) {
       return NS_OK;
     }
 
     JS::Rooted<JS::Value> value(cx);
     if (!JS_GetProperty(cx, obj, "value", &value) || !value.isInt32()) {
       return NS_OK;
     }
 
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/dom/workers/Workers.h"
 #ifdef MOZ_WIDGET_GONK
 #include "mozilla/ipc/Netd.h"
 #include "AutoMounter.h"
 #include "TimeZoneSettingObserver.h"
 #include "AudioManager.h"
 #endif
 #include "mozilla/ipc/Ril.h"
+#include "mozilla/ipc/KeyStore.h"
 #include "nsIObserverService.h"
 #include "nsCxPusher.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsRadioInterfaceLayer.h"
 #include "WifiWorker.h"
 
 USING_WORKERS_NAMESPACE
@@ -336,16 +337,18 @@ SystemWorkerManager::Init()
   mozilla::AutoSafeJSContext cx;
 
   nsresult rv = InitWifi(cx);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to initialize WiFi Networking!");
     return rv;
   }
 
+  InitKeyStore(cx);
+
 #ifdef MOZ_WIDGET_GONK
   InitAutoMounter();
   InitializeTimeZoneSettingObserver();
   rv = InitNetd(cx);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIAudioManager> audioManager =
     do_GetService(NS_AUDIOMANAGER_CONTRACTID);
 #endif
@@ -540,16 +543,23 @@ SystemWorkerManager::InitWifi(JSContext 
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
 
   mWifiWorker = worker;
   return NS_OK;
 }
 
+nsresult
+SystemWorkerManager::InitKeyStore(JSContext *cx)
+{
+  mKeyStore = new KeyStore();
+  return NS_OK;
+}
+
 NS_IMPL_ISUPPORTS3(SystemWorkerManager,
                    nsIObserver,
                    nsIInterfaceRequestor,
                    nsISystemWorkerManager)
 
 NS_IMETHODIMP
 SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic,
                              const PRUnichar *aData)
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -30,16 +30,17 @@
 
 class nsIWorkerHolder;
 
 namespace mozilla {
 
 namespace ipc {
   class RilConsumer;
   class UnixSocketRawData;
+  class KeyStore;
 }
 
 namespace dom {
 namespace gonk {
 
 class SystemWorkerManager : public nsIObserver,
                             public nsIInterfaceRequestor,
                             public nsISystemWorkerManager
@@ -65,23 +66,25 @@ public:
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
 #ifdef MOZ_WIDGET_GONK
   nsresult InitNetd(JSContext *cx);
 #endif
   nsresult InitWifi(JSContext *cx);
+  nsresult InitKeyStore(JSContext *cx);
 
 #ifdef MOZ_WIDGET_GONK
   nsCOMPtr<nsIWorkerHolder> mNetdWorker;
 #endif
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
   nsTArray<nsRefPtr<ipc::RilConsumer> > mRilConsumers;
+  nsRefPtr<ipc::KeyStore> mKeyStore;
 
   bool mShutdown;
 };
 
 }
 }
 }
 
--- a/dom/system/gonk/tests/marionette/manifest.ini
+++ b/dom/system/gonk/tests/marionette/manifest.ini
@@ -2,8 +2,9 @@
 b2g = true
 browser = false
 qemu = true
 
 [test_geolocation.js]
 disabled = Bug 808783
 [test_fakevolume.js]
 [test_ril_code_quality.py]
+[test_screen_state.js]
--- 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",
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -69,30 +69,30 @@ interface CanvasRenderingContext2D {
   void clearRect(double x, double y, double w, double h);
   [LenientFloat]
   void fillRect(double x, double y, double w, double h);
   [LenientFloat]
   void strokeRect(double x, double y, double w, double h);
 
   // path API (see also CanvasPathMethods)
   void beginPath();
-  void fill(optional CanvasWindingRule winding = "nonzero");
+  void fill([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
 // NOT IMPLEMENTED  void fill(Path path);
   void stroke();
 // NOT IMPLEMENTED  void stroke(Path path);
 // NOT IMPLEMENTED  void drawSystemFocusRing(Element element);
 // NOT IMPLEMENTED  void drawSystemFocusRing(Path path, Element element);
 // NOT IMPLEMENTED  boolean drawCustomFocusRing(Element element);
 // NOT IMPLEMENTED  boolean drawCustomFocusRing(Path path, Element element);
 // NOT IMPLEMENTED  void scrollPathIntoView();
 // NOT IMPLEMENTED  void scrollPathIntoView(Path path);
-  void clip(optional CanvasWindingRule winding = "nonzero");
+  void clip([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
 // NOT IMPLEMENTED  void clip(Path path);
 // NOT IMPLEMENTED  void resetClip();
-  boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
+  boolean isPointInPath(unrestricted double x, unrestricted double y, [TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
 // NOT IMPLEMENTED  boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
   boolean isPointInStroke(double x, double y);
 
   // text (see also the CanvasDrawingStyles interface)
   [Throws, LenientFloat]
   void fillText(DOMString text, double x, double y, optional double maxWidth);
   [Throws, LenientFloat]
   void strokeText(DOMString text, double x, double y, optional double maxWidth);
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -23,14 +23,14 @@ interface Promise {
   // Promise object in this scope without having resolved the interface object
   // first.
   [Creator, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
   static Promise resolve(any value); // same as any(value)
   [Creator, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
   static Promise reject(any value);
 
   [Creator]
-  Promise then(optional AnyCallback fulfillCallback,
-               optional AnyCallback rejectCallback);
+  Promise then([TreatUndefinedAs=Missing] optional AnyCallback fulfillCallback,
+               [TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
 
   [Creator]
-  Promise catch(optional AnyCallback rejectCallback);
+  Promise catch([TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
 };
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/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -66,19 +66,17 @@ interface XMLHttpRequest : XMLHttpReques
   const unsigned short HEADERS_RECEIVED = 2;
   const unsigned short LOADING = 3;
   const unsigned short DONE = 4;
 
   readonly attribute unsigned short readyState;
 
   // request
   [Throws]
-  void open(ByteString method, DOMString url);
-  [Throws]
-  void open(ByteString method, DOMString url, boolean async,
+  void open(ByteString method, DOMString url, optional boolean async = true,
             optional DOMString? user, optional DOMString? password);
   [Throws]
   void setRequestHeader(ByteString header, ByteString value);
 
   [SetterThrows]
   attribute unsigned long timeout;
 
   [SetterThrows]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -409,17 +409,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/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -116,21 +116,16 @@ public:
 #undef IMPL_GETTER_AND_SETTER
 
   uint16_t
   ReadyState() const
   {
     return mStateData.mReadyState;
   }
 
-  void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
-  {
-    Open(aMethod, aUrl, true, Optional<nsAString>(),
-         Optional<nsAString>(), aRv);
-  }
   void
   Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
        const Optional<nsAString>& aUser, const Optional<nsAString>& aPassword,
        ErrorResult& aRv);
 
   void
   SetRequestHeader(const nsACString& aHeader, const nsACString& aValue,
                    ErrorResult& aRv);
--- 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());
   }
 
new file mode 100644
--- /dev/null
+++ b/ipc/keystore/KeyStore.cpp
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et ft=cpp: */
+/* 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 <fcntl.h>
+#include <sys/stat.h>
+
+#undef LOG
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
+#else
+#define LOG(args...)  printf(args);
+#endif
+
+#include "KeyStore.h"
+#include "jsfriendapi.h"
+#include "MainThreadUtils.h" // For NS_IsMainThread.
+
+#include "plbase64.h"
+#include "certdb.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace ipc {
+
+static const char* KEYSTORE_SOCKET_NAME = "keystore";
+static const char* KEYSTORE_SOCKET_PATH = "/dev/socket/keystore";
+
+int
+KeyStoreConnector::Create()
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  int fd;
+
+  unlink(KEYSTORE_SOCKET_PATH);
+
+  fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+  if (fd < 0) {
+    NS_WARNING("Could not open keystore socket!");
+    return -1;
+  }
+
+  // Allow access of wpa_supplicant(different user, differnt group)
+  chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+  return fd;
+}
+
+bool
+KeyStoreConnector::CreateAddr(bool aIsServer,
+                              socklen_t& aAddrSize,
+                              sockaddr_any& aAddr,
+                              const char* aAddress)
+{
+  // Keystore socket must be server
+  MOZ_ASSERT(aIsServer);
+
+  aAddr.un.sun_family = AF_LOCAL;
+  if(strlen(KEYSTORE_SOCKET_PATH) > sizeof(aAddr.un.sun_path)) {
+      NS_WARNING("Address too long for socket struct!");
+      return false;
+  }
+  strcpy((char*)&aAddr.un.sun_path, KEYSTORE_SOCKET_PATH);
+  aAddrSize = strlen(KEYSTORE_SOCKET_PATH) + offsetof(struct sockaddr_un, sun_path) + 1;
+
+  return true;
+}
+
+bool
+KeyStoreConnector::SetUp(int aFd)
+{
+  return true;
+}
+
+void
+KeyStoreConnector::GetSocketAddr(const sockaddr_any& aAddr,
+                                 nsAString& aAddrStr)
+{
+  // Unused.
+  MOZ_CRASH("This should never be called!");
+}
+
+static char *
+get_cert_db_filename(void *arg, int vers)
+{
+  static char keystoreDbPath[] = "/data/misc/wifi/keystore";
+  return keystoreDbPath;
+}
+
+KeyStore::KeyStore()
+{
+  // Initial NSS
+  certdb = CERT_GetDefaultCertDB();
+
+  Listen();
+}
+
+void
+KeyStore::Shutdown()
+{
+  mShutdown = true;
+  CloseSocket();
+}
+
+void
+KeyStore::Listen()
+{
+  ListenSocket(new KeyStoreConnector());
+
+  ResetHandlerInfo();
+}
+
+void
+KeyStore::ResetHandlerInfo()
+{
+  mHandlerInfo.state = STATE_IDLE;
+  mHandlerInfo.command = 0;
+  mHandlerInfo.paramCount = 0;
+  mHandlerInfo.commandPattern = NULL;
+  for (int i = 0; i < MAX_PARAM; i++) {
+    mHandlerInfo.param[i].length = 0;
+    memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
+  }
+}
+
+bool
+KeyStore::CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize)
+{
+  return (aMessage->mSize - aMessage->mCurrentWriteOffset >= aExpectSize) ?
+         true : false;
+}
+
+bool
+KeyStore::ReadCommand(UnixSocketRawData *aMessage)
+{
+  if (mHandlerInfo.state != STATE_IDLE) {
+    NS_WARNING("Wrong state in ReadCommand()!");
+    return false;
+  }
+
+  if (!CheckSize(aMessage, 1)) {
+    NS_WARNING("Data size error in ReadCommand()!");
+    return false;
+  }
+
+  mHandlerInfo.command = aMessage->mData[aMessage->mCurrentWriteOffset];
+  aMessage->mCurrentWriteOffset++;
+
+  // Find corrsponding command pattern
+  const struct ProtocolCommand *command = commands;
+  while (command->command && command->command != mHandlerInfo.command) {
+    command++;
+  }
+
+  if (!command->command) {
+    NS_WARNING("Unsupported command!");
+    return false;
+  }
+
+  // Get command pattern.
+  mHandlerInfo.commandPattern = command;
+  if (command->paramNum) {
+    // Read command parameter if needed.
+    mHandlerInfo.state = STATE_READ_PARAM_LEN;
+  } else {
+    mHandlerInfo.state = STATE_PROCESSING;
+  }
+
+  return true;
+}
+
+bool
+KeyStore::ReadLength(UnixSocketRawData *aMessage)
+{
+  if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
+    NS_WARNING("Wrong state in ReadLength()!");
+    return false;
+  }
+
+  if (!CheckSize(aMessage, 2)) {
+    NS_WARNING("Data size error in ReadLength()!");
+    return false;
+  }
+
+  // Read length of command parameter.
+  unsigned short dataLength;
+  memcpy(&dataLength, &aMessage->mData[aMessage->mCurrentWriteOffset], 2);
+  aMessage->mCurrentWriteOffset += 2;
+  mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
+
+  mHandlerInfo.state = STATE_READ_PARAM_DATA;
+
+  return true;
+}
+
+bool
+KeyStore::ReadData(UnixSocketRawData *aMessage)
+{
+  if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
+    NS_WARNING("Wrong state in ReadData()!");
+    return false;
+  }
+
+  if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
+    NS_WARNING("Data size error in ReadData()!");
+    return false;
+  }
+
+  // Read command parameter.
+  memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
+         &aMessage->mData[aMessage->mCurrentWriteOffset],
+         mHandlerInfo.param[mHandlerInfo.paramCount].length);
+  aMessage->mCurrentWriteOffset += mHandlerInfo.param[mHandlerInfo.paramCount].length;
+  mHandlerInfo.paramCount++;
+
+  if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
+    mHandlerInfo.state = STATE_PROCESSING;
+  } else {
+    mHandlerInfo.state = STATE_READ_PARAM_LEN;
+  }
+
+  return true;
+}
+
+// Transform base64 certification data into DER format
+void
+KeyStore::FormatCaData(const uint8_t *aCaData, int aCaDataLength,
+                       const char *aName, const uint8_t **aFormatData,
+                       int &aFormatDataLength)
+{
+  int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
+                strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2;
+  char *buf = (char *)malloc(bufSize);
+
+  aFormatDataLength = bufSize;
+  *aFormatData = (const uint8_t *)buf;
+
+  char *ptr = buf;
+  int len;
+
+  // Create DER header.
+  len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
+  ptr += len;
+  bufSize -= len;
+
+  // Split base64 data in lines.
+  int copySize;
+  while (aCaDataLength > 0) {
+    copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
+
+    memcpy(ptr, aCaData, copySize);
+    ptr += copySize;
+    aCaData += copySize;
+    aCaDataLength -= copySize;
+    bufSize -= copySize;
+
+    *ptr = '\n';
+    ptr++;
+    bufSize--;
+  }
+
+  // Create DEA tailer.
+  snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
+}
+
+// Status response
+void
+KeyStore::SendResponse(ResponseCode aResponse)
+{
+  if (aResponse == NO_RESPONSE)
+    return;
+
+  uint8_t response = (uint8_t)aResponse;
+  UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
+  SendSocketData(data);
+}
+
+// Data response
+void
+KeyStore::SendData(const uint8_t *aData, int aLength)
+{
+  unsigned short dataLength = htons(aLength);
+
+  UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
+  SendSocketData(length);
+
+  UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
+  SendSocketData(data);
+}
+
+void
+KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  bool success = true;
+  while (aMessage->mCurrentWriteOffset < aMessage->mSize ||
+         mHandlerInfo.state == STATE_PROCESSING) {
+    switch (mHandlerInfo.state) {
+      case STATE_IDLE:
+        success = ReadCommand(aMessage);
+        break;
+      case STATE_READ_PARAM_LEN:
+        success = ReadLength(aMessage);
+        break;
+      case STATE_READ_PARAM_DATA:
+        success = ReadData(aMessage);
+        break;
+      case STATE_PROCESSING:
+        success = false;
+        if (mHandlerInfo.command == 'g') {
+          // Get CA
+          const uint8_t *certData;
+          int certDataLength;
+          const char *certName = (const char *)mHandlerInfo.param[0].data;
+
+          // Get cert from NSS by name
+          CERTCertificate *cert = CERT_FindCertByNickname(certdb, certName);
+          if (!cert) {
+            break;
+          }
+
+          char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
+                                          cert->derCert.len, nullptr);
+          if (!certDER) {
+            break;
+          }
+
+          FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE",
+                       &certData, certDataLength);
+          PL_strfree(certDER);
+
+          SendResponse(SUCCESS);
+          SendData(certData, certDataLength);
+          success = true;
+
+          free((void *)certData);
+        }
+
+        ResetHandlerInfo();
+        break;
+    }
+
+    if (!success) {
+      SendResponse(PROTOCOL_ERROR);
+      ResetHandlerInfo();
+      return;
+    }
+  }
+}
+
+void
+KeyStore::OnConnectSuccess()
+{
+  mShutdown = false;
+}
+
+void
+KeyStore::OnConnectError()
+{
+  if (!mShutdown) {
+    Listen();
+  }
+}
+
+void
+KeyStore::OnDisconnect()
+{
+  if (!mShutdown) {
+    Listen();
+  }
+}
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/keystore/KeyStore.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp: */
+/* 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_ipc_KeyStore_h
+#define mozilla_ipc_KeyStore_h 1
+
+#include "mozilla/ipc/UnixSocket.h"
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "cert.h"
+
+namespace mozilla {
+namespace ipc {
+
+enum ResponseCode {
+  SUCCESS           =  1,
+  LOCKED            =  2,
+  UNINITIALIZED     =  3,
+  SYSTEM_ERROR      =  4,
+  PROTOCOL_ERROR    =  5,
+  PERMISSION_DENIED =  6,
+  KEY_NOT_FOUND     =  7,
+  VALUE_CORRUPTED   =  8,
+  UNDEFINED_ACTION  =  9,
+  WRONG_PASSWORD_0  = 10,
+  WRONG_PASSWORD_1  = 11,
+  WRONG_PASSWORD_2  = 12,
+  WRONG_PASSWORD_3  = 13, // MAX_RETRY = 4
+  NO_RESPONSE
+};
+
+static const int MAX_PARAM = 2;
+static const int KEY_SIZE = ((NAME_MAX - 15) / 2);
+static const int VALUE_SIZE = 32768;
+static const int PASSWORD_SIZE = VALUE_SIZE;
+
+static const char *CA_BEGIN = "-----BEGIN ",
+                  *CA_END   = "-----END ",
+                  *CA_TAILER = "-----\n";
+static const int CA_LINE_SIZE = 64;
+
+struct ProtocolCommand {
+  int8_t  command;
+  int     paramNum;
+};
+
+static const struct ProtocolCommand commands[] = {
+  {'g', 1}, // Get CA, command "g CERT_NAME"
+  { 0,  0}
+};
+
+struct ProtocolParam{
+  uint    length;
+  int8_t  data[VALUE_SIZE];
+};
+
+typedef enum {
+  STATE_IDLE,
+  STATE_READ_PARAM_LEN,
+  STATE_READ_PARAM_DATA,
+  STATE_PROCESSING
+} ProtocolHandlerState;
+
+class KeyStoreConnector : public mozilla::ipc::UnixSocketConnector
+{
+public:
+  KeyStoreConnector()
+  {}
+
+  virtual ~KeyStoreConnector()
+  {}
+
+  virtual int Create();
+  virtual bool CreateAddr(bool aIsServer,
+                          socklen_t& aAddrSize,
+                          sockaddr_any& aAddr,
+                          const char* aAddress);
+  virtual bool SetUp(int aFd);
+  virtual void GetSocketAddr(const sockaddr_any& aAddr,
+                             nsAString& aAddrStr);
+};
+
+class KeyStore : public mozilla::ipc::UnixSocketConsumer
+{
+public:
+  KeyStore();
+  virtual ~KeyStore() {}
+
+  void Shutdown();
+
+private:
+  virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage);
+
+  virtual void OnConnectSuccess();
+  virtual void OnConnectError();
+  virtual void OnDisconnect();
+
+private:
+  struct {
+    ProtocolHandlerState          state;
+    uint8_t                       command;
+    struct ProtocolParam          param[MAX_PARAM];
+    int                           paramCount;
+    const struct ProtocolCommand  *commandPattern;
+  } mHandlerInfo;
+  void ResetHandlerInfo();
+  void Listen();
+
+  void FormatCaData(const uint8_t *caData, int caDataLength, const char *name,
+                    const uint8_t **formatData, int &formatDataLength);
+
+  bool CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize);
+  bool ReadCommand(UnixSocketRawData *aMessage);
+  bool ReadLength(UnixSocketRawData *aMessage);
+  bool ReadData(UnixSocketRawData *aMessage);
+  void SendResponse(ResponseCode response);
+  void SendData(const uint8_t *data, int length);
+
+  bool mShutdown;
+
+  CERTCertDBHandle *certdb;
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_KeyStore_h
new file mode 100644
--- /dev/null
+++ b/ipc/keystore/Makefile.in
@@ -0,0 +1,7 @@
+# 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/.
+
+EXPORT_LIBRARY = 1
+include $(topsrcdir)/config/rules.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
new file mode 100644
--- /dev/null
+++ b/ipc/keystore/moz.build
@@ -0,0 +1,21 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+MODULE = 'ipc'
+
+EXPORTS.mozilla.ipc += [
+  'KeyStore.h'
+]
+
+CPP_SOURCES += [
+  'KeyStore.cpp'
+]
+
+FAIL_ON_WARNINGS = True
+
+LIBXUL_LIBRARY = True
+
+LIBRARY_NAME = 'mozkeystore_s'
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -13,14 +13,14 @@ DIRS += [
 
 if CONFIG['MOZ_B2G_RIL']:
     DIRS += ['ril']
 
 if CONFIG['MOZ_B2G_BT']:
     DIRS += ['dbus']
 
 if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT']:
-    DIRS += ['unixsocket']
+    DIRS += ['unixsocket', 'keystore']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['netd']
 
 TOOL_DIRS += ['app']
--- a/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
+++ b/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
@@ -47,17 +47,17 @@ function run_test()
   httpserver.start(4444);
 
   httpserver2.registerPathHandler(negativetestpath, serverHandler);
   httpserver2.start(4445);
 
   // Test sync XHR sending
   cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
   var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
-  do_check_true(checkResults(res));
+  checkResults(res);
 
   // negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
   try {
     cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
     var res = cu.evalInSandbox('var sync = createXHR("4445/negative"); sync.send(null); sync', sb);
     do_check_false(true, "XHR created from sandbox should not have chrome caps");
   } catch (e) {
     do_check_true(true);
--- 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());
 }
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -166,18 +166,18 @@ let Scheduler = {
         }
         return data.ok;
       },
       function onError(error) {
         // Decode any serialized error
         if (error instanceof PromiseWorker.WorkerError) {
           throw OS.File.Error.fromMsg(error.data);
         }
-        // Extract something meaningful from ErrorEvent
-        if (error instanceof ErrorEvent) {
+        // Extract something meaningful from WorkerErrorEvent
+        if (typeof error == "object" && error && error.constructor.name == "WorkerErrorEvent") {
           let message = error.message;
           if (message == "uncaught exception: [object StopIteration]") {
             throw StopIteration;
           }
           throw new Error(message, error.filename, error.lineno);
         }
         throw error;
       }
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -92,17 +92,17 @@ endif #}
 ifdef MOZ_B2G_BT #{
 STATIC_LIBS += mozdbus_s
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += -ldbus
 endif
 endif #}
 
 ifneq ($(strip $(MOZ_B2G_RIL)$(MOZ_B2G_BT)),) #{
-STATIC_LIBS += mozipcunixsocket_s
+STATIC_LIBS += mozipcunixsocket_s mozkeystore_s
 endif #}
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 STATIC_LIBS += moznetd_s
 endif
 
 ifdef MOZ_B2G_CAMERA #{
 OS_LIBS += -lstagefright -lstagefright_omx