Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 18 Apr 2016 15:07:04 -0700
changeset 293637 f128e25d78d3e0633a4f668a4485e8f4b8a25549
parent 293569 d53b301a14e1dfa05324072a7159796a4f5e24c7 (current diff)
parent 293636 6e6c5143feaa28e2d374a9a12b30c090fa051093 (diff)
child 293638 67ac40fb8f680ea5e03805552187ba1b5e8392a1
push id18782
push userkwierso@gmail.com
push dateMon, 18 Apr 2016 22:15:58 +0000
treeherderfx-team@e8ef4670ee16 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
Merge inbound to central, a=merge MozReview-Commit-ID: ADcSE67n1t8
dom/plugins/test/testplugin/Makefile.in
dom/plugins/test/testplugin/flashplugin/Makefile.in
dom/plugins/test/testplugin/javaplugin/Makefile.in
dom/plugins/test/testplugin/secondplugin/Makefile.in
dom/plugins/test/testplugin/silverlightplugin/Makefile.in
dom/plugins/test/testplugin/testplugin.mk
dom/plugins/test/testplugin/thirdplugin/Makefile.in
testing/xpcshell/selftest.py
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2077,17 +2077,17 @@ Element::DispatchClickEvent(nsPresContex
                             const EventFlags* aExtraEventFlags,
                             nsEventStatus* aStatus)
 {
   NS_PRECONDITION(aTarget, "Must have target");
   NS_PRECONDITION(aSourceEvent, "Must have source event");
   NS_PRECONDITION(aStatus, "Null out param?");
 
   WidgetMouseEvent event(aSourceEvent->IsTrusted(), eMouseClick,
-                         aSourceEvent->widget, WidgetMouseEvent::eReal);
+                         aSourceEvent->mWidget, WidgetMouseEvent::eReal);
   event.refPoint = aSourceEvent->refPoint;
   uint32_t clickCount = 1;
   float pressure = 0;
   uint16_t inputSource = 0;
   WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
   if (sourceMouseEvent) {
     clickCount = sourceMouseEvent->clickCount;
     pressure = sourceMouseEvent->pressure;
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -702,60 +702,48 @@ WriteBlob(JSStructuredCloneWriter* aWrit
     aHolder->BlobImpls().AppendElement(blobImpl);
     return true;
   }
 
   return false;
 }
 
 // A directory is serialized as:
-// - pair of ints: SCTAG_DOM_DIRECTORY, 0
-// - pair of ints: type (eDOMRootDirectory/eDOMNotRootDirectory) - path length
+// - pair of ints: SCTAG_DOM_DIRECTORY, path length
 // - path as string
 bool
 WriteDirectory(JSStructuredCloneWriter* aWriter,
                Directory* aDirectory)
 {
   MOZ_ASSERT(aWriter);
   MOZ_ASSERT(aDirectory);
 
   nsAutoString path;
   aDirectory->GetFullRealPath(path);
 
   size_t charSize = sizeof(nsString::char_type);
-  return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, 0) &&
-         JS_WriteUint32Pair(aWriter, (uint32_t)aDirectory->Type(),
-                            path.Length()) &&
+  return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, path.Length()) &&
          JS_WriteBytes(aWriter, path.get(), path.Length() * charSize);
 }
 
 JSObject*
 ReadDirectory(JSContext* aCx,
               JSStructuredCloneReader* aReader,
-              uint32_t aZero,
+              uint32_t aPathLength,
               StructuredCloneHolder* aHolder)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aReader);
   MOZ_ASSERT(aHolder);
-  MOZ_ASSERT(aZero == 0);
-
-  uint32_t directoryType, lengthOfString;
-  if (!JS_ReadUint32Pair(aReader, &directoryType, &lengthOfString)) {
-    return nullptr;
-  }
-
-  MOZ_ASSERT(directoryType == Directory::eDOMRootDirectory ||
-             directoryType == Directory::eNotDOMRootDirectory);
 
   nsAutoString path;
-  path.SetLength(lengthOfString);
+  path.SetLength(aPathLength);
   size_t charSize = sizeof(nsString::char_type);
   if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
-                    lengthOfString * charSize)) {
+                    aPathLength * charSize)) {
     return nullptr;
   }
 
   nsCOMPtr<nsIFile> file;
   nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
                                       getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
@@ -764,18 +752,17 @@ ReadDirectory(JSContext* aCx,
   // RefPtr<Directory> needs to go out of scope before toObject() is
   // called because the static analysis thinks dereferencing XPCOM objects
   // can GC (because in some cases it can!), and a return statement with a
   // JSObject* type means that JSObject* is on the stack as a raw pointer
   // while destructors are running.
   JS::Rooted<JS::Value> val(aCx);
   {
     RefPtr<Directory> directory =
-      Directory::Create(aHolder->ParentDuringRead(), file,
-                        (Directory::DirectoryType) directoryType);
+      Directory::Create(aHolder->ParentDuringRead(), file);
 
     if (!ToJSValue(aCx, directory, &val)) {
       return nullptr;
     }
   }
 
   return &val.toObject();
 }
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7793,17 +7793,16 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<
   }
 
   WidgetMouseEvent event(true, msg, widget, WidgetMouseEvent::eReal,
                          contextMenuKey ? WidgetMouseEvent::eContextMenuKey :
                                           WidgetMouseEvent::eNormal);
   event.mModifiers = GetWidgetModifiers(aModifiers);
   event.button = aButton;
   event.buttons = GetButtonsFlagForButton(aButton);
-  event.widget = widget;
   event.pressure = aPressure;
   event.inputSource = aInputSourceArg;
   event.clickCount = aClickCount;
   event.mTime = PR_IntervalNow();
   event.mFlags.mIsSynthesizedForTests = aIsSynthesized;
 
   nsPresContext* presContext = aPresShell->GetPresContext();
   if (!presContext)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -667,17 +667,16 @@ nsDOMWindowUtils::SendPointerEventCommon
   if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) {
     aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
   }
 
   WidgetPointerEvent event(true, msg, widget);
   event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
   event.button = aButton;
   event.buttons = nsContentUtils::GetButtonsFlagForButton(aButton);
-  event.widget = widget;
   event.pressure = aPressure;
   event.inputSource = aInputSourceArg;
   event.pointerId = aPointerId;
   event.width = aWidth;
   event.height = aHeight;
   event.tiltX = aTiltX;
   event.tiltY = aTiltY;
   event.isPrimary = (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary;
@@ -800,17 +799,16 @@ nsDOMWindowUtils::SendWheelEvent(float a
   wheelEvent.mIsMomentum =
     (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
   wheelEvent.mIsNoLineOrPageDelta =
     (aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0;
   wheelEvent.mCustomizedByUserPrefs =
     (aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0;
   wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX;
   wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY;
-  wheelEvent.widget = widget;
 
   wheelEvent.mTime = PR_Now() / 1000;
 
   nsPresContext* presContext = GetPresContext();
   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 
   wheelEvent.refPoint = nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
 
@@ -933,17 +931,16 @@ nsDOMWindowUtils::SendTouchEventCommon(c
     msg = eTouchEnd;
   } else if (aType.EqualsLiteral("touchcancel")) {
     msg = eTouchCancel;
   } else {
     return NS_ERROR_UNEXPECTED;
   }
   WidgetTouchEvent event(true, msg, widget);
   event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
-  event.widget = widget;
   event.mTime = PR_Now();
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext) {
     return NS_ERROR_FAILURE;
   }
   event.mTouches.SetCapacity(aCount);
   for (uint32_t i = 0; i < aCount; ++i) {
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1529,32 +1529,32 @@ ContentEventHandler::OnQueryCharacterAtP
 
   nsIFrame* rootFrame = mPresShell->GetRootFrame();
   NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
   nsIWidget* rootWidget = rootFrame->GetNearestWidget();
   NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
 
   // The root frame's widget might be different, e.g., the event was fired on
   // a popup but the rootFrame is the document root.
-  if (rootWidget != aEvent->widget) {
-    NS_PRECONDITION(aEvent->widget, "The event must have the widget");
-    nsView* view = nsView::GetViewFor(aEvent->widget);
+  if (rootWidget != aEvent->mWidget) {
+    NS_PRECONDITION(aEvent->mWidget, "The event must have the widget");
+    nsView* view = nsView::GetViewFor(aEvent->mWidget);
     NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
     rootFrame = view->GetFrame();
     NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
     rootWidget = rootFrame->GetNearestWidget();
     NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
   }
 
   WidgetQueryContentEvent eventOnRoot(true, eQueryCharacterAtPoint,
                                       rootWidget);
   eventOnRoot.mUseNativeLineBreak = aEvent->mUseNativeLineBreak;
   eventOnRoot.refPoint = aEvent->refPoint;
-  if (rootWidget != aEvent->widget) {
-    eventOnRoot.refPoint += aEvent->widget->WidgetToScreenOffset() -
+  if (rootWidget != aEvent->mWidget) {
+    eventOnRoot.refPoint += aEvent->mWidget->WidgetToScreenOffset() -
       rootWidget->WidgetToScreenOffset();
   }
   nsPoint ptInRoot =
     nsLayoutUtils::GetEventCoordinatesRelativeTo(&eventOnRoot, rootFrame);
 
   nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
   if (!targetFrame || !targetFrame->GetContent() ||
       !nsContentUtils::ContentIsDescendantOf(targetFrame->GetContent(),
@@ -1606,17 +1606,17 @@ ContentEventHandler::OnQueryCharacterAtP
   rv = GetFlatTextLengthInRange(NodePosition(mRootContent, 0),
                                 NodePosition(contentOffsets),
                                 mRootContent, &offset,
                                 GetLineBreakType(aEvent));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->widget);
+  WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->mWidget);
   textRect.InitForQueryTextRect(offset, 1, aEvent->mUseNativeLineBreak);
   rv = OnQueryTextRect(&textRect);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE);
 
   // currently, we don't need to get the actual text.
   aEvent->mReply.mOffset = offset;
   aEvent->mReply.mRect = textRect.mReply.mRect;
@@ -1632,41 +1632,42 @@ ContentEventHandler::OnQueryDOMWidgetHit
   nsresult rv = InitBasic();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   aEvent->mSucceeded = false;
   aEvent->mReply.mWidgetIsHit = false;
 
-  NS_ENSURE_TRUE(aEvent->widget, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(aEvent->mWidget, NS_ERROR_FAILURE);
 
   nsIDocument* doc = mPresShell->GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   nsIFrame* docFrame = mPresShell->GetRootFrame();
   NS_ENSURE_TRUE(docFrame, NS_ERROR_FAILURE);
 
-  LayoutDeviceIntPoint eventLoc = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
+  LayoutDeviceIntPoint eventLoc =
+    aEvent->refPoint + aEvent->mWidget->WidgetToScreenOffset();
   nsIntRect docFrameRect = docFrame->GetScreenRect(); // Returns CSS pixels
   CSSIntPoint eventLocCSS(
     mPresContext->DevPixelsToIntCSSPixels(eventLoc.x) - docFrameRect.x,
     mPresContext->DevPixelsToIntCSSPixels(eventLoc.y) - docFrameRect.y);
 
   Element* contentUnderMouse =
     doc->ElementFromPointHelper(eventLocCSS.x, eventLocCSS.y, false, false);
   if (contentUnderMouse) {
     nsIWidget* targetWidget = nullptr;
     nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame();
     nsIObjectFrame* pluginFrame = do_QueryFrame(targetFrame);
     if (pluginFrame) {
       targetWidget = pluginFrame->GetWidget();
     } else if (targetFrame) {
       targetWidget = targetFrame->GetNearestWidget();
     }
-    if (aEvent->widget == targetWidget) {
+    if (aEvent->mWidget == targetWidget) {
       aEvent->mReply.mWidgetIsHit = true;
     }
   }
 
   aEvent->mSucceeded = true;
   return NS_OK;
 }
 
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -900,28 +900,28 @@ Event::GetScreenCoords(nsPresContext* aP
         aEvent->mClass != eDragEventClass &&
         aEvent->mClass != eSimpleGestureEventClass)) {
     return CSSIntPoint(0, 0);
   }
 
   // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
   // seem incorrect, but it is needed to maintain legacy functionality.
   WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
-  if (!aPresContext || !(guiEvent && guiEvent->widget)) {
+  if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
     return CSSIntPoint(aPoint.x, aPoint.y);
   }
 
   nsPoint pt =
     LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
   if (nsIPresShell* ps = aPresContext->GetPresShell()) {
     pt = pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(ps));
   }
 
-  pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(),
+  pt += LayoutDevicePixel::ToAppUnits(guiEvent->mWidget->WidgetToScreenOffset(),
                                       aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
   return CSSPixel::FromAppUnitsRounded(pt);
 }
 
 // static
 CSSIntPoint
 Event::GetPageCoords(nsPresContext* aPresContext,
@@ -959,17 +959,17 @@ Event::GetClientCoords(nsPresContext* aP
       (aEvent->mClass != eMouseEventClass &&
        aEvent->mClass != eMouseScrollEventClass &&
        aEvent->mClass != eWheelEventClass &&
        aEvent->mClass != eTouchEventClass &&
        aEvent->mClass != eDragEventClass &&
        aEvent->mClass != ePointerEventClass &&
        aEvent->mClass != eSimpleGestureEventClass) ||
       !aPresContext ||
-      !aEvent->AsGUIEvent()->widget) {
+      !aEvent->AsGUIEvent()->mWidget) {
     return aDefaultPoint;
   }
 
   nsIPresShell* shell = aPresContext->GetPresShell();
   if (!shell) {
     return CSSIntPoint(0, 0);
   }
   nsIFrame* rootFrame = shell->GetRootFrame();
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -817,17 +817,17 @@ EventStateManager::PreHandleEvent(nsPres
     DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
     break;
   case eCompositionStart:
     if (aEvent->IsTrusted()) {
       // If the event is trusted event, set the selected text to data of
       // composition event.
       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
       WidgetQueryContentEvent selectedText(true, eQuerySelectedText,
-                                           compositionEvent->widget);
+                                           compositionEvent->mWidget);
       HandleQueryContentEvent(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compositionEvent->mData = selectedText.mReply.mString;
     }
     break;
   default:
     break;
   }
@@ -1579,22 +1579,24 @@ EventStateManager::FireContextClick()
 // assume the user wants a click-hold, so fire a context-click event. We only
 // want to cancel the drag gesture if the context-click event is handled.
 //
 void
 EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
                                             WidgetMouseEvent* inDownEvent,
                                             nsIFrame* inDownFrame)
 {
-  if (!inDownEvent->widget)
+  if (!inDownEvent->mWidget) {
     return;
+  }
 
   // Note that |inDownEvent| could be either a mouse down event or a
   // synthesized mouse move event.
-  mGestureDownPoint = inDownEvent->refPoint + inDownEvent->widget->WidgetToScreenOffset();
+  mGestureDownPoint =
+    inDownEvent->refPoint + inDownEvent->mWidget->WidgetToScreenOffset();
 
   if (inDownFrame) {
     inDownFrame->GetContentForEvent(inDownEvent,
                                     getter_AddRefs(mGestureDownContent));
 
     mGestureDownFrameOwner = inDownFrame->GetContent();
     if (!mGestureDownFrameOwner) {
       mGestureDownFrameOwner = mGestureDownContent;
@@ -1627,23 +1629,24 @@ EventStateManager::StopTrackingDragGestu
 {
   mGestureDownContent = nullptr;
   mGestureDownFrameOwner = nullptr;
 }
 
 void
 EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent)
 {
-  NS_ASSERTION(aEvent->widget == mCurrentTarget->GetNearestWidget(),
+  NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),
                "Incorrect widget in event");
 
   // Set the coordinates in the new event to the coordinates of
   // the old event, adjusted for the fact that the widget might be
   // different
-  aEvent->refPoint = mGestureDownPoint - aEvent->widget->WidgetToScreenOffset();
+  aEvent->refPoint =
+    mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
   aEvent->mModifiers = mGestureModifiers;
   aEvent->buttons = mGestureDownButtons;
 }
 
 //
 // GenerateDragGesture
 //
 // If we're in the TRACKING state of the d&d gesture tracker, check the current position
@@ -1689,17 +1692,18 @@ EventStateManager::GenerateDragGesture(n
         LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0);
       if (!pixelThresholdX)
         pixelThresholdX = 5;
       if (!pixelThresholdY)
         pixelThresholdY = 5;
     }
 
     // fire drag gesture if mouse has moved enough
-    LayoutDeviceIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
+    LayoutDeviceIntPoint pt =
+      aEvent->refPoint + aEvent->mWidget->WidgetToScreenOffset();
     LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
     if (Abs(distance.x) > AssertedCast<uint32_t>(pixelThresholdX) ||
         Abs(distance.y) > AssertedCast<uint32_t>(pixelThresholdY)) {
       if (Prefs::ClickHoldContextMenu()) {
         // stop the click-hold before we fire off the drag gesture, in case
         // it takes a long time
         KillClickHoldTimer();
       }
@@ -2289,21 +2293,20 @@ EventStateManager::SendLineScrollEvent(n
   if (!targetContent)
     return;
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
   WidgetMouseScrollEvent event(aEvent->IsTrusted(),
-                               eLegacyMouseLineOrPageScroll, aEvent->widget);
+                               eLegacyMouseLineOrPageScroll, aEvent->mWidget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
-  event.widget = aEvent->widget;
   event.mTime = aEvent->mTime;
   event.mTimeStamp = aEvent->mTimeStamp;
   event.mModifiers = aEvent->mModifiers;
   event.buttons = aEvent->buttons;
   event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
   event.mDelta = aDelta;
   event.inputSource = aEvent->inputSource;
 
@@ -2329,21 +2332,20 @@ EventStateManager::SendPixelScrollEvent(
       return;
   }
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
   WidgetMouseScrollEvent event(aEvent->IsTrusted(),
-                               eLegacyMousePixelScroll, aEvent->widget);
+                               eLegacyMousePixelScroll, aEvent->mWidget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
-  event.widget = aEvent->widget;
   event.mTime = aEvent->mTime;
   event.mTimeStamp = aEvent->mTimeStamp;
   event.mModifiers = aEvent->mModifiers;
   event.buttons = aEvent->buttons;
   event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
   event.mDelta = aPixelDelta;
   event.inputSource = aEvent->inputSource;
 
@@ -3418,18 +3420,18 @@ EventStateManager::PostHandleEvent(nsPre
         mCurrentTarget->GetContentForEvent(aEvent,
                                            getter_AddRefs(targetContent));
 
         nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
         WidgetDragEvent event(aEvent->IsTrusted(), eLegacyDragDrop, widget);
 
         WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
         event.refPoint = mouseEvent->refPoint;
-        if (mouseEvent->widget) {
-          event.refPoint += mouseEvent->widget->WidgetToScreenOffset();
+        if (mouseEvent->mWidget) {
+          event.refPoint += mouseEvent->mWidget->WidgetToScreenOffset();
         }
         event.refPoint -= widget->WidgetToScreenOffset();
         event.mModifiers = mouseEvent->mModifiers;
         event.buttons = mouseEvent->buttons;
         event.inputSource = mouseEvent->inputSource;
 
         nsEventStatus status = nsEventStatus_eIgnore;
         nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
@@ -3841,31 +3843,31 @@ CreateMouseOrPointerWidgetEvent(WidgetMo
   WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
   if (sourcePointer) {
     PROFILER_LABEL("Input", "DispatchPointerEvent",
       js::ProfileEntry::Category::EVENTS);
 
     nsAutoPtr<WidgetPointerEvent> newPointerEvent;
     newPointerEvent =
       new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
-                             aMouseEvent->widget);
+                             aMouseEvent->mWidget);
     newPointerEvent->isPrimary = sourcePointer->isPrimary;
     newPointerEvent->pointerId = sourcePointer->pointerId;
     newPointerEvent->width = sourcePointer->width;
     newPointerEvent->height = sourcePointer->height;
     newPointerEvent->inputSource = sourcePointer->inputSource;
     newPointerEvent->relatedTarget =
       nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
         ? nullptr
         : aRelatedContent;
     aNewEvent = newPointerEvent.forget();
   } else {
     aNewEvent =
       new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
-                           aMouseEvent->widget, WidgetMouseEvent::eReal);
+                           aMouseEvent->mWidget, WidgetMouseEvent::eReal);
     aNewEvent->relatedTarget = aRelatedContent;
   }
   aNewEvent->refPoint = aMouseEvent->refPoint;
   aNewEvent->mModifiers = aMouseEvent->mModifiers;
   aNewEvent->button = aMouseEvent->button;
   aNewEvent->buttons = aMouseEvent->buttons;
   aNewEvent->pressure = aMouseEvent->pressure;
   aNewEvent->mPluginEvent = aMouseEvent->mPluginEvent;
@@ -4200,35 +4202,35 @@ EventStateManager::GenerateMouseEnterExi
   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
 
   switch(aMouseEvent->mMessage) {
   case eMouseMove:
     {
       // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
       // Movement is calculated in UIEvent::GetMovementPoint() as:
       //   previous_mousemove_refPoint - current_mousemove_refPoint.
-      if (sIsPointerLocked && aMouseEvent->widget) {
+      if (sIsPointerLocked && aMouseEvent->mWidget) {
         // The pointer is locked. If the pointer is not located at the center of
         // the window, dispatch a synthetic mousemove to return the pointer there.
         // Doing this between "real" pointer moves gives the impression that the
         // (locked) pointer can continue moving and won't stop at the screen
         // boundary. We cancel the synthetic event so that we don't end up
         // dispatching the centering move event to content.
         LayoutDeviceIntPoint center =
-          GetWindowClientRectCenter(aMouseEvent->widget);
+          GetWindowClientRectCenter(aMouseEvent->mWidget);
         aMouseEvent->lastRefPoint = center;
         if (aMouseEvent->refPoint != center) {
           // Mouse move doesn't finish at the center of the window. Dispatch a
           // synthetic native mouse event to move the pointer back to the center
           // of the window, to faciliate more movement. But first, record that
           // we've dispatched a synthetic mouse movement, so we can cancel it
           // in the other branch here.
           sSynthCenteringPoint = center;
-          aMouseEvent->widget->SynthesizeNativeMouseMove(
-            center + aMouseEvent->widget->WidgetToScreenOffset(), nullptr);
+          aMouseEvent->mWidget->SynthesizeNativeMouseMove(
+            center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
         } else if (aMouseEvent->refPoint == sSynthCenteringPoint) {
           // This is the "synthetic native" event we dispatched to re-center the
           // pointer. Cancel it so we don't expose the centering move to content.
           aMouseEvent->StopPropagation();
           // Clear sSynthCenteringPoint so we don't cancel other events
           // targeted at the center.
           sSynthCenteringPoint = kInvalidRefPoint;
         }
@@ -4285,17 +4287,17 @@ EventStateManager::GenerateMouseEnterExi
   case ePointerCancel:
   case eMouseExitFromWidget:
     {
       // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
       OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
       if (helper->mLastOverFrame &&
-          nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
+          nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
           nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
         // the Mouse/PointerOut event widget doesn't have same top widget with
         // mLastOverFrame, it's a spurious event for mLastOverFrame
         break;
       }
 
       // Reset sLastRefPoint, so that we'll know not to report any
       // movement the next time we re-enter the window.
@@ -4466,17 +4468,17 @@ void
 EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
                                        WidgetDragEvent* aDragEvent,
                                        EventMessage aMessage,
                                        nsIContent* aRelatedTarget,
                                        nsIContent* aTargetContent,
                                        nsWeakFrame& aTargetFrame)
 {
   nsEventStatus status = nsEventStatus_eIgnore;
-  WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
+  WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
   event.refPoint = aDragEvent->refPoint;
   event.mModifiers = aDragEvent->mModifiers;
   event.buttons = aDragEvent->buttons;
   event.relatedTarget = aRelatedTarget;
   event.inputSource = aDragEvent->inputSource;
 
   mCurrentTargetContent = aTargetContent;
 
@@ -4502,17 +4504,18 @@ EventStateManager::FireDragEnterOrExit(n
   }
 
   // Finally dispatch the event to the frame
   if (aTargetFrame)
     aTargetFrame->HandleEvent(aPresContext, &event, &status);
 
   if (aMessage == eDragExit && IsRemoteTarget(aTargetContent)) {
     nsEventStatus status = nsEventStatus_eIgnore;
-    WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
+    WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), aMessage,
+                                aDragEvent->mWidget);
     remoteEvent.AssignDragEventData(*aDragEvent, true);
     HandleCrossProcessEvent(&remoteEvent, &status);
   }
 }
 
 void
 EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent)
 {
@@ -4620,26 +4623,26 @@ EventStateManager::CheckForAndDispatchCl
 {
   nsresult ret = NS_OK;
 
   //If mouse is still over same element, clickcount will be > 1.
   //If it has moved it will be zero, so no click.
   if (0 != aEvent->clickCount) {
     //Check that the window isn't disabled before firing a click
     //(see bug 366544).
-    if (aEvent->widget && !aEvent->widget->IsEnabled()) {
+    if (aEvent->mWidget && !aEvent->mWidget->IsEnabled()) {
       return ret;
     }
     //fire click
     bool notDispatchToContents =
      (aEvent->button == WidgetMouseEvent::eMiddleButton ||
       aEvent->button == WidgetMouseEvent::eRightButton);
 
     WidgetMouseEvent event(aEvent->IsTrusted(), eMouseClick,
-                           aEvent->widget, WidgetMouseEvent::eReal);
+                           aEvent->mWidget, WidgetMouseEvent::eReal);
     event.refPoint = aEvent->refPoint;
     event.clickCount = aEvent->clickCount;
     event.mModifiers = aEvent->mModifiers;
     event.buttons = aEvent->buttons;
     event.mTime = aEvent->mTime;
     event.mTimeStamp = aEvent->mTimeStamp;
     event.mFlags.mNoContentDispatch = notDispatchToContents;
     event.button = aEvent->button;
@@ -4663,17 +4666,17 @@ EventStateManager::CheckForAndDispatchCl
       // HandleEvent clears out mCurrentTarget which we might need again
       nsWeakFrame currentTarget = mCurrentTarget;
       ret = presShell->HandleEventWithTarget(&event, currentTarget,
                                              mouseContent, aStatus);
       if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2 &&
           mouseContent && mouseContent->IsInComposedDoc()) {
         //fire double click
         WidgetMouseEvent event2(aEvent->IsTrusted(), eMouseDoubleClick,
-                                aEvent->widget, WidgetMouseEvent::eReal);
+                                aEvent->mWidget, WidgetMouseEvent::eReal);
         event2.refPoint = aEvent->refPoint;
         event2.clickCount = aEvent->clickCount;
         event2.mModifiers = aEvent->mModifiers;
         event2.buttons = aEvent->buttons;
         event2.mFlags.mNoContentDispatch = notDispatchToContents;
         event2.button = aEvent->button;
         event2.inputSource = aEvent->inputSource;
 
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -865,17 +865,17 @@ protected:
                           dom::DataTransfer* aDataTransfer,
                           nsIContent* aDragTarget,
                           nsISelection* aSelection);
 
   bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nullptr; }
   /**
    * Set the fields of aEvent to reflect the mouse position and modifier keys
    * that were set when the user first pressed the mouse button (stored by
-   * BeginTrackingDragGesture). aEvent->widget must be
+   * BeginTrackingDragGesture). aEvent->mWidget must be
    * mCurrentTarget->GetNearestWidget().
    */
   void FillInEventFromGestureDown(WidgetMouseEvent* aEvent);
 
   nsresult DoContentCommandEvent(WidgetContentCommandEvent* aEvent);
   nsresult DoContentCommandScrollEvent(WidgetContentCommandEvent* aEvent);
 
   dom::TabParent *GetCrossProcessTarget();
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -753,17 +753,17 @@ bool
 IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
                                        WidgetMouseEvent* aMouseEvent)
 {
   if (!mUpdatePreference.WantMouseButtonEventOnChar()) {
     return false;
   }
   if (!aMouseEvent->IsTrusted() ||
       aMouseEvent->DefaultPrevented() ||
-      !aMouseEvent->widget) {
+      !aMouseEvent->mWidget) {
     return false;
   }
   // Now, we need to notify only mouse down and mouse up event.
   switch (aMouseEvent->mMessage) {
     case eMouseUp:
     case eMouseDown:
       break;
     default:
@@ -771,17 +771,17 @@ IMEContentObserver::OnMouseButtonEvent(n
   }
   if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) {
     return false;
   }
 
   RefPtr<IMEContentObserver> kungFuDeathGrip(this);
 
   WidgetQueryContentEvent charAtPt(true, eQueryCharacterAtPoint,
-                                   aMouseEvent->widget);
+                                   aMouseEvent->mWidget);
   charAtPt.refPoint = aMouseEvent->refPoint;
   ContentEventHandler handler(aPresContext);
   handler.OnQueryCharacterAtPoint(&charAtPt);
   if (NS_WARN_IF(!charAtPt.mSucceeded) ||
       charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
     return false;
   }
 
@@ -796,18 +796,18 @@ IMEContentObserver::OnMouseButtonEvent(n
   nsIWidget* topLevelWidget = mWidget->GetTopLevelWidget();
   if (topLevelWidget && topLevelWidget != mWidget) {
     charAtPt.mReply.mRect.MoveBy(
       topLevelWidget->WidgetToScreenOffset() -
         mWidget->WidgetToScreenOffset());
   }
   // The refPt is relative to its widget.
   // We should notify it with offset in the widget.
-  if (aMouseEvent->widget != mWidget) {
-    charAtPt.refPoint += aMouseEvent->widget->WidgetToScreenOffset() -
+  if (aMouseEvent->mWidget != mWidget) {
+    charAtPt.refPoint += aMouseEvent->mWidget->WidgetToScreenOffset() -
       mWidget->WidgetToScreenOffset();
   }
 
   IMENotification notification(NOTIFY_IME_OF_MOUSE_BUTTON_EVENT);
   notification.mMouseButtonEventData.mEventMessage = aMouseEvent->mMessage;
   notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset;
   notification.mMouseButtonEventData.mCursorPos.Set(
     charAtPt.refPoint.ToUnknownPoint());
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1142,29 +1142,29 @@ IMEStateManager::DispatchCompositionEven
   RefPtr<TabParent> tabParent =
     aEventTargetNode->IsContent() ?
       TabParent::GetFrom(aEventTargetNode->AsContent()) : nullptr;
 
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
      "aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
      "mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
-     "mOriginProcessID=0x%X }, widget(0x%p)={ "
+     "mOriginProcessID=0x%X }, mWidget(0x%p)={ "
      "GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
      "mOriginProcessID=0x%X }, Destroyed()=%s }, "
      "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
      "aIsSynthesized=%s), tabParent=%p",
      aEventTargetNode, aPresContext,
      ToChar(aCompositionEvent->mMessage),
      aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
      aCompositionEvent->mNativeIMEContext.mOriginProcessID,
-     aCompositionEvent->widget.get(),
-     aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
-     aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
-     GetBoolName(aCompositionEvent->widget->Destroyed()),
+     aCompositionEvent->mWidget.get(),
+     aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
+     aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
+     GetBoolName(aCompositionEvent->mWidget->Destroyed()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
      GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
      GetBoolName(aIsSynthesized), tabParent.get()));
 
   if (!aCompositionEvent->IsTrusted() ||
       aCompositionEvent->PropagationStopped()) {
     return;
   }
@@ -1212,17 +1212,17 @@ IMEStateManager::DispatchCompositionEven
   //       during not safe to dispatch events, PresShell must have discarded
   //       compositionend event.  Then, the synthesized compositionend event is
   //       the last event for the composition.  In this case, we need to
   //       destroy the TextComposition with synthesized compositionend event.
   if ((!aIsSynthesized ||
        composition->WasNativeCompositionEndEventDiscarded()) &&
       aCompositionEvent->CausesDOMCompositionEndEvent()) {
     TextCompositionArray::index_type i =
-      sTextCompositions->IndexOf(aCompositionEvent->widget);
+      sTextCompositions->IndexOf(aCompositionEvent->mWidget);
     if (i != TextCompositionArray::NoIndex) {
       MOZ_LOG(sISMLog, LogLevel::Debug,
         ("ISM:   IMEStateManager::DispatchCompositionEvent(), "
          "removing TextComposition from the array since NS_COMPOSTION_END "
          "was dispatched"));
       sTextCompositions->ElementAt(i)->Destroy();
       sTextCompositions->RemoveElementAt(i);
     }
@@ -1261,17 +1261,17 @@ IMEStateManager::HandleSelectionEvent(ns
      GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
      tabParent.get()));
 
   if (!aSelectionEvent->IsTrusted()) {
     return;
   }
 
   RefPtr<TextComposition> composition = sTextCompositions ?
-    sTextCompositions->GetCompositionFor(aSelectionEvent->widget) : nullptr;
+    sTextCompositions->GetCompositionFor(aSelectionEvent->mWidget) : nullptr;
   if (composition) {
     // When there is a composition, TextComposition should guarantee that the
     // selection event will be handled in same target as composition events.
     composition->HandleSelectionEvent(aSelectionEvent);
   } else {
     // When there is no composition, the selection event should be handled
     // in the aPresContext or tabParent.
     TextComposition::HandleSelectionEvent(aPresContext, tabParent,
@@ -1285,41 +1285,41 @@ IMEStateManager::OnCompositionEventDisca
                    WidgetCompositionEvent* aCompositionEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
 
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ "
      "mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
-     "mOriginProcessID=0x%X }, widget(0x%p)={ "
+     "mOriginProcessID=0x%X }, mWidget(0x%p)={ "
      "GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
      "mOriginProcessID=0x%X }, Destroyed()=%s }, "
      "mFlags={ mIsTrusted=%s } })",
      ToChar(aCompositionEvent->mMessage),
      aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
      aCompositionEvent->mNativeIMEContext.mOriginProcessID,
-     aCompositionEvent->widget.get(),
-     aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
-     aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
-     GetBoolName(aCompositionEvent->widget->Destroyed()),
+     aCompositionEvent->mWidget.get(),
+     aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
+     aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
+     GetBoolName(aCompositionEvent->mWidget->Destroyed()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
 
   if (!aCompositionEvent->IsTrusted()) {
     return;
   }
 
   // Ignore compositionstart for now because sTextCompositions may not have
   // been created yet.
   if (aCompositionEvent->mMessage == eCompositionStart) {
     return;
   }
 
   RefPtr<TextComposition> composition =
-    sTextCompositions->GetCompositionFor(aCompositionEvent->widget);
+    sTextCompositions->GetCompositionFor(aCompositionEvent->mWidget);
   if (!composition) {
     // If the PresShell has been being destroyed during composition,
     // a TextComposition instance for the composition was already removed from
     // the array and destroyed in OnDestroyPresContext().  Therefore, we may
     // fail to retrieve a TextComposition instance here.
     MOZ_LOG(sISMLog, LogLevel::Info,
       ("ISM:   IMEStateManager::OnCompositionEventDiscarded(), "
        "TextComposition instance for the widget has already gone"));
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -90,41 +90,41 @@ TextComposition::IsValidStateForComposit
 }
 
 bool
 TextComposition::MaybeDispatchCompositionUpdate(
                    const WidgetCompositionEvent* aCompositionEvent)
 {
   MOZ_RELEASE_ASSERT(!mTabParent);
 
-  if (!IsValidStateForComposition(aCompositionEvent->widget)) {
+  if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
     return false;
   }
 
   if (mLastData == aCompositionEvent->mData) {
     return true;
   }
   CloneAndDispatchAs(aCompositionEvent, eCompositionUpdate);
-  return IsValidStateForComposition(aCompositionEvent->widget);
+  return IsValidStateForComposition(aCompositionEvent->mWidget);
 }
 
 BaseEventFlags
 TextComposition::CloneAndDispatchAs(
                    const WidgetCompositionEvent* aCompositionEvent,
                    EventMessage aMessage,
                    nsEventStatus* aStatus,
                    EventDispatchingCallback* aCallBack)
 {
   MOZ_RELEASE_ASSERT(!mTabParent);
 
-  MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
+  MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->mWidget),
              "Should be called only when it's safe to dispatch an event");
 
   WidgetCompositionEvent compositionEvent(aCompositionEvent->IsTrusted(),
-                                          aMessage, aCompositionEvent->widget);
+                                          aMessage, aCompositionEvent->mWidget);
   compositionEvent.mTime = aCompositionEvent->mTime;
   compositionEvent.mTimeStamp = aCompositionEvent->mTimeStamp;
   compositionEvent.mData = aCompositionEvent->mData;
   compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
   compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
   compositionEvent.mFlags.mIsSynthesizedForTests =
     aCompositionEvent->mFlags.mIsSynthesizedForTests;
 
@@ -274,17 +274,17 @@ TextComposition::DispatchCompositionEven
       aCompositionEvent->mData = mLastData;
     }
   } else if (aCompositionEvent->mMessage == eCompositionCommit) {
     NS_ASSERTION(!aCompositionEvent->mRanges,
                  "mRanges of eCompositionCommit should be null");
     aCompositionEvent->mRanges = nullptr;
   }
 
-  if (!IsValidStateForComposition(aCompositionEvent->widget)) {
+  if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
     *aStatus = nsEventStatus_eConsumeNoDefault;
     return;
   }
 
   // If this instance has requested to commit or cancel composition but
   // is not synthesizing commit event, that means that the IME commits or
   // cancels the composition asynchronously.  Typically, iBus behaves so.
   // Then, synthesized events which were dispatched immediately after
@@ -372,17 +372,17 @@ TextComposition::DispatchCompositionEven
                            aStatus, aCallBack);
     } else {
       DispatchEvent(aCompositionEvent, aStatus, aCallBack);
     }
   } else {
     *aStatus = nsEventStatus_eConsumeNoDefault;
   }
 
-  if (!IsValidStateForComposition(aCompositionEvent->widget)) {
+  if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
     return;
   }
 
   // Emulate editor behavior of compositionchange event (DOM text event) handler
   // if no editor handles composition events.
   if (dispatchDOMTextEvent && !HasEditor()) {
     EditorWillHandleCompositionChangeEvent(aCompositionEvent);
     EditorDidHandleCompositionChangeEvent();
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -120,17 +120,17 @@ UIEvent::GetMovementPoint()
 
   if (!mEvent ||
       (mEvent->mClass != eMouseEventClass &&
        mEvent->mClass != eMouseScrollEventClass &&
        mEvent->mClass != eWheelEventClass &&
        mEvent->mClass != eDragEventClass &&
        mEvent->mClass != ePointerEventClass &&
        mEvent->mClass != eSimpleGestureEventClass) ||
-       !mEvent->AsGUIEvent()->widget) {
+       !mEvent->AsGUIEvent()->mWidget) {
     return nsIntPoint(0, 0);
   }
 
   // Calculate the delta between the last screen point and the current one.
   nsIntPoint current = DevPixelsToCSSPixels(mEvent->refPoint, mPresContext);
   nsIntPoint last = DevPixelsToCSSPixels(mEvent->lastRefPoint, mPresContext);
   return current - last;
 }
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -333,18 +333,18 @@ WheelTransaction::SetTimeout()
                                  nsITimer::TYPE_ONE_SHOT);
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "nsITimer::InitWithFuncCallback failed");
 }
 
 /* static */ nsIntPoint
 WheelTransaction::GetScreenPoint(WidgetGUIEvent* aEvent)
 {
   NS_ASSERTION(aEvent, "aEvent is null");
-  NS_ASSERTION(aEvent->widget, "aEvent-widget is null");
-  return (aEvent->refPoint + aEvent->widget->WidgetToScreenOffset())
+  NS_ASSERTION(aEvent->mWidget, "aEvent-mWidget is null");
+  return (aEvent->refPoint + aEvent->mWidget->WidgetToScreenOffset())
       .ToUnknownPoint();
 }
 
 /* static */ uint32_t
 WheelTransaction::GetTimeoutTime()
 {
   return Preferences::GetUint("mousewheel.transaction.timeout", 1500);
 }
--- a/dom/filesystem/CreateDirectoryTask.cpp
+++ b/dom/filesystem/CreateDirectoryTask.cpp
@@ -114,19 +114,17 @@ CreateDirectoryTaskChild::HandlerCallbac
 
   if (HasError()) {
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
 
   RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
-                                            mTargetPath,
-                                            Directory::eNotDOMRootDirectory,
-                                            mFileSystem);
+                                            mTargetPath, mFileSystem);
   MOZ_ASSERT(dir);
 
   mPromise->MaybeResolve(dir);
   mPromise = nullptr;
 }
 
 void
 CreateDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -110,20 +110,42 @@ DeviceStorageFileSystem::GetParentObject
   AssertIsOnOwningThread();
 
   nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
   MOZ_ASSERT_IF(!mShutdown, window);
   return window ? window->AsInner() : nullptr;
 }
 
 void
-DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const
+DeviceStorageFileSystem::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+                                          ErrorResult& aRv) const
 {
   AssertIsOnOwningThread();
-  aRetval = mStorageName;
+  MOZ_ASSERT(aFile);
+
+  nsCOMPtr<nsIFile> rootPath;
+  aRv = NS_NewLocalFile(LocalOrDeviceStorageRootPath(), false,
+                        getter_AddRefs(rootPath));
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  bool equal = false;
+  aRv = aFile->Equals(rootPath, &equal);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  if (equal) {
+    aRetval = mStorageName;
+    return;
+  }
+
+  FileSystemBase::GetDirectoryName(aFile, aRetval, aRv);
+  NS_WARN_IF(aRv.Failed());
 }
 
 bool
 DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
 {
   MOZ_ASSERT(XRE_IsParentProcess(), "Should be on parent process!");
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aFile);
--- a/dom/filesystem/DeviceStorageFileSystem.h
+++ b/dom/filesystem/DeviceStorageFileSystem.h
@@ -25,24 +25,28 @@ public:
   void
   Init(nsDOMDeviceStorage* aDeviceStorage);
 
   // Overrides FileSystemBase
 
   virtual already_AddRefed<FileSystemBase>
   Clone() override;
 
+  virtual bool
+  ShouldCreateDirectory() override { return true; }
+
   virtual void
   Shutdown() override;
 
   virtual nsISupports*
   GetParentObject() const override;
 
   virtual void
-  GetRootName(nsAString& aRetval) const override;
+  GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+                   ErrorResult& aRv) const override;
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const override;
 
   virtual bool
   IsSafeDirectory(Directory* aDir) const override;
 
   virtual void
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -132,58 +132,47 @@ Directory::GetRoot(FileSystemBase* aFile
   nsCOMPtr<nsIFile> path;
   aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->LocalOrDeviceStorageRootPath()),
                               true, getter_AddRefs(path));
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<GetFileOrDirectoryTaskChild> task =
-    GetFileOrDirectoryTaskChild::Create(aFileSystem, path, eDOMRootDirectory,
-                                        true, aRv);
+    GetFileOrDirectoryTaskChild::Create(aFileSystem, path, true, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 /* static */ already_AddRefed<Directory>
 Directory::Create(nsISupports* aParent, nsIFile* aFile,
-                  DirectoryType aType, FileSystemBase* aFileSystem)
+                  FileSystemBase* aFileSystem)
 {
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(aFile);
 
 #ifdef DEBUG
   bool isDir;
   nsresult rv = aFile->IsDirectory(&isDir);
   MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
-
-  if (aType == eNotDOMRootDirectory) {
-    RefPtr<nsIFile> parent;
-    rv = aFile->GetParent(getter_AddRefs(parent));
-    // We must have a parent if this is not the root directory.
-    MOZ_ASSERT(NS_SUCCEEDED(rv) && parent);
-  }
 #endif
 
-  RefPtr<Directory> directory =
-    new Directory(aParent, aFile, aType, aFileSystem);
+  RefPtr<Directory> directory = new Directory(aParent, aFile, aFileSystem);
   return directory.forget();
 }
 
 Directory::Directory(nsISupports* aParent,
                      nsIFile* aFile,
-                     DirectoryType aType,
                      FileSystemBase* aFileSystem)
   : mParent(aParent)
   , mFile(aFile)
-  , mType(aType)
 {
   MOZ_ASSERT(aFile);
 
   // aFileSystem can be null. In this case we create a OSFileSystem when needed.
   if (aFileSystem) {
     // More likely, this is a OSFileSystem. This object keeps a reference of
     // mParent but it's not cycle collectable and to avoid manual
     // addref/release, it's better to have 1 object per directory. For this
@@ -208,28 +197,22 @@ Directory::WrapObject(JSContext* aCx, JS
   return DirectoryBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
 {
   aRetval.Truncate();
 
-  if (mType == eDOMRootDirectory) {
-    RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
-
-    fs->GetRootName(aRetval);
+  RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  aRv = mFile->GetLeafName(aRetval);
-  NS_WARN_IF(aRv.Failed());
+  fs->GetDirectoryName(mFile, aRetval, aRv);
 }
 
 already_AddRefed<Promise>
 Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
                       ErrorResult& aRv)
 {
   // Only exposed for DeviceStorage.
   MOZ_ASSERT(NS_IsMainThread());
@@ -313,18 +296,17 @@ Directory::Get(const nsAString& aPath, E
   nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
 
   RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<GetFileOrDirectoryTaskChild> task =
-    GetFileOrDirectoryTaskChild::Create(fs, realPath, eNotDOMRootDirectory,
-                                        false, aRv);
+    GetFileOrDirectoryTaskChild::Create(fs, realPath, false, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
@@ -404,17 +386,17 @@ Directory::GetPath(nsAString& aRetval, E
 {
   // This operation is expensive. Better to cache the result.
   if (mPath.IsEmpty()) {
     RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
-    fs->GetDOMPath(mFile, mType, mPath, aRv);
+    fs->GetDOMPath(mFile, mPath, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
   aRetval = mPath;
 }
 
@@ -433,17 +415,17 @@ already_AddRefed<Promise>
 Directory::GetFilesAndDirectories(ErrorResult& aRv)
 {
   RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<GetDirectoryListingTaskChild> task =
-    GetDirectoryListingTaskChild::Create(fs, mFile, mType, mFilters, aRv);
+    GetDirectoryListingTaskChild::Create(fs, mFile, mFilters, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
@@ -473,20 +455,16 @@ Directory::SetContentFilters(const nsASt
 {
   mFilters = aFilters;
 }
 
 FileSystemBase*
 Directory::GetFileSystem(ErrorResult& aRv)
 {
   if (!mFileSystem) {
-    // Any subdir inherits the FileSystem of the parent Directory. If we are
-    // here it's because we are dealing with the DOM root.
-    MOZ_ASSERT(mType == eDOMRootDirectory);
-
     nsAutoString path;
     aRv = mFile->GetPath(path);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     RefPtr<OSFileSystem> fs = new OSFileSystem(path);
     fs->Init(mParent);
--- a/dom/filesystem/Directory.h
+++ b/dom/filesystem/Directory.h
@@ -54,30 +54,19 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
 
   static bool
   DeviceStorageEnabled(JSContext* aCx, JSObject* aObj);
 
   static already_AddRefed<Promise>
   GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
 
-  enum DirectoryType {
-    // When a directory is selected using a HTMLInputElement, that will be the
-    // DOM root directory and its name will be '/'. All the sub directory will
-    // be called with they real name. We use this enum to mark what we must
-    // consider the '/' of this DOM filesystem.
-    eDOMRootDirectory,
-
-    // All the sub directories of the '/' will be marked using this other value.
-    eNotDOMRootDirectory
-  };
-
   static already_AddRefed<Directory>
   Create(nsISupports* aParent, nsIFile* aDirectory,
-         DirectoryType aType, FileSystemBase* aFileSystem = 0);
+         FileSystemBase* aFileSystem = 0);
 
   // ========= Begin WebIDL bindings. ===========
 
   nsISupports*
   GetParentObject() const;
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -140,44 +129,38 @@ public:
    * picker operation.
    */
   void
   SetContentFilters(const nsAString& aFilters);
 
   FileSystemBase*
   GetFileSystem(ErrorResult& aRv);
 
-  DirectoryType Type() const
-  {
-    return mType;
-  }
-
   bool
   ClonableToDifferentThreadOrProcess() const;
 
 private:
   Directory(nsISupports* aParent,
-            nsIFile* aFile, DirectoryType aType,
+            nsIFile* aFile,
             FileSystemBase* aFileSystem = nullptr);
   ~Directory();
 
   /*
    * Convert relative DOM path to the absolute real path.
    */
   nsresult
   DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
 
   already_AddRefed<Promise>
   RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
                  ErrorResult& aRv);
 
   nsCOMPtr<nsISupports> mParent;
   RefPtr<FileSystemBase> mFileSystem;
   nsCOMPtr<nsIFile> mFile;
-  DirectoryType mType;
 
   nsString mFilters;
   nsString mPath;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/filesystem/FileSystemBase.cpp
+++ b/dom/filesystem/FileSystemBase.cpp
@@ -106,83 +106,86 @@ FileSystemBase::IsSafeFile(nsIFile* aFil
 bool
 FileSystemBase::IsSafeDirectory(Directory* aDir) const
 {
   AssertIsOnOwningThread();
   return false;
 }
 
 void
+FileSystemBase::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+                                 ErrorResult& aRv) const
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(aFile);
+
+  aRv = aFile->GetLeafName(aRetval);
+  NS_WARN_IF(aRv.Failed());
+}
+
+void
 FileSystemBase::GetDOMPath(nsIFile* aFile,
-                           Directory::DirectoryType aType,
                            nsAString& aRetval,
                            ErrorResult& aRv) const
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aFile);
 
-  if (aType == Directory::eDOMRootDirectory) {
-    aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
-    return;
-  }
+  aRetval.Truncate();
 
   nsCOMPtr<nsIFile> fileSystemPath;
   aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(LocalOrDeviceStorageRootPath()),
                               true, getter_AddRefs(fileSystemPath));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  MOZ_ASSERT(FileSystemUtils::IsDescendantPath(fileSystemPath, aFile));
-
   nsCOMPtr<nsIFile> path;
   aRv = aFile->Clone(getter_AddRefs(path));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   nsTArray<nsString> parts;
 
   while (true) {
+    nsAutoString leafName;
+    aRv = path->GetLeafName(leafName);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return;
+    }
+
+    parts.AppendElement(leafName);
+
     bool equal = false;
     aRv = fileSystemPath->Equals(path, &equal);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     if (equal) {
       break;
     }
 
-    nsAutoString leafName;
-    aRv = path->GetLeafName(leafName);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
-
-    parts.AppendElement(leafName);
-
     nsCOMPtr<nsIFile> parentPath;
     aRv = path->GetParent(getter_AddRefs(parentPath));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     MOZ_ASSERT(parentPath);
 
     aRv = parentPath->Clone(getter_AddRefs(path));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
   MOZ_ASSERT(!parts.IsEmpty());
 
-  aRetval.Truncate();
-
   for (int32_t i = parts.Length() - 1; i >= 0; --i) {
     aRetval.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
     aRetval.Append(parts[i]);
   }
 }
 
 void
 FileSystemBase::AssertIsOnOwningThread() const
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -32,29 +32,28 @@ public:
 
   // SerializeDOMPath the FileSystem to string.
   virtual void
   SerializeDOMPath(nsAString& aOutput) const = 0;
 
   virtual already_AddRefed<FileSystemBase>
   Clone() = 0;
 
+  virtual bool
+  ShouldCreateDirectory() = 0;
+
   virtual nsISupports*
   GetParentObject() const;
 
-  /*
-   * Get the virtual name of the root directory. This name will be exposed to
-   * the content page.
-   */
   virtual void
-  GetRootName(nsAString& aRetval) const = 0;
+  GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+                   ErrorResult& aRv) const;
 
   void
-  GetDOMPath(nsIFile* aFile, Directory::DirectoryType aType,
-             nsAString& aRetval, ErrorResult& aRv) const;
+  GetDOMPath(nsIFile* aFile, nsAString& aRetval, ErrorResult& aRv) const;
 
   /*
    * Return the local root path of the FileSystem implementation.
    * For OSFileSystem, this is equal to the path of the root Directory;
    * For DeviceStorageFileSystem, this is the path of the SDCard, parent
    * directory of the exposed root Directory (per type).
    */
   const nsAString&
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -23,25 +23,24 @@ namespace dom {
 
 /**
  * GetDirectoryListingTaskChild
  */
 
 /* static */ already_AddRefed<GetDirectoryListingTaskChild>
 GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
                                      nsIFile* aTargetPath,
-                                     Directory::DirectoryType aType,
                                      const nsAString& aFilters,
                                      ErrorResult& aRv)
 {
   MOZ_ASSERT(aFileSystem);
   aFileSystem->AssertIsOnOwningThread();
 
   RefPtr<GetDirectoryListingTaskChild> task =
-    new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aType, aFilters);
+    new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aFilters);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -52,22 +51,20 @@ GetDirectoryListingTaskChild::Create(Fil
     return nullptr;
   }
 
   return task.forget();
 }
 
 GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
                                                            nsIFile* aTargetPath,
-                                                           Directory::DirectoryType aType,
                                                            const nsAString& aFilters)
   : FileSystemTaskChildBase(aFileSystem)
   , mTargetPath(aTargetPath)
   , mFilters(aFilters)
-  , mType(aType)
 {
   MOZ_ASSERT(aFileSystem);
   aFileSystem->AssertIsOnOwningThread();
 }
 
 GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
 {
   mFileSystem->AssertIsOnOwningThread();
@@ -88,17 +85,16 @@ GetDirectoryListingTaskChild::GetRequest
 
   nsAutoString path;
   aRv = mTargetPath->GetPath(path);
   if (NS_WARN_IF(aRv.Failed())) {
     return FileSystemGetDirectoryListingParams();
   }
 
   return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
-                                             mType == Directory::eDOMRootDirectory,
                                              mFilters);
 }
 
 void
 GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                                                       ErrorResult& aRv)
 {
   mFileSystem->AssertIsOnOwningThread();
@@ -174,18 +170,17 @@ GetDirectoryListingTaskChild::HandlerCal
       return;
     }
 
     MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
 #endif
 
     if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
       RefPtr<Directory> directory =
-        Directory::Create(mFileSystem->GetParentObject(), path,
-                          Directory::eNotDOMRootDirectory, mFileSystem);
+        Directory::Create(mFileSystem->GetParentObject(), path, mFileSystem);
       MOZ_ASSERT(directory);
 
       // Propogate mFilter onto sub-Directory object:
       directory->SetContentFilters(mFilters);
       listing[i].SetAsDirectory() = directory;
     } else {
       MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
 
@@ -225,18 +220,16 @@ GetDirectoryListingTaskParent::Create(Fi
     new GetDirectoryListingTaskParent(aFileSystem, aParam, aParent);
 
   NS_ConvertUTF16toUTF8 path(aParam.realPath());
   aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  task->mType = aParam.isRoot()
-                  ? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
   return task.forget();
 }
 
 GetDirectoryListingTaskParent::GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
                                                              const FileSystemGetDirectoryListingParams& aParam,
                                                              FileSystemRequestParent* aParent)
   : FileSystemTaskParentBase(aFileSystem, aParam, aParent)
   , mFilters(aParam.filters())
@@ -286,21 +279,20 @@ GetDirectoryListingTaskParent::IOWork()
 
   bool exists;
   nsresult rv = mTargetPath->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!exists) {
-    if (mType == Directory::eNotDOMRootDirectory) {
+    if (!mFileSystem->ShouldCreateDirectory()) {
       return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
     }
 
-    // If the root directory doesn't exit, create it.
     rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // Get isDirectory.
   bool isDir;
--- a/dom/filesystem/GetDirectoryListingTask.h
+++ b/dom/filesystem/GetDirectoryListingTask.h
@@ -18,51 +18,48 @@ namespace dom {
 class BlobImpl;
 
 class GetDirectoryListingTaskChild final : public FileSystemTaskChildBase
 {
 public:
   static already_AddRefed<GetDirectoryListingTaskChild>
   Create(FileSystemBase* aFileSystem,
          nsIFile* aTargetPath,
-         Directory::DirectoryType aType,
          const nsAString& aFilters,
          ErrorResult& aRv);
 
   virtual
   ~GetDirectoryListingTaskChild();
 
   already_AddRefed<Promise>
   GetPromise();
 
   virtual void
   GetPermissionAccessType(nsCString& aAccess) const override;
 
 private:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
                                nsIFile* aTargetPath,
-                               Directory::DirectoryType aType,
                                const nsAString& aFilters);
 
   virtual FileSystemParams
   GetRequestParams(const nsString& aSerializedDOMPath,
                    ErrorResult& aRv) const override;
 
   virtual void
   SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                           ErrorResult& aRv) override;
 
   virtual void
   HandlerCallback() override;
 
   RefPtr<Promise> mPromise;
   nsCOMPtr<nsIFile> mTargetPath;
   nsString mFilters;
-  Directory::DirectoryType mType;
 
   // We cannot store File or Directory objects bacause this object is created
   // on a different thread and File and Directory are not thread-safe.
   FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
 };
 
 class GetDirectoryListingTaskParent final : public FileSystemTaskParentBase
 {
@@ -84,17 +81,16 @@ private:
   virtual FileSystemResponseValue
   GetSuccessRequestResult(ErrorResult& aRv) const override;
 
   virtual nsresult
   IOWork() override;
 
   nsCOMPtr<nsIFile> mTargetPath;
   nsString mFilters;
-  Directory::DirectoryType mType;
 
   // We cannot store File or Directory objects bacause this object is created
   // on a different thread and File and Directory are not thread-safe.
   FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -22,26 +22,24 @@ namespace dom {
 
 /**
  * GetFileOrDirectoryTaskChild
  */
 
 /* static */ already_AddRefed<GetFileOrDirectoryTaskChild>
 GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
                                     nsIFile* aTargetPath,
-                                    Directory::DirectoryType aType,
                                     bool aDirectoryOnly,
                                     ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem);
 
   RefPtr<GetFileOrDirectoryTaskChild> task =
-    new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aType,
-                                    aDirectoryOnly);
+    new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aDirectoryOnly);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -52,22 +50,20 @@ GetFileOrDirectoryTaskChild::Create(File
     return nullptr;
   }
 
   return task.forget();
 }
 
 GetFileOrDirectoryTaskChild::GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
                                                          nsIFile* aTargetPath,
-                                                         Directory::DirectoryType aType,
                                                          bool aDirectoryOnly)
   : FileSystemTaskChildBase(aFileSystem)
   , mTargetPath(aTargetPath)
   , mIsDirectory(aDirectoryOnly)
-  , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem);
 }
 
 GetFileOrDirectoryTaskChild::~GetFileOrDirectoryTaskChild()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -87,18 +83,17 @@ GetFileOrDirectoryTaskChild::GetRequestP
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
 
   nsAutoString path;
   aRv = mTargetPath->GetPath(path);
   if (NS_WARN_IF(aRv.Failed())) {
     return FileSystemGetFileOrDirectoryParams();
   }
 
-  return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
-                                            mType == Directory::eDOMRootDirectory);
+  return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path);
 }
 
 void
 GetFileOrDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                                                      ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   switch (aValue.type()) {
@@ -146,17 +141,16 @@ GetFileOrDirectoryTaskChild::HandlerCall
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
 
   if (mIsDirectory) {
     RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
                                               mTargetPath,
-                                              mType,
                                               mFileSystem);
     MOZ_ASSERT(dir);
 
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
@@ -190,18 +184,16 @@ GetFileOrDirectoryTaskParent::Create(Fil
     new GetFileOrDirectoryTaskParent(aFileSystem, aParam, aParent);
 
   NS_ConvertUTF16toUTF8 path(aParam.realPath());
   aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  task->mType = aParam.isRoot()
-                  ? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
   return task.forget();
 }
 
 GetFileOrDirectoryTaskParent::GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
                                                            const FileSystemGetFileOrDirectoryParams& aParam,
                                                            FileSystemRequestParent* aParent)
   : FileSystemTaskParentBase(aFileSystem, aParam, aParent)
   , mIsDirectory(false)
@@ -243,42 +235,36 @@ GetFileOrDirectoryTaskParent::IOWork()
   // Whether we want to get the root directory.
   bool exists;
   nsresult rv = mTargetPath->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!exists) {
-    if (mType == Directory::eNotDOMRootDirectory) {
+    if (!mFileSystem->ShouldCreateDirectory()) {
       return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
     }
 
-    // If the root directory doesn't exit, create it.
     rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // Get isDirectory.
   rv = mTargetPath->IsDirectory(&mIsDirectory);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (mIsDirectory) {
     return NS_OK;
   }
 
-  // Check if the root is a directory.
-  if (mType == Directory::eDOMRootDirectory) {
-    return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
-  }
-
   bool isFile;
   // Get isFile
   rv = mTargetPath->IsFile(&isFile);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!isFile) {
--- a/dom/filesystem/GetFileOrDirectoryTask.h
+++ b/dom/filesystem/GetFileOrDirectoryTask.h
@@ -18,17 +18,16 @@ namespace dom {
 class BlobImpl;
 
 class GetFileOrDirectoryTaskChild final : public FileSystemTaskChildBase
 {
 public:
   static already_AddRefed<GetFileOrDirectoryTaskChild>
   Create(FileSystemBase* aFileSystem,
          nsIFile* aTargetPath,
-         Directory::DirectoryType aType,
          bool aDirectoryOnly,
          ErrorResult& aRv);
 
   virtual
   ~GetFileOrDirectoryTaskChild();
 
   already_AddRefed<Promise>
   GetPromise();
@@ -46,25 +45,23 @@ protected:
                           ErrorResult& aRv) override;
   virtual void
   HandlerCallback() override;
 
 private:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
                               nsIFile* aTargetPath,
-                              Directory::DirectoryType aType,
                               bool aDirectoryOnly);
 
   RefPtr<Promise> mPromise;
   nsCOMPtr<nsIFile> mTargetPath;
 
   // Whether we get a directory.
   bool mIsDirectory;
-  Directory::DirectoryType mType;
 };
 
 class GetFileOrDirectoryTaskParent final : public FileSystemTaskParentBase
 {
 public:
   static already_AddRefed<GetFileOrDirectoryTaskParent>
   Create(FileSystemBase* aFileSystem,
          const FileSystemGetFileOrDirectoryParams& aParam,
@@ -85,15 +82,14 @@ private:
   GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
                                const FileSystemGetFileOrDirectoryParams& aParam,
                                FileSystemRequestParent* aParent);
 
   nsCOMPtr<nsIFile> mTargetPath;
 
   // Whether we get a directory.
   bool mIsDirectory;
-  Directory::DirectoryType mType;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_GetFileOrDirectory_h
--- a/dom/filesystem/OSFileSystem.cpp
+++ b/dom/filesystem/OSFileSystem.cpp
@@ -57,23 +57,16 @@ OSFileSystem::Init(nsISupports* aParent)
 
 nsISupports*
 OSFileSystem::GetParentObject() const
 {
   AssertIsOnOwningThread();
   return mParent;
 }
 
-void
-OSFileSystem::GetRootName(nsAString& aRetval) const
-{
-  AssertIsOnOwningThread();
-  aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
-}
-
 bool
 OSFileSystem::IsSafeFile(nsIFile* aFile) const
 {
   // The concept of "safe files" is specific to the Device Storage API where
   // files are only "safe" if they're of a type that is appropriate for the
   // area of device storage that is being used.
   MOZ_CRASH("Don't use OSFileSystem with the Device Storage API");
   return true;
--- a/dom/filesystem/OSFileSystem.h
+++ b/dom/filesystem/OSFileSystem.h
@@ -20,22 +20,28 @@ public:
   void
   Init(nsISupports* aParent);
 
   // Overrides FileSystemBase
 
   virtual already_AddRefed<FileSystemBase>
   Clone() override;
 
+  virtual bool
+  ShouldCreateDirectory() override
+  {
+    MOZ_CRASH("This should not be called.");
+    // Because OSFileSystem should not be used when the creation of directories
+    // is needed. For that we have OSFileSystemParent.
+    return false;
+  }
+
   virtual nsISupports*
   GetParentObject() const override;
 
-  virtual void
-  GetRootName(nsAString& aRetval) const override;
-
   virtual bool
   IsSafeFile(nsIFile* aFile) const override;
 
   virtual bool
   IsSafeDirectory(Directory* aDir) const override;
 
   virtual void
   SerializeDOMPath(nsAString& aOutput) const override;
@@ -62,25 +68,29 @@ public:
 
   virtual already_AddRefed<FileSystemBase>
   Clone() override
   {
     MOZ_CRASH("This should not be called on the PBackground thread.");
     return nullptr;
   }
 
+  virtual bool
+  ShouldCreateDirectory() override { return false; }
+
   virtual nsISupports*
   GetParentObject() const override
   {
     MOZ_CRASH("This should not be called on the PBackground thread.");
     return nullptr;
   }
 
   virtual void
-  GetRootName(nsAString& aRetval) const override
+  GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+                   ErrorResult& aRv) const override
   {
     MOZ_CRASH("This should not be called on the PBackground thread.");
   }
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const override
   {
     MOZ_CRASH("This should not be called on the PBackground thread.");
--- a/dom/filesystem/PFileSystemParams.ipdlh
+++ b/dom/filesystem/PFileSystemParams.ipdlh
@@ -26,17 +26,17 @@ struct FileSystemCreateFileParams
   FileSystemFileDataValue data;
   bool replace;
 };
 
 struct FileSystemGetDirectoryListingParams
 {
   nsString filesystem;
   nsString realPath;
-  bool isRoot;
+
   // 'filters' could be an array rather than a semicolon separated string
   // (we'd then use InfallibleTArray<nsString> internally), but that is
   // wasteful.  E10s requires us to pass the filters over as a string anyway,
   // so avoiding using an array avoids serialization on the side passing the
   // filters.  Since an nsString can share its buffer when copied,
   // using that instead of InfallibleTArray<nsString> makes copying the filters
   // around in any given process a bit more efficient too, since copying a
   // single nsString is cheaper than copying InfallibleTArray member data and
@@ -50,17 +50,16 @@ struct FileSystemGetFilesParams
   nsString realPath;
   bool recursiveFlag;
 };
 
 struct FileSystemGetFileOrDirectoryParams
 {
   nsString filesystem;
   nsString realPath;
-  bool isRoot;
 };
 
 struct FileSystemRemoveParams
 {
   nsString filesystem;
   nsString directory;
   nsString targetDirectory;
   bool recursive;
--- a/dom/filesystem/tests/filesystem_commons.js
+++ b/dom/filesystem/tests/filesystem_commons.js
@@ -1,42 +1,41 @@
 function test_basic(aDirectory, aNext) {
   ok(aDirectory, "Directory exists.");
   ok(aDirectory instanceof Directory, "We have a directory.");
-  is(aDirectory.name, '/', "directory.name must be '/'");
-  is(aDirectory.path, '/', "directory.path must be '/'");
+  is(aDirectory.path, '/' + aDirectory.name, "directory.path must be '/'+name");
   aNext();
 }
 
 function test_getFilesAndDirectories(aDirectory, aRecursive, aNext) {
   function checkSubDir(dir) {
     return dir.getFilesAndDirectories().then(
       function(data) {
         for (var i = 0; i < data.length; ++i) {
           ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
           if (data[i] instanceof Directory) {
             isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
             isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
             isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
-            is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
+            is(data[i].path, dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
           }
         }
       }
     );
   }
 
   aDirectory.getFilesAndDirectories().then(
     function(data) {
       ok(data.length, "We should have some data.");
       var promises = [];
       for (var i = 0; i < data.length; ++i) {
         ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories: " + data[i].name);
         if (data[i] instanceof Directory) {
           isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
-          is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
+          is(data[i].path, aDirectory.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
           if (aRecursive) {
             promises.push(checkSubDir(data[i]));
           }
         }
       }
 
       return Promise.all(promises);
     },
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -267,18 +267,17 @@ class HTMLInputElementState final : publ
 
           nsCOMPtr<nsIFile> file;
           NS_ConvertUTF16toUTF8 path(mBlobImplsOrDirectoryPaths[i].mDirectoryPath);
           nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
           if (NS_WARN_IF(NS_FAILED(rv))) {
             continue;
           }
 
-          RefPtr<Directory> directory = Directory::Create(aWindow, file,
-                                                          Directory::eDOMRootDirectory);
+          RefPtr<Directory> directory = Directory::Create(aWindow, file);
           MOZ_ASSERT(directory);
 
           OwningFileOrDirectory* element = aResult.AppendElement();
           element->SetAsDirectory() = directory;
         }
       }
     }
 
@@ -2306,18 +2305,17 @@ HTMLInputElement::MozSetDirectory(const 
   }
 
   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
   if (NS_WARN_IF(!window)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  RefPtr<Directory> directory = Directory::Create(window, file,
-                                                  Directory::eDOMRootDirectory);
+  RefPtr<Directory> directory = Directory::Create(window, file);
   MOZ_ASSERT(directory);
 
   nsTArray<OwningFileOrDirectory> array;
   OwningFileOrDirectory* element = array.AppendElement();
   element->SetAsDirectory() = directory;
 
   SetFilesOrDirectories(array, true);
 }
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -897,17 +897,17 @@ nsTextInputListener::HandleEvent(nsIDOME
   if (keyEvent->mMessage != eKeyPress) {
     return NS_OK;
   }
 
   nsIWidget::NativeKeyBindingsType nativeKeyBindingsType =
     mTxtCtrlElement->IsTextArea() ?
       nsIWidget::NativeKeyBindingsForMultiLineEditor :
       nsIWidget::NativeKeyBindingsForSingleLineEditor;
-  nsIWidget* widget = keyEvent->widget;
+  nsIWidget* widget = keyEvent->mWidget;
   // If the event is created by chrome script, the widget is nullptr.
   if (!widget) {
     widget = mFrame->GetNearestWidget();
     NS_ENSURE_TRUE(widget, NS_OK);
   }
                                          
   if (widget->ExecuteNativeKeyBinding(nativeKeyBindingsType,
                                       *keyEvent, DoCommandCallback, mFrame)) {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -420,56 +420,61 @@ private:
   ~ConsoleListener() {}
 
   ContentChild* mChild;
   friend class ContentChild;
 };
 
 NS_IMPL_ISUPPORTS(ConsoleListener, nsIConsoleListener)
 
+// Before we send the error to the parent process (which
+// involves copying the memory), truncate any long lines.  CSS
+// errors in particular share the memory for long lines with
+// repeated errors, but the IPC communication we're about to do
+// will break that sharing, so we better truncate now.
+static void
+TruncateString(nsAString& aString)
+{
+  if (aString.Length() > 1000) {
+    aString.Truncate(1000);
+  }
+}
+
 NS_IMETHODIMP
 ConsoleListener::Observe(nsIConsoleMessage* aMessage)
 {
   if (!mChild) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
   if (scriptError) {
     nsString msg, sourceName, sourceLine;
     nsXPIDLCString category;
     uint32_t lineNum, colNum, flags;
 
     nsresult rv = scriptError->GetErrorMessage(msg);
     NS_ENSURE_SUCCESS(rv, rv);
+    TruncateString(msg);
     rv = scriptError->GetSourceName(sourceName);
     NS_ENSURE_SUCCESS(rv, rv);
+    TruncateString(sourceName);
     rv = scriptError->GetSourceLine(sourceLine);
     NS_ENSURE_SUCCESS(rv, rv);
-
-    // Before we send the error to the parent process (which
-    // involves copying the memory), truncate any long lines.  CSS
-    // errors in particular share the memory for long lines with
-    // repeated errors, but the IPC communication we're about to do
-    // will break that sharing, so we better truncate now.
-    if (sourceName.Length() > 1000) {
-      sourceName.Truncate(1000);
-    }
-    if (sourceLine.Length() > 1000) {
-      sourceLine.Truncate(1000);
-    }
+    TruncateString(sourceLine);
 
     rv = scriptError->GetCategory(getter_Copies(category));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = scriptError->GetLineNumber(&lineNum);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = scriptError->GetColumnNumber(&colNum);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = scriptError->GetFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
+
     mChild->SendScriptError(msg, sourceName, sourceLine,
                             lineNum, colNum, flags, category);
     return NS_OK;
   }
 
   nsXPIDLString msg;
   nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1851,17 +1851,17 @@ bool
 TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
                                    const ScrollableLayerGuid& aGuid,
                                    const uint64_t& aInputBlockId)
 {
   nsEventStatus unused;
   InputAPZContext context(aGuid, aInputBlockId, unused);
 
   WidgetMouseEvent localEvent(aEvent);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
       mPuppetWidget->GetDefaultScale());
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (aEvent.mFlags.mHandledByAPZ) {
     mAPZEventState->ProcessMouseEvent(aEvent, aGuid, aInputBlockId);
   }
   return true;
@@ -1874,17 +1874,17 @@ TabChild::RecvMouseWheelEvent(const Widg
 {
   if (aEvent.mFlags.mHandledByAPZ) {
     nsCOMPtr<nsIDocument> document(GetDocument());
     APZCCallbackHelper::SendSetTargetAPZCNotification(
       mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
   }
 
   WidgetWheelEvent localEvent(aEvent);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
       mPuppetWidget->GetDefaultScale());
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (localEvent.mCanTriggerSwipe) {
     SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
   }
 
@@ -1918,17 +1918,17 @@ bool
 TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
                              const ScrollableLayerGuid& aGuid,
                              const uint64_t& aInputBlockId,
                              const nsEventStatus& aApzResponse)
 {
   TABC_LOG("Receiving touch event of type %d\n", aEvent.mMessage);
 
   WidgetTouchEvent localEvent(aEvent);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
 
   APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
       mPuppetWidget->GetDefaultScale());
 
   if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
     if (gfxPrefs::TouchActionEnabled()) {
       APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(mPuppetWidget,
           localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback);
@@ -1963,17 +1963,17 @@ TabChild::RecvRealTouchMoveEvent(const W
 }
 
 bool
 TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent,
                             const uint32_t& aDragAction,
                             const uint32_t& aDropEffect)
 {
   WidgetDragEvent localEvent(aEvent);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
 
   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
   if (dragSession) {
     dragSession->SetDragAction(aDragAction);
     nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
     dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
     if (initialDataTransfer) {
       initialDataTransfer->SetDropEffectInt(aDropEffect);
@@ -1999,17 +1999,17 @@ TabChild::RecvRealDragEvent(const Widget
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   return true;
 }
 
 bool
 TabChild::RecvPluginEvent(const WidgetPluginEvent& aEvent)
 {
   WidgetPluginEvent localEvent(aEvent);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
   nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   if (status != nsEventStatus_eConsumeNoDefault) {
     // If not consumed, we should call default action
     SendDefaultProcOfPluginEvent(aEvent);
   }
   return true;
 }
 
@@ -2058,17 +2058,17 @@ TabChild::RecvRealKeyEvent(const WidgetK
                       bindings.multiLineCommands(),
                       bindings.richTextCommands());
     } else {
       autoCache.CacheNoCommands();
     }
   }
 
   WidgetKeyboardEvent localEvent(event);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
   nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (event.mMessage == eKeyDown) {
     mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
   }
 
   if (localEvent.mFlags.mWantReplyFromContentProcess) {
     SendReplyKeyEvent(localEvent);
@@ -2093,27 +2093,27 @@ TabChild::RecvKeyEvent(const nsString& a
                                aModifiers, aPreventDefault, &ignored);
   return true;
 }
 
 bool
 TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
 {
   WidgetCompositionEvent localEvent(event);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   Unused << SendOnEventNeedingAckHandled(event.mMessage);
   return true;
 }
 
 bool
 TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
 {
   WidgetSelectionEvent localEvent(event);
-  localEvent.widget = mPuppetWidget;
+  localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   Unused << SendOnEventNeedingAckHandled(event.mMessage);
   return true;
 }
 
 a11y::PDocAccessibleChild*
 TabChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1245,49 +1245,49 @@ bool TabParent::SendMouseWheelEvent(Widg
 bool TabParent::RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
   WidgetWheelEvent localEvent(aEvent);
-  localEvent.widget = widget;
+  localEvent.mWidget = widget;
   localEvent.refPoint -= GetChildProcessOffset();
 
   widget->DispatchInputEvent(&localEvent);
   return true;
 }
 
 bool
 TabParent::RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
   WidgetMouseEvent localEvent(aEvent);
-  localEvent.widget = widget;
+  localEvent.mWidget = widget;
   localEvent.refPoint -= GetChildProcessOffset();
 
   widget->DispatchInputEvent(&localEvent);
   return true;
 }
 
 bool
 TabParent::RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
   WidgetKeyboardEvent localEvent(aEvent);
-  localEvent.widget = widget;
+  localEvent.mWidget = widget;
   localEvent.refPoint -= GetChildProcessOffset();
 
   widget->DispatchInputEvent(&localEvent);
   return true;
 }
 
 static void
 DoCommandCallback(mozilla::Command aCommand, void* aData)
@@ -2015,17 +2015,17 @@ TabParent::RecvReplyKeyEvent(const Widge
 }
 
 bool
 TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mFrameElement, true);
 
   WidgetKeyboardEvent localEvent(aEvent);
-  localEvent.widget = GetWidget();
+  localEvent.mWidget = GetWidget();
 
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, true);
 
   if (mFrameElement &&
       PresShell::BeforeAfterKeyboardEventEnabled() &&
       localEvent.mMessage != eKeyPress) {
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -1,62 +1,94 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "AudioConverter.h"
 #include <string.h>
+#include <speex/speex_resampler.h>
 
 /*
  *  Parts derived from MythTV AudioConvert Class
  *  Created by Jean-Yves Avenard.
  *
  *  Copyright (C) Bubblestuff Pty Ltd 2013
  *  Copyright (C) foobum@gmail.com 2010
  */
 
 namespace mozilla {
 
 AudioConverter::AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut)
   : mIn(aIn)
   , mOut(aOut)
+  , mResampler(nullptr)
 {
-  MOZ_DIAGNOSTIC_ASSERT(aIn.Rate() == aOut.Rate() &&
-                        aIn.Format() == aOut.Format() &&
+  MOZ_DIAGNOSTIC_ASSERT(aIn.Format() == aOut.Format() &&
                         aIn.Interleaved() == aOut.Interleaved(),
                         "No format or rate conversion is supported at this stage");
   MOZ_DIAGNOSTIC_ASSERT((aIn.Channels() > aOut.Channels() && aOut.Channels() <= 2) ||
                         aIn.Channels() == aOut.Channels(),
                         "Only downmixing to mono or stereo is supported at this stage");
   MOZ_DIAGNOSTIC_ASSERT(aOut.Interleaved(), "planar audio format not supported");
   mIn.Layout().MappingTable(mOut.Layout(), mChannelOrderMap);
+  if (aIn.Rate() != aOut.Rate()) {
+    int error;
+    mResampler = speex_resampler_init(aOut.Channels(),
+                                      aIn.Rate(),
+                                      aOut.Rate(),
+                                      SPEEX_RESAMPLER_QUALITY_DEFAULT,
+                                      &error);
+
+    if (error == RESAMPLER_ERR_SUCCESS) {
+      speex_resampler_skip_zeros(mResampler);
+    } else {
+      NS_WARNING("Failed to initialize resampler.");
+      mResampler = nullptr;
+    }
+  }
+}
+
+AudioConverter::~AudioConverter()
+{
+  if (mResampler) {
+    speex_resampler_destroy(mResampler);
+    mResampler = nullptr;
+  }
 }
 
 bool
 AudioConverter::CanWorkInPlace() const
 {
-  return mIn.Channels() * mIn.Rate() * AudioConfig::SampleSize(mIn.Format()) >=
-    mOut.Channels() * mOut.Rate() * AudioConfig::SampleSize(mOut.Format());
+  bool needDownmix = mIn.Channels() > mOut.Channels();
+  bool canDownmixInPlace =
+    mIn.Channels() * AudioConfig::SampleSize(mIn.Format()) >=
+    mOut.Channels() * AudioConfig::SampleSize(mOut.Format());
+  bool needResample = mIn.Rate() != mOut.Rate();
+  bool canResampleInPlace = mIn.Rate() >= mOut.Rate();
+  // We should be able to work in place if 1s of audio input takes less space
+  // than 1s of audio output. However, as we downmix before resampling we can't
+  // perform any upsampling in place (e.g. if incoming rate >= outgoing rate)
+  return (!needDownmix || canDownmixInPlace) &&
+         (!needResample || canResampleInPlace);
 }
 
 size_t
-AudioConverter::Process(void* aOut, const void* aIn, size_t aBytes)
+AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aFrames)
 {
-  if (!CanWorkInPlace()) {
-    return 0;
-  }
   if (mIn.Channels() > mOut.Channels()) {
-    return DownmixAudio(aOut, aIn, aBytes);
+    return DownmixAudio(aOut, aIn, aFrames);
   } else if (mIn.Layout() != mOut.Layout() &&
       CanReorderAudio()) {
-    ReOrderInterleavedChannels(aOut, aIn, aBytes);
+    ReOrderInterleavedChannels(aOut, aIn, aFrames);
+  } else if (aIn != aOut) {
+    memmove(aOut, aIn, FramesOutToBytes(aFrames));
   }
-  return aBytes;
+  return aFrames;
 }
 
 // Reorder interleaved channels.
 // Can work in place (e.g aOut == aIn).
 template <class AudioDataType>
 void
 _ReOrderInterleavedChannels(AudioDataType* aOut, const AudioDataType* aIn,
                             uint32_t aFrames, uint32_t aChannels,
@@ -73,95 +105,90 @@ void
     }
     aOut += aChannels;
     aIn += aChannels;
   }
 }
 
 void
 AudioConverter::ReOrderInterleavedChannels(void* aOut, const void* aIn,
-                                           size_t aDataSize) const
+                                           size_t aFrames) const
 {
   MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() == mOut.Channels());
 
   if (mOut.Layout() == mIn.Layout()) {
     return;
   }
   if (mOut.Channels() == 1) {
     // If channel count is 1, planar and non-planar formats are the same and
     // there's nothing to reorder.
     if (aOut != aIn) {
-      memmove(aOut, aIn, aDataSize);
+      memmove(aOut, aIn, FramesOutToBytes(aFrames));
     }
     return;
   }
 
   uint32_t bits = AudioConfig::FormatToBits(mOut.Format());
   switch (bits) {
     case 8:
       _ReOrderInterleavedChannels((uint8_t*)aOut, (const uint8_t*)aIn,
-                                  aDataSize/sizeof(uint8_t)/mIn.Channels(),
-                                  mIn.Channels(), mChannelOrderMap);
+                                  aFrames, mIn.Channels(), mChannelOrderMap);
       break;
     case 16:
       _ReOrderInterleavedChannels((int16_t*)aOut,(const int16_t*)aIn,
-                                  aDataSize/sizeof(int16_t)/mIn.Channels(),
-                                  mIn.Channels(), mChannelOrderMap);
+                                  aFrames, mIn.Channels(), mChannelOrderMap);
       break;
     default:
       MOZ_DIAGNOSTIC_ASSERT(AudioConfig::SampleSize(mOut.Format()) == 4);
       _ReOrderInterleavedChannels((int32_t*)aOut,(const int32_t*)aIn,
-                                  aDataSize/sizeof(int32_t)/mIn.Channels(),
-                                  mIn.Channels(), mChannelOrderMap);
+                                  aFrames, mIn.Channels(), mChannelOrderMap);
       break;
   }
 }
 
 static inline int16_t clipTo15(int32_t aX)
 {
   return aX < -32768 ? -32768 : aX <= 32767 ? aX : 32767;
 }
 
 size_t
-AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const
+AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
 {
   MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
              mIn.Format() == AudioConfig::FORMAT_FLT);
   MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
   MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
              "Can only downmix input data in SMPTE layout");
   MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
              mOut.Layout() == AudioConfig::ChannelLayout(1));
 
   uint32_t channels = mIn.Channels();
-  uint32_t frames =
-    aDataSize / AudioConfig::SampleSize(mOut.Format()) / channels;
 
   if (channels == 1 && mOut.Channels() == 1) {
     if (aOut != aIn) {
-      memmove(aOut, aIn, aDataSize);
+      memmove(aOut, aIn, FramesOutToBytes(aFrames));
     }
-    return aDataSize;
+    return aFrames;
   }
 
   if (channels > 2) {
     if (mIn.Format() == AudioConfig::FORMAT_FLT) {
       // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
       static const float dmatrix[6][8][2]= {
           /*3*/{{0.5858f,0},{0,0.5858f},{0.4142f,0.4142f}},
           /*4*/{{0.4226f,0},{0,0.4226f},{0.366f, 0.2114f},{0.2114f,0.366f}},
           /*5*/{{0.6510f,0},{0,0.6510f},{0.4600f,0.4600f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
           /*6*/{{0.5290f,0},{0,0.5290f},{0.3741f,0.3741f},{0.3741f,0.3741f},{0.4582f,0.2645f},{0.2645f,0.4582f}},
           /*7*/{{0.4553f,0},{0,0.4553f},{0.3220f,0.3220f},{0.3220f,0.3220f},{0.2788f,0.2788f},{0.3943f,0.2277f},{0.2277f,0.3943f}},
           /*8*/{{0.3886f,0},{0,0.3886f},{0.2748f,0.2748f},{0.2748f,0.2748f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f}},
       };
       // Re-write the buffer with downmixed data
       const float* in = static_cast<const float*>(aIn);
       float* out = static_cast<float*>(aOut);
-      for (uint32_t i = 0; i < frames; i++) {
+      for (uint32_t i = 0; i < aFrames; i++) {
         float sampL = 0.0;
         float sampR = 0.0;
         for (uint32_t j = 0; j < channels; j++) {
           sampL += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][0];
           sampR += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][1];
         }
         *out++ = sampL;
         *out++ = sampR;
@@ -175,17 +202,17 @@ AudioConverter::DownmixAudio(void* aOut,
           /*5*/{{10663,0},{0,  10663},{7540,7540},{9234,5331},{5331,9234}},
           /*6*/{{8668, 0},{0,   8668},{6129,6129},{6129,6129},{7507,4335},{4335,7507}},
           /*7*/{{7459, 0},{0,   7459},{5275,5275},{5275,5275},{4568,4568},{6460,3731},{3731,6460}},
           /*8*/{{6368, 0},{0,   6368},{4502,4502},{4502,4502},{5514,3184},{3184,5514},{5514,3184},{3184,5514}}
       };
       // Re-write the buffer with downmixed data
       const int16_t* in = static_cast<const int16_t*>(aIn);
       int16_t* out = static_cast<int16_t*>(aOut);
-      for (uint32_t i = 0; i < frames; i++) {
+      for (uint32_t i = 0; i < aFrames; i++) {
         int32_t sampL = 0;
         int32_t sampR = 0;
         for (uint32_t j = 0; j < channels; j++) {
           sampL+=in[i*channels+j]*dmatrix[channels-3][j][0];
           sampR+=in[i*channels+j]*dmatrix[channels-3][j][1];
         }
         *out++ = clipTo15((sampL + 8192)>>14);
         *out++ = clipTo15((sampR + 8192)>>14);
@@ -199,31 +226,80 @@ AudioConverter::DownmixAudio(void* aOut,
     aIn = aOut;
     channels = 2;
   }
 
   if (mOut.Channels() == 1) {
     if (mIn.Format() == AudioConfig::FORMAT_FLT) {
       const float* in = static_cast<const float*>(aIn);
       float* out = static_cast<float*>(aOut);
-      for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+      for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
         float sample = 0.0;
         // The sample of the buffer would be interleaved.
         sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
         *out++ = sample;
       }
     } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
       const int16_t* in = static_cast<const int16_t*>(aIn);
       int16_t* out = static_cast<int16_t*>(aOut);
-      for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+      for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
         int32_t sample = 0.0;
         // The sample of the buffer would be interleaved.
         sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
         *out++ = sample;
       }
     } else {
       MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
     }
   }
-  return frames * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels();
+  return aFrames;
 }
 
-} // namespace mozilla
\ No newline at end of file
+size_t
+AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
+{
+  if (!mResampler) {
+    return 0;
+  }
+  uint32_t outframes = ResampleRecipientFrames(aFrames);
+  uint32_t inframes = aFrames;
+
+  if (mOut.Format() == AudioConfig::FORMAT_FLT) {
+    const float* in = reinterpret_cast<const float*>(aIn);
+    float* out = reinterpret_cast<float*>(aOut);
+    speex_resampler_process_interleaved_float(mResampler, in, &inframes,
+                                              out, &outframes);
+  } else if (mOut.Format() == AudioConfig::FORMAT_S16) {
+    const int16_t* in = reinterpret_cast<const int16_t*>(aIn);
+    int16_t* out = reinterpret_cast<int16_t*>(aOut);
+    speex_resampler_process_interleaved_int(mResampler, in, &inframes,
+                                            out, &outframes);
+  } else {
+    MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
+  }
+  MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
+  return outframes;
+}
+
+size_t
+AudioConverter::ResampleRecipientFrames(size_t aFrames) const
+{
+  return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
+}
+
+size_t
+AudioConverter::FramesOutToSamples(size_t aFrames) const
+{
+  return aFrames * mOut.Channels();
+}
+
+size_t
+AudioConverter::SamplesInToFrames(size_t aSamples) const
+{
+  return aSamples / mIn.Channels();
+}
+
+size_t
+AudioConverter::FramesOutToBytes(size_t aFrames) const
+{
+  return FramesOutToSamples(aFrames) * AudioConfig::SampleSize(mOut.Format());
+}
+} // namespace mozilla
--- a/dom/media/AudioConverter.h
+++ b/dom/media/AudioConverter.h
@@ -4,16 +4,19 @@
  * 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/. */
 
 #if !defined(AudioConverter_h)
 #define AudioConverter_h
 
 #include "MediaInfo.h"
 
+// Forward declaration
+typedef struct SpeexResamplerState_ SpeexResamplerState;
+
 namespace mozilla {
 
 template <AudioConfig::SampleFormat T> struct AudioDataBufferTypeChooser;
 template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_U8>
 { typedef uint8_t Type; };
 template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S16>
 { typedef int16_t Type; };
 template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24LSB>
@@ -82,16 +85,26 @@ public:
                   "Conversion not implemented yet");
   }
   explicit AudioDataBuffer(const AlignedFloatBuffer&& aBuffer)
     : mBuffer(Move(aBuffer))
   {
     static_assert(Format == AudioConfig::FORMAT_FLT,
                   "Conversion not implemented yet");
   }
+  AudioDataBuffer& operator=(AudioDataBuffer&& aOther)
+  {
+    mBuffer = Move(aOther.mBuffer);
+    return *this;
+  }
+  AudioDataBuffer& operator=(const AudioDataBuffer& aOther)
+  {
+    mBuffer = aOther.mBuffer;
+    return *this;
+  }
 
   Value* Data() const { return mBuffer.Data(); }
   size_t Length() const { return mBuffer.Length(); }
   size_t Size() const { return mBuffer.Size(); }
   AlignedBuffer<Value> Forget()
   {
     // Correct type -> Just give values as-is.
     return Move(mBuffer);
@@ -100,52 +113,117 @@ private:
   AlignedBuffer<Value> mBuffer;
 };
 
 typedef AudioDataBuffer<AudioConfig::FORMAT_DEFAULT> AudioSampleBuffer;
 
 class AudioConverter {
 public:
   AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut);
+  ~AudioConverter();
+
+  // Convert the AudioDataBuffer.
+  // Conversion will be done in place if possible. Otherwise a new buffer will
+  // be returned.
+  template <AudioConfig::SampleFormat Format, typename Value>
+  AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
+    AudioDataBuffer<Format, Value> buffer = Move(aBuffer);
+    if (CanWorkInPlace()) {
+      size_t frames = SamplesInToFrames(buffer.Length());
+      frames = ProcessInternal(buffer.Data(), buffer.Data(), frames);
+      if (frames && mIn.Rate() != mOut.Rate()) {
+        frames = ResampleAudio(buffer.Data(), buffer.Data(), frames);
+      }
+      AlignedBuffer<Value> temp = buffer.Forget();
+      temp.SetLength(FramesOutToSamples(frames));
+      return AudioDataBuffer<Format, Value>(Move(temp));;
+    }
+    return Process(buffer);
+  }
+
+  template <AudioConfig::SampleFormat Format, typename Value>
+  AudioDataBuffer<Format, Value> Process(const AudioDataBuffer<Format, Value>& aBuffer)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
+    // Perform the downmixing / reordering in temporary buffer.
+    size_t frames = SamplesInToFrames(aBuffer.Length());
+    AlignedBuffer<Value> temp1;
+    if (!temp1.SetLength(FramesOutToSamples(frames))) {
+      return AudioDataBuffer<Format, Value>(Move(temp1));
+    }
+    frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
+    if (!frames || mIn.Rate() == mOut.Rate()) {
+      temp1.SetLength(FramesOutToSamples(frames));
+      return AudioDataBuffer<Format, Value>(Move(temp1));
+    }
+
+    // At this point, temp1 contains the buffer reordered and downmixed.
+    // If we are downsampling we can re-use it.
+    AlignedBuffer<Value>* outputBuffer = &temp1;
+    AlignedBuffer<Value> temp2;
+    if (mOut.Rate() > mIn.Rate()) {
+      // We are upsampling, we can't work in place. Allocate another temporary
+      // buffer where the upsampling will occur.
+      temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)));
+      outputBuffer = &temp2;
+    }
+    frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
+    outputBuffer->SetLength(FramesOutToSamples(frames));
+    return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
+  }
 
   // Attempt to convert the AudioDataBuffer in place.
   // Will return 0 if the conversion wasn't possible.
-  // Process may allocate memory internally should intermediary steps be
-  // required.
-  template <AudioConfig::SampleFormat Type, typename Value>
-  size_t Process(AudioDataBuffer<Type, Value>& aBuffer)
-  {
-    MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Type);
-    return Process(aBuffer.Data(), aBuffer.Data(), aBuffer.Size());
-  }
   template <typename Value>
-  size_t Process(Value* aBuffer, size_t aSamples)
+  size_t Process(Value* aBuffer, size_t aFrames)
   {
     MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
-    return Process(aBuffer, aBuffer, aSamples * AudioConfig::SampleSize(mIn.Format()));
+    if (!CanWorkInPlace()) {
+      return 0;
+    }
+    size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
+    if (frames && mIn.Rate() != mOut.Rate()) {
+      frames = ResampleAudio(aBuffer, aBuffer, aFrames);
+    }
+    return frames;
   }
+
   bool CanWorkInPlace() const;
   bool CanReorderAudio() const
   {
     return mIn.Layout().MappingTable(mOut.Layout());
   }
 
+  const AudioConfig& InputConfig() const { return mIn; }
+  const AudioConfig& OutputConfig() const { return mOut; }
+
 private:
   const AudioConfig mIn;
   const AudioConfig mOut;
   uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS];
   /**
-   * Process
+   * ProcessInternal
    * Parameters:
    * aOut  : destination buffer where converted samples will be copied
    * aIn   : source buffer
-   * aBytes: size in bytes of source buffer
+   * aSamples: number of frames in source buffer
    *
-   * Return Value: size in bytes of samples converted or 0 if error
+   * Return Value: number of frames converted or 0 if error
    */
-  size_t Process(void* aOut, const void* aIn, size_t aBytes);
-  void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aDataSize) const;
-  size_t DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const;
+  size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
+  void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
+  size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
+
+  size_t FramesOutToSamples(size_t aFrames) const;
+  size_t SamplesInToFrames(size_t aSamples) const;
+  size_t FramesOutToBytes(size_t aFrames) const;
+
+  // Resampler context.
+  SpeexResamplerState* mResampler;
+  size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
+  size_t ResampleRecipientFrames(size_t aFrames) const;
 };
 
 } // namespace mozilla
 
 #endif /* AudioConverter_h */
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -326,17 +326,17 @@ AudioStream::Init(uint32_t aNumChannels,
   if (!CubebUtils::GetCubebContext()) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_LOG(gAudioStreamLog, LogLevel::Debug,
     ("%s  channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
   mInRate = mOutRate = aRate;
   mChannels = aNumChannels;
-  mOutChannels = (aNumChannels > 2) ? 2 : aNumChannels;
+  mOutChannels = mIsMonoAudioEnabled ? 1 : aNumChannels;
 
   mDumpFile = OpenDumpFile(this);
 
   cubeb_stream_params params;
   params.rate = aRate;
   params.channels = mOutChannels;
 #if defined(__ANDROID__)
 #if defined(MOZ_B2G)
@@ -348,19 +348,21 @@ AudioStream::Init(uint32_t aNumChannels,
   if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
     return NS_ERROR_INVALID_ARG;
   }
 #endif
 
   params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
   mAudioClock.Init();
 
-  AudioConfig inConfig(mChannels, mInRate);
-  AudioConfig outConfig(mOutChannels, mOutRate);
-  mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
+  if (mIsMonoAudioEnabled) {
+    AudioConfig inConfig(mChannels, mInRate);
+    AudioConfig outConfig(mOutChannels, mOutRate);
+    mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
+  }
   return OpenCubeb(params);
 }
 
 // This code used to live inside AudioStream::Init(), but on Mac (others?)
 // it has been known to take 300-800 (or even 8500) ms to execute(!)
 nsresult
 AudioStream::OpenCubeb(cubeb_stream_params &aParams)
 {
@@ -556,24 +558,18 @@ AudioStream::Downmix(Chunk* aChunk)
     LOGW("mismatched sample %u, mInRate=%u", aChunk->Rate(), mInRate);
     return false;
   }
 
   if (aChunk->Channels() > 8) {
     return false;
   }
 
-  if (aChunk->Channels() > 2) {
-    MOZ_ASSERT(mAudioConverter);
-    mAudioConverter->Process(aChunk->GetWritable(),
-                             aChunk->Channels() * aChunk->Frames());
-  }
-
-  if (aChunk->Channels() >= 2 && mIsMonoAudioEnabled) {
-    DownmixStereoToMono(aChunk->GetWritable(), aChunk->Frames());
+  if (mAudioConverter) {
+    mAudioConverter->Process(aChunk->GetWritable(), aChunk->Frames());
   }
 
   return true;
 }
 
 void
 AudioStream::GetUnprocessed(AudioBufferWriter& aWriter)
 {
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -599,16 +599,26 @@ public:
   SampleFormat Format() const
   {
     return mFormat;
   }
   bool Interleaved() const
   {
     return mInterleaved;
   }
+  bool operator==(const AudioConfig& aOther) const
+  {
+    return mChannelLayout == aOther.mChannelLayout &&
+      mRate == aOther.mRate && mFormat == aOther.mFormat &&
+      mInterleaved == aOther.mInterleaved;
+  }
+  bool operator!=(const AudioConfig& aOther) const
+  {
+    return !(*this == aOther);
+  }
 
   static const char* FormatToString(SampleFormat aFormat);
   static uint32_t SampleSize(SampleFormat aFormat);
   static uint32_t FormatToBits(SampleFormat aFormat);
 
 private:
   // Channels configuration.
   ChannelLayout mChannelLayout;
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -29,20 +29,16 @@
 #include "GMPUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsXULAppAPI.h"
 #include "gmp-audio-decode.h"
 #include "gmp-video-decode.h"
 
-#if defined(XP_WIN) || defined(XP_MACOSX)
-#define PRIMETIME_EME_SUPPORTED 1
-#endif
-
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
                                       mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeySystemAccess)
@@ -275,17 +271,17 @@ MediaKeySystemAccess::GetKeySystemStatus
   if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
     if (!Preferences::GetBool("media.eme.clearkey.enabled", true)) {
       aOutMessage = NS_LITERAL_CSTRING("ClearKey was disabled");
       return MediaKeySystemStatus::Cdm_disabled;
     }
     return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
   }
 
-#ifdef PRIMETIME_EME_SUPPORTED
+#ifdef MOZ_ADOBE_EME
   if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
     if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
       aOutMessage = NS_LITERAL_CSTRING("Adobe EME disabled");
       return MediaKeySystemStatus::Cdm_disabled;
     }
 #ifdef XP_WIN
     // Win Vista and later only.
     if (!IsVistaOrLater()) {
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -3,19 +3,21 @@
 /* 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 "nsPrintfCString.h"
 #include "MediaQueue.h"
 #include "DecodedAudioDataSink.h"
 #include "VideoUtils.h"
+#include "AudioConverter.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
+#include "gfxPrefs.h"
 
 namespace mozilla {
 
 extern LazyLogModule gMediaDecoderLog;
 #define SINK_LOG(msg, ...) \
   MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, \
     ("DecodedAudioDataSink=%p " msg, this, ##__VA_ARGS__))
 #define SINK_LOG_V(msg, ...) \
@@ -35,16 +37,24 @@ DecodedAudioDataSink::DecodedAudioDataSi
   , mStartTime(aStartTime)
   , mWritten(0)
   , mLastGoodPosition(0)
   , mInfo(aInfo)
   , mChannel(aChannel)
   , mPlaying(true)
   , mPlaybackComplete(false)
 {
+  bool resampling = gfxPrefs::AudioSinkResampling();
+  uint32_t resamplingRate = gfxPrefs::AudioSinkResampleRate();
+  mConverter =
+    MakeUnique<AudioConverter>(
+      AudioConfig(mInfo.mChannels, mInfo.mRate),
+      AudioConfig(mInfo.mChannels > 2 && gfxPrefs::AudioSinkForceStereo()
+                    ? 2 : mInfo.mChannels,
+                  resampling ? resamplingRate : mInfo.mRate));
 }
 
 DecodedAudioDataSink::~DecodedAudioDataSink()
 {
 }
 
 RefPtr<GenericPromise>
 DecodedAudioDataSink::Init(const PlaybackParams& aParams)
@@ -131,17 +141,19 @@ DecodedAudioDataSink::SetPlaying(bool aP
   }
   mPlaying = aPlaying;
 }
 
 nsresult
 DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
 {
   mAudioStream = new AudioStream(*this);
-  nsresult rv = mAudioStream->Init(mInfo.mChannels, mInfo.mRate, mChannel);
+  nsresult rv = mAudioStream->Init(mConverter->OutputConfig().Channels(),
+                                   mConverter->OutputConfig().Rate(),
+                                   mChannel);
   if (NS_FAILED(rv)) {
     mAudioStream->Shutdown();
     mAudioStream = nullptr;
     return rv;
   }
 
   // Set playback params before calling Start() so they can take effect
   // as soon as the 1st DataCallback of the AudioStream fires.
@@ -151,17 +163,18 @@ DecodedAudioDataSink::InitializeAudioStr
   mAudioStream->Start();
 
   return NS_OK;
 }
 
 int64_t
 DecodedAudioDataSink::GetEndTime() const
 {
-  CheckedInt64 playedUsecs = FramesToUsecs(mWritten, mInfo.mRate) + mStartTime;
+  CheckedInt64 playedUsecs =
+    FramesToUsecs(mWritten, mConverter->OutputConfig().Rate()) + mStartTime;
   if (!playedUsecs.isValid()) {
     NS_WARNING("Int overflow calculating audio end time");
     return -1;
   }
   return playedUsecs.value();
 }
 
 UniquePtr<AudioStream::Chunk>
@@ -226,40 +239,61 @@ DecodedAudioDataSink::PopFrames(uint32_t
       RefPtr<MediaData> releaseMe = AudioQueue().PopFront();
       continue;
     }
 
     // See if there's a gap in the audio. If there is, push silence into the
     // audio hardware, so we can play across the gap.
     // Calculate the timestamp of the next chunk of audio in numbers of
     // samples.
-    CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime, mInfo.mRate);
+    CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime,
+                                            mConverter->OutputConfig().Rate());
     // Calculate the number of frames that have been pushed onto the audio hardware.
-    CheckedInt64 playedFrames = UsecsToFrames(mStartTime, mInfo.mRate) +
+    CheckedInt64 playedFrames = UsecsToFrames(mStartTime,
+                                              mConverter->OutputConfig().Rate()) +
                                 static_cast<int64_t>(mWritten);
     CheckedInt64 missingFrames = sampleTime - playedFrames;
 
     if (!missingFrames.isValid() || !sampleTime.isValid()) {
       NS_WARNING("Int overflow in DecodedAudioDataSink");
       mErrored = true;
       return MakeUnique<Chunk>();
     }
 
+    const uint32_t rate = mConverter->OutputConfig().Rate();
+    const uint32_t channels = mConverter->OutputConfig().Channels();
+
     if (missingFrames.value() > AUDIO_FUZZ_FRAMES) {
       // The next audio chunk begins some time after the end of the last chunk
       // we pushed to the audio hardware. We must push silence into the audio
       // hardware so that the next audio chunk begins playback at the correct
       // time.
       missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
       auto framesToPop = std::min<uint32_t>(missingFrames.value(), aFrames);
       mWritten += framesToPop;
-      return MakeUnique<SilentChunk>(framesToPop, mInfo.mChannels, mInfo.mRate);
+      return MakeUnique<SilentChunk>(framesToPop, channels, rate);
     }
 
-    mCurrentData = dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
+    RefPtr<AudioData> data =
+      dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
+    if (mConverter->InputConfig() != mConverter->OutputConfig()) {
+      AlignedAudioBuffer convertedData =
+        mConverter->Process(AudioSampleBuffer(Move(data->mAudioData))).Forget();
+      mCurrentData =
+        new AudioData(data->mOffset,
+                      data->mTime,
+                      data->mDuration,
+                      convertedData.Length() / channels,
+                      Move(convertedData),
+                      channels,
+                      rate);
+    } else {
+      mCurrentData = Move(data);
+    }
+
     mCursor = MakeUnique<AudioBufferCursor>(mCurrentData->mAudioData.get(),
                                             mCurrentData->mChannels,
                                             mCurrentData->mFrames);
     MOZ_ASSERT(mCurrentData->mFrames > 0);
   }
 
   auto framesToPop = std::min(aFrames, mCursor->Available());
 
--- a/dom/media/mediasink/DecodedAudioDataSink.h
+++ b/dom/media/mediasink/DecodedAudioDataSink.h
@@ -16,16 +16,18 @@
 #include "mozilla/dom/AudioChannelBinding.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/ReentrantMonitor.h"
 
 namespace mozilla {
 
+class AudioConverter;
+
 namespace media {
 
 class DecodedAudioDataSink : public AudioSink,
                              private AudioStream::DataSource {
 public:
   DecodedAudioDataSink(MediaQueue<MediaData>& aAudioQueue,
                        int64_t aStartTime,
                        const AudioInfo& aInfo,
@@ -92,21 +94,23 @@ private:
   MozPromiseHolder<GenericPromise> mEndPromise;
 
   /*
    * Members to implement AudioStream::DataSource.
    * Used on the callback thread of cubeb.
    */
   // The AudioData at which AudioStream::DataSource is reading.
   RefPtr<AudioData> mCurrentData;
-  // Keep track of the read positoin of mCurrentData.
+  // Keep track of the read position of mCurrentData.
   UniquePtr<AudioBufferCursor> mCursor;
   // True if there is any error in processing audio data like overflow.
   bool mErrored = false;
 
   // Set on the callback thread of cubeb once the stream has drained.
   Atomic<bool> mPlaybackComplete;
+
+  UniquePtr<AudioConverter> mConverter;
 };
 
 } // namespace media
 } // namespace mozilla
 
 #endif
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -222,17 +222,17 @@ VorbisDataDecoder::DoDecode(MediaRawData
     if (!mAudioConverter) {
       AudioConfig in(AudioConfig::ChannelLayout(channels, VorbisLayout(channels)),
                      rate);
       AudioConfig out(channels, rate);
       mAudioConverter = MakeUnique<AudioConverter>(in, out);
     }
     MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
     AudioSampleBuffer data(Move(buffer));
-    mAudioConverter->Process(data);
+    data = mAudioConverter->Process(Move(data));
 
     aTotalFrames += frames;
     mCallback->Output(new AudioData(aOffset,
                                     time.value(),
                                     duration.value(),
                                     frames,
                                     data.Forget(),
                                     channels,
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -282,17 +282,17 @@ AppleATDecoder::DecodeSample(MediaRawDat
   }
   if (mChannelLayout && !mAudioConverter) {
     AudioConfig in(*mChannelLayout.get(), rate);
     AudioConfig out(channels, rate);
     mAudioConverter = MakeUnique<AudioConverter>(in, out);
   }
   if (mAudioConverter) {
     MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
-    mAudioConverter->Process(data);
+    data = mAudioConverter->Process(Move(data));
   }
 
   RefPtr<AudioData> audio = new AudioData(aSample->mOffset,
                                           aSample->mTime,
                                           duration.ToMicroseconds(),
                                           numFrames,
                                           data.Forget(),
                                           channels,
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -760,16 +760,17 @@ skip-if = appname == "seamonkey"
 skip-if = toolkit == 'gonk' # bug 1128845
 [test_playback_rate.html]
 [test_playback_rate_playpause.html]
 [test_playback_reactivate.html]
 [test_played.html]
 [test_preload_actions.html]
 [test_preload_attribute.html]
 [test_preload_suspend.html]
+[test_preserve_playbackrate_after_ui_play.html]
 [test_progress.html]
 [test_reactivate.html]
 skip-if = toolkit == 'gonk' # bug 1128845 on gonk
 [test_readyState.html]
 [test_referer.html]
 [test_replay_metadata.html]
 [test_reset_events_async.html]
 [test_reset_src.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_preserve_playbackrate_after_ui_play.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title> Bug 1013933 - preserve playbackRate after clicking play button </title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<div id="content">
+  <video width="320" height="240" id="video" controls mozNoDynamicControls preload="auto"></video>
+</div>
+
+<script type="text/javascript">
+/*
+ * Positions of the UI elements, relative to the upper-left corner of the
+ * <video> box.
+ */
+const videoHeight = 240;
+const playButtonWidth = 28;
+const playButtonHeight = 28;
+const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
+const playButtonCenterY = videoHeight - Math.round(playButtonHeight / 2);
+
+var expectedPlaybackRate = 0.5
+
+function runTest() {
+  var video = document.getElementById("video");
+  video.src = "audio.wav";
+  video.loop = true;
+  video.playbackRate = expectedPlaybackRate;
+
+  video.oncanplaythrough = function() {
+    video.oncanplaythrough = null;
+    is(video.paused, true, "video is not playing yet.");
+    is(video.playbackRate, expectedPlaybackRate,
+       "playbackRate is correct before clicking play button.");
+
+    // Click the play button
+    synthesizeMouse(video, playButtonCenterX, playButtonCenterY, { });
+  };
+
+  video.onplay = function() {
+    video.onplay = null;
+    is(video.paused, false, "video starts playing.");
+    is(video.playbackRate, expectedPlaybackRate,
+       "playbackRate is correct after clicking play button.");
+    video.pause();
+    SimpleTest.finish();
+  };
+}
+
+window.addEventListener("load", runTest, false);
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/wave/WaveDemuxer.cpp
+++ b/dom/media/wave/WaveDemuxer.cpp
@@ -623,18 +623,16 @@ WAVTrackDemuxer::Read(uint8_t* aBuffer, 
   return static_cast<int32_t>(read);
 }
 
 // RIFFParser
 
 uint32_t
 RIFFParser::Parse(ByteReader& aReader)
 {
-  MOZ_ASSERT(&aReader);
-
   while (aReader.CanRead8() && !mRiffHeader.ParseNext(aReader.ReadU8())) { }
 
   if (mRiffHeader.IsValid()) {
     return RIFF_CHUNK_SIZE;
   }
 
   return 0;
 }
@@ -779,18 +777,16 @@ HeaderParser::ChunkHeader::Update(uint8_
   }
 }
 
 // FormatParser
 
 uint32_t
 FormatParser::Parse(ByteReader& aReader)
 {
-  MOZ_ASSERT(&aReader);
-
   while (aReader.CanRead8() && !mFmtChunk.ParseNext(aReader.ReadU8())) { }
 
   if (mFmtChunk.IsValid()) {
     return FMT_CHUNK_MIN_SIZE;
   }
 
   return 0;
 }
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AlignmentUtils.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 AlignmentUtils_h__
+#define AlignmentUtils_h__
+
+#define IS_ALIGNED16(ptr) ((((uintptr_t)ptr + 15) & ~0x0F) == (uintptr_t)ptr)
+
+#ifdef DEBUG
+  #define ASSERT_ALIGNED16(ptr)                                                  \
+            MOZ_ASSERT(IS_ALIGNED16(ptr), \
+                       #ptr " has to be aligned to a 16 byte boundary");
+#else
+  #define ASSERT_ALIGNED16(ptr)
+#endif
+
+#ifdef DEBUG
+  #define ASSERT_MULTIPLE16(v) \
+            MOZ_ASSERT(v % 16 == 0, #v " has to be a a multiple of 16");
+#else
+  #define ASSERT_MULTIPLE16(v)
+#endif
+
+#define ALIGNED16(ptr) (float*)(((uintptr_t)ptr + 15) & ~0x0F);
+
+#endif
--- a/dom/media/webaudio/AudioBlock.cpp
+++ b/dom/media/webaudio/AudioBlock.cpp
@@ -1,50 +1,53 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "AudioBlock.h"
+#include "AlignmentUtils.h"
 
 namespace mozilla {
 
 /**
  * Heap-allocated buffer of channels of 128-sample float arrays, with
  * threadsafe refcounting.  Typically you would allocate one of these, fill it
  * in, and then treat it as immutable while it's shared.
  *
  * Downstream references are accounted specially so that the creator of the
  * buffer can reuse and modify its contents next iteration if other references
  * are all downstream temporary references held by AudioBlock.
  *
- * This only guarantees 4-byte alignment of the data. For alignment we simply
- * assume that the memory from malloc is at least 4-byte aligned and that
- * AudioBlockBuffer's size is divisible by 4.
+ * We guarantee 16 byte alignment of the channel data.
  */
 class AudioBlockBuffer final : public ThreadSharedObject {
 public:
 
   virtual AudioBlockBuffer* AsAudioBlockBuffer() override { return this; };
 
   float* ChannelData(uint32_t aChannel)
   {
-    return reinterpret_cast<float*>(this + 1) + aChannel * WEBAUDIO_BLOCK_SIZE;
+    float* base = reinterpret_cast<float*>(((uintptr_t)(this + 1) + 15) & ~0x0F);
+    ASSERT_ALIGNED16(base);
+    return base + aChannel * WEBAUDIO_BLOCK_SIZE;
   }
 
   static already_AddRefed<AudioBlockBuffer> Create(uint32_t aChannelCount)
   {
     CheckedInt<size_t> size = WEBAUDIO_BLOCK_SIZE;
     size *= aChannelCount;
     size *= sizeof(float);
     size += sizeof(AudioBlockBuffer);
+    size += 15;  //padding for alignment
     if (!size.isValid()) {
       MOZ_CRASH();
     }
+
     void* m = moz_xmalloc(size.value());
     RefPtr<AudioBlockBuffer> p = new (m) AudioBlockBuffer();
     NS_ASSERTION((reinterpret_cast<char*>(p.get() + 1) - reinterpret_cast<char*>(p.get())) % 4 == 0,
                  "AudioBlockBuffers should be at least 4-byte aligned");
     return p.forget();
   }
 
   // Graph thread only.
@@ -145,18 +148,16 @@ AudioBlock::AllocateChannels(uint32_t aC
     if (buffer && !buffer->HasLastingShares()) {
       MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32);
       // No need to allocate again.
       mVolume = 1.0f;
       return;
     }
   }
 
-  // XXX for SIMD purposes we should do something here to make sure the
-  // channel buffers are 16-byte aligned.
   RefPtr<AudioBlockBuffer> buffer = AudioBlockBuffer::Create(aChannelCount);
   mChannelData.SetLength(aChannelCount);
   for (uint32_t i = 0; i < aChannelCount; ++i) {
     mChannelData[i] = buffer->ChannelData(i);
   }
   mBuffer = buffer.forget();
   mVolume = 1.0f;
   mBufferFormat = AUDIO_FORMAT_FLOAT32;
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "AudioDestinationNode.h"
+#include "AlignmentUtils.h"
 #include "AudioContext.h"
 #include "mozilla/dom/AudioDestinationNodeBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "AudioChannelAgent.h"
 #include "AudioChannelService.h"
 #include "AudioNodeEngine.h"
@@ -82,17 +83,17 @@ public:
     const uint32_t duration = std::min(WEBAUDIO_BLOCK_SIZE, mLength - mWriteIndex);
     const uint32_t inputChannelCount = aInput.ChannelCount();
     for (uint32_t i = 0; i < outputChannelCount; ++i) {
       float* outputData = mBuffer->GetDataForWrite(i) + mWriteIndex;
       if (aInput.IsNull() || i >= inputChannelCount) {
         PodZero(outputData, duration);
       } else {
         const float* inputBuffer = static_cast<const float*>(aInput.mChannelData[i]);
-        if (duration == WEBAUDIO_BLOCK_SIZE) {
+        if (duration == WEBAUDIO_BLOCK_SIZE && IS_ALIGNED16(inputBuffer)) {
           // Use the optimized version of the copy with scale operation
           AudioBlockCopyChannelWithScale(inputBuffer, aInput.mVolume,
                                          outputData);
         } else {
           if (aInput.mVolume == 1.0f) {
             PodCopy(outputData, inputBuffer, duration);
           } else {
             for (uint32_t j = 0; j < duration; ++j) {
--- a/dom/media/webaudio/AudioNodeEngine.cpp
+++ b/dom/media/webaudio/AudioNodeEngine.cpp
@@ -4,16 +4,19 @@
  * 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 "AudioNodeEngine.h"
 #ifdef BUILD_ARM_NEON
 #include "mozilla/arm.h"
 #include "AudioNodeEngineNEON.h"
 #endif
+#ifdef USE_SSE2
+#include "AudioNodeEngineSSE2.h"
+#endif
 
 namespace mozilla {
 
 already_AddRefed<ThreadSharedFloatArrayBufferList>
 ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount,
                                          size_t aLength,
                                          const mozilla::fallible_t&)
 {
@@ -66,16 +69,24 @@ void AudioBufferAddWithScale(const float
                              uint32_t aSize)
 {
 #ifdef BUILD_ARM_NEON
   if (mozilla::supports_neon()) {
     AudioBufferAddWithScale_NEON(aInput, aScale, aOutput, aSize);
     return;
   }
 #endif
+
+#ifdef USE_SSE2
+  if (mozilla::supports_sse2()) {
+    AudioBufferAddWithScale_SSE(aInput, aScale, aOutput, aSize);
+    return;
+  }
+#endif
+
   if (aScale == 1.0f) {
     for (uint32_t i = 0; i < aSize; ++i) {
       aOutput[i] += aInput[i];
     }
   } else {
     for (uint32_t i = 0; i < aSize; ++i) {
       aOutput[i] += aInput[i]*aScale;
     }
@@ -99,28 +110,44 @@ AudioBlockCopyChannelWithScale(const flo
     memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE*sizeof(float));
   } else {
 #ifdef BUILD_ARM_NEON
     if (mozilla::supports_neon()) {
       AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
       return;
     }
 #endif
+
+#ifdef USE_SSE2
+  if (mozilla::supports_sse2()) {
+    AudioBlockCopyChannelWithScale_SSE(aInput, aScale, aOutput);
+    return;
+  }
+#endif
+
     for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
       aOutput[i] = aInput[i]*aScale;
     }
   }
 }
 
 void
 BufferComplexMultiply(const float* aInput,
                       const float* aScale,
                       float* aOutput,
                       uint32_t aSize)
 {
+
+#ifdef USE_SSE2
+  if (mozilla::supports_sse()) {
+    BufferComplexMultiply_SSE(aInput, aScale, aOutput, aSize);
+    return;
+  }
+#endif
+
   for (uint32_t i = 0; i < aSize * 2; i += 2) {
     float real1 = aInput[i];
     float imag1 = aInput[i + 1];
     float real2 = aScale[i];
     float imag2 = aScale[i + 1];
     float realResult = real1 * real2 - imag1 * imag2;
     float imagResult = real1 * imag2 + imag1 * real2;
     aOutput[i] = realResult;
@@ -147,16 +174,24 @@ AudioBlockCopyChannelWithScale(const flo
                                float aOutput[WEBAUDIO_BLOCK_SIZE])
 {
 #ifdef BUILD_ARM_NEON
   if (mozilla::supports_neon()) {
     AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
     return;
   }
 #endif
+
+#ifdef USE_SSE2
+  if (mozilla::supports_sse2()) {
+    AudioBlockCopyChannelWithScale_SSE(aInput, aScale, aOutput);
+    return;
+  }
+#endif
+
   for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
     aOutput[i] = aInput[i]*aScale[i];
   }
 }
 
 void
 AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
                        float aScale)
@@ -173,16 +208,24 @@ AudioBufferInPlaceScale(float* aBlock,
     return;
   }
 #ifdef BUILD_ARM_NEON
   if (mozilla::supports_neon()) {
     AudioBufferInPlaceScale_NEON(aBlock, aScale, aSize);
     return;
   }
 #endif
+
+#ifdef USE_SSE2
+  if (mozilla::supports_sse2()) {
+    AudioBufferInPlaceScale_SSE(aBlock, aScale, aSize);
+    return;
+  }
+#endif
+
   for (uint32_t i = 0; i < aSize; ++i) {
     *aBlock++ *= aScale;
   }
 }
 
 void
 AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
                           float aGainL[WEBAUDIO_BLOCK_SIZE],
@@ -215,16 +258,25 @@ AudioBlockPanStereoToStereo(const float 
   if (mozilla::supports_neon()) {
     AudioBlockPanStereoToStereo_NEON(aInputL, aInputR,
                                      aGainL, aGainR, aIsOnTheLeft,
                                      aOutputL, aOutputR);
     return;
   }
 #endif
 
+#ifdef USE_SSE2
+  if (mozilla::supports_sse2()) {
+    AudioBlockPanStereoToStereo_SSE(aInputL, aInputR,
+                                    aGainL, aGainR, aIsOnTheLeft,
+                                    aOutputL, aOutputR);
+    return;
+  }
+#endif
+
   uint32_t i;
 
   if (aIsOnTheLeft) {
     for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
       aOutputL[i] = aInputL[i] + aInputR[i] * aGainL;
       aOutputR[i] = aInputR[i] * aGainR;
     }
   } else {
@@ -264,16 +316,37 @@ AudioBlockPanStereoToStereo(const float 
     }
   }
 }
 
 float
 AudioBufferSumOfSquares(const float* aInput, uint32_t aLength)
 {
   float sum = 0.0f;
+
+#ifdef USE_SSE2
+  if (mozilla::supports_sse()) {
+    const float* alignedInput = ALIGNED16(aInput);
+    float vLength = (aLength >> 4) << 4;
+
+    // use scalar operations for any unaligned data at the beginning
+    while (aInput != alignedInput) {
+        sum += *aInput * *aInput;
+        ++aInput;
+    }
+
+    sum += AudioBufferSumOfSquares_SSE(alignedInput, vLength);
+
+    // adjust aInput and aLength to use scalar operations for any
+    // remaining values
+    aInput = alignedInput + 1;
+    aLength -= vLength;
+  }
+#endif
+
   while (aLength--) {
     sum += *aInput * *aInput;
     ++aInput;
   }
   return sum;
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AudioNodeEngineSSE2.cpp
@@ -0,0 +1,315 @@
+/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* this source code form is subject to the terms of the mozilla public
+ * license, v. 2.0. if a copy of the mpl was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AlignmentUtils.h"
+#include "AudioNodeEngineSSE2.h"
+#include <emmintrin.h>
+
+
+namespace mozilla {
+void
+AudioBufferAddWithScale_SSE(const float* aInput,
+                            float aScale,
+                            float* aOutput,
+                            uint32_t aSize)
+{
+  __m128 vin0, vin1, vin2, vin3,
+         vscaled0, vscaled1, vscaled2, vscaled3,
+         vout0, vout1, vout2, vout3,
+         vgain;
+
+  ASSERT_ALIGNED16(aInput);
+  ASSERT_ALIGNED16(aOutput);
+  ASSERT_MULTIPLE16(aSize);
+
+  vgain = _mm_load1_ps(&aScale);
+
+  for (unsigned i = 0; i < aSize; i+=16) {
+    vin0 = _mm_load_ps(&aInput[i]);
+    vin1 = _mm_load_ps(&aInput[i + 4]);
+    vin2 = _mm_load_ps(&aInput[i + 8]);
+    vin3 = _mm_load_ps(&aInput[i + 12]);
+
+    vscaled0 = _mm_mul_ps(vin0, vgain);
+    vscaled1 = _mm_mul_ps(vin1, vgain);
+    vscaled2 = _mm_mul_ps(vin2, vgain);
+    vscaled3 = _mm_mul_ps(vin3, vgain);
+
+    vin0 = _mm_load_ps(&aOutput[i]);
+    vin1 = _mm_load_ps(&aOutput[i + 4]);
+    vin2 = _mm_load_ps(&aOutput[i + 8]);
+    vin3 = _mm_load_ps(&aOutput[i + 12]);
+
+    vout0 = _mm_add_ps(vin0, vscaled0);
+    vout1 = _mm_add_ps(vin1, vscaled1);
+    vout2 = _mm_add_ps(vin2, vscaled2);
+    vout3 = _mm_add_ps(vin3, vscaled3);
+
+    _mm_store_ps(&aOutput[i], vout0);
+    _mm_store_ps(&aOutput[i + 4], vout1);
+    _mm_store_ps(&aOutput[i + 8], vout2);
+    _mm_store_ps(&aOutput[i + 12], vout3);
+  }
+}
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float* aInput,
+                                   float aScale,
+                                   float* aOutput)
+{
+  __m128 vin0, vin1, vin2, vin3,
+         vout0, vout1, vout2, vout3;
+
+  ASSERT_ALIGNED16(aInput);
+  ASSERT_ALIGNED16(aOutput);
+
+  __m128 vgain = _mm_load1_ps(&aScale);
+
+  for (unsigned i = 0 ; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
+    vin0 = _mm_load_ps(&aInput[i]);
+    vin1 = _mm_load_ps(&aInput[i + 4]);
+    vin2 = _mm_load_ps(&aInput[i + 8]);
+    vin3 = _mm_load_ps(&aInput[i + 12]);
+    vout0 = _mm_mul_ps(vin0, vgain);
+    vout1 = _mm_mul_ps(vin1, vgain);
+    vout2 = _mm_mul_ps(vin2, vgain);
+    vout3 = _mm_mul_ps(vin3, vgain);
+    _mm_store_ps(&aOutput[i], vout0);
+    _mm_store_ps(&aOutput[i + 4], vout1);
+    _mm_store_ps(&aOutput[i + 8], vout2);
+    _mm_store_ps(&aOutput[i + 12], vout3);
+  }
+}
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float aInput[WEBAUDIO_BLOCK_SIZE],
+                                   const float aScale[WEBAUDIO_BLOCK_SIZE],
+                                   float aOutput[WEBAUDIO_BLOCK_SIZE])
+{
+  __m128 vin0, vin1, vin2, vin3,
+         vscaled0, vscaled1, vscaled2, vscaled3,
+         vout0, vout1, vout2, vout3;
+
+  ASSERT_ALIGNED16(aInput);
+  ASSERT_ALIGNED16(aScale);
+  ASSERT_ALIGNED16(aOutput);
+
+  for (unsigned i = 0 ; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
+    vscaled0 = _mm_load_ps(&aScale[i]);
+    vscaled1 = _mm_load_ps(&aScale[i+4]);
+    vscaled2 = _mm_load_ps(&aScale[i+8]);
+    vscaled3 = _mm_load_ps(&aScale[i+12]);
+
+    vin0 = _mm_load_ps(&aInput[i]);
+    vin1 = _mm_load_ps(&aInput[i + 4]);
+    vin2 = _mm_load_ps(&aInput[i + 8]);
+    vin3 = _mm_load_ps(&aInput[i + 12]);
+
+    vout0 = _mm_mul_ps(vin0, vscaled0);
+    vout1 = _mm_mul_ps(vin1, vscaled1);
+    vout2 = _mm_mul_ps(vin2, vscaled2);
+    vout3 = _mm_mul_ps(vin3, vscaled3);
+
+    _mm_store_ps(&aOutput[i], vout0);
+    _mm_store_ps(&aOutput[i + 4], vout1);
+    _mm_store_ps(&aOutput[i + 8], vout2);
+    _mm_store_ps(&aOutput[i + 12], vout3);
+  }
+}
+
+void
+AudioBufferInPlaceScale_SSE(float* aBlock,
+                            float aScale,
+                            uint32_t aSize)
+{
+  __m128 vout0, vout1, vout2, vout3,
+         vin0, vin1, vin2, vin3;
+
+  ASSERT_ALIGNED16(aBlock);
+  ASSERT_MULTIPLE16(aSize);
+
+  __m128 vgain = _mm_load1_ps(&aScale);
+
+  for (unsigned i = 0; i < aSize; i+=16) {
+    vin0 = _mm_load_ps(&aBlock[i]);
+    vin1 = _mm_load_ps(&aBlock[i + 4]);
+    vin2 = _mm_load_ps(&aBlock[i + 8]);
+    vin3 = _mm_load_ps(&aBlock[i + 12]);
+    vout0 = _mm_mul_ps(vin0, vgain);
+    vout1 = _mm_mul_ps(vin1, vgain);
+    vout2 = _mm_mul_ps(vin2, vgain);
+    vout3 = _mm_mul_ps(vin3, vgain);
+    _mm_store_ps(&aBlock[i], vout0);
+    _mm_store_ps(&aBlock[i + 4], vout1);
+    _mm_store_ps(&aBlock[i + 8], vout2);
+    _mm_store_ps(&aBlock[i + 12], vout3);
+  }
+}
+
+void
+AudioBlockPanStereoToStereo_SSE(const float aInputL[WEBAUDIO_BLOCK_SIZE],
+                                const float aInputR[WEBAUDIO_BLOCK_SIZE],
+                                float aGainL, float aGainR, bool aIsOnTheLeft,
+                                float aOutputL[WEBAUDIO_BLOCK_SIZE],
+                                float aOutputR[WEBAUDIO_BLOCK_SIZE])
+{
+  __m128 vinl0, vinr0, vinl1, vinr1,
+         vout0, vout1,
+         vscaled0, vscaled1,
+         vgainl, vgainr;
+
+  ASSERT_ALIGNED16(aInputL);
+  ASSERT_ALIGNED16(aInputR);
+  ASSERT_ALIGNED16(aOutputL);
+  ASSERT_ALIGNED16(aOutputR);
+
+  vgainl = _mm_load1_ps(&aGainL);
+  vgainr = _mm_load1_ps(&aGainR);
+
+  if (aIsOnTheLeft) {
+    for (unsigned i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=8) {
+      vinl0 = _mm_load_ps(&aInputL[i]);
+      vinr0 = _mm_load_ps(&aInputR[i]);
+      vinl1 = _mm_load_ps(&aInputL[i+4]);
+      vinr1 = _mm_load_ps(&aInputR[i+4]);
+
+      /* left channel : aOutputL  = aInputL + aInputR * gainL */
+      vscaled0 = _mm_mul_ps(vinr0, vgainl);
+      vscaled1 = _mm_mul_ps(vinr1, vgainl);
+      vout0 = _mm_add_ps(vscaled0, vinl0);
+      vout1 = _mm_add_ps(vscaled1, vinl1);
+      _mm_store_ps(&aOutputL[i], vout0);
+      _mm_store_ps(&aOutputL[i+4], vout1);
+
+      /* right channel : aOutputR = aInputR * gainR */
+      vscaled0 = _mm_mul_ps(vinr0, vgainr);
+      vscaled1 = _mm_mul_ps(vinr1, vgainr);
+      _mm_store_ps(&aOutputR[i], vscaled0);
+      _mm_store_ps(&aOutputR[i+4], vscaled1);
+    }
+  } else {
+    for (unsigned i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=8) {
+      vinl0 = _mm_load_ps(&aInputL[i]);
+      vinr0 = _mm_load_ps(&aInputR[i]);
+      vinl1 = _mm_load_ps(&aInputL[i+4]);
+      vinr1 = _mm_load_ps(&aInputR[i+4]);
+
+      /* left channel : aInputL * gainL */
+      vscaled0 = _mm_mul_ps(vinl0, vgainl);
+      vscaled1 = _mm_mul_ps(vinl1, vgainl);
+      _mm_store_ps(&aOutputL[i], vscaled0);
+      _mm_store_ps(&aOutputL[i+4], vscaled1);
+
+      /* right channel: aOutputR = aInputR + aInputL * gainR */
+      vscaled0 = _mm_mul_ps(vinl0, vgainr);
+      vscaled1 = _mm_mul_ps(vinl1, vgainr);
+      vout0 = _mm_add_ps(vscaled0, vinr0);
+      vout1 = _mm_add_ps(vscaled1, vinr1);
+      _mm_store_ps(&aOutputR[i], vout0);
+      _mm_store_ps(&aOutputR[i+4], vout1);
+    }
+  }
+}
+
+void BufferComplexMultiply_SSE(const float* aInput,
+                               const float* aScale,
+                               float* aOutput,
+                               uint32_t aSize)
+{
+  unsigned i;
+  __m128 in0, in1, in2, in3,
+         outreal0, outreal1, outreal2, outreal3,
+         outimag0, outimag1, outimag2, outimag3;
+
+  ASSERT_ALIGNED16(aInput);
+  ASSERT_ALIGNED16(aScale);
+  ASSERT_ALIGNED16(aOutput);
+  ASSERT_MULTIPLE16(aSize);
+
+  for (i = 0; i < aSize * 2; i += 16) {
+    in0 = _mm_load_ps(&aInput[i]);
+    in1 = _mm_load_ps(&aInput[i + 4]);
+    in2 = _mm_load_ps(&aInput[i + 8]);
+    in3 = _mm_load_ps(&aInput[i + 12]);
+
+    outreal0 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(2, 0, 2, 0));
+    outimag0 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(3, 1, 3, 1));
+    outreal2 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(2, 0, 2, 0));
+    outimag2 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(3, 1, 3, 1));
+
+    in0 = _mm_load_ps(&aScale[i]);
+    in1 = _mm_load_ps(&aScale[i + 4]);
+    in2 = _mm_load_ps(&aScale[i + 8]);
+    in3 = _mm_load_ps(&aScale[i + 12]);
+
+    outreal1 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(2, 0, 2, 0));
+    outimag1 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(3, 1, 3, 1));
+    outreal3 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(2, 0, 2, 0));
+    outimag3 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(3, 1, 3, 1));
+
+    in0 = _mm_sub_ps(_mm_mul_ps(outreal0, outreal1),
+                     _mm_mul_ps(outimag0, outimag1));
+    in1 = _mm_add_ps(_mm_mul_ps(outreal0, outimag1),
+                     _mm_mul_ps(outimag0, outreal1));
+    in2 = _mm_sub_ps(_mm_mul_ps(outreal2, outreal3),
+                     _mm_mul_ps(outimag2, outimag3));
+    in3 = _mm_add_ps(_mm_mul_ps(outreal2, outimag3),
+                     _mm_mul_ps(outimag2, outreal3));
+
+    outreal0 = _mm_unpacklo_ps(in0, in1);
+    outreal1 = _mm_unpackhi_ps(in0, in1);
+    outreal2 = _mm_unpacklo_ps(in2, in3);
+    outreal3 = _mm_unpackhi_ps(in2, in3);
+
+    _mm_store_ps(&aOutput[i], outreal0);
+    _mm_store_ps(&aOutput[i + 4], outreal1);
+    _mm_store_ps(&aOutput[i + 8], outreal2);
+    _mm_store_ps(&aOutput[i + 12], outreal3);
+  }
+}
+
+float
+AudioBufferSumOfSquares_SSE(const float* aInput, uint32_t aLength)
+{
+  unsigned i;
+  __m128 in0, in1, in2, in3,
+         acc0, acc1, acc2, acc3;
+  float out[4];
+
+  ASSERT_ALIGNED16(aInput);
+  ASSERT_MULTIPLE16(aLength);
+
+  acc0 = _mm_setzero_ps();
+  acc1 = _mm_setzero_ps();
+  acc2 = _mm_setzero_ps();
+  acc3 = _mm_setzero_ps();
+
+  for (i = 0; i < aLength; i+=16) {
+    in0 = _mm_load_ps(&aInput[i]);
+    in1 = _mm_load_ps(&aInput[i + 4]);
+    in2 = _mm_load_ps(&aInput[i + 8]);
+    in3 = _mm_load_ps(&aInput[i + 12]);
+
+    in0 = _mm_mul_ps(in0, in0);
+    in1 = _mm_mul_ps(in1, in1);
+    in2 = _mm_mul_ps(in2, in2);
+    in3 = _mm_mul_ps(in3, in3);
+
+    acc0 = _mm_add_ps(acc0, in0);
+    acc1 = _mm_add_ps(acc1, in1);
+    acc2 = _mm_add_ps(acc2, in2);
+    acc3 = _mm_add_ps(acc3, in3);
+  }
+
+  acc0 = _mm_add_ps(acc0, acc1);
+  acc0 = _mm_add_ps(acc0, acc2);
+  acc0 = _mm_add_ps(acc0, acc3);
+
+  _mm_store_ps(out, acc0);
+
+  return out[0] + out[1] + out[2] + out[3];
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AudioNodeEngineSSE2.h
@@ -0,0 +1,45 @@
+/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* this source code form is subject to the terms of the mozilla public
+ * license, v. 2.0. if a copy of the mpl was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AudioNodeEngine.h"
+
+namespace mozilla {
+void
+AudioBufferAddWithScale_SSE(const float* aInput,
+                            float aScale,
+                            float* aOutput,
+                            uint32_t aSize);
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float* aInput,
+                                   float aScale,
+                                   float* aOutput);
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float aInput[WEBAUDIO_BLOCK_SIZE],
+                                   const float aScale[WEBAUDIO_BLOCK_SIZE],
+                                   float aOutput[WEBAUDIO_BLOCK_SIZE]);
+
+void
+AudioBufferInPlaceScale_SSE(float* aBlock,
+                            float aScale,
+                            uint32_t aSize);
+
+void
+AudioBlockPanStereoToStereo_SSE(const float aInputL[WEBAUDIO_BLOCK_SIZE],
+                                const float aInputR[WEBAUDIO_BLOCK_SIZE],
+                                float aGainL, float aGainR, bool aIsOnTheLeft,
+                                float aOutputL[WEBAUDIO_BLOCK_SIZE],
+                                float aOutputR[WEBAUDIO_BLOCK_SIZE]);
+
+float
+AudioBufferSumOfSquares_SSE(const float* aInput, uint32_t aLength);
+
+void
+BufferComplexMultiply_SSE(const float* aInput,
+                          const float* aScale,
+                          float* aOutput,
+                          uint32_t aSize);
+}
--- a/dom/media/webaudio/AudioNodeExternalInputStream.cpp
+++ b/dom/media/webaudio/AudioNodeExternalInputStream.cpp
@@ -1,13 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "AlignedTArray.h"
+#include "AlignmentUtils.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeExternalInputStream.h"
 #include "AudioChannelFormat.h"
 #include "mozilla/dom/MediaStreamAudioSourceNode.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
@@ -85,19 +87,30 @@ static void ConvertSegmentToAudioBlock(A
 {
   NS_ASSERTION(aSegment->GetDuration() == WEBAUDIO_BLOCK_SIZE, "Bad segment duration");
 
   {
     AudioSegment::ChunkIterator ci(*aSegment);
     NS_ASSERTION(!ci.IsEnded(), "Should be at least one chunk!");
     if (ci->GetDuration() == WEBAUDIO_BLOCK_SIZE &&
         (ci->IsNull() || ci->mBufferFormat == AUDIO_FORMAT_FLOAT32)) {
+
+      bool aligned = true;
+      for (size_t i = 0; i < ci->mChannelData.Length(); ++i) {
+        if (!IS_ALIGNED16(ci->mChannelData[i])) {
+            aligned = false;
+            break;
+        }
+      }
+
       // Return this chunk directly to avoid copying data.
-      *aBlock = *ci;
-      return;
+      if (aligned) {
+        *aBlock = *ci;
+        return;
+      }
     }
   }
 
   aBlock->AllocateChannels(aFallbackChannelCount);
 
   uint32_t duration = 0;
   for (AudioSegment::ChunkIterator ci(*aSegment); !ci.IsEnded(); ci.Next()) {
     switch (ci->mBufferFormat) {
@@ -187,17 +200,20 @@ AudioNodeExternalInputStream::ProcessInp
 
     for (AudioSegment::ChunkIterator iter(segment); !iter.IsEnded(); iter.Next()) {
       inputChannels = GetAudioChannelsSuperset(inputChannels, iter->ChannelCount());
     }
   }
 
   uint32_t accumulateIndex = 0;
   if (inputChannels) {
-    AutoTArray<float,GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
+    // TODO: See Bug 1261168. Ideally we would use an aligned version of
+    // AutoTArray (of size GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE) here.
+    AlignedTArray<float,16> downmixBuffer;
+    downmixBuffer.SetLength(GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE);
     for (uint32_t i = 0; i < audioSegments.Length(); ++i) {
       AudioBlock tmpChunk;
       ConvertSegmentToAudioBlock(&audioSegments[i], &tmpChunk, inputChannels);
       if (!tmpChunk.IsNull()) {
         if (accumulateIndex == 0) {
           mLastChunks[0].AllocateChannels(inputChannels);
         }
         AccumulateInputChunk(accumulateIndex, tmpChunk, &mLastChunks[0], &downmixBuffer);
--- a/dom/media/webaudio/AudioNodeStream.cpp
+++ b/dom/media/webaudio/AudioNodeStream.cpp
@@ -448,29 +448,31 @@ AudioNodeStream::ObtainInputBlock(AudioB
   }
 
   if (outputChannelCount == 0) {
     aTmpChunk.SetNull(WEBAUDIO_BLOCK_SIZE);
     return;
   }
 
   aTmpChunk.AllocateChannels(outputChannelCount);
-  // The static storage here should be 1KB, so it's fine
-  AutoTArray<float, GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
+  // TODO: See Bug 1261168. Ideally we would use an aligned version of
+  // AutoTArray (of size GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE) here.
+  AlignedTArray<float, 16> downmixBuffer;
+  downmixBuffer.SetLength(GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE);
 
   for (uint32_t i = 0; i < inputChunkCount; ++i) {
     AccumulateInputChunk(i, *inputChunks[i], &aTmpChunk, &downmixBuffer);
   }
 }
 
 void
 AudioNodeStream::AccumulateInputChunk(uint32_t aInputIndex,
                                       const AudioBlock& aChunk,
                                       AudioBlock* aBlock,
-                                      nsTArray<float>* aDownmixBuffer)
+                                      AlignedTArray<float, 16>* aDownmixBuffer)
 {
   AutoTArray<const float*,GUESS_AUDIO_CHANNELS> channels;
   UpMixDownMixChunk(&aChunk, aBlock->ChannelCount(), channels, *aDownmixBuffer);
 
   for (uint32_t c = 0; c < channels.Length(); ++c) {
     const float* inputData = static_cast<const float*>(channels[c]);
     float* outputData = aBlock->ChannelFloatsForWrite(c);
     if (inputData) {
@@ -486,17 +488,17 @@ AudioNodeStream::AccumulateInputChunk(ui
     }
   }
 }
 
 void
 AudioNodeStream::UpMixDownMixChunk(const AudioBlock* aChunk,
                                    uint32_t aOutputChannelCount,
                                    nsTArray<const float*>& aOutputChannels,
-                                   nsTArray<float>& aDownmixBuffer)
+                                   AlignedTArray<float, 16>& aDownmixBuffer)
 {
   for (uint32_t i = 0; i < aChunk->ChannelCount(); i++) {
     aOutputChannels.AppendElement(static_cast<const float*>(aChunk->mChannelData[i]));
   }
   if (aOutputChannels.Length() < aOutputChannelCount) {
     if (mChannelInterpretation == ChannelInterpretation::Speakers) {
       AudioChannelsUpMix<float>(&aOutputChannels, aOutputChannelCount, nullptr);
       NS_ASSERTION(aOutputChannelCount == aOutputChannels.Length(),
--- a/dom/media/webaudio/AudioNodeStream.h
+++ b/dom/media/webaudio/AudioNodeStream.h
@@ -3,16 +3,17 @@
  * 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_AUDIONODESTREAM_H_
 #define MOZILLA_AUDIONODESTREAM_H_
 
 #include "MediaStreamGraph.h"
 #include "mozilla/dom/AudioNodeBinding.h"
+#include "AlignedTArray.h"
 #include "AudioBlock.h"
 
 namespace mozilla {
 
 namespace dom {
 struct ThreeDPoint;
 struct AudioTimelineEvent;
 class AudioContext;
@@ -185,20 +186,20 @@ protected:
    * again until SetActive() is called.
    */
   void CheckForInactive();
 
   void AdvanceOutputSegment();
   void FinishOutput();
   void AccumulateInputChunk(uint32_t aInputIndex, const AudioBlock& aChunk,
                             AudioBlock* aBlock,
-                            nsTArray<float>* aDownmixBuffer);
+                            AlignedTArray<float, 16>* aDownmixBuffer);
   void UpMixDownMixChunk(const AudioBlock* aChunk, uint32_t aOutputChannelCount,
                          nsTArray<const float*>& aOutputChannels,
-                         nsTArray<float>& aDownmixBuffer);
+                         AlignedTArray<float, 16>& aDownmixBuffer);
 
   uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount);
   void ObtainInputBlock(AudioBlock& aTmpChunk, uint32_t aPortIndex);
   void IncrementActiveInputCount();
   void DecrementActiveInputCount();
 
   // The engine that will generate output for this node.
   nsAutoPtr<AudioNodeEngine> mEngine;
--- a/dom/media/webaudio/BiquadFilterNode.cpp
+++ b/dom/media/webaudio/BiquadFilterNode.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "BiquadFilterNode.h"
+#include "AlignmentUtils.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioDestinationNode.h"
 #include "PlayingRefChangeHandler.h"
 #include "WebAudioUtils.h"
 #include "blink/Biquad.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/UniquePtr.h"
@@ -132,17 +133,19 @@ public:
   }
 
   void ProcessBlock(AudioNodeStream* aStream,
                     GraphTime aFrom,
                     const AudioBlock& aInput,
                     AudioBlock* aOutput,
                     bool* aFinished) override
   {
-    float inputBuffer[WEBAUDIO_BLOCK_SIZE];
+    float inputBuffer[WEBAUDIO_BLOCK_SIZE + 4];
+    float* alignedInputBuffer = ALIGNED16(inputBuffer);
+    ASSERT_ALIGNED16(alignedInputBuffer);
 
     if (aInput.IsNull()) {
       bool hasTail = false;
       for (uint32_t i = 0; i < mBiquads.Length(); ++i) {
         if (mBiquads[i].hasTail()) {
           hasTail = true;
           break;
         }
@@ -186,22 +189,22 @@ public:
     double freq = mFrequency.GetValueAtTime(pos);
     double q = mQ.GetValueAtTime(pos);
     double gain = mGain.GetValueAtTime(pos);
     double detune = mDetune.GetValueAtTime(pos);
 
     for (uint32_t i = 0; i < numberOfChannels; ++i) {
       const float* input;
       if (aInput.IsNull()) {
-        input = inputBuffer;
+        input = alignedInputBuffer;
       } else {
         input = static_cast<const float*>(aInput.mChannelData[i]);
         if (aInput.mVolume != 1.0) {
-          AudioBlockCopyChannelWithScale(input, aInput.mVolume, inputBuffer);
-          input = inputBuffer;
+          AudioBlockCopyChannelWithScale(input, aInput.mVolume, alignedInputBuffer);
+          input = alignedInputBuffer;
         }
       }
       SetParamsOnBiquad(mBiquads[i], aStream->SampleRate(), mType, freq, q, gain, detune);
 
       mBiquads[i].process(input,
                           aOutput->ChannelFloatsForWrite(i),
                           aInput.GetDuration());
     }
--- a/dom/media/webaudio/ConvolverNode.cpp
+++ b/dom/media/webaudio/ConvolverNode.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "ConvolverNode.h"
 #include "mozilla/dom/ConvolverNodeBinding.h"
+#include "AlignmentUtils.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "blink/Reverb.h"
 #include "PlayingRefChangeHandler.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -256,21 +257,23 @@ ConvolverNode::SetBuffer(JSContext* aCx,
       mBuffer->GetThreadSharedChannelsForRate(aCx);
     if (data && length < WEBAUDIO_BLOCK_SIZE) {
       // For very small impulse response buffers, we need to pad the
       // buffer with 0 to make sure that the Reverb implementation
       // has enough data to compute FFTs from.
       length = WEBAUDIO_BLOCK_SIZE;
       RefPtr<ThreadSharedFloatArrayBufferList> paddedBuffer =
         new ThreadSharedFloatArrayBufferList(data->GetChannels());
-      float* channelData = (float*) malloc(sizeof(float) * length * data->GetChannels());
+      void* channelData = malloc(sizeof(float) * length * data->GetChannels() + 15);
+      float* alignedChannelData = ALIGNED16(channelData);
+      ASSERT_ALIGNED16(alignedChannelData);
       for (uint32_t i = 0; i < data->GetChannels(); ++i) {
-        PodCopy(channelData + length * i, data->GetData(i), mBuffer->Length());
-        PodZero(channelData + length * i + mBuffer->Length(), WEBAUDIO_BLOCK_SIZE - mBuffer->Length());
-        paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, free, channelData);
+        PodCopy(alignedChannelData + length * i, data->GetData(i), mBuffer->Length());
+        PodZero(alignedChannelData + length * i + mBuffer->Length(), WEBAUDIO_BLOCK_SIZE - mBuffer->Length());
+        paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, free, alignedChannelData);
       }
       data = paddedBuffer;
     }
     SendInt32ParameterToStream(ConvolverNodeEngine::BUFFER_LENGTH, length);
     SendDoubleParameterToStream(ConvolverNodeEngine::SAMPLE_RATE,
                                 mBuffer->SampleRate());
     ns->SetBuffer(data.forget());
   } else {
--- a/dom/media/webaudio/GainNode.cpp
+++ b/dom/media/webaudio/GainNode.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "GainNode.h"
 #include "mozilla/dom/GainNodeBinding.h"
+#include "AlignmentUtils.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioDestinationNode.h"
 #include "WebAudioUtils.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -74,28 +75,30 @@ public:
     } else {
       // First, compute a vector of gains for each track tick based on the
       // timeline at hand, and then for each channel, multiply the values
       // in the buffer with the gain vector.
       aOutput->AllocateChannels(aInput.ChannelCount());
 
       // Compute the gain values for the duration of the input AudioChunk
       StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
-      float computedGain[WEBAUDIO_BLOCK_SIZE];
-      mGain.GetValuesAtTime(tick, computedGain, WEBAUDIO_BLOCK_SIZE);
+      float computedGain[WEBAUDIO_BLOCK_SIZE + 4];
+      float* alignedComputedGain = ALIGNED16(computedGain);
+      ASSERT_ALIGNED16(alignedComputedGain);
+      mGain.GetValuesAtTime(tick, alignedComputedGain, WEBAUDIO_BLOCK_SIZE);
 
       for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
-        computedGain[counter] *= aInput.mVolume;
+        alignedComputedGain[counter] *= aInput.mVolume;
       }
 
       // Apply the gain to the output buffer
       for (size_t channel = 0; channel < aOutput->ChannelCount(); ++channel) {
         const float* inputBuffer = static_cast<const float*> (aInput.mChannelData[channel]);
         float* buffer = aOutput->ChannelFloatsForWrite(channel);
-        AudioBlockCopyChannelWithScale(inputBuffer, computedGain, buffer);
+        AudioBlockCopyChannelWithScale(inputBuffer, alignedComputedGain, buffer);
       }
     }
   }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     // Not owned:
     // - mDestination (probably)
--- a/dom/media/webaudio/StereoPannerNode.cpp
+++ b/dom/media/webaudio/StereoPannerNode.cpp
@@ -4,16 +4,17 @@
  * 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 "StereoPannerNode.h"
 #include "mozilla/dom/StereoPannerNodeBinding.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioDestinationNode.h"
+#include "AlignmentUtils.h"
 #include "WebAudioUtils.h"
 #include "PanningUtils.h"
 #include "AudioParamTimeline.h"
 #include "AudioParam.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -132,34 +133,36 @@ public:
 
         GetGainValuesForPanning(panning, monoToStereo, gainL, gainR);
         ApplyStereoPanning(aInput, aOutput,
                            gainL * aInput.mVolume,
                            gainR * aInput.mVolume,
                            panning <= 0);
       }
     } else {
-      float computedGain[2][WEBAUDIO_BLOCK_SIZE];
+      float computedGain[2*WEBAUDIO_BLOCK_SIZE + 4];
       bool onLeft[WEBAUDIO_BLOCK_SIZE];
 
       float values[WEBAUDIO_BLOCK_SIZE];
       StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
       mPan.GetValuesAtTime(tick, values, WEBAUDIO_BLOCK_SIZE);
 
+      float* alignedComputedGain = ALIGNED16(computedGain);
+      ASSERT_ALIGNED16(alignedComputedGain);
       for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
         float left, right;
         GetGainValuesForPanning(values[counter], monoToStereo, left, right);
 
-        computedGain[0][counter] = left * aInput.mVolume;
-        computedGain[1][counter] = right * aInput.mVolume;
+        alignedComputedGain[counter] = left * aInput.mVolume;
+        alignedComputedGain[WEBAUDIO_BLOCK_SIZE + counter] = right * aInput.mVolume;
         onLeft[counter] = values[counter] <= 0;
       }
 
       // Apply the gain to the output buffer
-      ApplyStereoPanning(aInput, aOutput, computedGain[0], computedGain[1], onLeft);
+      ApplyStereoPanning(aInput, aOutput, alignedComputedGain, &alignedComputedGain[WEBAUDIO_BLOCK_SIZE], onLeft);
     }
   }
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
--- a/dom/media/webaudio/WaveShaperNode.cpp
+++ b/dom/media/webaudio/WaveShaperNode.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "WaveShaperNode.h"
 #include "mozilla/dom/WaveShaperNodeBinding.h"
+#include "AlignmentUtils.h"
 #include "AudioNode.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "mozilla/PodOperations.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -226,23 +227,25 @@ public:
       // or the input is null.
       *aOutput = aInput;
       return;
     }
 
     aOutput->AllocateChannels(channelCount);
     for (uint32_t i = 0; i < channelCount; ++i) {
       const float* inputSamples;
-      float scaledInput[WEBAUDIO_BLOCK_SIZE];
+      float scaledInput[WEBAUDIO_BLOCK_SIZE + 4];
+      float* alignedScaledInput = ALIGNED16(scaledInput);
+      ASSERT_ALIGNED16(alignedScaledInput);
       if (aInput.mVolume != 1.0f) {
         AudioBlockCopyChannelWithScale(
             static_cast<const float*>(aInput.mChannelData[i]),
                                       aInput.mVolume,
-                                      scaledInput);
-        inputSamples = scaledInput;
+                                      alignedScaledInput);
+        inputSamples = alignedScaledInput;
       } else {
         inputSamples = static_cast<const float*>(aInput.mChannelData[i]);
       }
       float* outputBuffer = aOutput->ChannelFloatsForWrite(i);
       float* sampleBuffer;
 
       switch (mType) {
       case OverSampleType::None:
--- a/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp
+++ b/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp
@@ -91,22 +91,40 @@ int ReverbAccumulationBuffer::accumulate
 
     float* destination = m_buffer.Elements();
 
     bool isSafe = writeIndex <= bufferLength && numberOfFrames1 + writeIndex <= bufferLength && numberOfFrames2 <= bufferLength;
     MOZ_ASSERT(isSafe);
     if (!isSafe)
         return 0;
 
-    AudioBufferAddWithScale(source, 1.0f, destination + writeIndex, numberOfFrames1);
+#ifdef USE_SSE2
+    // It is unlikely either the source is aligned or the number of values
+    // is a multiple of 16, so we just add them here rather than calling
+    // AudioBufferAddWithScale.
+    //
+    // TODO: Ideally we would use scalar calls when necessary and switch
+    //       to vector calls when we have aligned sources and destinations.
+    //       See Bug 1263910.
+    for (uint32_t i = 0; i < numberOfFrames1; ++i) {
+      destination[writeIndex + i] += source[i];
+    }
 
-    // Handle wrap-around if necessary
+    // Handle wrap-around if necessary.
+    if (numberOfFrames2 > 0) {
+        for (uint32_t i = 0; i < numberOfFrames2; ++i) {
+          destination[i] += source[numberOfFrames1 + i];
+        }
+    }
+#else
+    AudioBufferAddWithScale(source, 1.0f, destination + writeIndex, numberOfFrames1);
     if (numberOfFrames2 > 0) {
         AudioBufferAddWithScale(source + numberOfFrames1, 1.0f, destination, numberOfFrames2);
     }
+#endif
 
     return writeIndex;
 }
 
 void ReverbAccumulationBuffer::reset()
 {
     PodZero(m_buffer.Elements(), m_buffer.Length());
     m_readIndex = 0;
--- a/dom/media/webaudio/blink/ReverbAccumulationBuffer.h
+++ b/dom/media/webaudio/blink/ReverbAccumulationBuffer.h
@@ -24,23 +24,21 @@
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef ReverbAccumulationBuffer_h
 #define ReverbAccumulationBuffer_h
 
-#include "nsTArray.h"
+#include "AlignedTArray.h"
 #include "mozilla/MemoryReporting.h"
 
 namespace WebCore {
 
-typedef nsTArray<float> AudioFloatArray;
-
 // ReverbAccumulationBuffer is a circular delay buffer with one client reading from it and multiple clients
 // writing/accumulating to it at different delay offsets from the read position.  The read operation will zero the memory
 // just read from the buffer, so it will be ready for accumulation the next time around.
 class ReverbAccumulationBuffer {
 public:
     explicit ReverbAccumulationBuffer(size_t length);
 
     // This will read from, then clear-out numberOfFrames
@@ -60,16 +58,16 @@ public:
     void reset();
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     {
         return m_buffer.ShallowSizeOfExcludingThis(aMallocSizeOf);
     }
 
 private:
-    AudioFloatArray m_buffer;
+    AlignedTArray<float, 16> m_buffer;
     size_t m_readIndex;
     size_t m_readTimeFrame; // for debugging (frame on continuous timeline)
 };
 
 } // namespace WebCore
 
 #endif // ReverbAccumulationBuffer_h
--- a/dom/media/webaudio/blink/moz.build
+++ b/dom/media/webaudio/blink/moz.build
@@ -18,14 +18,18 @@ UNIFIED_SOURCES += [
     'Reverb.cpp',
     'ReverbAccumulationBuffer.cpp',
     'ReverbConvolver.cpp',
     'ReverbConvolverStage.cpp',
     'ReverbInputBuffer.cpp',
     'ZeroPole.cpp',
 ]
 
+# Are we targeting x86 or x64?  If so, build SSE2 files.
+if CONFIG['INTEL_ARCHITECTURE']:
+    DEFINES['USE_SSE2'] = True
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/dom/media/webaudio',
 ]
--- a/dom/media/webaudio/moz.build
+++ b/dom/media/webaudio/moz.build
@@ -109,15 +109,22 @@ UNIFIED_SOURCES += [
 
 if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
     SOURCES += ['AudioNodeEngineNEON.cpp']
     SOURCES['AudioNodeEngineNEON.cpp'].flags += ['-mfpu=neon']
     LOCAL_INCLUDES += [
         '/media/openmax_dl/dl/api/'
     ]
 
+# Are we targeting x86 or x64?  If so, build SSE2 files.
+if CONFIG['INTEL_ARCHITECTURE']:
+    SOURCES += ['AudioNodeEngineSSE2.cpp']
+    DEFINES['USE_SSE2'] = True
+    SOURCES['AudioNodeEngineSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '..'
 ]
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2534,17 +2534,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
                            NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
     if (response == kNPEventHandled)
       rv = nsEventStatus_eConsumeNoDefault;
   }
 #endif
 
 #ifdef MOZ_X11
   // this code supports windowless plugins
-  nsIWidget* widget = anEvent.widget;
+  nsIWidget* widget = anEvent.mWidget;
   XEvent pluginEvent = XEvent();
   pluginEvent.type = 0;
 
   switch(anEvent.mClass) {
     case eMouseEventClass:
       {
         switch (anEvent.mMessage) {
           case eMouseClick:
deleted file mode 100644
--- a/dom/plugins/test/testplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# 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/.
-
-RELATIVE_PATH=.
-COCOA_NAME=Test
-include @srcdir@/testplugin.mk
deleted file mode 100644
--- a/dom/plugins/test/testplugin/flashplugin/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# 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/.
-
-RELATIVE_PATH=..
-COCOA_NAME=npswftest
-include @srcdir@/../testplugin.mk
-
--- a/dom/plugins/test/testplugin/flashplugin/moz.build
+++ b/dom/plugins/test/testplugin/flashplugin/moz.build
@@ -2,9 +2,10 @@
 # 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/.
 
 SharedLibrary('npswftest')
 
 relative_path = 'flashplugin'
+cocoa_name = 'npswftest'
 include('../testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/javaplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# 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/.
-
-RELATIVE_PATH=..
-COCOA_NAME=JavaTest
-include @srcdir@/../testplugin.mk
--- a/dom/plugins/test/testplugin/javaplugin/moz.build
+++ b/dom/plugins/test/testplugin/javaplugin/moz.build
@@ -2,9 +2,10 @@
 # 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/.
 
 SharedLibrary('nptestjava')
 
 relative_path = 'javaplugin'
+cocoa_name = 'JavaTest'
 include('../testplugin.mozbuild')
--- a/dom/plugins/test/testplugin/moz.build
+++ b/dom/plugins/test/testplugin/moz.build
@@ -4,9 +4,10 @@
 # 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/.
 
 DIRS += ['secondplugin', 'javaplugin', 'thirdplugin', 'flashplugin', 'silverlightplugin']
 
 SharedLibrary('nptest')
 
 relative_path = '.'
+cocoa_name = 'Test'
 include('testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/secondplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# 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/.
-
-RELATIVE_PATH=..
-COCOA_NAME=SecondTest
-include @srcdir@/../testplugin.mk
--- a/dom/plugins/test/testplugin/secondplugin/moz.build
+++ b/dom/plugins/test/testplugin/secondplugin/moz.build
@@ -2,9 +2,10 @@
 # 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/.
 
 SharedLibrary('npsecondtest')
 
 relative_path = 'secondplugin'
+cocoa_name = 'SecondTest'
 include('../testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/silverlightplugin/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# 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/.
-
-RELATIVE_PATH=..
-COCOA_NAME=npctrltest
-include @srcdir@/../testplugin.mk
-
--- a/dom/plugins/test/testplugin/silverlightplugin/moz.build
+++ b/dom/plugins/test/testplugin/silverlightplugin/moz.build
@@ -2,9 +2,10 @@
 # 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/.
 
 SharedLibrary('npctrltest')
 
 relative_path = 'silverlightplugin'
+cocoa_name = 'npctrltest'
 include('../testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/testplugin.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# 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/.
-
-TEST_PLUGIN_FILES = $(SHARED_LIBRARY)
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-MAC_PLIST_FILES += $(srcdir)/Info.plist
-MAC_PLIST_DEST   = $(DIST)/plugins/$(COCOA_NAME).plugin/Contents
-TEST_PLUGIN_DEST = $(DIST)/plugins/$(COCOA_NAME).plugin/Contents/MacOS
-INSTALL_TARGETS += \
-	TEST_PLUGIN \
-	MAC_PLIST \
-	$(NULL)
-else
-TEST_PLUGIN_DEST = $(DIST)/plugins
-INSTALL_TARGETS += TEST_PLUGIN
-endif
--- a/dom/plugins/test/testplugin/testplugin.mozbuild
+++ b/dom/plugins/test/testplugin/testplugin.mozbuild
@@ -1,16 +1,14 @@
 # -*- 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/.
 
-DIST_INSTALL = False
-
 UNIFIED_SOURCES += [
     'nptest.cpp',
     'nptest_utils.cpp',
 ]
 
 UNIFIED_SOURCES += [
     '%s/nptest_name.cpp' % relative_path,
 ]
@@ -69,8 +67,14 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
     OS_LIBS += CONFIG['MOZ_QT_LIBS']
     OS_LIBS += CONFIG['XLDFLAGS']
     OS_LIBS += CONFIG['XLIBS']
 
 if CONFIG['_MSC_VER']:
     # This is intended as a temporary hack to support building with VS2015.
     # conversion from 'X' to 'Y' requires a narrowing conversion
     CXXFLAGS += ['-wd4838']
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+    FINAL_TARGET = 'dist/plugins/%s.plugin/Contents/MacOS' % cocoa_name
+    OBJDIR_FILES.dist.plugins['%s.plugin' % cocoa_name].Contents += ['Info.plist']
+else:
+    FINAL_TARGET = 'dist/plugins'
deleted file mode 100644
--- a/dom/plugins/test/testplugin/thirdplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# 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/.
-
-RELATIVE_PATH=..
-COCOA_NAME=ThirdTest
-include @srcdir@/../testplugin.mk
--- a/dom/plugins/test/testplugin/thirdplugin/moz.build
+++ b/dom/plugins/test/testplugin/thirdplugin/moz.build
@@ -2,9 +2,10 @@
 # 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/.
 
 SharedLibrary('npthirdtest')
 
 relative_path = 'thirdplugin'
+cocoa_name = 'ThirdTest'
 include('../testplugin.mozbuild')
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -701,23 +701,25 @@ nsCSPContext::logToConsole(const char16_
 void
 StripURIForReporting(nsIURI* aURI,
                      nsIPrincipal* aProtectedResourcePrincipal,
                      nsACString& outStrippedURI)
 {
   // 1) If the origin of uri is a globally unique identifier (for example,
   // aURI has a scheme of data, blob, or filesystem), then return the
   // ASCII serialization of uri’s scheme.
-  bool isHttp =
-    (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttp)) && isHttp) ||
-    (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttp)) && isHttp);
-  if (!isHttp) {
+  bool isHttpOrFtp =
+    (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpOrFtp)) && isHttpOrFtp) ||
+    (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpOrFtp)) && isHttpOrFtp) ||
+    (NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpOrFtp)) && isHttpOrFtp);
+
+  if (!isHttpOrFtp) {
     // not strictly spec compliant, but what we really care about is
-    // http/https. If it's not http/https, then treat aURI as if
-    // it's a globally unique identifier and just return the scheme.
+    // http/https and also ftp. If it's not http/https or ftp, then treat aURI
+    // as if it's a globally unique identifier and just return the scheme.
     aURI->GetScheme(outStrippedURI);
     return;
   }
 
   // 2) If the origin of uri is not the same as the origin of the protected
   // resource, then return the ASCII serialization of uri’s origin.
   bool sameOrigin =
     NS_SUCCEEDED(aProtectedResourcePrincipal->CheckMayLoad(aURI, false, false));
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -207,9 +207,18 @@ function run_test() {
   makeTest(7, {"blocked-uri": selfSpec}, false,
     function(csp) {
       var uri = NetUtil
       // shouldLoad creates and sends out the report here.
       csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
                      NetUtil.newURI(selfSpec + "#bar"),
                      null, null, null, null);
       });
+
+  // test scheme of ftp:
+  makeTest(8, {"blocked-uri": "ftp://blocked.test"}, false,
+    function(csp) {
+      // shouldLoad creates and sends out the report here.
+      csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
+                    NetUtil.newURI("ftp://blocked.test/profile.png"),
+                    null, null, null, null);
+    });
 }
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -5087,17 +5087,17 @@ nsEditor::IsAcceptableInputEvent(nsIDOME
       // WidgetCompositionEvent.
       widgetGUIEvent = aEvent->WidgetEventPtr()->AsCompositionEvent();
       needsWidget = true;
       break;
     default:
       break;
   }
   if (needsWidget &&
-      (!widgetGUIEvent || !widgetGUIEvent->widget)) {
+      (!widgetGUIEvent || !widgetGUIEvent->mWidget)) {
     return false;
   }
 
   // Accept all trusted events.
   if (widgetEvent->IsTrusted()) {
     return true;
   }
 
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -639,17 +639,17 @@ nsEditorEventListener::KeyPress(nsIDOMKe
     return NS_OK;
   }
 
   // Now, ask the native key bindings to handle the event.
   WidgetKeyboardEvent* keyEvent =
     aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   MOZ_ASSERT(keyEvent,
              "DOM key event's internal event must be WidgetKeyboardEvent");
-  nsIWidget* widget = keyEvent->widget;
+  nsIWidget* widget = keyEvent->mWidget;
   // If the event is created by chrome script, the widget is always nullptr.
   if (!widget) {
     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     nsPresContext* pc = ps ? ps->GetPresContext() : nullptr;
     widget = pc ? pc->GetNearestWidget() : nullptr;
     NS_ENSURE_TRUE(widget, NS_OK);
   }
 
--- a/embedding/components/printingui/win/nsPrintDialogUtil.cpp
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp
@@ -50,16 +50,18 @@ WIN_LIBS=                               
 #include "nsIStringBundle.h"
 
 // For NS_CopyUnicodeToNative
 #include "nsNativeCharsetUtils.h"
 
 // This is for extending the dialog
 #include <dlgs.h>
 
+#include "nsWindowsHelpers.h"
+
 // Default labels for the radio buttons
 static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen";
 static const char* kTheSelectedFrameStr  = "The selected &frame";
 static const char* kEachFrameSeparately  = "&Each frame separately";
 
 
 //-----------------------------------------------
 // Global Data
@@ -457,89 +459,81 @@ static UINT CALLBACK PrintHookProc(HWND 
 //----------------------------------------------------------------------------------
 // Returns a Global Moveable Memory Handle to a DevMode
 // from the Printer by the name of aPrintName
 //
 // NOTE:
 //   This function assumes that aPrintName has already been converted from 
 //   unicode
 //
-HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
+static nsReturnRef<nsHGLOBAL>
+CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName,
+                           nsIPrintSettings* aPS)
 {
-  HGLOBAL hGlobalDevMode = nullptr;
-
-  HANDLE hPrinter = nullptr;
+  nsHPRINTER hPrinter = nullptr;
   // const cast kludge for silly Win32 api's
   LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
   BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
-  if (status) {
-
-    LPDEVMODEW  pNewDevMode;
-    DWORD       dwNeeded, dwRet;
-
-    // Get the buffer size
-    dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0);
-    if (dwNeeded == 0) {
-      return nullptr;
-    }
-
-    // Allocate a buffer of the correct size.
-    pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
-    if (!pNewDevMode) return nullptr;
+  if (!status) {
+    return nsReturnRef<nsHGLOBAL>();
+  }
 
-    hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded);
-    if (!hGlobalDevMode) {
-      ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
-      return nullptr;
-    }
-
-    dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER);
-
-    if (dwRet != IDOK) {
-      ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
-      ::GlobalFree(hGlobalDevMode);
-      ::ClosePrinter(hPrinter);
-      return nullptr;
-    }
+  // Make sure hPrinter is closed on all paths
+  nsAutoPrinter autoPrinter(hPrinter);
 
-    // Lock memory and copy contents from DEVMODE (current printer)
-    // to Global Memory DEVMODE
-    LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode);
-    if (devMode) {
-      memcpy(devMode, pNewDevMode, dwNeeded);
-      // Initialize values from the PrintSettings
-      nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
-      MOZ_ASSERT(psWin);
-      psWin->CopyToNative(devMode);
+  // Get the buffer size
+  DWORD dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr,
+                                         nullptr, 0);
+  if (dwNeeded == 0) {
+    return nsReturnRef<nsHGLOBAL>();
+  }
 
-      // Sets back the changes we made to the DevMode into the Printer Driver
-      dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER);
-      if (dwRet != IDOK) {
-        ::GlobalUnlock(hGlobalDevMode);
-        ::GlobalFree(hGlobalDevMode);
-        ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
-        ::ClosePrinter(hPrinter);
-        return nullptr;
-      }
+  // Allocate a buffer of the correct size.
+  nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                                   dwNeeded));
+  if (!newDevMode) {
+    return nsReturnRef<nsHGLOBAL>();
+  }
 
-      ::GlobalUnlock(hGlobalDevMode);
-    } else {
-      ::GlobalFree(hGlobalDevMode);
-      hGlobalDevMode = nullptr;
-    }
-
-    ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
-
-    ::ClosePrinter(hPrinter);
-
-  } else {
-    return nullptr;
+  nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded);
+  nsAutoGlobalMem globalDevMode(hDevMode);
+  if (!hDevMode) {
+    return nsReturnRef<nsHGLOBAL>();
   }
 
-  return hGlobalDevMode;
+  DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode,
+                                      nullptr, DM_OUT_BUFFER);
+  if (dwRet != IDOK) {
+    return nsReturnRef<nsHGLOBAL>();
+  }
+
+  // Lock memory and copy contents from DEVMODE (current printer)
+  // to Global Memory DEVMODE
+  LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode);
+  if (!devMode) {
+    return nsReturnRef<nsHGLOBAL>();
+  }
+
+  memcpy(devMode, newDevMode.get(), dwNeeded);
+  // Initialize values from the PrintSettings
+  nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
+  MOZ_ASSERT(psWin);
+  psWin->CopyToNative(devMode);
+
+  // Sets back the changes we made to the DevMode into the Printer Driver
+  dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode,
+                                DM_IN_BUFFER | DM_OUT_BUFFER);
+  if (dwRet != IDOK) {
+    ::GlobalUnlock(hDevMode);
+    return nsReturnRef<nsHGLOBAL>();
+  }
+
+  ::GlobalUnlock(hDevMode);
+
+  return globalDevMode.out();
 }
 
 //------------------------------------------------------------------
 // helper
 static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName)
 {
   nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1");
   if (prtEnum) {
@@ -571,73 +565,69 @@ static nsresult
 ShowNativePrintDialog(HWND              aHWnd,
                       nsIPrintSettings* aPrintSettings)
 {
   //NS_ENSURE_ARG_POINTER(aHWnd);
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   gDialogWasExtended  = false;
 
-  HGLOBAL hGlobalDevMode = nullptr;
-  HGLOBAL hDevNames      = nullptr;
-
   // Get the Print Name to be used
   nsXPIDLString printerName;
   aPrintSettings->GetPrinterName(getter_Copies(printerName));
 
   // If there is no name then use the default printer
   if (printerName.IsEmpty()) {
     GetDefaultPrinterNameFromGlobalPrinters(printerName);
   } else {
     HANDLE hPrinter = nullptr;
-    if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())), &hPrinter, nullptr)) {
+    if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())),
+                       &hPrinter, nullptr)) {
       // If the last used printer is not found, we should use default printer.
       GetDefaultPrinterNameFromGlobalPrinters(printerName);
     } else {
       ::ClosePrinter(hPrinter);
     }
   }
 
   // Now create a DEVNAMES struct so the the dialog is initialized correctly.
 
   uint32_t len = printerName.Length();
-  hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + 
-                                     sizeof(DEVNAMES));
+  nsHGLOBAL hDevNames = ::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1)
+                                      + sizeof(DEVNAMES));
+  nsAutoGlobalMem autoDevNames(hDevNames);
   if (!hDevNames) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames);
   if (!pDevNames) {
-    ::GlobalFree(hDevNames);
     return NS_ERROR_FAILURE;
   }
   pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len;
   pDevNames->wDefault      = 0;
 
   memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t));
   ::GlobalUnlock(hDevNames);
 
   // Create a Moveable Memory Object that holds a new DevMode
   // from the Printer Name
   // The PRINTDLG.hDevMode requires that it be a moveable memory object
-  // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled
-  // When the user prints, it comes back in the printdlg struct and 
-  // is used and cleaned up later
-  hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings);
+  // NOTE: autoDevMode is automatically freed when any error occurred
+  nsAutoGlobalMem autoDevMode(CreateGlobalDevModeAndInit(printerName, aPrintSettings));
 
   // Prepare to Display the Print Dialog
   PRINTDLGW  prntdlg;
   memset(&prntdlg, 0, sizeof(PRINTDLGW));
 
   prntdlg.lStructSize = sizeof(prntdlg);
   prntdlg.hwndOwner   = aHWnd;
-  prntdlg.hDevMode    = hGlobalDevMode;
+  prntdlg.hDevMode    = autoDevMode.get();
   prntdlg.hDevNames   = hDevNames;
   prntdlg.hDC         = nullptr;
   prntdlg.Flags       = PD_ALLPAGES | PD_RETURNIC | 
                         PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE;
 
   // if there is a current selection then enable the "Selection" radio button
   int16_t howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone;
   bool isOn;
@@ -677,23 +667,21 @@ ShowNativePrintDialog(HWND              
 
   BOOL result = ::PrintDlgW(&prntdlg);
 
   if (TRUE == result) {
     // check to make sure we don't have any nullptr pointers
     NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE);
 
     if (prntdlg.hDevNames == nullptr) {
-      ::GlobalFree(hGlobalDevMode);
       return NS_ERROR_FAILURE;
     }
     // Lock the deviceNames and check for nullptr
     DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames);
     if (devnames == nullptr) {
-      ::GlobalFree(hGlobalDevMode);
       return NS_ERROR_FAILURE;
     }
 
     char16_t* device = &(((char16_t *)devnames)[devnames->wDeviceOffset]);
     char16_t* driver = &(((char16_t *)devnames)[devnames->wDriverOffset]);
 
     // Check to see if the "Print To File" control is checked
     // then take the name from devNames and set it in the PrintSettings
@@ -711,17 +699,16 @@ ShowNativePrintDialog(HWND              
     } else {
       // clear "print to file" info
       aPrintSettings->SetPrintToFile(false);
       aPrintSettings->SetToFileName(nullptr);
     }
 
     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
     if (!psWin) {
-      ::GlobalFree(hGlobalDevMode);
       return NS_ERROR_FAILURE;
     }
 
     // Setup local Data members
     psWin->SetDeviceName(device);
     psWin->SetDriverName(driver);
 
 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
@@ -767,17 +754,16 @@ ShowNativePrintDialog(HWND              
       aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames);
     }
     // Unlock DeviceNames
     ::GlobalUnlock(prntdlg.hDevNames);
 
     // Transfer the settings from the native data to the PrintSettings
     LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode);
     if (!devMode || !prntdlg.hDC) {
-      ::GlobalFree(hGlobalDevMode);
       return NS_ERROR_FAILURE;
     }
     psWin->SetDevMode(devMode); // copies DevMode
     psWin->CopyFromNative(prntdlg.hDC, devMode);
     ::GlobalUnlock(prntdlg.hDevMode);
     ::DeleteDC(prntdlg.hDC);
 
 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
@@ -800,17 +786,16 @@ ShowNativePrintDialog(HWND              
     } else {
       printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum);
     }
 #endif
     
   } else {
     ::SetFocus(aHWnd);
     aPrintSettings->SetIsCancelled(true);
-    if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode);
     return NS_ERROR_ABORT;
   }
 
   return NS_OK;
 }
 
 //------------------------------------------------------------------
 static void 
--- a/embedding/components/printingui/win/nsPrintDialogUtil.h
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.h
@@ -4,11 +4,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsFlyOwnDialog_h___
 #define nsFlyOwnDialog_h___
 
 nsresult NativeShowPrintDialog(HWND                aHWnd,
                                nsIWebBrowserPrint* aWebBrowserPrint,
                                nsIPrintSettings*   aPrintSettings);
 
-HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS);
-
 #endif /* nsFlyOwnDialog_h___ */
--- a/gfx/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -32,24 +32,16 @@ public:
   /**
    * Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
    * Implementations per-platform are responsible for actually handling this.
    * This method will always be called on the Gecko main thread.
    */
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
 
   /**
-   * Acknowledges the recipt of a scroll offset update for the scrollable
-   * frame with the given scroll id. This is used to maintain consistency
-   * between APZ and other sources of scroll changes.
-   */
-  virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                       const uint32_t& aScrollGeneration) = 0;
-
-  /**
    * Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
    * the current scroll offset. This should eventually round-trip back to
    * AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
    * to.
    */
   virtual void HandleDoubleTap(const CSSPoint& aPoint,
                                Modifiers aModifiers,
                                const ScrollableLayerGuid& aGuid) = 0;
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3452,17 +3452,17 @@ void AsyncPanZoomController::NotifyLayer
 
   if ((aIsFirstPaint && aThisLayerTreeUpdated) || isDefault) {
     // Initialize our internal state to something sane when the content
     // that was just painted is something we knew nothing about previously
     CancelAnimation();
 
     mScrollMetadata = aScrollMetadata;
     if (scrollOffsetUpdated) {
-      AcknowledgeScrollUpdate();
+      needContentRepaint = true;
     }
     mExpectedGeckoMetrics = aLayerMetrics;
     ShareCompositorFrameMetrics();
 
     if (mFrameMetrics.GetDisplayPortMargins() != ScreenMargin()) {
       // A non-zero display port margin here indicates a displayport has
       // been set by a previous APZC for the content at this guid. The
       // scrollable rect may have changed since then, making the margins
@@ -3527,17 +3527,16 @@ void AsyncPanZoomController::NotifyLayer
       // Send an acknowledgement with the new scroll generation so that any
       // repaint requests later in this function go through.
       // Because of the scroll generation update, any inflight paint requests are
       // going to be ignored by layout, and so mExpectedGeckoMetrics
       // becomes incorrect for the purposes of calculating the LD transform. To
       // correct this we need to update mExpectedGeckoMetrics to be the
       // last thing we know was painted by Gecko.
       mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
-      AcknowledgeScrollUpdate();
       mExpectedGeckoMetrics = aLayerMetrics;
 
       // Cancel the animation (which might also trigger a repaint request)
       // after we update the scroll offset above. Otherwise we can be left
       // in a state where things are out of sync.
       CancelAnimation();
 
       // Since the scroll offset has changed, we need to recompute the
@@ -3559,43 +3558,28 @@ void AsyncPanZoomController::NotifyLayer
     APZC_LOG("%p smooth scrolling from %s to %s in state %d\n", this,
       Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
       Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str(),
       mState);
 
     // See comment on the similar code in the |if (scrollOffsetUpdated)| block
     // above.
     mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
-    AcknowledgeScrollUpdate();
+    needContentRepaint = true;
     mExpectedGeckoMetrics = aLayerMetrics;
 
     SmoothScrollTo(mFrameMetrics.GetSmoothScrollOffset());
   }
 
   if (needContentRepaint) {
     RequestContentRepaint();
   }
   UpdateSharedCompositorFrameMetrics();
 }
 
-void
-AsyncPanZoomController::AcknowledgeScrollUpdate() const
-{
-  // Once layout issues a scroll offset update, it becomes impervious to
-  // scroll offset updates from APZ until we acknowledge the update it sent.
-  // This prevents APZ updates from clobbering scroll updates from other
-  // more "legitimate" sources like content scripts.
-  RefPtr<GeckoContentController> controller = GetGeckoContentController();
-  if (controller) {
-    APZC_LOG("%p sending scroll update acknowledgement with gen %u\n", this, mFrameMetrics.GetScrollGeneration());
-    controller->AcknowledgeScrollUpdate(mFrameMetrics.GetScrollId(),
-                                        mFrameMetrics.GetScrollGeneration());
-  }
-}
-
 const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() const {
   mMonitor.AssertCurrentThreadIn();
   return mFrameMetrics;
 }
 
 APZCTreeManager* AsyncPanZoomController::GetApzcTreeManager() const {
   mMonitor.AssertNotCurrentThreadIn();
   return mTreeManager;
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -891,18 +891,16 @@ private:
   // Start an overscroll animation with the given initial velocity.
   void StartOverscrollAnimation(const ParentLayerPoint& aVelocity);
 
   void SmoothScrollTo(const CSSPoint& aDestination);
 
   // Returns whether overscroll is allowed during an event.
   bool AllowScrollHandoffInCurrentBlock() const;
 
-  void AcknowledgeScrollUpdate() const;
-
   /* ===================================================================
    * The functions and members in this section are used to make ancestor chains
    * out of APZC instances. These chains can only be walked or manipulated
    * while holding the lock in the associated APZCTreeManager instance.
    */
 public:
   void SetParent(AsyncPanZoomController* aParent) {
     mParent = aParent;
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -119,19 +119,19 @@ ScrollFrameTo(nsIScrollableFrame* aFrame
  */
 static void
 ScrollFrame(nsIContent* aContent,
             FrameMetrics& aMetrics)
 {
   // Scroll the window to the desired spot
   nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
   if (sf) {
+    sf->ResetScrollInfoIfGeneration(aMetrics.GetScrollGeneration());
     sf->SetScrollableByAPZ(!aMetrics.IsScrollInfoLayer());
   }
-
   bool scrollUpdated = false;
   CSSPoint apzScrollOffset = aMetrics.GetScrollOffset();
   CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated);
 
   if (scrollUpdated) {
     if (aMetrics.IsScrollInfoLayer()) {
       // In cases where the APZ scroll offset is different from the content scroll
       // offset, we want to interpret the margins as relative to the APZ scroll
@@ -325,64 +325,16 @@ APZCCallbackHelper::InitializeRootDispla
     // nsRootBoxFrame::BuildDisplayList.
     nsLayoutUtils::SetDisplayPortMargins(content, aPresShell, ScreenMargin(), 0,
         nsLayoutUtils::RepaintMode::DoNotRepaint);
     nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
         content->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::DoNotRepaint);
   }
 }
 
-class AcknowledgeScrollUpdateEvent : public nsRunnable
-{
-    typedef mozilla::layers::FrameMetrics::ViewID ViewID;
-
-public:
-    AcknowledgeScrollUpdateEvent(const ViewID& aScrollId, const uint32_t& aScrollGeneration)
-        : mScrollId(aScrollId)
-        , mScrollGeneration(aScrollGeneration)
-    {
-    }
-
-    NS_IMETHOD Run() {
-        MOZ_ASSERT(NS_IsMainThread());
-
-        nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
-        if (sf) {
-            sf->ResetScrollInfoIfGeneration(mScrollGeneration);
-        }
-
-        // Since the APZ and content are in sync, we need to clear any callback transform
-        // that might have been set on the last repaint request (which might have failed
-        // due to the inflight scroll update that this message is acknowledging).
-        nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mScrollId);
-        if (content) {
-            content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(),
-                                 nsINode::DeleteProperty<CSSPoint>);
-        }
-
-        return NS_OK;
-    }
-
-protected:
-    ViewID mScrollId;
-    uint32_t mScrollGeneration;
-};
-
-void
-APZCCallbackHelper::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                            const uint32_t& aScrollGeneration)
-{
-    nsCOMPtr<nsIRunnable> r1 = new AcknowledgeScrollUpdateEvent(aScrollId, aScrollGeneration);
-    if (!NS_IsMainThread()) {
-        NS_DispatchToMainThread(r1);
-    } else {
-        r1->Run();
-    }
-}
-
 nsIPresShell*
 APZCCallbackHelper::GetRootContentDocumentPresShellForContent(nsIContent* aContent)
 {
     nsIDocument* doc = aContent->GetComposedDoc();
     if (!doc) {
         return nullptr;
     }
     nsIPresShell* shell = doc->GetShell();
@@ -509,44 +461,43 @@ APZCCallbackHelper::ApplyCallbackTransfo
         aEvent.refPoint, aGuid, aScale);
   }
 }
 
 nsEventStatus
 APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
 {
   nsEventStatus status = nsEventStatus_eConsumeNoDefault;
-  if (aEvent.widget) {
-    aEvent.widget->DispatchEvent(&aEvent, status);
+  if (aEvent.mWidget) {
+    aEvent.mWidget->DispatchEvent(&aEvent, status);
   }
   return status;
 }
 
 nsEventStatus
 APZCCallbackHelper::DispatchSynthesizedMouseEvent(EventMessage aMsg,
                                                   uint64_t aTime,
                                                   const LayoutDevicePoint& aRefPoint,
                                                   Modifiers aModifiers,
                                                   nsIWidget* aWidget)
 {
   MOZ_ASSERT(aMsg == eMouseMove || aMsg == eMouseDown ||
              aMsg == eMouseUp || aMsg == eMouseLongTap);
 
-  WidgetMouseEvent event(true, aMsg, nullptr,
+  WidgetMouseEvent event(true, aMsg, aWidget,
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
   event.mTime = aTime;
   event.button = WidgetMouseEvent::eLeftButton;
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   event.ignoreRootScrollFrame = true;
   if (aMsg != eMouseMove) {
     event.clickCount = 1;
   }
   event.mModifiers = aModifiers;
-  event.widget = aWidget;
 
   return DispatchWidgetEvent(event);
 }
 
 bool
 APZCCallbackHelper::DispatchMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
                                        const nsString& aType,
                                        const CSSPoint& aPoint,
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -61,21 +61,16 @@ public:
     static bool GetOrCreateScrollIdentifiers(nsIContent* aContent,
                                              uint32_t* aPresShellIdOut,
                                              FrameMetrics::ViewID* aViewIdOut);
 
     /* Initialize a zero-margin displayport on the root document element of the
        given presShell. */
     static void InitializeRootDisplayport(nsIPresShell* aPresShell);
 
-    /* Tell layout that we received the scroll offset update for the given view ID, so
-       that it accepts future scroll offset updates from APZ. */
-    static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                        const uint32_t& aScrollGeneration);
-
     /* Get the pres shell associated with the root content document enclosing |aContent|. */
     static nsIPresShell* GetRootContentDocumentPresShellForContent(nsIContent* aContent);
 
     /* Apply an "input transform" to the given |aInput| and return the transformed value.
        The input transform applied is the one for the content element corresponding to
        |aGuid|; this is populated in a previous call to UpdateCallbackTransform. See that
        method's documentations for details.
        This method additionally adjusts |aInput| by inversely scaling by the provided
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -323,17 +323,17 @@ APZEventState::ProcessTouchEvent(const W
     cancelEvent.mMessage = eTouchCancel;
     cancelEvent.mFlags.mCancelable = false; // mMessage != eTouchCancel;
     for (uint32_t i = 0; i < cancelEvent.mTouches.Length(); ++i) {
       if (mozilla::dom::Touch* touch = cancelEvent.mTouches[i]) {
         touch->convertToPointer = true;
       }
     }
     nsEventStatus status;
-    cancelEvent.widget->DispatchEvent(&cancelEvent, status);
+    cancelEvent.mWidget->DispatchEvent(&cancelEvent, status);
   }
 }
 
 void
 APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  uint64_t aInputBlockId)
 {
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -64,23 +64,16 @@ ChromeProcessController::RequestContentR
 
 void
 ChromeProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
 {
   MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
 }
 
 void
-ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                                 const uint32_t& aScrollGeneration)
-{
-  APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-}
-
-void
 ChromeProcessController::Destroy()
 {
   if (MessageLoop::current() != mUILoop) {
     mUILoop->PostTask(
       FROM_HERE,
       NewRunnableMethod(this, &ChromeProcessController::Destroy));
     return;
   }
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -35,19 +35,16 @@ protected:
 public:
   explicit ChromeProcessController(nsIWidget* aWidget, APZEventState* aAPZEventState, APZCTreeManager* aAPZCTreeManager);
   ~ChromeProcessController();
   virtual void Destroy() override;
 
   // GeckoContentController interface
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) override;
-  virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                       const uint32_t& aScrollGeneration) override;
-
   virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
                                const ScrollableLayerGuid& aGuid) override;
   virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
                                const ScrollableLayerGuid& aGuid) override;
   virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
                                const ScrollableLayerGuid& aGuid,
                                uint64_t aInputBlockId) override;
   virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
--- a/gfx/layers/ipc/APZChild.cpp
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -90,24 +90,16 @@ APZChild::~APZChild()
 
 bool
 APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   return mBrowser->UpdateFrame(aFrameMetrics);
 }
 
 bool
-APZChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
-                                      const uint32_t& aScrollGeneration)
-{
-  APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-  return true;
-}
-
-bool
 APZChild::RecvHandleDoubleTap(const CSSPoint& aPoint,
                               const Modifiers& aModifiers,
                               const ScrollableLayerGuid& aGuid)
 {
   mBrowser->HandleDoubleTap(aPoint, aModifiers, aGuid);
   return true;
 }
 
--- a/gfx/layers/ipc/APZChild.h
+++ b/gfx/layers/ipc/APZChild.h
@@ -23,19 +23,16 @@ class APZChild final : public PAPZChild
 {
 public:
   static APZChild* Create(const dom::TabId& aTabId);
 
   ~APZChild();
 
   virtual bool RecvUpdateFrame(const FrameMetrics& frame) override;
 
-  virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
-                                           const uint32_t& aScrollGeneration) override;
-
   virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
                                    const Modifiers& aModifiers,
                                    const ScrollableLayerGuid& aGuid) override;
 
   virtual bool RecvHandleSingleTap(const CSSPoint& aPoint,
                                    const Modifiers& aModifiers,
                                    const ScrollableLayerGuid& aGuid,
                                    const bool& aCallTakeFocusForClickFromTap) override;
--- a/gfx/layers/ipc/PAPZ.ipdl
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -84,17 +84,16 @@ parent:
                               MaybeZoomConstraints aConstraints);
 
 child:
   async UpdateFrame(FrameMetrics frame);
 
   // The following methods correspond to functions on the GeckoContentController
   // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
   // in that file for these functions.
-  async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
   async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
   async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap);
   async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
   async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);
   async NotifyFlushComplete();
 
   async __delete__();
 };
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -47,34 +47,16 @@ RemoteContentController::RequestContentR
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (CanSend()) {
     Unused << SendUpdateFrame(aFrameMetrics);
   }
 }
 
 void
-RemoteContentController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                                 const uint32_t& aScrollGeneration)
-{
-  if (MessageLoop::current() != mUILoop) {
-    // We have to send this message from the "UI thread" (main
-    // thread).
-    mUILoop->PostTask(
-      FROM_HERE,
-      NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate,
-                        aScrollId, aScrollGeneration));
-    return;
-  }
-  if (CanSend()) {
-    Unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-  }
-}
-
-void
 RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint,
                                          Modifiers aModifiers,
                                          const ScrollableLayerGuid& aGuid)
 {
   if (MessageLoop::current() != mUILoop) {
     // We have to send this message from the "UI thread" (main
     // thread).
     mUILoop->PostTask(
--- a/gfx/layers/ipc/RemoteContentController.h
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -37,19 +37,16 @@ public:
   explicit RemoteContentController(uint64_t aLayersId,
                                    dom::TabParent* aBrowserParent);
 
   virtual ~RemoteContentController();
 
   // Needs to be called on the main thread.
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
 
-  virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                       const uint32_t& aScrollGeneration) override;
-
   virtual void HandleDoubleTap(const CSSPoint& aPoint,
                                Modifiers aModifiers,
                                const ScrollableLayerGuid& aGuid) override;
 
   virtual void HandleSingleTap(const CSSPoint& aPoint,
                                Modifiers aModifiers,
                                const ScrollableLayerGuid& aGuid) override;
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -130,16 +130,19 @@ private:
   };
 
   // This is where DECL_GFX_PREF for each of the preferences should go.
   // We will keep these in an alphabetical order to make it easier to see if
   // a method accessing a pref already exists. Just add yours in the list.
 
   // It's a short time fix, and will be removed after landing bug 1206637.
   DECL_GFX_PREF(Live, "accessibility.monoaudio.enable",        MonoAudio, bool, false);
+  DECL_GFX_PREF(Live, "media.resampling.enabled",              AudioSinkResampling, bool, false);
+  DECL_GFX_PREF(Live, "media.resampling.rate",                 AudioSinkResampleRate, uint32_t, 48000);
+  DECL_GFX_PREF(Live, "media.forcestereo.enabled",             AudioSinkForceStereo, bool, true);
 
   // The apz prefs are explained in AsyncPanZoomController.cpp
   DECL_GFX_PREF(Live, "apz.allow_checkerboarding",             APZAllowCheckerboarding, bool, true);
   DECL_GFX_PREF(Live, "apz.allow_immediate_handoff",           APZAllowImmediateHandoff, bool, true);
   DECL_GFX_PREF(Live, "apz.allow_zooming",                     APZAllowZooming, bool, false);
   DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle",          APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
   DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold",      APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
   DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle",        APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -76,16 +76,26 @@ Unify(ExprType one, ExprType two)
         return two;
     if (two == AnyType)
         return one;
     if (one == two)
         return one;
     return ExprType::Void;
 }
 
+static bool
+IsI64Implemented()
+{
+#ifdef JS_CPU_X64
+        return true;
+#else
+        return false;
+#endif
+}
+
 class FunctionDecoder
 {
     JSContext* cx_;
     Decoder& d_;
     ModuleGenerator& mg_;
     FunctionGenerator& fg_;
     uint32_t funcIndex_;
     const ValTypeVector& locals_;
@@ -103,21 +113,19 @@ class FunctionDecoder
     uint32_t funcIndex() const { return funcIndex_; }
     const ValTypeVector& locals() const { return locals_; }
     const DeclaredSig& sig() const { return mg_.funcSig(funcIndex_); }
 
     bool fail(const char* str) {
         return Fail(cx_, d_, str);
     }
     bool checkI64Support() {
-#ifdef JS_CPU_X64
+        if (!IsI64Implemented())
+            return fail("i64 NYI on this platform");
         return true;
-#else
-        return fail("i64 NYI on this platform");
-#endif
     }
 
     MOZ_WARN_UNUSED_RESULT bool pushBlock() {
         return blocks_.append(AnyType);
     }
     ExprType popBlock() {
         return blocks_.popCopy();
     }
@@ -1068,24 +1076,26 @@ DecodeFunctionTable(JSContext* cx, Decod
     }
 
     return true;
 }
 
 static bool
 CheckTypeForJS(JSContext* cx, Decoder& d, const Sig& sig)
 {
+    bool allowI64 = IsI64Implemented() && JitOptions.wasmTestMode;
+
     for (ValType argType : sig.args()) {
-        if (argType == ValType::I64)
+        if (argType == ValType::I64 && !allowI64)
             return Fail(cx, d, "cannot import/export i64 argument");
         if (IsSimdType(argType))
             return Fail(cx, d, "cannot import/export SIMD argument");
     }
 
-    if (sig.ret() == ExprType::I64)
+    if (sig.ret() == ExprType::I64 && !allowI64)
         return Fail(cx, d, "cannot import/export i64 return type");
     if (IsSimdType(sig.ret()))
         return Fail(cx, d, "cannot import/export SIMD return type");
 
     return true;
 }
 
 struct ImportName
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -953,41 +953,65 @@ class FunctionCompiler
   private:
     static bool hasPushed(MBasicBlock* block)
     {
         uint32_t numPushed = block->stackDepth() - block->info().firstStackSlot();
         MOZ_ASSERT(numPushed == 0 || numPushed == 1);
         return numPushed;
     }
 
+    static MDefinition* peekPushedDef(MBasicBlock* block)
+    {
+        MOZ_ASSERT(hasPushed(block));
+        return block->getSlot(block->stackDepth() - 1);
+    }
+
   public:
     void pushDef(MDefinition* def)
     {
         if (inDeadCode())
             return;
         MOZ_ASSERT(!hasPushed(curBlock_));
         if (def && def->type() != MIRType_None)
             curBlock_->push(def);
     }
 
+    MDefinition* popDefIfPushed()
+    {
+        if (!hasPushed(curBlock_))
+            return nullptr;
+        MDefinition* def = curBlock_->pop();
+        MOZ_ASSERT(def->type() != MIRType_Value);
+        return def;
+    }
+
     template <typename GetBlock>
     void ensurePushInvariants(const GetBlock& getBlock, size_t numBlocks)
     {
-        // Preserve the invariant that, for every iterated MBasicBlock,
-        // either: every MBasicBlock has a non-void pushed expression OR no
-        // MBasicBlock has any pushed expression. This is required by
-        // MBasicBlock::addPredecessor.
-        bool allPushed = true;
-
-        for (size_t i = 0; allPushed && i < numBlocks; i++)
-            allPushed = hasPushed(getBlock(i));
+        // Preserve the invariant that, for every iterated MBasicBlock, either:
+        // every MBasicBlock has a pushed expression with the same type (to
+        // prevent creating phis with type Value) OR no MBasicBlock has any
+        // pushed expression. This is required by MBasicBlock::addPredecessor.
+        if (numBlocks < 2)
+            return;
+
+        MBasicBlock* block = getBlock(0);
+
+        bool allPushed = hasPushed(block);
+        if (allPushed) {
+            MIRType type = peekPushedDef(block)->type();
+            for (size_t i = 1; allPushed && i < numBlocks; i++) {
+                block = getBlock(i);
+                allPushed = hasPushed(block) && peekPushedDef(block)->type() == type;
+            }
+        }
 
         if (!allPushed) {
             for (size_t i = 0; i < numBlocks; i++) {
-                MBasicBlock* block = getBlock(i);
+                block = getBlock(i);
                 if (hasPushed(block))
                     block->pop();
             }
         }
     }
 
     bool joinIf(MBasicBlock* joinBlock, BlockVector* blocks, MDefinition** def)
     {
@@ -1029,20 +1053,17 @@ class FunctionCompiler
         if (!goToNewBlock((*blocks)[0], &join))
             return false;
         for (size_t i = 1; i < blocks->length(); i++) {
             if (!goToExistingBlock((*blocks)[i], join))
                 return false;
         }
 
         curBlock_ = join;
-        if (hasPushed(curBlock_))
-            *def = curBlock_->pop();
-        else
-            *def = nullptr;
+        *def = popDefIfPushed();
         return true;
     }
 
     bool startBlock()
     {
         MOZ_ASSERT_IF(blockDepth_ < blockPatches_.length(), blockPatches_[blockDepth_].empty());
         blockDepth_++;
         return true;
@@ -1352,17 +1373,17 @@ class FunctionCompiler
         MOZ_ASSERT(next);
         prev->end(MGoto::New(alloc(), next));
         return next->addPredecessor(alloc(), prev);
     }
 
     bool bindBranches(uint32_t absolute, MDefinition** def)
     {
         if (absolute >= blockPatches_.length() || blockPatches_[absolute].empty()) {
-            *def = !inDeadCode() && hasPushed(curBlock_) ? curBlock_->pop() : nullptr;
+            *def = inDeadCode() ? nullptr : popDefIfPushed();
             return true;
         }
 
         ControlFlowPatchVector& patches = blockPatches_[absolute];
 
         auto getBlock = [&](size_t i) -> MBasicBlock* {
             if (i < patches.length())
                 return patches[i].ins->block();
@@ -1395,17 +1416,17 @@ class FunctionCompiler
         MOZ_ASSERT_IF(curBlock_, !curBlock_->isMarked());
         for (uint32_t i = 0; i < join->numPredecessors(); i++)
             join->getPredecessor(i)->unmark();
 
         if (curBlock_ && !goToExistingBlock(curBlock_, join))
             return false;
         curBlock_ = join;
 
-        *def = hasPushed(curBlock_) ? curBlock_->pop() : nullptr;
+        *def = popDefIfPushed();
 
         patches.clear();
         return true;
     }
 };
 
 static bool
 EmitLiteral(FunctionCompiler& f, ValType type, MDefinition** def)
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -1269,16 +1269,34 @@ Module::deoptimizeImportExit(uint32_t im
 {
     MOZ_ASSERT(dynamicallyLinked_);
     const Import& import = imports()[importIndex];
     ImportExit& exit = importToExit(import);
     exit.code = code() + import.interpExitCodeOffset();
     exit.baselineScript = nullptr;
 }
 
+static JSObject*
+CreateI64Object(JSContext* cx, int64_t i64)
+{
+    RootedObject result(cx, JS_NewPlainObject(cx));
+    if (!result)
+        return nullptr;
+
+    RootedValue val(cx, Int32Value(uint32_t(i64)));
+    if (!JS_DefineProperty(cx, result, "low", val, JSPROP_ENUMERATE))
+        return nullptr;
+
+    val = Int32Value(uint32_t(i64 >> 32));
+    if (!JS_DefineProperty(cx, result, "high", val, JSPROP_ENUMERATE))
+        return nullptr;
+
+    return result;
+}
+
 bool
 Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
 {
     MOZ_ASSERT(dynamicallyLinked_);
 
     const Export& exp = exports()[exportIndex];
 
     // Enable/disable profiling in the Module to match the current global
@@ -1306,17 +1324,20 @@ Module::callExport(JSContext* cx, uint32
     for (unsigned i = 0; i < exp.sig().args().length(); ++i) {
         v = i < args.length() ? args[i] : UndefinedValue();
         switch (exp.sig().arg(i)) {
           case ValType::I32:
             if (!ToInt32(cx, v, (int32_t*)&coercedArgs[i]))
                 return false;
             break;
           case ValType::I64:
-            MOZ_CRASH("int64");
+            MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+            if (!ReadI64Object(cx, v, (int64_t*)&coercedArgs[i]))
+                return false;
+            break;
           case ValType::F32:
             if (!RoundFloat32(cx, v, (float*)&coercedArgs[i]))
                 return false;
             break;
           case ValType::F64:
             if (!ToNumber(cx, v, (double*)&coercedArgs[i]))
                 return false;
             break;
@@ -1369,85 +1390,125 @@ Module::callExport(JSContext* cx, uint32
         // returned instead.
         PlainObject* obj = NewBuiltinClassInstance<PlainObject>(cx);
         if (!obj)
             return false;
         args.rval().set(ObjectValue(*obj));
         return true;
     }
 
-    JSObject* simdObj;
+    void* retAddr = &coercedArgs[0];
+    JSObject* retObj = nullptr;
     switch (exp.sig().ret()) {
       case ExprType::Void:
         args.rval().set(UndefinedValue());
         break;
       case ExprType::I32:
-        args.rval().set(Int32Value(*(int32_t*)&coercedArgs[0]));
+        args.rval().set(Int32Value(*(int32_t*)retAddr));
         break;
       case ExprType::I64:
-        MOZ_CRASH("int64");
+        MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+        retObj = CreateI64Object(cx, *(int64_t*)retAddr);
+        if (!retObj)
+            return false;
+        break;
       case ExprType::F32:
+        // The entry stub has converted the F32 into a double for us.
       case ExprType::F64:
-        args.rval().set(NumberValue(*(double*)&coercedArgs[0]));
+        args.rval().set(NumberValue(*(double*)retAddr));
         break;
       case ExprType::I32x4:
-        simdObj = CreateSimd<Int32x4>(cx, (int32_t*)&coercedArgs[0]);
-        if (!simdObj)
+        retObj = CreateSimd<Int32x4>(cx, (int32_t*)retAddr);
+        if (!retObj)
             return false;
-        args.rval().set(ObjectValue(*simdObj));
         break;
       case ExprType::F32x4:
-        simdObj = CreateSimd<Float32x4>(cx, (float*)&coercedArgs[0]);
-        if (!simdObj)
+        retObj = CreateSimd<Float32x4>(cx, (float*)retAddr);
+        if (!retObj)
             return false;
-        args.rval().set(ObjectValue(*simdObj));
         break;
       case ExprType::B32x4:
-        simdObj = CreateSimd<Bool32x4>(cx, (int32_t*)&coercedArgs[0]);
-        if (!simdObj)
+        retObj = CreateSimd<Bool32x4>(cx, (int32_t*)retAddr);
+        if (!retObj)
             return false;
-        args.rval().set(ObjectValue(*simdObj));
         break;
       case ExprType::Limit:
         MOZ_CRASH("Limit");
     }
 
+    if (retObj)
+        args.rval().set(ObjectValue(*retObj));
+
     return true;
 }
 
 bool
-Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Value* argv,
+Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const uint64_t* argv,
                    MutableHandleValue rval)
 {
     MOZ_ASSERT(dynamicallyLinked_);
 
     const Import& import = imports()[importIndex];
 
     InvokeArgs args(cx);
     if (!args.init(argc))
         return false;
 
-    for (size_t i = 0; i < argc; i++)
-        args[i].set(argv[i]);
+    bool hasI64Arg = false;
+    MOZ_ASSERT(import.sig().args().length() == argc);
+    for (size_t i = 0; i < argc; i++) {
+        switch (import.sig().args()[i]) {
+          case ValType::I32:
+            args[i].set(Int32Value(*(int32_t*)&argv[i]));
+            break;
+          case ValType::F32:
+            args[i].set(JS::CanonicalizedDoubleValue(*(float*)&argv[i]));
+            break;
+          case ValType::F64:
+            args[i].set(JS::CanonicalizedDoubleValue(*(double*)&argv[i]));
+            break;
+          case ValType::I64: {
+            MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+            RootedObject obj(cx, CreateI64Object(cx, *(int64_t*)&argv[i]));
+            if (!obj)
+                return false;
+            args[i].set(ObjectValue(*obj));
+            hasI64Arg = true;
+            break;
+          }
+          case ValType::I32x4:
+          case ValType::F32x4:
+          case ValType::B32x4:
+          case ValType::Limit:
+            MOZ_CRASH("unhandled type in callImport");
+        }
+    }
 
     RootedValue fval(cx, ObjectValue(*importToExit(import).fun));
     RootedValue thisv(cx, UndefinedValue());
     if (!Call(cx, fval, thisv, args, rval))
         return false;
 
+    // Don't try to optimize if the function has at least one i64 arg or if
+    // it returns an int64. GenerateJitExit relies on this, as does the
+    // type inference code below in this function.
+    if (hasI64Arg || import.sig().ret() == ExprType::I64)
+        return true;
+
     ImportExit& exit = importToExit(import);
 
     // The exit may already have become optimized.
     void* jitExitCode = code() + import.jitExitCodeOffset();
     if (exit.code == jitExitCode)
         return true;
 
     // Test if the function is JIT compiled.
     if (!exit.fun->hasScript())
         return true;
+
     JSScript* script = exit.fun->nonLazyScript();
     if (!script->hasBaselineScript()) {
         MOZ_ASSERT(!script->hasIonScript());
         return true;
     }
 
     // Don't enable jit entry when we have a pending ion builder.
     // Take the interpreter path which will link it and enable
@@ -1468,17 +1529,17 @@ Module::callImport(JSContext* cx, uint32
     // the BaselineScript is discarded and when that happens the import exit is
     // patched back.
     if (!TypeScript::ThisTypes(script)->hasType(TypeSet::UndefinedType()))
         return true;
     for (uint32_t i = 0; i < exit.fun->nargs(); i++) {
         TypeSet::Type type = TypeSet::UnknownType();
         switch (import.sig().args()[i]) {
           case ValType::I32:   type = TypeSet::Int32Type(); break;
-          case ValType::I64:   MOZ_CRASH("NYI");
+          case ValType::I64:   MOZ_CRASH("can't happen because of above guard");
           case ValType::F32:   type = TypeSet::DoubleType(); break;
           case ValType::F64:   type = TypeSet::DoubleType(); break;
           case ValType::I32x4: MOZ_CRASH("NYI");
           case ValType::F32x4: MOZ_CRASH("NYI");
           case ValType::B32x4: MOZ_CRASH("NYI");
           case ValType::Limit: MOZ_CRASH("Limit");
         }
         if (!TypeScript::ArgTypes(script, i)->hasType(type))
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -595,17 +595,17 @@ class Module : public mozilla::LinkedLis
     bool callExport(JSContext* cx, uint32_t exportIndex, CallArgs args);
 
     // Initially, calls to imports in wasm code call out through the generic
     // callImport method. If the imported callee gets JIT compiled and the types
     // match up, callImport will patch the code to instead call through a thunk
     // directly into the JIT code. If the JIT code is released, the Module must
     // be notified so it can go back to the generic callImport.
 
-    bool callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Value* argv,
+    bool callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const uint64_t* argv,
                     MutableHandleValue rval);
     void deoptimizeImportExit(uint32_t importIndex);
 
     // At runtime, when $pc is in wasm function code (containsFunctionPC($pc)),
     // $pc may be moved abruptly to interrupt() or outOfBounds() by a signal
     // handler or SetContext() from another thread.
 
     uint8_t* interrupt() const { MOZ_ASSERT(staticallyLinked_); return interrupt_; }
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -130,16 +130,18 @@ wasm::GenerateEntry(MacroAssembler& masm
         masm.loadAsmJSHeapRegisterFromGlobalData();
 
     // Put the 'argv' argument into a non-argument/return register so that we
     // can use 'argv' while we fill in the arguments for the asm.js callee.
     // Also, save 'argv' on the stack so that we can recover it after the call.
     // Use a second non-argument/return register as temporary scratch.
     Register argv = ABIArgGenerator::NonArgReturnReg0;
     Register scratch = ABIArgGenerator::NonArgReturnReg1;
+    Register64 scratch64(scratch);
+
 #if defined(JS_CODEGEN_X86)
     masm.loadPtr(Address(masm.getStackPointer(), EntryFrameSize + masm.framePushed()), argv);
 #else
     masm.movePtr(IntArgReg0, argv);
 #endif
     masm.Push(argv);
 
     // Save the stack pointer to the saved non-volatile registers. We will use
@@ -159,19 +161,23 @@ wasm::GenerateEntry(MacroAssembler& masm
     masm.reserveStack(AlignBytes(StackArgBytes(sig.args()), AsmJSStackAlignment));
 
     // Copy parameters out of argv and into the registers/stack-slots specified by
     // the system ABI.
     for (ABIArgValTypeIter iter(sig.args()); !iter.done(); iter++) {
         unsigned argOffset = iter.index() * Module::SizeOfEntryArg;
         Address src(argv, argOffset);
         MIRType type = iter.mirType();
+        MOZ_ASSERT_IF(type == MIRType_Int64, JitOptions.wasmTestMode);
         switch (iter->kind()) {
           case ABIArg::GPR:
-            masm.load32(src, iter->gpr());
+            if (type == MIRType_Int32)
+                masm.load32(src, iter->gpr());
+            else if (type == MIRType_Int64)
+                masm.load64(src, iter->gpr64());
             break;
 #ifdef JS_CODEGEN_REGISTER_PAIR
           case ABIArg::GPR_PAIR:
             MOZ_CRASH("wasm uses hardfp for function calls.");
             break;
 #endif
           case ABIArg::FPU: {
             static_assert(Module::SizeOfEntryArg >= jit::Simd128DataSize,
@@ -197,16 +203,20 @@ wasm::GenerateEntry(MacroAssembler& masm
             break;
           }
           case ABIArg::Stack:
             switch (type) {
               case MIRType_Int32:
                 masm.load32(src, scratch);
                 masm.storePtr(scratch, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
                 break;
+              case MIRType_Int64:
+                masm.load64(src, scratch64);
+                masm.store64(scratch64, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
+                break;
               case MIRType_Double:
                 masm.loadDouble(src, ScratchDoubleReg);
                 masm.storeDouble(ScratchDoubleReg, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
                 break;
               case MIRType_Float32:
                 masm.loadFloat32(src, ScratchFloat32Reg);
                 masm.storeFloat32(ScratchFloat32Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
                 break;
@@ -240,20 +250,22 @@ wasm::GenerateEntry(MacroAssembler& masm
     // Recover the 'argv' pointer which was saved before aligning the stack.
     masm.Pop(argv);
 
     // Store the return value in argv[0]
     switch (sig.ret()) {
       case ExprType::Void:
         break;
       case ExprType::I32:
-        masm.storeValue(JSVAL_TYPE_INT32, ReturnReg, Address(argv, 0));
+        masm.store32(ReturnReg, Address(argv, 0));
         break;
       case ExprType::I64:
-        MOZ_CRASH("no int64 in asm.js");
+        MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+        masm.store64(ReturnReg64, Address(argv, 0));
+        break;
       case ExprType::F32:
         masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
         MOZ_FALLTHROUGH; // as ReturnDoubleReg now contains a Double
       case ExprType::F64:
         masm.canonicalizeDouble(ReturnDoubleReg);
         masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
         break;
       case ExprType::I32x4:
@@ -275,61 +287,95 @@ wasm::GenerateEntry(MacroAssembler& masm
 
     masm.move32(Imm32(true), ReturnReg);
     masm.ret();
 
     offsets.end = masm.currentOffset();
     return offsets;
 }
 
+typedef bool ToValue;
+
 static void
 FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argOffset,
-                  unsigned offsetToCallerStackArgs, Register scratch)
+                  unsigned offsetToCallerStackArgs, Register scratch, ToValue toValue)
 {
+    Register64 scratch64(scratch);
     for (ABIArgValTypeIter i(args); !i.done(); i++) {
         Address dstAddr(masm.getStackPointer(), argOffset + i.index() * sizeof(Value));
+
+        MIRType type = i.mirType();
+        MOZ_ASSERT_IF(type == MIRType_Int64, JitOptions.wasmTestMode);
+
         switch (i->kind()) {
           case ABIArg::GPR:
-            masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr);
+            if (type == MIRType_Int32) {
+                if (toValue)
+                    masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr);
+                else
+                    masm.store32(i->gpr(), dstAddr);
+            } else if (type == MIRType_Int64) {
+                // We can't box int64 into Values (yet).
+                if (toValue)
+                    masm.breakpoint();
+                else
+                    masm.store64(i->gpr64(), dstAddr);
+            } else {
+                MOZ_CRASH("unexpected input type?");
+            }
             break;
 #ifdef JS_CODEGEN_REGISTER_PAIR
           case ABIArg::GPR_PAIR:
             MOZ_CRASH("AsmJS uses hardfp for function calls.");
             break;
 #endif
           case ABIArg::FPU: {
-            MOZ_ASSERT(IsFloatingPointType(i.mirType()));
+            MOZ_ASSERT(IsFloatingPointType(type));
             FloatRegister srcReg = i->fpu();
-            if (i.mirType() == MIRType_Float32) {
-                masm.convertFloat32ToDouble(i->fpu(), ScratchDoubleReg);
-                srcReg = ScratchDoubleReg;
+            if (toValue) {
+                if (type == MIRType_Float32) {
+                    masm.convertFloat32ToDouble(i->fpu(), ScratchDoubleReg);
+                    srcReg = ScratchDoubleReg;
+                }
+                masm.canonicalizeDouble(srcReg);
             }
-            masm.canonicalizeDouble(srcReg);
             masm.storeDouble(srcReg, dstAddr);
             break;
           }
           case ABIArg::Stack:
-            if (i.mirType() == MIRType_Int32) {
+            if (type == MIRType_Int32) {
                 Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
                 masm.load32(src, scratch);
-                masm.storeValue(JSVAL_TYPE_INT32, scratch, dstAddr);
-#else
-                masm.memIntToValue(src, dstAddr);
-#endif
+                if (toValue)
+                    masm.storeValue(JSVAL_TYPE_INT32, scratch, dstAddr);
+                else
+                    masm.store32(scratch, dstAddr);
+            } else if (type == MIRType_Int64) {
+                // We can't box int64 into Values (yet).
+                if (toValue) {
+                    masm.breakpoint();
+                } else {
+                    Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
+                    masm.load64(src, scratch64);
+                    masm.store64(scratch64, dstAddr);
+                }
             } else {
-                MOZ_ASSERT(IsFloatingPointType(i.mirType()));
+                MOZ_ASSERT(IsFloatingPointType(type));
                 Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
-                if (i.mirType() == MIRType_Float32) {
-                    masm.loadFloat32(src, ScratchFloat32Reg);
-                    masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
+                if (toValue) {
+                    if (type == MIRType_Float32) {
+                        masm.loadFloat32(src, ScratchFloat32Reg);
+                        masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
+                    } else {
+                        masm.loadDouble(src, ScratchDoubleReg);
+                    }
+                    masm.canonicalizeDouble(ScratchDoubleReg);
                 } else {
                     masm.loadDouble(src, ScratchDoubleReg);
                 }
-                masm.canonicalizeDouble(ScratchDoubleReg);
                 masm.storeDouble(ScratchDoubleReg, dstAddr);
             }
             break;
         }
     }
 }
 
 // Generate a stub that is called via the internal ABI derived from the
@@ -358,17 +404,17 @@ wasm::GenerateInterpExit(MacroAssembler&
     unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes);
 
     ProfilingOffsets offsets;
     GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = sizeof(AsmJSFrame) + masm.framePushed();
     Register scratch = ABIArgGenerator::NonArgReturnReg0;
-    FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch);
+    FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch, ToValue(false));
 
     // Prepare the arguments for the call to InvokeImport_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
 
     // argument 0: importIndex
     if (i->kind() == ABIArg::GPR)
         masm.mov(ImmWord(importIndex), i->gpr());
     else
@@ -399,20 +445,24 @@ wasm::GenerateInterpExit(MacroAssembler&
     switch (sig.ret()) {
       case ExprType::Void:
         masm.call(SymbolicAddress::InvokeImport_Void);
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
         break;
       case ExprType::I32:
         masm.call(SymbolicAddress::InvokeImport_I32);
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
-        masm.unboxInt32(argv, ReturnReg);
+        masm.load32(argv, ReturnReg);
         break;
       case ExprType::I64:
-        MOZ_CRASH("no int64 in asm.js");
+        MOZ_ASSERT(JitOptions.wasmTestMode);
+        masm.call(SymbolicAddress::InvokeImport_I64);
+        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
+        masm.load64(argv, ReturnReg64);
+        break;
       case ExprType::F32:
         masm.call(SymbolicAddress::InvokeImport_F64);
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
         masm.loadDouble(argv, ReturnDoubleReg);
         masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg);
         break;
       case ExprType::F64:
         masm.call(SymbolicAddress::InvokeImport_F64);
@@ -504,17 +554,17 @@ wasm::GenerateJitExit(MacroAssembler& ma
     argOffset += sizeof(size_t);
 
     // 4. |this| value
     masm.storeValue(UndefinedValue(), Address(masm.getStackPointer(), argOffset));
     argOffset += sizeof(Value);
 
     // 5. Fill the arguments
     unsigned offsetToCallerStackArgs = jitFramePushed + sizeof(AsmJSFrame);
-    FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch);
+    FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch, ToValue(true));
     argOffset += sig.args().length() * sizeof(Value);
     MOZ_ASSERT(argOffset == jitFrameBytes);
 
     // 6. Jit code will clobber all registers, even non-volatiles. GlobalReg and
     //    HeapReg are removed from the general register set for asm.js code, so
     //    these will not have been saved by the caller like all other registers,
     //    so they must be explicitly preserved. Only save GlobalReg since
     //    HeapReg can be reloaded (from global data) after the call.
@@ -654,17 +704,21 @@ wasm::GenerateJitExit(MacroAssembler& ma
     switch (sig.ret()) {
       case ExprType::Void:
         break;
       case ExprType::I32:
         masm.convertValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert,
                                  /* -0 check */ false);
         break;
       case ExprType::I64:
-        MOZ_CRASH("no int64 in asm.js");
+        MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+        // We don't expect int64 to be returned from Ion yet, because of a
+        // guard in callImport.
+        masm.breakpoint();
+        break;
       case ExprType::F32:
         masm.convertValueToFloat(JSReturnOperand, ReturnFloat32Reg, &oolConvert);
         break;
       case ExprType::F64:
         masm.convertValueToDouble(JSReturnOperand, ReturnDoubleReg, &oolConvert);
         break;
       case ExprType::I32x4:
       case ExprType::F32x4:
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -632,17 +632,19 @@ class WasmAstModule : public WasmAstNode
     }
     bool declare(WasmAstSig&& sig, uint32_t* sigIndex) {
         SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
         if (p) {
             *sigIndex = p->value();
             return true;
         }
         *sigIndex = sigs_.length();
-        return sigs_.append(new (lifo_) WasmAstSig(WasmName(), Move(sig))) &&
+        auto* lifoSig = new (lifo_) WasmAstSig(WasmName(), Move(sig));
+        return lifoSig &&
+               sigs_.append(lifoSig) &&
                sigMap_.add(p, sigs_.back(), *sigIndex);
     }
     bool append(WasmAstSig* sig) {
         uint32_t sigIndex = sigs_.length();
         if (!sigs_.append(sig))
             return false;
         SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
         return p || sigMap_.add(p, sig, sigIndex);
@@ -2456,17 +2458,17 @@ ParseConst(WasmParseContext& c, WasmToke
         switch (val.kind()) {
           case WasmToken::Index:
             return new(c.lifo) WasmAstConst(Val(uint64_t(val.index())));
           case WasmToken::UnsignedInteger:
             return new(c.lifo) WasmAstConst(Val(val.uint()));
           case WasmToken::SignedInteger:
             return new(c.lifo) WasmAstConst(Val(uint64_t(val.sint())));
           case WasmToken::NegativeZero:
-            return new(c.lifo) WasmAstConst(Val(uint32_t(0)));
+            return new(c.lifo) WasmAstConst(Val(uint64_t(0)));
           default:
             break;
         }
         break;
       }
       case ValType::F32: {
         float result;
         if (!ParseFloatLiteral(c, val, &result))
--- a/js/src/asmjs/WasmTypes.cpp
+++ b/js/src/asmjs/WasmTypes.cpp
@@ -110,62 +110,105 @@ CoerceInPlace_ToNumber(MutableHandleValu
     val.set(DoubleValue(dbl));
 
     return true;
 }
 
 // Use an int32_t return type instead of bool since bool does not have a
 // specified width and the caller is assuming a word-sized return.
 static int32_t
-InvokeImport_Void(int32_t importIndex, int32_t argc, Value* argv)
+InvokeImport_Void(int32_t importIndex, int32_t argc, uint64_t* argv)
 {
     WasmActivation* activation = JSRuntime::innermostWasmActivation();
     JSContext* cx = activation->cx();
 
     RootedValue rval(cx);
     return activation->module().callImport(cx, importIndex, argc, argv, &rval);
 }
 
 // Use an int32_t return type instead of bool since bool does not have a
 // specified width and the caller is assuming a word-sized return.
 static int32_t
-InvokeImport_I32(int32_t importIndex, int32_t argc, Value* argv)
+InvokeImport_I32(int32_t importIndex, int32_t argc, uint64_t* argv)
 {
     WasmActivation* activation = JSRuntime::innermostWasmActivation();
     JSContext* cx = activation->cx();
 
     RootedValue rval(cx);
     if (!activation->module().callImport(cx, importIndex, argc, argv, &rval))
         return false;
 
     int32_t i32;
     if (!ToInt32(cx, rval, &i32))
         return false;
 
-    argv[0] = Int32Value(i32);
+    argv[0] = i32;
+    return true;
+}
+
+bool
+js::wasm::ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64)
+{
+    if (!v.isObject()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL,
+                             "i64 JS value must be an object");
+        return false;
+    }
+
+    RootedObject obj(cx, &v.toObject());
+
+    int32_t* i32 = (int32_t*)i64;
+
+    RootedValue val(cx);
+    if (!JS_GetProperty(cx, obj, "low", &val))
+        return false;
+    if (!ToInt32(cx, val, &i32[0]))
+        return false;
+
+    if (!JS_GetProperty(cx, obj, "high", &val))
+        return false;
+    if (!ToInt32(cx, val, &i32[1]))
+        return false;
+
+    return true;
+}
+
+static int32_t
+InvokeImport_I64(int32_t importIndex, int32_t argc, uint64_t* argv)
+{
+    WasmActivation* activation = JSRuntime::innermostWasmActivation();
+    JSContext* cx = activation->cx();
+
+    RootedValue rval(cx);
+    if (!activation->module().callImport(cx, importIndex, argc, argv, &rval))
+        return false;
+
+    if (!ReadI64Object(cx, rval, (int64_t*)argv))
+        return false;
+
     return true;
 }
 
 // Use an int32_t return type instead of bool since bool does not have a
 // specified width and the caller is assuming a word-sized return.
 static int32_t
-InvokeImport_F64(int32_t importIndex, int32_t argc, Value* argv)
+InvokeImport_F64(int32_t importIndex, int32_t argc, uint64_t* argv)
 {
     WasmActivation* activation = JSRuntime::innermostWasmActivation();
     JSContext* cx = activation->cx();
 
     RootedValue rval(cx);
     if (!activation->module().callImport(cx, importIndex, argc, argv, &rval))
         return false;
 
     double dbl;
     if (!ToNumber(cx, rval, &dbl))
         return false;
 
-    argv[0] = DoubleValue(dbl);
+    ((double*)argv)[0] = dbl;
     return true;
 }
 
 template <class F>
 static inline void*
 FuncCast(F* pf, ABIFunctionType type)
 {
     void *pv = JS_FUNC_TO_DATA_PTR(void*, pf);
@@ -196,16 +239,18 @@ wasm::AddressOf(SymbolicAddress imm, Exc
       case SymbolicAddress::UnreachableTrap:
         return FuncCast(UnreachableTrap, Args_General0);
       case SymbolicAddress::HandleExecutionInterrupt:
         return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
       case SymbolicAddress::InvokeImport_Void:
         return FuncCast(InvokeImport_Void, Args_General3);
       case SymbolicAddress::InvokeImport_I32:
         return FuncCast(InvokeImport_I32, Args_General3);
+      case SymbolicAddress::InvokeImport_I64:
+        return FuncCast(InvokeImport_I64, Args_General3);
       case SymbolicAddress::InvokeImport_F64:
         return FuncCast(InvokeImport_F64, Args_General3);
       case SymbolicAddress::CoerceInPlace_ToInt32:
         return FuncCast(CoerceInPlace_ToInt32, Args_General1);
       case SymbolicAddress::CoerceInPlace_ToNumber:
         return FuncCast(CoerceInPlace_ToNumber, Args_General1);
       case SymbolicAddress::ToInt32:
         return FuncCast<int32_t (double)>(JS::ToInt32, Args_Int_Double);
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -534,25 +534,30 @@ enum class SymbolicAddress
     ReportOverRecursed,
     OnOutOfBounds,
     OnImpreciseConversion,
     BadIndirectCall,
     UnreachableTrap,
     HandleExecutionInterrupt,
     InvokeImport_Void,
     InvokeImport_I32,
+    InvokeImport_I64,
     InvokeImport_F64,
     CoerceInPlace_ToInt32,
     CoerceInPlace_ToNumber,
     Limit
 };
 
 void*
 AddressOf(SymbolicAddress imm, ExclusiveContext* cx);
 
+// Extracts low and high from an int64 object {low: int32, high: int32}, for
+// testing purposes mainly.
+bool ReadI64Object(JSContext* cx, HandleValue v, int64_t* val);
+
 // A wasm::JumpTarget represents one of a special set of stubs that can be
 // jumped to from any function. Because wasm modules can be larger than the
 // range of a plain jump, these potentially out-of-range jumps must be recorded
 // and patched specially by the MacroAssembler and ModuleGenerator.
 
 enum class JumpTarget
 {
     StackOverflow,
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -41,17 +41,17 @@ class FullParseHandler
         return node;
     }
 
     /*
      * If this is a full parse to construct the bytecode for a function that
      * was previously lazily parsed, that lazy function and the current index
      * into its inner functions. We do not want to reparse the inner functions.
      */
-    LazyScript * const lazyOuterFunction_;
+    const Rooted<LazyScript*> lazyOuterFunction_;
     size_t lazyInnerFunctionIndex;
 
     const TokenPos& pos() {
         return tokenStream.currentToken().pos;
     }
 
     inline ParseNode* makeAssignmentFromArg(ParseNode* arg, ParseNode* lhs, ParseNode* rhs);
     inline void replaceLastFunctionArgument(ParseNode* funcpn, ParseNode* pn);
@@ -98,17 +98,17 @@ class FullParseHandler
                isParenthesizedDestructuringPattern(node);
     }
 
     FullParseHandler(ExclusiveContext* cx, LifoAlloc& alloc,
                      TokenStream& tokenStream, Parser<SyntaxParseHandler>* syntaxParser,
                      LazyScript* lazyOuterFunction)
       : allocator(cx, alloc),
         tokenStream(tokenStream),
-        lazyOuterFunction_(lazyOuterFunction),
+        lazyOuterFunction_(cx, lazyOuterFunction),
         lazyInnerFunctionIndex(0),
         syntaxParser(syntaxParser)
     {}
 
     static ParseNode* null() { return nullptr; }
 
     ParseNode* freeTree(ParseNode* pn) { return allocator.freeTree(pn); }
     void prepareNodeForMutation(ParseNode* pn) { return allocator.prepareNodeForMutation(pn); }
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -122,16 +122,17 @@ CheckHashTablesAfterMovingGC(JSRuntime* 
 struct MovingTracer : JS::CallbackTracer
 {
     explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
 
     void onObjectEdge(JSObject** objp) override;
     void onShapeEdge(Shape** shapep) override;
     void onStringEdge(JSString** stringp) override;
     void onScriptEdge(JSScript** scriptp) override;
+    void onLazyScriptEdge(LazyScript** lazyp) override;
     void onChild(const JS::GCCellPtr& thing) override {
         MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
     }
 
 #ifdef DEBUG
     TracerKind getTracerKind() const override { return TracerKind::Moving; }
 #endif
 };
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -6,8 +6,47 @@ load(libdir + "asserts.js");
 function wasmEvalText(str, imports) {
     return Wasm.instantiateModule(wasmTextToBinary(str), imports).exports;
 }
 
 function mismatchError(actual, expect) {
     var str = `type mismatch: expression has type ${actual} but expected ${expect}`;
     return RegExp(str);
 }
+
+function hasI64() {
+    return getBuildConfiguration().x64;
+}
+
+// Assert that the expected value is equal to the int64 value, as passed by
+// Baldr with --wasm-extra-tests {low: int32, high: int32}.
+// - if the expected value is in the int32 range, it can be just a number.
+// - otherwise, an object with the properties "high" and "low".
+function assertEqI64(obj, expect) {
+    assertEq(typeof obj, 'object');
+    assertEq(typeof expect === 'object' || typeof expect === 'number', true);
+
+    let {low, high} = obj;
+    if (typeof expect === 'number') {
+        assertEq(expect, expect | 0, "in int32 range");
+        assertEq(low, expect | 0, "low");
+        assertEq(high, expect < 0 ? -1 : 0), "high";
+    } else {
+        assertEq(typeof expect.low, 'number');
+        assertEq(typeof expect.high, 'number');
+        assertEq(low, expect.low | 0, "low");
+        assertEq(high, expect.high | 0, "high");
+    }
+}
+
+function createI64(val) {
+    let ret;
+    if (typeof val === 'number') {
+        assertEq(val, val|0, "number input to createI64 must be an int32");
+        ret = { low: val, high: val < 0 ? -1 : 0 };
+    } else {
+        assertEq(typeof val, 'string');
+        assertEq(val.slice(0, 2), "0x");
+        val = val.slice(2).padStart(16, '0');
+        ret = { low: parseInt(val.slice(8, 16), 16), high: parseInt(val.slice(0, 8), 16) };
+    }
+    return ret;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1263884.js
@@ -0,0 +1,10 @@
+if (!('oomTest' in this))
+    quit();
+
+oomTest(function() {
+  eval(`
+    var argObj = function () { return arguments }()
+    for (var p in argObj);
+    delete argObj.callee;
+  `);
+});
--- a/js/src/jit-test/tests/wasm/basic-const.js
+++ b/js/src/jit-test/tests/wasm/basic-const.js
@@ -1,15 +1,15 @@
 load(libdir + "wasm.js");
 
-if (!wasmIsSupported())
-    quit();
-
 function testConst(type, str, expect) {
-  assertEq(wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), expect);
+    if (type === 'i64')
+        assertEqI64(wasmEvalText('(module (func (result i64) (i64.const ' + str + ')) (export "" 0))')(), expect);
+    else
+        assertEq(wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), expect);
 }
 
 function testConstError(type, str) {
   // For now at least, we don't distinguish between parse errors and OOMs.
   assertErrorMessage(() => wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), Error, /parsing wasm text/);
 }
 
 testConst('i32', '0', 0);
@@ -21,29 +21,69 @@ testConst('i32', '-0x23', -35);
 testConst('i32', '2147483647', 2147483647);
 testConst('i32', '4294967295', -1);
 testConst('i32', '-2147483648', -2147483648);
 testConst('i32', '0x7fffffff', 2147483647);
 testConst('i32', '0x80000000', -2147483648);
 testConst('i32', '-0x80000000', -2147483648);
 testConst('i32', '0xffffffff', -1);
 
-//testConst('i64', '0', 0); // TODO: NYI
-//testConst('i64', '-0', 0); // TODO: NYI
-//testConst('i64', '23', 23); // TODO: NYI
-//testConst('i64', '-23', -23); // TODO: NYI
-//testConst('i64', '0x23', 35); // TODO: NYI
-//testConst('i64', '-0x23', -35); // TODO: NYI
-//testConst('i64', '9223372036854775807', 9223372036854775807); // TODO: NYI
-//testConst('i64', '18446744073709551615', -1); // TODO: NYI
-//testConst('i64', '-9223372036854775808', -9223372036854775808); // TODO: NYI
-//testConst('i64', '0x7fffffffffffffff', 9223372036854775807); // TODO: NYI
-//testConst('i64', '0x8000000000000000', -9223372036854775808); // TODO: NYI
-//testConst('i64', '-0x8000000000000000', -9223372036854775808); // TODO: NYI
-//testConst('i64', '0xffffffffffffffff', -1); // TODO: NYI
+if (hasI64()) {
+
+    assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /cannot .* i64/);
+
+    setJitCompilerOption('wasm.test-mode', 1);
+
+    testConst('i64', '0', 0);
+    testConst('i64', '-0', 0);
+
+    testConst('i64', '23', 23);
+    testConst('i64', '-23', -23);
+
+    testConst('i64', '0x23', 35);
+    testConst('i64', '-0x23', -35);
+
+    testConst('i64', '-0x1', -1);
+    testConst('i64', '-1', -1);
+    testConst('i64', '0xffffffffffffffff', -1);
+
+    testConst('i64', '0xdeadc0de', {low: 0xdeadc0de, high: 0x0});
+    testConst('i64', '0x1337c0de00000000', {low: 0x0, high: 0x1337c0de});
+
+    testConst('i64', '0x0102030405060708', {low: 0x05060708, high: 0x01020304});
+    testConst('i64', '-0x0102030405060708', {low: -0x05060708, high: -0x01020305});
+
+    // INT64_MAX
+    testConst('i64', '9223372036854775807', {low: 0xffffffff, high: 0x7fffffff});
+    testConst('i64', '0x7fffffffffffffff',  {low: 0xffffffff, high: 0x7fffffff});
+
+    // INT64_MAX + 1
+    testConst('i64', '9223372036854775808', {low: 0x00000000, high: 0x80000000});
+    testConst('i64', '0x8000000000000000', {low: 0x00000000, high: 0x80000000});
+
+    // UINT64_MAX
+    testConst('i64', '18446744073709551615', {low: 0xffffffff, high: 0xffffffff});
+
+    // INT64_MIN
+    testConst('i64', '-9223372036854775808', {low: 0x00000000, high: 0x80000000});
+    testConst('i64', '-0x8000000000000000',  {low: 0x00000000, high: 0x80000000});
+
+    // INT64_MIN - 1
+    testConstError('i64', '-9223372036854775809');
+
+    testConstError('i64', '');
+    testConstError('i64', '0.0');
+    testConstError('i64', 'not an i64');
+
+    setJitCompilerOption('wasm.test-mode', 0);
+
+    assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /cannot .* i64/);
+} else {
+    assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /NYI/);
+}
 
 testConst('f32', '0.0', 0.0);
 testConst('f32', '-0', -0.0);
 testConst('f32', '-0.0', -0.0);
 testConst('f32', '0x0.0', 0.0);
 testConst('f32', '-0x0.0', -0.0);
 testConst('f32', '-0x0', -0.0);
 testConst('f32', '0x0.0p0', 0.0);
@@ -210,22 +250,16 @@ testConst('f64', '0x24c6.004d0deaa3p-103
 testConst('f64', '0', 0);
 
 testConstError('i32', '');
 testConstError('i32', '0.0');
 testConstError('i32', 'not an i32');
 testConstError('i32', '4294967296');
 testConstError('i32', '-2147483649');
 
-//testConstError('i64', ''); // TODO: NYI
-//testConstError('i64', '0.0'); // TODO: NYI
-//testConstError('i64', 'not an i64'); // TODO: NYI
-//testConstError('i64', '9223372036854775808'); // TODO: NYI
-//testConstError('i64', '-9223372036854775809'); // TODO: NYI
-
 testConstError('f32', '');
 testConstError('f32', 'not an f32');
 testConstError('f32', 'nan:');
 testConstError('f32', 'nan:0');
 testConstError('f32', 'nan:0x');
 testConstError('f32', 'nan:0x0');
 
 testConstError('f64', '');
--- a/js/src/jit-test/tests/wasm/basic-conversion.js
+++ b/js/src/jit-test/tests/wasm/basic-conversion.js
@@ -1,55 +1,61 @@
 load(libdir + "wasm.js");
 
-if (!wasmIsSupported())
-    quit();
-
 function testConversion(resultType, opcode, paramType, op, expect) {
   if (paramType === 'i64') {
     // i64 cannot be imported, so we use a wrapper function.
     assertEq(wasmEvalText(`(module
                             (func (param i64) (result ${resultType}) (${resultType}.${opcode}/i64 (get_local 0)))
-                            (func (result ${resultType}) (call 0 (i64.const ${op})))
-                            (export "" 1))`)(), expect);
+                            (export "" 0))`)(createI64(op)), expect);
     // The same, but now the input is a constant.
     assertEq(wasmEvalText(`(module
                             (func (result ${resultType}) (${resultType}.${opcode}/i64 (i64.const ${op})))
                             (export "" 0))`)(), expect);
   } else if (resultType === 'i64') {
-    assertEq(wasmEvalText(`(module
+    assertEqI64(wasmEvalText(`(module
                             (func (param ${paramType}) (result i64) (i64.${opcode}/${paramType} (get_local 0)))
-                            (func (result i32) (i64.eq (i64.const ${expect}) (call 0 (${paramType}.const ${op}))))
-                            (export "" 1))`)(), 1);
+                            (export "" 0))`)(op), createI64(expect));
     // The same, but now the input is a constant.
-    assertEq(wasmEvalText(`(module
+    assertEqI64(wasmEvalText(`(module
                             (func (result i64) (i64.${opcode}/${paramType} (${paramType}.const ${op})))
-                            (func (result i32) (i64.eq (i64.const ${expect}) (call 0)))
-                            (export "" 1))`)(), 1);
+                            (export "" 0))`)(), createI64(expect));
   } else {
     assertEq(wasmEvalText('(module (func (param ' + paramType + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))) (export "" 0))')(op), expect);
   }
 
-  // TODO: i64 NYI
-  for (var bad of ['i32', 'f32', 'f64']) {
-    if (bad != resultType)
-      assertErrorMessage(() => wasmEvalText('(module (func (param ' + paramType + ') (result ' + bad + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))))'),
-                         TypeError,
-                         mismatchError(resultType, bad)
-                        );
-    if (bad != paramType)
-      assertErrorMessage(() => wasmEvalText('(module (func (param ' + bad + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))))'),
-                         TypeError,
-                         mismatchError(bad, paramType)
-                        );
+  let formerWasmExtraTests = getJitCompilerOptions()['wasm.test-mode'];
+  setJitCompilerOption('wasm.test-mode', 1);
+  for (var bad of ['i32', 'f32', 'f64', 'i64']) {
+      if (bad === 'i64' && !hasI64())
+          continue;
+
+      if (bad != resultType) {
+          assertErrorMessage(
+              () => wasmEvalText(`(module (func (param ${paramType}) (result ${bad}) (${resultType}.${opcode}/${paramType} (get_local 0))))`),
+              TypeError,
+              mismatchError(resultType, bad)
+          );
+      }
+
+      if (bad != paramType) {
+          assertErrorMessage(
+              () => wasmEvalText(`(module (func (param ${bad}) (result ${resultType}) (${resultType}.${opcode}/${paramType} (get_local 0))))`),
+              TypeError,
+              mismatchError(bad, paramType)
+          );
+      }
   }
+  setJitCompilerOption('wasm.test-mode', formerWasmExtraTests);
 }
 
-if (getBuildConfiguration().x64) {
-    testConversion('i32', 'wrap', 'i64', 4294967336, 40);
+if (hasI64()) {
+    setJitCompilerOption('wasm.test-mode', 1);
+
+    testConversion('i32', 'wrap', 'i64', '0x100000028', 40);
     testConversion('i32', 'wrap', 'i64', -10, -10);
     testConversion('i32', 'wrap', 'i64', "0xffffffff7fffffff", 0x7fffffff);
     testConversion('i32', 'wrap', 'i64', "0xffffffff00000000", 0);
     testConversion('i32', 'wrap', 'i64', "0xfffffffeffffffff", -1);
     testConversion('i32', 'wrap', 'i64', "0x1234567801abcdef", 0x01abcdef);
     testConversion('i32', 'wrap', 'i64', "0x8000000000000002", 2);
 
     testConversion('i64', 'extend_s', 'i32', 0, 0);
@@ -63,101 +69,101 @@ if (getBuildConfiguration().x64) {
     testConversion('i64', 'extend_u', 'i32', -567, "0x00000000fffffdc9");
     testConversion('i64', 'extend_u', 'i32', -1, "0x00000000ffffffff");
     testConversion('i64', 'extend_u', 'i32', 0x7fffffff, "0x000000007fffffff");
     testConversion('i64', 'extend_u', 'i32', 0x80000000, "0x0000000080000000");
 
     testConversion('f32', 'convert_s', 'i64', 1, 1.0);
     testConversion('f32', 'convert_s', 'i64', -1, -1.0);
     testConversion('f32', 'convert_s', 'i64', 0, 0.0);
-    testConversion('f32', 'convert_s', 'i64', "9223372036854775807", 9223372036854775807.0);
-    testConversion('f32', 'convert_s', 'i64', "-9223372036854775808", -9223372036854775808.0);
-    testConversion('f32', 'convert_s', 'i64', "314159265358979", 314159275180032.0);
+    testConversion('f32', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+    testConversion('f32', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
+    testConversion('f32', 'convert_s', 'i64', "0x11db9e76a2483", 314159275180032.0);
 
     testConversion('f64', 'convert_s', 'i64', 1, 1.0);
     testConversion('f64', 'convert_s', 'i64', -1, -1.0);
     testConversion('f64', 'convert_s', 'i64', 0, 0.0);
-    testConversion('f64', 'convert_s', 'i64', "9223372036854775807", 9223372036854775807.0);
-    testConversion('f64', 'convert_s', 'i64', "-9223372036854775808", -9223372036854775808.0);
-    testConversion('f64', 'convert_s', 'i64', "4669201609102990", 4669201609102990);
+    testConversion('f64', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+    testConversion('f64', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
+    testConversion('f64', 'convert_s', 'i64', "0x10969d374b968e", 4669201609102990);
 
     testConversion('f32', 'convert_u', 'i64', 1, 1.0);
     testConversion('f32', 'convert_u', 'i64', 0, 0.0);
-    testConversion('f32', 'convert_u', 'i64', "9223372036854775807", 9223372036854775807.0);
-    testConversion('f32', 'convert_u', 'i64', "-9223372036854775808", 9223372036854775808.0);
+    testConversion('f32', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+    testConversion('f32', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
 
     testConversion('f64', 'convert_u', 'i64', 1, 1.0);
     testConversion('f64', 'convert_u', 'i64', 0, 0.0);
-    testConversion('f64', 'convert_u', 'i64', "9223372036854775807", 9223372036854775807.0);
-    testConversion('f64', 'convert_u', 'i64', "-9223372036854775808", 9223372036854775808.0);
+    testConversion('f64', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+    testConversion('f64', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f64', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f64', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462603027743000.0);
 
     testConversion('i64', 'trunc_s', 'f64', 0.0, 0);
     testConversion('i64', 'trunc_s', 'f64', "-0.0", 0);
     testConversion('i64', 'trunc_s', 'f64', 1.0, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.1, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.5, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.99, 1);
     testConversion('i64', 'trunc_s', 'f64', 40.1, 40);
     testConversion('i64', 'trunc_s', 'f64', -1.0, -1);
     testConversion('i64', 'trunc_s', 'f64', -1.1, -1);
     testConversion('i64', 'trunc_s', 'f64', -1.5, -1);
     testConversion('i64', 'trunc_s', 'f64', -1.99, -1);
     testConversion('i64', 'trunc_s', 'f64', -2.0, -2);
-    testConversion('i64', 'trunc_s', 'f64', 4294967296.1, "4294967296");
-    testConversion('i64', 'trunc_s', 'f64', -4294967296.8, "-4294967296");
-    testConversion('i64', 'trunc_s', 'f64', 9223372036854774784.8, "9223372036854774784");
-    testConversion('i64', 'trunc_s', 'f64', -9223372036854775808.3, "-9223372036854775808");
+    testConversion('i64', 'trunc_s', 'f64', 4294967296.1, "0x100000000");
+    testConversion('i64', 'trunc_s', 'f64', -4294967296.8, "0xffffffff00000000");
+    testConversion('i64', 'trunc_s', 'f64', 9223372036854774784.8, "0x7ffffffffffffc00");
+    testConversion('i64', 'trunc_s', 'f64', -9223372036854775808.3, "0x8000000000000000");
 
     testConversion('i64', 'trunc_u', 'f64', 0.0, 0);
     testConversion('i64', 'trunc_u', 'f64', "-0.0", 0);
     testConversion('i64', 'trunc_u', 'f64', 1.0, 1);
     testConversion('i64', 'trunc_u', 'f64', 1.1, 1);
     testConversion('i64', 'trunc_u', 'f64', 1.5, 1);
     testConversion('i64', 'trunc_u', 'f64', 1.99, 1);
     testConversion('i64', 'trunc_u', 'f64', -0.9, 0);
     testConversion('i64', 'trunc_u', 'f64', 40.1, 40);
     testConversion('i64', 'trunc_u', 'f64', 4294967295, "0xffffffff");
-    testConversion('i64', 'trunc_u', 'f64', 4294967296.1, "4294967296");
-    testConversion('i64', 'trunc_u', 'f64', 1e8, "100000000");
-    testConversion('i64', 'trunc_u', 'f64', 1e16, "10000000000000000");
-    testConversion('i64', 'trunc_u', 'f64', 9223372036854775808, "-9223372036854775808");
+    testConversion('i64', 'trunc_u', 'f64', 4294967296.1, "0x100000000");
+    testConversion('i64', 'trunc_u', 'f64', 1e8, "0x5f5e100");
+    testConversion('i64', 'trunc_u', 'f64', 1e16, "0x2386f26fc10000");
+    testConversion('i64', 'trunc_u', 'f64', 9223372036854775808, "0x8000000000000000");
     testConversion('i64', 'trunc_u', 'f64', 18446744073709549568.1, -2048);
 
     testConversion('i64', 'trunc_s', 'f32', 0.0, 0);
     testConversion('i64', 'trunc_s', 'f32', "-0.0", 0);
     testConversion('i64', 'trunc_s', 'f32', 1.0, 1);
     testConversion('i64', 'trunc_s', 'f32', 1.1, 1);
     testConversion('i64', 'trunc_s', 'f32', 1.5, 1);
     testConversion('i64', 'trunc_s', 'f32', 1.99, 1);
     testConversion('i64', 'trunc_s', 'f32', 40.1, 40);
     testConversion('i64', 'trunc_s', 'f32', -1.0, -1);
     testConversion('i64', 'trunc_s', 'f32', -1.1, -1);
     testConversion('i64', 'trunc_s', 'f32', -1.5, -1);
     testConversion('i64', 'trunc_s', 'f32', -1.99, -1);
     testConversion('i64', 'trunc_s', 'f32', -2.0, -2);
-    testConversion('i64', 'trunc_s', 'f32', 4294967296.1, "4294967296");
-    testConversion('i64', 'trunc_s', 'f32', -4294967296.8, "-4294967296");
-    testConversion('i64', 'trunc_s', 'f32', 9223371487098961920.0, "9223371487098961920");
-    testConversion('i64', 'trunc_s', 'f32', -9223372036854775808.3, "-9223372036854775808");
+    testConversion('i64', 'trunc_s', 'f32', 4294967296.1, "0x100000000");
+    testConversion('i64', 'trunc_s', 'f32', -4294967296.8, "0xffffffff00000000");
+    testConversion('i64', 'trunc_s', 'f32', 9223371487098961920.0, "0x7fffff8000000000");
+    testConversion('i64', 'trunc_s', 'f32', -9223372036854775808.3, "0x8000000000000000");
 
     testConversion('i64', 'trunc_u', 'f32', 0.0, 0);
     testConversion('i64', 'trunc_u', 'f32', "-0.0", 0);
     testConversion('i64', 'trunc_u', 'f32', 1.0, 1);
     testConversion('i64', 'trunc_u', 'f32', 1.1, 1);
     testConversion('i64', 'trunc_u', 'f32', 1.5, 1);
     testConversion('i64', 'trunc_u', 'f32', 1.99, 1);
     testConversion('i64', 'trunc_u', 'f32', -0.9, 0);
     testConversion('i64', 'trunc_u', 'f32', 40.1, 40);
-    testConversion('i64', 'trunc_u', 'f32', 1e8, "100000000");
-    testConversion('i64', 'trunc_u', 'f32', 4294967296, "4294967296");
-    testConversion('i64', 'trunc_u', 'f32', 18446742974197923840.0, "-1099511627776");
+    testConversion('i64', 'trunc_u', 'f32', 1e8, "0x5f5e100");
+    testConversion('i64', 'trunc_u', 'f32', 4294967296, "0x100000000");
+    testConversion('i64', 'trunc_u', 'f32', 18446742974197923840.0, "0xffffff0000000000");
 
     // TODO: these should trap.
     testConversion('i64', 'trunc_s', 'f64', 9223372036854775808.0, "0x8000000000000000");
     testConversion('i64', 'trunc_s', 'f64', -9223372036854777856.0, "0x8000000000000000");
     testConversion('i64', 'trunc_s', 'f64', "nan", "0x8000000000000000");
     testConversion('i64', 'trunc_s', 'f64', "infinity", "0x8000000000000000");
     testConversion('i64', 'trunc_s', 'f64', "-infinity", "0x8000000000000000");
 
@@ -174,18 +180,20 @@ if (getBuildConfiguration().x64) {
     testConversion('i64', 'trunc_s', 'f32', "-infinity", "0x8000000000000000");
 
     testConversion('i64', 'trunc_u', 'f32', 18446744073709551616.0, "0x8000000000000000");
     testConversion('i64', 'trunc_u', 'f32', -1, "0x8000000000000000");
     testConversion('i64', 'trunc_u', 'f32', "nan", "0x8000000000000000");
     testConversion('i64', 'trunc_u', 'f32', "infinity", "0x8000000000000000");
     testConversion('i64', 'trunc_u', 'f32', "-infinity", "0x8000000000000000");
 
-    testConversion('i64', 'reinterpret', 'f64', 40.09999999999968, 4630840390592548000);
-    testConversion('f64', 'reinterpret', 'i64', 4630840390592548000, 40.09999999999968);
+    testConversion('i64', 'reinterpret', 'f64', 40.09999999999968, "0x40440ccccccccca0");
+    testConversion('f64', 'reinterpret', 'i64', "0x40440ccccccccca0", 40.09999999999968);
+
+    setJitCompilerOption('wasm.test-mode', 0);
 } else {
     // Sleeper test: once i64 works on more platforms, remove this if-else.
     try {
         testConversion('i32', 'wrap', 'i64', 4294967336, 40);
         assertEq(0, 1);
     } catch(e) {
         assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
     }
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -4,55 +4,50 @@ assertEq(wasmEvalText('(module (func (re
 assertEq(wasmEvalText('(module (func (result i32) (i32.const -2147483648)) (export "" 0))')(), -2147483648);
 assertEq(wasmEvalText('(module (func (result i32) (i32.const 4294967295)) (export "" 0))')(), -1);
 
 function testUnary(type, opcode, op, expect) {
   assertEq(wasmEvalText('(module (func (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0))) (export "" 0))')(op), expect);
 }
 
 function testBinary(type, opcode, lhs, rhs, expect) {
-  if (type === 'i64') {
-    // i64 cannot be imported/exported, so we use a wrapper function.
-    assertEq(wasmEvalText(`(module
-                            (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1)))
-                            (func (result i32) (i64.eq (call 0 (i64.const ${lhs}) (i64.const ${rhs})) (i64.const ${expect})))
-                            (export "" 1))`)(), 1);
-    // The same, but now the RHS is a constant.
-    assertEq(wasmEvalText(`(module
-                            (func (param i64) (result i64) (i64.${opcode} (get_local 0) (i64.const ${rhs})))
-                            (func (result i32) (i64.eq (call 0 (i64.const ${lhs})) (i64.const ${expect})))
-                            (export "" 1))`)(), 1);
-    // LHS and RHS are constants.
-    assertEq(wasmEvalText(`(module
-                            (func (result i64) (i64.${opcode} (i64.const ${lhs}) (i64.const ${rhs})))
-                            (func (result i32) (i64.eq (call 0) (i64.const ${expect})))
-                            (export "" 1))`)(), 1);
-  } else {
-    assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
-  }
+    if (type === 'i64') {
+        let lobj = createI64(lhs);
+        let robj = createI64(rhs);
+        expect = createI64(expect);
+
+        assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lobj, robj), expect);
+        // The same, but now the RHS is a constant.
+        assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (i64.const ${rhs}))) (export "" 0))`)(lobj, robj), expect);
+        // LHS and RHS are constants.
+        assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (i64.const ${lhs}) (i64.const ${rhs}))) (export "" 0))`)(lobj, robj), expect);
+    } else {
+        assertEq(wasmEvalText(`(module (func (param ${type}) (param ${type}) (result ${type}) (${type}.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lhs, rhs), expect);
+    }
 }
 
 function testComparison(type, opcode, lhs, rhs, expect) {
-  if (type === 'i64') {
-    // i64 cannot be imported/exported, so we use a wrapper function.
-    assertEq(wasmEvalText(`(module
-                            (func (param i64) (param i64) (result i32) (i64.${opcode} (get_local 0) (get_local 1)))
-                            (func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
-                            (export "" 1))`)(), expect);
-    // Also test if, for the compare-and-branch path.
-    assertEq(wasmEvalText(`(module
-                            (func (param i64) (param i64) (result i32)
-                              (if (i64.${opcode} (get_local 0) (get_local 1))
-                                (i32.const 1)
-                                (i32.const 0)))
-                            (func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
-                            (export "" 1))`)(), expect);
-  } else {
-    assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result i32) (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
-  }
+    if (type === 'i64') {
+        let lobj = createI64(lhs);
+        let robj = createI64(rhs);
+
+        assertEq(wasmEvalText(`(module
+                                (func (param i64) (param i64) (result i32) (i64.${opcode} (get_local 0) (get_local 1)))
+                                (export "" 0))`)(lobj, robj), expect);
+
+        // Also test if, for the compare-and-branch path.
+        assertEq(wasmEvalText(`(module
+                                (func (param i64) (param i64) (result i32)
+                                 (if (i64.${opcode} (get_local 0) (get_local 1))
+                                  (i32.const 1)
+                                  (i32.const 0)))
+                                  (export "" 0))`)(lobj, robj), expect);
+    } else {
+        assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result i32) (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
+    }
 }
 
 testUnary('i32', 'clz', 40, 26);
 testUnary('i32', 'ctz', 40, 3);
 testUnary('i32', 'ctz', 0, 32);
 testUnary('i32', 'ctz', -2147483648, 31);
 
 testUnary('i32', 'popcnt', 40, 2);
@@ -90,17 +85,20 @@ testComparison('i32', 'gt_u', 40, 40, 0)
 testComparison('i32', 'ge_s', 40, 40, 1);
 testComparison('i32', 'ge_u', 40, 40, 1);
 
 //testUnary('i64', 'clz', 40, 58); // TODO: NYI
 //testUnary('i64', 'ctz', 40, 0); // TODO: NYI
 //testUnary('i64', 'popcnt', 40, 0); // TODO: NYI
 //testUnary('i64', 'eqz', 40, 0); // TODO: NYI
 
-if (getBuildConfiguration().x64) {
+if (hasI64()) {
+
+    setJitCompilerOption('wasm.test-mode', 1);
+
     testBinary('i64', 'add', 40, 2, 42);
     testBinary('i64', 'add', "0x1234567887654321", -1, "0x1234567887654320");
     testBinary('i64', 'add', "0xffffffffffffffff", 1, 0);
     testBinary('i64', 'sub', 40, 2, 38);
     testBinary('i64', 'sub', "0x1234567887654321", "0x123456789", "0x12345677641fdb98");
     testBinary('i64', 'sub', 3, 5, -2);
     testBinary('i64', 'mul', 40, 2, 80);
     testBinary('i64', 'mul', -1, 2, -2);
@@ -152,25 +150,27 @@ if (getBuildConfiguration().x64) {
     testComparison('i64', 'le_u', 40, 40, 1);
     testComparison('i64', 'gt_s', 40, 40, 0);
     testComparison('i64', 'gt_u', 40, 40, 0);
     testComparison('i64', 'ge_s', 40, 40, 1);
     testComparison('i64', 'ge_u', 40, 40, 1);
     testComparison('i64', 'eq', "0x400012345678", "0x400012345678", 1);
     testComparison('i64', 'ne', "0x400012345678", "0x400012345678", 0);
     testComparison('i64', 'ne', "0x400012345678", "0x500012345678", 1);
-    testComparison('i64', 'eq', "0xffffffffffffffff", "-1", 1);
+    testComparison('i64', 'eq', "0xffffffffffffffff", -1, 1);
     testComparison('i64', 'lt_s', "0x8000000012345678", "0x1", 1);
     testComparison('i64', 'lt_u', "0x8000000012345678", "0x1", 0);
-    testComparison('i64', 'le_s', "-1", "0", 1);
-    testComparison('i64', 'le_u', "-1", "-1", 1);
-    testComparison('i64', 'gt_s', "1", "0x8000000000000000", 1);
-    testComparison('i64', 'gt_u', "1", "0x8000000000000000", 0);
-    testComparison('i64', 'ge_s', "1", "0x8000000000000000", 1);
-    testComparison('i64', 'ge_u', "1", "0x8000000000000000", 0);
+    testComparison('i64', 'le_s', -1, 0, 1);
+    testComparison('i64', 'le_u', -1, -1, 1);
+    testComparison('i64', 'gt_s', 1, "0x8000000000000000", 1);
+    testComparison('i64', 'gt_u', 1, "0x8000000000000000", 0);
+    testComparison('i64', 'ge_s', 1, "0x8000000000000000", 1);
+    testComparison('i64', 'ge_u', 1, "0x8000000000000000", 0);
+
+    setJitCompilerOption('wasm.test-mode', 0);
 } else {
     // Sleeper test: once i64 works on more platforms, remove this if-else.
     try {
         testComparison('i64', 'eq', 40, 40, 1);
         assertEq(0, 1);
     } catch(e) {
         assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
     }
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -82,21 +82,32 @@ assertErrorMessage(() => wasmEvalText('(
 wasmEvalText('(module (func (nop)))');
 wasmEvalText('(module (func (result i32) (i32.const 42)))');
 wasmEvalText('(module (func (param i32)))');
 wasmEvalText('(module (func (param i32) (result i32) (i32.const 42)))');
 wasmEvalText('(module (func (result i32) (param i32) (i32.const 42)))');
 wasmEvalText('(module (func (param f32)))');
 wasmEvalText('(module (func (param f64)))');
 
-var hasI64 = getBuildConfiguration().x64;
-if (!hasI64) {
+if (!hasI64()) {
     assertErrorMessage(() => wasmEvalText('(module (func (param i64)))'), TypeError, /NYI/);
     assertErrorMessage(() => wasmEvalText('(module (func (result i64)))'), TypeError, /NYI/);
     assertErrorMessage(() => wasmEvalText('(module (func (result i32) (i32.wrap/i64 (i64.add (i64.const 1) (i64.const 2)))))'), TypeError, /NYI/);
+} else {
+    assertErrorMessage(() => wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))'), TypeError, /i64 argument/);
+    assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))'), TypeError, /i64 return type/);
+
+    setJitCompilerOption('wasm.test-mode', 1);
+
+    assertEqI64(wasmEvalText('(module (func (result i64) (i64.const 123)) (export "" 0))')(), {low: 123, high: 0});
+    assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (get_local 0)) (export "" 0))')({ low: 0x7fffffff, high: 0x12340000}),
+                {low: 0x7fffffff, high: 0x12340000});
+    assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (i64.add (get_local 0) (i64.const 1))) (export "" 0))')({ low: 0xffffffff, high: 0x12340000}), {low: 0x0, high: 0x12340001});
+
+    setJitCompilerOption('wasm.test-mode', 0);
 }
 
 // ----------------------------------------------------------------------------
 // imports
 
 assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /second argument, if present, must be an object/);
 assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /second argument, if present, must be an object/);
 
@@ -255,17 +266,17 @@ assertErrorMessage(() => wasmEvalText('(
 assertErrorMessage(() => wasmEvalText('(module (func (local f32) (set_local 0 (nop))))'), TypeError, mismatchError("void", "f32"));
 assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))'), TypeError, mismatchError("f32", "i32"));
 assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))'), TypeError, mismatchError("i32", "f32"));
 wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 0))))');
 wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 1))))');
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (i32.const 42))) (export "" 0))')(), 42);
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (get_local 0))) (export "" 0))')(), 0);
 
-if (!hasI64)
+if (!hasI64())
     assertErrorMessage(() => wasmEvalText('(module (func (local i64)))'), TypeError, /NYI/);
 
 assertEq(wasmEvalText('(module (func (param $a i32) (result i32) (get_local $a)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (param $a i32) (local $b i32) (result i32) (block (set_local $b (get_local $a)) (get_local $b))) (export "" 0))')(42), 42);
 
 wasmEvalText('(module (func (local i32) (local $a f32) (set_local 0 (i32.const 1)) (set_local $a (f32.const nan))))');
 
 // ----------------------------------------------------------------------------
@@ -342,16 +353,80 @@ var code = '(module (import "one" "" (re
 var imports = {one:()=>1, two:()=>2};
 assertEq(wasmEvalText(code.replace('BODY', '(call_import 0)'), imports)(), 1);
 assertEq(wasmEvalText(code.replace('BODY', '(call_import 1)'), imports)(), 2);
 assertEq(wasmEvalText(code.replace('BODY', '(call 0)'), imports)(), 3);
 assertEq(wasmEvalText(code.replace('BODY', '(call 1)'), imports)(), 4);
 
 assertEq(wasmEvalText(`(module (import "evalcx" "" (param i32) (result i32)) (func (result i32) (call_import 0 (i32.const 0))) (export "" 0))`, {evalcx})(), 0);
 
+if (typeof evaluate === 'function')
+    evaluate(`Wasm.instantiateModule(wasmTextToBinary('(module)')) `, { fileName: null });
+
+if (hasI64()) {
+    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /i64 argument/);
+    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /i64 return type/);
+
+    setJitCompilerOption('wasm.test-mode', 1);
+
+    let imp = {
+        param(i64) {
+            assertEqI64(i64, {
+                low: 0x9abcdef0,
+                high: 0x12345678
+            });
+            return 42;
+        },
+        result(i32) {
+            return {
+                low: 0xabcdef01,
+                high: 0x12345678 + i32
+            }
+        },
+        paramAndResult(i64) {
+            assertEqI64(i64, {
+                low: 0x9abcdef0,
+                high: 0x12345678
+            });
+            i64.low = 1337;
+            return i64;
+        }
+    }
+
+    assertEq(wasmEvalText(`(module
+        (import "param" "" (param i64) (result i32))
+        (func (result i32) (call_import 0 (i64.const 0x123456789abcdef0)))
+        (export "" 0))`, imp)(), 42);
+
+    assertEqI64(wasmEvalText(`(module
+        (import "result" "" (param i32) (result i64))
+        (func (result i64) (call_import 0 (i32.const 3)))
+        (export "" 0))`, imp)(), { low: 0xabcdef01, high: 0x1234567b });
+
+    // Ensure the ion exit is never taken.
+    let ionThreshold = 2 * getJitCompilerOptions()['ion.warmup.trigger'];
+    assertEqI64(wasmEvalText(`(module
+        (import "paramAndResult" "" (param i64) (result i64))
+        (func (result i64) (local i32) (local i64)
+         (set_local 0 (i32.const 0))
+         (loop $out $in
+             (set_local 1 (call_import 0 (i64.const 0x123456789abcdef0)))
+             (set_local 0 (i32.add (get_local 0) (i32.const 1)))
+             (if (i32.le_s (get_local 0) (i32.const ${ionThreshold})) (br $in))
+         )
+         (get_local 1)
+        )
+    (export "" 0))`, imp)(), { low: 1337, high: 0x12345678 });
+
+    setJitCompilerOption('wasm.test-mode', 0);
+} else {
+    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /NYI/);
+    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /NYI/);
+}
+
 var {v2i, i2i, i2v} = wasmEvalText(`(module
     (type (func (result i32)))
     (type (func (param i32) (result i32)))
     (type (func (param i32)))
     (func (type 0) (i32.const 13))
     (func (type 0) (i32.const 42))
     (func (type 1) (i32.add (get_local 0) (i32.const 1)))
     (func (type 1) (i32.add (get_local 0) (i32.const 2)))
@@ -402,23 +477,16 @@ assertErrorMessage(() => i2v(5), Error, 
 }
 
 for (bad of [6, 7, 100, Math.pow(2,31)-1, Math.pow(2,31), Math.pow(2,31)+1, Math.pow(2,32)-2, Math.pow(2,32)-1]) {
     assertThrowsInstanceOf(() => v2i(bad), RangeError);
     assertThrowsInstanceOf(() => i2i(bad, 0), RangeError);
     assertThrowsInstanceOf(() => i2v(bad, 0), RangeError);
 }
 
-if (hasI64) {
-    assertErrorMessage(() => wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))'), TypeError, /i64 argument/);
-    assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))'), TypeError, /i64 return type/);
-    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /i64 argument/);
-    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /i64 return type/);
-}
-
 var {v2i, i2i, i2v} = wasmEvalText(`(module
     (type $a (func (result i32)))
     (type $b (func (param i32) (result i32)))
     (type $c (func (param i32)))
     (func $a (type $a) (i32.const 13))
     (func $b (type $a) (i32.const 42))
     (func $c (type $b) (i32.add (get_local 0) (i32.const 1)))
     (func $d (type $b) (i32.add (get_local 0) (i32.const 2)))
@@ -577,31 +645,33 @@ testSelect('i32', Math.pow(2, 31) - 1, -
 testSelect('f32', Math.fround(13.37), Math.fround(19.89));
 testSelect('f32', 'infinity', '-0');
 testSelect('f32', 'nan', Math.pow(2, -31));
 
 testSelect('f64', 13.37, 19.89);
 testSelect('f64', 'infinity', '-0');
 testSelect('f64', 'nan', Math.pow(2, -31));
 
-if (!hasI64) {
+if (!hasI64()) {
     assertErrorMessage(() => wasmEvalText('(module (func (select (i64.const 0) (i64.const 1) (i32.const 0))))'), TypeError, /NYI/);
 } else {
+
+    setJitCompilerOption('wasm.test-mode', 1);
+
     var f = wasmEvalText(`
     (module
-     (func (result i32) (param i32)
-      (i64.gt_s
-       (select
-        (i64.const ${Math.pow(2, 31) + 1})
-        (i64.const ${-Math.pow(2, 31) - 1})
-        (get_local 0)
-       )
-       (i64.const ${Math.pow(2, 31)})
+     (func (result i64) (param i32)
+      (select
+       (i64.const 0xc0010ff08badf00d)
+       (i64.const 0x12345678deadc0de)
+       (get_local 0)
       )
      )
      (export "" 0)
-    )
-    `, imports);
+    )`, imports);
 
-    assertEq(f(0), 0);
-    assertEq(f(1), 1);
-    assertEq(f(-1), 1);
+    assertEqI64(f(0),  { low: 0xdeadc0de, high: 0x12345678});
+    assertEqI64(f(1),  { low: 0x8badf00d, high: 0xc0010ff0});
+    assertEqI64(f(-1), { low: 0x8badf00d, high: 0xc0010ff0});
+
+    setJitCompilerOption('wasm.test-mode', 0);
 }
+
--- a/js/src/jit-test/tests/wasm/random-control-flow.js
+++ b/js/src/jit-test/tests/wasm/random-control-flow.js
@@ -123,8 +123,28 @@ wasmEvalText(`(module (func
       (i32.const 0)
      )
     )
     (br $in)
    )
   )
  )
 ))`);
+
+wasmEvalText(`
+(module
+  (func $func$0
+   (select
+    (if
+     (i32.const 0)
+     (f32.const 0)
+     (i32.const 0)
+    )
+    (if
+     (i32.const 0)
+     (f32.const 0)
+     (i32.const 0)
+    )
+    (i32.const 0)
+   )
+  )
+)
+`);
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -51,16 +51,17 @@ T overrideDefault(const char* param, T d
     } else {
         Maybe<int> value = ParseInt(str);
         if (value.isSome())
             return value.ref();
         Warn(param, str);
     }
     return dflt;
 }
+
 #define SET_DEFAULT(var, dflt) var = overrideDefault("JIT_OPTION_" #var, dflt)
 DefaultJitOptions::DefaultJitOptions()
 {
     // Whether to perform expensive graph-consistency DEBUG-only assertions.
     // It can be useful to disable this to reduce DEBUG-compile time of large
     // asm.js programs.
     SET_DEFAULT(checkGraphConsistency, true);
 
@@ -183,16 +184,19 @@ DefaultJitOptions::DefaultJitOptions()
     if (const char* env = getenv(forcedRegisterAllocatorEnv)) {
         forcedRegisterAllocator = LookupRegisterAllocator(env);
         if (!forcedRegisterAllocator.isSome())
             Warn(forcedRegisterAllocatorEnv, env);
     }
 
     // Toggles whether unboxed plain objects can be created by the VM.
     SET_DEFAULT(disableUnboxedObjects, false);
+
+    // Test whether wasm int64 / double NaN bits testing is enabled.
+    SET_DEFAULT(wasmTestMode, false);
 }
 
 bool
 DefaultJitOptions::isSmallFunction(JSScript* script) const
 {
     return script->length() <= smallFunctionMaxBytecodeLength_;
 }
 
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -61,16 +61,17 @@ struct DefaultJitOptions
     bool disableScalarReplacement;
     bool disableSharedStubs;
     bool disableSincos;
     bool disableSink;
     bool eagerCompilation;
     bool forceInlineCaches;
     bool limitScriptSize;
     bool osr;
+    bool wasmTestMode;
     uint32_t baselineWarmUpThreshold;
     uint32_t exceptionBailoutThreshold;
     uint32_t frequentBailoutThreshold;
     uint32_t maxStackArgs;
     uint32_t osrPcMismatchesBeforeRecompile;
     uint32_t smallFunctionMaxBytecodeLength_;
     uint32_t jumpThreshold;
     mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -1282,16 +1282,23 @@ class ABIArg
 #else
     bool isGeneralRegPair() const { return false; }
 #endif
 
     Register gpr() const {
         MOZ_ASSERT(kind() == GPR);
         return Register::FromCode(u.gpr_);
     }
+    Register64 gpr64() const {
+#ifdef JS_PUNBOX64
+        return Register64(gpr());
+#else
+        MOZ_CRASH("NYI");
+#endif
+    }
     Register evenGpr() const {
         MOZ_ASSERT(isGeneralRegPair());
         return Register::FromCode(u.gpr_);
     }
     Register oddGpr() const {
         MOZ_ASSERT(isGeneralRegPair());
         return Register::FromCode(u.gpr_ + 1);
     }
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -41,16 +41,20 @@ struct Register {
         Register r = { Encoding(i) };
         return r;
     }
     static Register FromName(const char* name) {
         Code code = Registers::FromName(name);
         Register r = { Encoding(code) };
         return r;
     }
+    static Register Invalid() {
+        Register r = { Encoding(Codes::Invalid) };
+        return r;
+    }
     MOZ_CONSTEXPR Code code() const {
         return Code(reg_);
     }
     Encoding encoding() const {
         MOZ_ASSERT(Code(reg_) < Registers::Total);
         return reg_;
     }
     const char* name() const {
@@ -104,16 +108,20 @@ struct Register64
     Register low;
 #endif
 
 #ifdef JS_PUNBOX64
     explicit MOZ_CONSTEXPR Register64(Register r)
       : reg(r)
     {}
 #else
+    explicit Register64(Register r)
+      : high(Register::Invalid()), low(Register::Invalid())
+    {}
+
     MOZ_CONSTEXPR Register64(Register h, Register l)
       : high(h), low(l)
     {}
 #endif
 };
 
 class RegisterDump
 {
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -113,16 +113,17 @@ static MOZ_CONSTEXPR_VAR Register PreBar
 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg;
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = r3;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = r2;
 static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
 static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
 static MOZ_CONSTEXPR_VAR Register ReturnReg = r0;
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::d0, VFPRegister::Single };
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::d0, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnSimd128Reg = InvalidFloatReg;
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::d30, VFPRegister::Single };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::d15, VFPRegister::Double };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimd128Reg = InvalidFloatReg;
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchUIntReg = { FloatRegisters::d15, VFPRegister::UInt };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchIntReg = { FloatRegisters::d15, VFPRegister::Int };
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1419,21 +1419,16 @@ class MacroAssemblerARMCompat : public M
         // This is the instruction sequence that gcc generated for this
         // operation.
         ScratchRegisterScope scratch(asMasm());
         ma_sub(r, Imm32(0x80000001), scratch);
         ma_cmn(scratch, Imm32(3));
         ma_b(handleNotAnInt, Above);
     }
 
-    void memIntToValue(Address Source, Address Dest) {
-        load32(Source, lr);
-        storeValue(JSVAL_TYPE_INT32, lr, Dest);
-    }
-
     void lea(Operand addr, Register dest) {
         ma_add(addr.baseReg(), Imm32(addr.disp()), dest);
     }
 
     void abiret() {
         as_bx(lr);
     }
 
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -50,16 +50,17 @@ static constexpr Register CallTempReg1 =
 static constexpr Register CallTempReg2 = { Registers::x11 };
 static constexpr Register CallTempReg3 = { Registers::x12 };
 static constexpr Register CallTempReg4 = { Registers::x13 };
 static constexpr Register CallTempReg5 = { Registers::x14 };
 
 static constexpr Register PreBarrierReg = { Registers::x1 };
 
 static constexpr Register ReturnReg = { Registers::x0 };
+static constexpr Register64 ReturnReg64(ReturnReg);
 static constexpr Register JSReturnReg = { Registers::x2 };
 static constexpr Register FramePointer = { Registers::fp };
 static constexpr Register ZeroRegister = { Registers::sp };
 static constexpr ARMRegister ZeroRegister64 = { Registers::sp, 64 };
 static constexpr ARMRegister ZeroRegister32 = { Registers::sp, 32 };
 
 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1917,25 +1917,16 @@ class MacroAssemblerCompat : public vixl
 
     // FIXME: See CodeGeneratorX64 calls to noteAsmJSGlobalAccess.
     void patchAsmJSGlobalAccess(CodeOffset patchAt, uint8_t* code,
                                 uint8_t* globalData, unsigned globalDataOffset)
     {
         MOZ_CRASH("patchAsmJSGlobalAccess");
     }
 
-    void memIntToValue(const Address& src, const Address& dest) {
-        vixl::UseScratchRegisterScope temps(this);
-        const Register scratch = temps.AcquireX().asUnsized();
-        MOZ_ASSERT(scratch != src.base);
-        MOZ_ASSERT(scratch != dest.base);
-        load32(src, scratch);
-        storeValue(JSVAL_TYPE_INT32, scratch, dest);
-    }
-
     void profilerEnterFrame(Register framePtr, Register scratch) {
         AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
         loadPtr(activation, scratch);
         storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
         storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
     }
     void profilerExitFrame() {
         branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -997,21 +997,16 @@ class MacroAssemblerMIPS64Compat : publi
   protected:
     bool buildOOLFakeExitFrame(void* fakeReturnAddr);
 
   public:
     CodeOffset labelForPatch() {
         return CodeOffset(nextOffset().getOffset());
     }
 
-    void memIntToValue(Address Source, Address Dest) {
-        load32(Source, ScratchRegister);
-        storeValue(JSVAL_TYPE_INT32, ScratchRegister, Dest);
-    }
-
     void lea(Operand addr, Register dest) {
         ma_daddu(dest, addr.baseReg(), Imm32(addr.disp()));
     }
 
     void abiret() {
         as_jr(ra);
         as_nop();
     }
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -6,17 +6,16 @@
 
 #ifndef jit_none_MacroAssembler_none_h
 #define jit_none_MacroAssembler_none_h
 
 #include "jit/JitCompartment.h"
 #include "jit/MoveResolver.h"
 #include "jit/shared/Assembler-shared.h"
 
-
 namespace js {
 namespace jit {
 
 static MOZ_CONSTEXPR_VAR Register StackPointer = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR Register FramePointer = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR Register ReturnReg = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::invalid_reg };
@@ -67,18 +66,20 @@ static MOZ_CONSTEXPR_VAR Register RegExp
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = { Registers::invalid_reg };
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR Register JSReturnReg = { Registers::invalid_reg };
 
 #if defined(JS_NUNBOX32)
 static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg, InvalidReg);
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
 #elif defined(JS_PUNBOX64)
 static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg);
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg);
 #else
 #error "Bad architecture"
 #endif
 
 static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 4;
 static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 4;
 static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 8;
 static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value);
@@ -391,17 +392,16 @@ class MacroAssemblerNone : public Assemb
     void incrementInt32Value(Address) { MOZ_CRASH(); }
     void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); }
     void handleFailureWithHandlerTail(void*) { MOZ_CRASH(); }
 
     void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); }
     bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
     void loadWasmActivation(Register) { MOZ_CRASH(); }
     void loadAsmJSHeapRegisterFromGlobalData() { MOZ_CRASH(); }
-    void memIntToValue(Address, Address) { MOZ_CRASH(); }
 
     void setPrinter(Sprinter*) { MOZ_CRASH(); }
     Operand ToPayload(Operand base) { MOZ_CRASH(); }
 
     static const Register getStackPointer() { MOZ_CRASH(); }
 
     // Instrumentation for entering and leaving the profiler.
     void profilerEnterFrame(Register , Register ) { MOZ_CRASH(); }
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -78,16 +78,17 @@ struct ScratchRegisterScope : public Aut
 {
     explicit ScratchRegisterScope(MacroAssembler& masm)
       : AutoRegisterScope(masm, ScratchReg)
     { }
 };
 
 static MOZ_CONSTEXPR_VAR Register ReturnReg = rax;
 static MOZ_CONSTEXPR_VAR Register HeapReg = r15;
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(rax);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Single);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimd128Reg = xmm15;
 
 // Avoid rbp, which is the FramePointer, which is unavailable in some modes.
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -937,21 +937,16 @@ class MacroAssemblerX64 : public MacroAs
     void patchAsmJSGlobalAccess(CodeOffset patchAt, uint8_t* code, uint8_t* globalData,
                                 unsigned globalDataOffset)
     {
         uint8_t* nextInsn = code + patchAt.offset();
         MOZ_ASSERT(nextInsn <= globalData);
         uint8_t* target = globalData + globalDataOffset;
         ((int32_t*)nextInsn)[-1] = target - nextInsn;
     }
-    void memIntToValue(Address Source, Address Dest) {
-        ScratchRegisterScope scratch(asMasm());
-        load32(Source, scratch);
-        storeValue(JSVAL_TYPE_INT32, scratch, Dest);
-    }
 
     // Instrumentation for entering and leaving the profiler.
     void profilerEnterFrame(Register framePtr, Register scratch);
     void profilerExitFrame();
 };
 
 typedef MacroAssemblerX64 MacroAssemblerSpecific;
 
--- a/js/src/jit/x86-shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -100,16 +100,47 @@ AssemblerX86Shared::trace(JSTracer* trc)
         ::TraceDataRelocations(trc, masm.data(), reader);
     }
 }
 
 void
 AssemblerX86Shared::executableCopy(void* buffer)
 {
     masm.executableCopy(buffer);
+
+    // Crash diagnostics for bug 1124397. Check the code buffer has not been
+    // poisoned with 0xE5 bytes.
+    static const size_t MinPoisoned = 16;
+    const uint8_t* bytes = (const uint8_t*)buffer;
+    size_t len = size();
+
+    for (size_t i = 0; i < len; i += MinPoisoned) {
+        if (bytes[i] != 0xE5)
+            continue;
+
+        size_t startOffset = i;
+        while (startOffset > 0 && bytes[startOffset - 1] == 0xE5)
+            startOffset--;
+
+        size_t endOffset = i;
+        while (endOffset + 1 < len && bytes[endOffset + 1] == 0xE5)
+            endOffset++;
+
+        if (endOffset - startOffset < MinPoisoned)
+            continue;
+
+        volatile uintptr_t dump[5];
+        blackbox = dump;
+        blackbox[0] = uintptr_t(0xABCD4321);
+        blackbox[1] = uintptr_t(len);
+        blackbox[2] = uintptr_t(startOffset);
+        blackbox[3] = uintptr_t(endOffset);
+        blackbox[4] = uintptr_t(0xFFFF8888);
+        MOZ_CRASH("Corrupt code buffer");
+    }
 }
 
 void
 AssemblerX86Shared::processCodeLabels(uint8_t* rawCode)
 {
     for (size_t i = 0; i < codeLabels_.length(); i++) {
         CodeLabel label = codeLabels_[i];
         Bind(rawCode, label.patchAt(), rawCode + label.target()->offset());
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -39,16 +39,17 @@ static MOZ_CONSTEXPR_VAR FloatRegister x
 static MOZ_CONSTEXPR_VAR Register InvalidReg = { X86Encoding::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = FloatRegister();
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = ecx;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = edx;
 static MOZ_CONSTEXPR_VAR Register StackPointer = esp;
 static MOZ_CONSTEXPR_VAR Register FramePointer = ebp;
 static MOZ_CONSTEXPR_VAR Register ReturnReg = eax;
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimd128Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Simd128);
 
 // Avoid ebp, which is the FramePointer, which is unavailable in some modes.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6151,16 +6151,19 @@ JS_SetGlobalJitCompilerOption(JSRuntime*
         break;
       case JSJITCOMPILER_JUMP_THRESHOLD:
         if (value == uint32_t(-1)) {
             jit::DefaultJitOptions defaultValues;
             value = defaultValues.jumpThreshold;
         }
         jit::JitOptions.jumpThreshold = value;
         break;
+      case JSJITCOMPILER_WASM_TEST_MODE:
+        jit::JitOptions.wasmTestMode = !!value;
+        break;
       default:
         break;
     }
 }
 
 JS_PUBLIC_API(int)
 JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt)
 {
@@ -6177,16 +6180,18 @@ JS_GetGlobalJitCompilerOption(JSRuntime*
       case JSJITCOMPILER_ION_ENABLE:
         return JS::RuntimeOptionsRef(rt).ion();
       case JSJITCOMPILER_BASELINE_ENABLE:
         return JS::RuntimeOptionsRef(rt).baseline();
       case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
         return rt->canUseOffthreadIonCompilation();
       case JSJITCOMPILER_SIGNALS_ENABLE:
         return rt->canUseSignalHandlers();
+      case JSJITCOMPILER_WASM_TEST_MODE:
+        return jit::JitOptions.wasmTestMode ? 1 : 0;
       default:
         break;
     }
 #endif
     return 0;
 }
 
 /************************************************************************/
@@ -6267,17 +6272,17 @@ void AutoFilename::setScriptSource(js::S
         p->incref();
         setUnowned(p->filename());
     }
 }
 
 void AutoFilename::setUnowned(const char* filename)
 {
     MOZ_ASSERT(!get());
-    filename_.as<const char*>() = filename;
+    filename_.as<const char*>() = filename ? filename : "";
 }
 
 void AutoFilename::setOwned(UniqueChars&& filename)
 {
     MOZ_ASSERT(!get());
     filename_ = AsVariant(Move(filename));
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5515,17 +5515,18 @@ JS_SetOffthreadIonCompilationEnabled(JSR
     Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger")           \
     Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger")                     \
     Register(ION_GVN_ENABLE, "ion.gvn.enable")                             \
     Register(ION_FORCE_IC, "ion.forceinlineCaches")                        \
     Register(ION_ENABLE, "ion.enable")                                     \
     Register(BASELINE_ENABLE, "baseline.enable")                           \
     Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
     Register(SIGNALS_ENABLE, "signals.enable")                             \
-    Register(JUMP_THRESHOLD, "jump-threshold")
+    Register(JUMP_THRESHOLD, "jump-threshold")                             \
+    Register(WASM_TEST_MODE, "wasm.test-mode")
 
 typedef enum JSJitCompilerOption {
 #define JIT_COMPILER_DECLARE(key, str) \
     JSJITCOMPILER_ ## key,
 
     JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE)
 #undef JIT_COMPILER_DECLARE
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2040,16 +2040,17 @@ static const AllocKind AllocKindsToReloc
     AllocKind::OBJECT4_BACKGROUND,
     AllocKind::OBJECT8,
     AllocKind::OBJECT8_BACKGROUND,
     AllocKind::OBJECT12,
     AllocKind::OBJECT12_BACKGROUND,
     AllocKind::OBJECT16,
     AllocKind::OBJECT16_BACKGROUND,
     AllocKind::SCRIPT,
+    AllocKind::LAZY_SCRIPT,
     AllocKind::SHAPE,
     AllocKind::ACCESSOR_SHAPE,
     AllocKind::FAT_INLINE_STRING,
     AllocKind::STRING,
     AllocKind::EXTERNAL_STRING
 };
 
 Arena*
@@ -2408,16 +2409,24 @@ void
 MovingTracer::onScriptEdge(JSScript** scriptp)
 {
     JSScript* script = *scriptp;
     if (IsForwarded(script))
         *scriptp = Forwarded(script);
 }
 
 void
+MovingTracer::onLazyScriptEdge(LazyScript** lazyp)
+{
+    LazyScript* lazy = *lazyp;
+    if (IsForwarded(lazy))
+        *lazyp = Forwarded(lazy);
+}
+
+void
 Zone::prepareForCompacting()
 {
     FreeOp* fop = runtimeFromMainThread()->defaultFreeOp();
     discardJitCode(fop);
 }
 
 void
 GCRuntime::sweepTypesAfterCompacting(Zone* zone)
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1101,17 +1101,18 @@ struct MightBeForwarded
     static_assert(mozilla::IsBaseOf<Cell, T>::value,
                   "T must derive from Cell");
     static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
                   "T must not be Cell or TenuredCell");
 
     static const bool value = mozilla::IsBaseOf<JSObject, T>::value ||
                               mozilla::IsBaseOf<Shape, T>::value ||
                               mozilla::IsBaseOf<JSString, T>::value ||
-                              mozilla::IsBaseOf<JSScript, T>::value;
+                              mozilla::IsBaseOf<JSScript, T>::value ||
+                              mozilla::IsBaseOf<js::LazyScript, T>::value;
 };
 
 template <typename T>
 inline bool
 IsForwarded(T* t)
 {
     RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
     if (!MightBeForwarded<T>::value) {
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -42,20 +42,16 @@ ShapeTable::init(ExclusiveContext* cx, S
 {
     uint32_t sizeLog2 = CeilingLog2Size(entryCount_);
     uint32_t size = JS_BIT(sizeLog2);
     if (entryCount_ >= size - (size >> 2))
         sizeLog2++;
     if (sizeLog2 < MIN_SIZE_LOG2)
         sizeLog2 = MIN_SIZE_LOG2;
 
-    /*
-     * Use rt->calloc for memory accounting and overpressure handling
-     * without OOM reporting. See ShapeTable::change.
-     */
     size = JS_BIT(sizeLog2);
     entries_ = cx->pod_calloc<Entry>(size);
     if (!entries_)
         return false;
 
     MOZ_ASSERT(sizeLog2 <= HASH_BITS);
     hashShift_ = HASH_BITS - sizeLog2;
 
@@ -263,29 +259,29 @@ ShapeTable::search(jsid id)
 
     MOZ_CRASH("Shape::search failed to find an expected entry.");
 }
 
 template ShapeTable::Entry& ShapeTable::search<MaybeAdding::Adding>(jsid id);
 template ShapeTable::Entry& ShapeTable::search<MaybeAdding::NotAdding>(jsid id);
 
 bool
-ShapeTable::change(int log2Delta, ExclusiveContext* cx)
+ShapeTable::change(ExclusiveContext* cx, int log2Delta)
 {
     MOZ_ASSERT(entries_);
     MOZ_ASSERT(-1 <= log2Delta && log2Delta <= 1);
 
     /*
      * Grow, shrink, or compress by changing this->entries_.
      */
     uint32_t oldLog2 = HASH_BITS - hashShift_;
     uint32_t newLog2 = oldLog2 + log2Delta;
     uint32_t oldSize = JS_BIT(oldLog2);
     uint32_t newSize = JS_BIT(newLog2);
-    Entry* newTable = cx->pod_calloc<Entry>(newSize);
+    Entry* newTable = cx->maybe_pod_calloc<Entry>(newSize);
     if (!newTable)
         return false;
 
     /* Now that we have newTable allocated, update members. */
     MOZ_ASSERT(newLog2 <= HASH_BITS);
     hashShift_ = HASH_BITS - newLog2;
     removedCount_ = 0;
     Entry* oldTable = entries_;
@@ -313,21 +309,21 @@ ShapeTable::grow(ExclusiveContext* cx)
 {
     MOZ_ASSERT(needsToGrow());
 
     uint32_t size = capacity();
     int delta = removedCount_ < (size >> 2);
 
     MOZ_ASSERT(entryCount_ + removedCount_ <= size - 1);
 
-    if (!change(delta, cx)) {
-        if (entryCount_ + removedCount_ == size - 1)
+    if (!change(cx, delta)) {
+        if (entryCount_ + removedCount_ == size - 1) {
+            ReportOutOfMemory(cx);
             return false;
-
-        cx->recoverFromOutOfMemory();
+        }
     }
 
     return true;
 }
 
 void
 ShapeTable::trace(JSTracer* trc)
 {
@@ -1043,17 +1039,17 @@ NativeObject::removeProperty(ExclusiveCo
         }
 
         /* Generate a new shape for the object, infallibly. */
         JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
 
         /* Consider shrinking table if its load factor is <= .25. */
         uint32_t size = table.capacity();
         if (size > ShapeTable::MIN_SIZE && table.entryCount() <= size >> 2)
-            (void) table.change(-1, cx);
+            (void) table.change(cx, -1);
     } else {
         /*
          * Non-dictionary-mode shape tables are shared immutables, so all we
          * need do is retract the last property and we'll either get or else
          * lazily make via a later hashify the exact table for the new property
          * lineage.
          */
         MOZ_ASSERT(shape == self->lastProperty());
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -212,23 +212,21 @@ class ShapeTable {
     /*
      * This counts the ShapeTable object itself (which must be
      * heap-allocated) and its |entries| array.
      */
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
         return mallocSizeOf(this) + mallocSizeOf(entries_);
     }
 
-    /*
-     * NB: init and change are fallible but do not report OOM, so callers can
-     * cope or ignore. They do however use the context's calloc method in
-     * order to update the malloc counter on success.
-     */
+    // init() is fallible and reports OOM to the context.
     bool init(ExclusiveContext* cx, Shape* lastProp);
-    bool change(int log2Delta, ExclusiveContext* cx);
+
+    // change() is fallible but does not report OOM.
+    bool change(ExclusiveContext* cx, int log2Delta);
 
     template<MaybeAdding Adding>
     Entry& search(jsid id);
 
     void trace(JSTracer* trc);
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkAfterMovingGC();
 #endif
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -640,17 +640,17 @@ FindFrameTargetedByInputEvent(WidgetGUIE
   }
   // Now we basically undo the operations in GetEventCoordinatesRelativeTo, to
   // get back the (now-clamped) coordinates in the event's widget's space.
   nsView* view = aRootFrame->GetView();
   if (!view) {
     return target;
   }
   LayoutDeviceIntPoint widgetPoint = nsLayoutUtils::TranslateViewToWidget(
-        aRootFrame->PresContext(), view, point, aEvent->widget);
+        aRootFrame->PresContext(), view, point, aEvent->mWidget);
   if (widgetPoint.x != NS_UNCONSTRAINEDSIZE) {
     // If that succeeded, we update the point in the event
     aEvent->refPoint = widgetPoint;
   }
   return target;
 }
 
 } // namespace mozilla
--- a/layout/base/TouchManager.cpp
+++ b/layout/base/TouchManager.cpp
@@ -60,17 +60,16 @@ EvictTouchPoint(RefPtr<dom::Touch>& aTou
       nsIPresShell* presShell = doc->GetShell();
       if (presShell) {
         nsIFrame* frame = presShell->GetRootFrame();
         if (frame) {
           nsPoint pt(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
           nsCOMPtr<nsIWidget> widget = frame->GetView()->GetNearestWidget(&pt);
           if (widget) {
             WidgetTouchEvent event(true, eTouchEnd, widget);
-            event.widget = widget;
             event.mTime = PR_IntervalNow();
             event.mTouches.AppendElement(aTouch);
             nsEventStatus status;
             widget->DispatchEvent(&event, status);
             return;
           }
         }
       }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2168,17 +2168,17 @@ nsPoint
 nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
                                              const LayoutDeviceIntPoint& aPoint,
                                              nsIFrame* aFrame)
 {
   if (!aFrame) {
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
-  nsIWidget* widget = aEvent->AsGUIEvent()->widget;
+  nsIWidget* widget = aEvent->AsGUIEvent()->mWidget;
   if (!widget) {
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
   return GetEventCoordinatesRelativeTo(widget, aPoint, aFrame);
 }
 
 nsPoint
@@ -7630,16 +7630,36 @@ nsLayoutUtils::SizeOfTextRunsForFrames(n
     for (nsFrameList::Enumerator e(childLists.CurrentList());
          !e.AtEnd(); e.Next()) {
       total += SizeOfTextRunsForFrames(e.get(), aMallocSizeOf, clear);
     }
   }
   return total;
 }
 
+struct PrefCallbacks
+{
+  const char* name;
+  PrefChangedFunc func;
+};
+static const PrefCallbacks kPrefCallbacks[] = {
+  { GRID_ENABLED_PREF_NAME,
+    GridEnabledPrefChangeCallback },
+  { WEBKIT_PREFIXES_ENABLED_PREF_NAME,
+    WebkitPrefixEnabledPrefChangeCallback },
+  { TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
+    TextAlignUnsafeEnabledPrefChangeCallback },
+  { DISPLAY_CONTENTS_ENABLED_PREF_NAME,
+    DisplayContentsEnabledPrefChangeCallback },
+  { FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
+    FloatLogicalValuesEnabledPrefChangeCallback },
+  { BG_CLIP_TEXT_ENABLED_PREF_NAME,
+    BackgroundClipTextEnabledPrefChangeCallback },
+};
+
 /* static */
 void
 nsLayoutUtils::Initialize()
 {
   Preferences::AddUintVarCache(&sFontSizeInflationMaxRatio,
                                "font.size.inflation.maxRatio");
   Preferences::AddUintVarCache(&sFontSizeInflationEmPerLine,
                                "font.size.inflation.emPerLine");
@@ -7657,56 +7677,34 @@ nsLayoutUtils::Initialize()
                                "nglayout.debug.invalidation");
   Preferences::AddBoolVarCache(&sCSSVariablesEnabled,
                                "layout.css.variables.enabled");
   Preferences::AddBoolVarCache(&sInterruptibleReflowEnabled,
                                "layout.interruptible-reflow.enabled");
   Preferences::AddBoolVarCache(&sSVGTransformBoxEnabled,
                                "svg.transform-box.enabled");
 
-  Preferences::RegisterCallback(GridEnabledPrefChangeCallback,
-                                GRID_ENABLED_PREF_NAME);
-  GridEnabledPrefChangeCallback(GRID_ENABLED_PREF_NAME, nullptr);
-  Preferences::RegisterCallback(WebkitPrefixEnabledPrefChangeCallback,
-                                WEBKIT_PREFIXES_ENABLED_PREF_NAME);
-  WebkitPrefixEnabledPrefChangeCallback(WEBKIT_PREFIXES_ENABLED_PREF_NAME,
-                                        nullptr);
-  Preferences::RegisterCallback(TextAlignUnsafeEnabledPrefChangeCallback,
-                                TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME);
-  Preferences::RegisterCallback(DisplayContentsEnabledPrefChangeCallback,
-                                DISPLAY_CONTENTS_ENABLED_PREF_NAME);
-  DisplayContentsEnabledPrefChangeCallback(DISPLAY_CONTENTS_ENABLED_PREF_NAME,
-                                           nullptr);
-  TextAlignUnsafeEnabledPrefChangeCallback(TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
-                                           nullptr);
-  Preferences::RegisterCallback(FloatLogicalValuesEnabledPrefChangeCallback,
-                                FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME);
-  FloatLogicalValuesEnabledPrefChangeCallback(FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
-                                              nullptr);
-  Preferences::RegisterCallback(BackgroundClipTextEnabledPrefChangeCallback,
-                                BG_CLIP_TEXT_ENABLED_PREF_NAME);
-  BackgroundClipTextEnabledPrefChangeCallback(BG_CLIP_TEXT_ENABLED_PREF_NAME,
-                                              nullptr);
-
+  for (auto& callback : kPrefCallbacks) {
+    Preferences::RegisterCallbackAndCall(callback.func, callback.name);
+  }
   nsComputedDOMStyle::RegisterPrefChangeCallbacks();
 }
 
 /* static */
 void
 nsLayoutUtils::Shutdown()
 {
   if (sContentMap) {
     delete sContentMap;
     sContentMap = nullptr;
   }
 
-  Preferences::UnregisterCallback(GridEnabledPrefChangeCallback,
-                                  GRID_ENABLED_PREF_NAME);
-  Preferences::UnregisterCallback(WebkitPrefixEnabledPrefChangeCallback,
-                                  WEBKIT_PREFIXES_ENABLED_PREF_NAME);
+  for (auto& callback : kPrefCallbacks) {
+    Preferences::UnregisterCallback(callback.func, callback.name);
+  }
   nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
 
   // so the cached initial quotes array doesn't appear to be a leak
   nsStyleList::Shutdown();
 }
 
 /* static */
 void
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3640,17 +3640,17 @@ PresShell::DispatchSynthMouseMove(Widget
   if (restyleManager->IsServo()) {
     NS_ERROR("stylo: cannot dispatch synthetic mouse moves when using a "
              "ServoRestyleManager yet");
     return;
   }
   uint32_t hoverGenerationBefore =
     restyleManager->AsGecko()->GetHoverGeneration();
   nsEventStatus status;
-  nsView* targetView = nsView::GetViewFor(aEvent->widget);
+  nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
   if (!targetView)
     return;
   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
   if (MOZ_UNLIKELY(mIsDestroying)) {
     return;
   }
   if (aFlushOnHoverChange &&
       hoverGenerationBefore != restyleManager->AsGecko()->GetHoverGeneration()) {
@@ -6762,27 +6762,27 @@ PresShell::RecordMouseLocation(WidgetGUI
        aEvent->AsMouseEvent()->reason == WidgetMouseEvent::eReal) ||
       aEvent->mMessage == eMouseEnterIntoWidget ||
       aEvent->mMessage == eMouseDown ||
       aEvent->mMessage == eMouseUp) {
     nsIFrame* rootFrame = GetRootFrame();
     if (!rootFrame) {
       nsView* rootView = mViewManager->GetRootView();
       mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
-        aEvent->widget, aEvent->refPoint, rootView);
+        aEvent->mWidget, aEvent->refPoint, rootView);
       mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
     } else {
       mMouseLocation =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
       mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
     }
 #ifdef DEBUG_MOUSE_LOCATION
     if (aEvent->mMessage == eMouseEnterIntoWidget) {
       printf("[ps=%p]got mouse enter for %p\n",
-             this, aEvent->widget);
+             this, aEvent->mWidget);
     }
     printf("[ps=%p]setting mouse location to (%d,%d)\n",
            this, mMouseLocation.x, mMouseLocation.y);
 #endif
     if (aEvent->mMessage == eMouseEnterIntoWidget) {
       SynthesizeMouseMove(false);
     }
   } else if (aEvent->mMessage == eMouseExitFromWidget) {
@@ -6790,17 +6790,17 @@ PresShell::RecordMouseLocation(WidgetGUI
     // pres shell doesn't receive mouse move events, we don't check which widget
     // the mouse exit was for since this seems to vary by platform.  Hopefully
     // this won't matter at all since we'll get the mouse move or enter after
     // the mouse exit when the mouse moves from one of our widgets into another.
     mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
     mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
 #ifdef DEBUG_MOUSE_LOCATION
     printf("[ps=%p]got mouse exit for %p\n",
-           this, aEvent->widget);
+           this, aEvent->mWidget);
     printf("[ps=%p]clearing mouse location\n",
            this);
 #endif
   }
 }
 
 nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
 {
@@ -6899,17 +6899,17 @@ DispatchPointerFromMouseOrTouch(PresShel
 
     for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
       mozilla::dom::Touch* touch = touchEvent->mTouches[i];
       if (!touch || !touch->convertToPointer) {
         continue;
       }
 
       WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
-                               touchEvent->widget);
+                               touchEvent->mWidget);
       event.isPrimary = i == 0;
       event.pointerId = touch->Identifier();
       event.refPoint = touch->mRefPoint;
       event.mModifiers = touchEvent->mModifiers;
       event.width = touch->RadiusX();
       event.height = touch->RadiusY();
       event.tiltX = touch->tiltX;
       event.tiltY = touch->tiltY;
@@ -7032,17 +7032,17 @@ PresShell::DispatchBeforeKeyboardEventIn
   for (int32_t i = length - 1; i >= 0; i--) {
     eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
     if (!eventTarget || !CanDispatchEvent(&aEvent)) {
       return;
     }
 
     aChainIndex = i;
     InternalBeforeAfterKeyboardEvent beforeEvent(aEvent.IsTrusted(),
-                                                 message, aEvent.widget);
+                                                 message, aEvent.mWidget);
     beforeEvent.AssignBeforeAfterKeyEventData(aEvent, false);
     EventDispatcher::Dispatch(eventTarget, mPresContext, &beforeEvent);
 
     if (beforeEvent.DefaultPrevented()) {
       aDefaultPrevented = true;
       return;
     }
   }
@@ -7066,17 +7066,17 @@ PresShell::DispatchAfterKeyboardEventInt
   // Dispatch after events from the innermost element.
   for (uint32_t i = aStartOffset; i < length; i++) {
     eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
     if (!eventTarget || !CanDispatchEvent(&aEvent)) {
       return;
     }
 
     InternalBeforeAfterKeyboardEvent afterEvent(aEvent.IsTrusted(),
-                                                message, aEvent.widget);
+                                                message, aEvent.mWidget);
     afterEvent.AssignBeforeAfterKeyEventData(aEvent, false);
     afterEvent.mEmbeddedCancelled.SetValue(embeddedCancelled);
     EventDispatcher::Dispatch(eventTarget, mPresContext, &afterEvent);
     embeddedCancelled = afterEvent.DefaultPrevented();
   }
 }
 
 void
@@ -7099,17 +7099,17 @@ PresShell::DispatchAfterKeyboardEvent(ns
 }
 
 bool
 PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
 {
   bool rv =
     mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
   if (aEvent) {
-    rv &= (aEvent && aEvent->widget && !aEvent->widget->Destroyed());
+    rv &= (aEvent && aEvent->mWidget && !aEvent->mWidget->Destroyed());
   }
   return rv;
 }
 
 void
 PresShell::HandleKeyboardEvent(nsINode* aTarget,
                                WidgetKeyboardEvent& aEvent,
                                bool aEmbeddedCancelled,
@@ -8365,17 +8365,17 @@ PresShell::DispatchTouchEventToDOM(Widge
       if (capturingContent->OwnerDoc() != doc) {
         // Wrong document, don't dispatch anything.
         continue;
       }
       content = capturingContent;
     }
     // copy the event
     WidgetTouchEvent newEvent(touchEvent->IsTrusted(),
-                              touchEvent->mMessage, touchEvent->widget);
+                              touchEvent->mMessage, touchEvent->mWidget);
     newEvent.AssignTouchEventData(*touchEvent, false);
     newEvent.target = targetPtr;
 
     RefPtr<PresShell> contentPresShell;
     if (doc == mDocument) {
       contentPresShell = static_cast<PresShell*>(doc->GetShell());
       if (contentPresShell) {
         //XXXsmaug huge hack. Pushing possibly capturing content,
@@ -8473,17 +8473,17 @@ PresShell::AdjustContextMenuKeyEvent(Wid
     nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
     if (popupFrame) {
       nsIFrame* itemFrame =
         (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
       if (!itemFrame)
         itemFrame = popupFrame;
 
       nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
-      aEvent->widget = widget;
+      aEvent->mWidget = widget;
       LayoutDeviceIntPoint widgetPoint = widget->WidgetToScreenOffset();
       aEvent->refPoint = LayoutDeviceIntPoint::FromUnknownPoint(
         itemFrame->GetScreenRect().BottomLeft()) - widgetPoint;
 
       mCurrentEventContent = itemFrame->GetContent();
       mCurrentEventFrame = itemFrame;
 
       return true;
@@ -8499,38 +8499,38 @@ PresShell::AdjustContextMenuKeyEvent(Wid
   // Use the root view manager's widget since it's most likely to have one,
   // and the coordinates returned by GetCurrentItemAndPositionForElement
   // are relative to the widget of the root of the root view manager.
   nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
   aEvent->refPoint.x = 0;
   aEvent->refPoint.y = 0;
   if (rootPC) {
     rootPC->PresShell()->GetViewManager()->
-      GetRootWidget(getter_AddRefs(aEvent->widget));
-
-    if (aEvent->widget) {
+      GetRootWidget(getter_AddRefs(aEvent->mWidget));
+
+    if (aEvent->mWidget) {
       // default the refpoint to the topleft of our document
       nsPoint offset(0, 0);
       nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
       if (rootFrame) {
         nsView* view = rootFrame->GetClosestView(&offset);
-        offset += view->GetOffsetToWidget(aEvent->widget);
+        offset += view->GetOffsetToWidget(aEvent->mWidget);
         aEvent->refPoint =
           LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel());
       }
     }
   } else {
-    aEvent->widget = nullptr;
+    aEvent->mWidget = nullptr;
   }
 
   // see if we should use the caret position for the popup
   LayoutDeviceIntPoint caretPoint;
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
-  if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
+  if (PrepareToUseCaretPosition(aEvent->mWidget, caretPoint)) {
     // caret position is good
     aEvent->refPoint = caretPoint;
     return true;
   }
 
   // If we're here because of the key-equiv for showing context menus, we
   // have to reset the event target to the currently focused element. Get it
   // from the focus controller.
@@ -8540,17 +8540,17 @@ PresShell::AdjustContextMenuKeyEvent(Wid
     fm->GetFocusedElement(getter_AddRefs(currentFocus));
 
   // Reset event coordinates relative to focused frame in view
   if (currentFocus) {
     nsCOMPtr<nsIContent> currentPointElement;
     GetCurrentItemAndPositionForElement(currentFocus,
                                         getter_AddRefs(currentPointElement),
                                         aEvent->refPoint,
-                                        aEvent->widget);
+                                        aEvent->mWidget);
     if (currentPointElement) {
       mCurrentEventContent = currentPointElement;
       mCurrentEventFrame = nullptr;
       GetCurrentEventFrame();
     }
   }
 
   return true;
@@ -9809,44 +9809,44 @@ PresShell::DelayedInputEvent::DelayedInp
 PresShell::DelayedInputEvent::~DelayedInputEvent()
 {
   delete mEvent;
 }
 
 void
 PresShell::DelayedInputEvent::Dispatch()
 {
-  if (!mEvent || !mEvent->widget) {
-    return;
-  }
-  nsCOMPtr<nsIWidget> widget = mEvent->widget;
+  if (!mEvent || !mEvent->mWidget) {
+    return;
+  }
+  nsCOMPtr<nsIWidget> widget = mEvent->mWidget;
   nsEventStatus status;
   widget->DispatchEvent(mEvent, status);
 }
 
 PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) :
   DelayedInputEvent()
 {
   WidgetMouseEvent* mouseEvent =
     new WidgetMouseEvent(aEvent->IsTrusted(),
                          aEvent->mMessage,
-                         aEvent->widget,
+                         aEvent->mWidget,
                          aEvent->reason,
                          aEvent->context);
   mouseEvent->AssignMouseEventData(*aEvent, false);
   mEvent = mouseEvent;
 }
 
 PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) :
   DelayedInputEvent()
 {
   WidgetKeyboardEvent* keyEvent =
     new WidgetKeyboardEvent(aEvent->IsTrusted(),
                             aEvent->mMessage,
-                            aEvent->widget);
+                            aEvent->mWidget);
   keyEvent->AssignKeyEventData(*aEvent, false);
   keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
   mEvent = keyEvent;
 }
 
 // Start of DEBUG only code
 
 #ifdef DEBUG
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -100,33 +100,33 @@ nsResizerFrame::HandleEvent(nsPresContex
           // If there is no window, then resizing isn't allowed.
           if (!window)
             break;
 
           doDefault = false;
 
           // ask the widget implementation to begin a resize drag if it can
           Direction direction = GetDirection();
-          nsresult rv = aEvent->widget->BeginResizeDrag(aEvent,
+          nsresult rv = aEvent->mWidget->BeginResizeDrag(aEvent,
                         direction.mHorizontal, direction.mVertical);
           // for native drags, don't set the fields below
           if (rv != NS_ERROR_NOT_IMPLEMENTED)
              break;
              
           // if there's no native resize support, we need to do window
           // resizing ourselves
           window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y,
                                      &mMouseDownRect.width, &mMouseDownRect.height);
         }
 
         // remember current mouse coordinates
         LayoutDeviceIntPoint refPoint;
         if (!GetEventPoint(aEvent, refPoint))
           return NS_OK;
-        mMouseDownPoint = refPoint + aEvent->widget->WidgetToScreenOffset();
+        mMouseDownPoint = refPoint + aEvent->mWidget->WidgetToScreenOffset();
 
         // we're tracking
         mTrackingMouseMove = true;
 
         nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
       }
     }
     break;
@@ -164,17 +164,18 @@ nsResizerFrame::HandleEvent(nsPresContex
       // both MouseMove and direction are negative when pointing to the
       // top and left, and positive when pointing to the bottom and right
 
       // retrieve the offset of the mousemove event relative to the mousedown.
       // The difference is how much the resize needs to be
       LayoutDeviceIntPoint refPoint;
       if (!GetEventPoint(aEvent, refPoint))
         return NS_OK;
-      LayoutDeviceIntPoint screenPoint = refPoint + aEvent->widget->WidgetToScreenOffset();
+      LayoutDeviceIntPoint screenPoint =
+        refPoint + aEvent->mWidget->WidgetToScreenOffset();
       LayoutDeviceIntPoint mouseMove(screenPoint - mMouseDownPoint);
 
       // Determine which direction to resize by checking the dir attribute.
       // For windows and menus, ensure that it can be resized in that direction.
       Direction direction = GetDirection();
       if (window || menuPopupFrame) {
         if (menuPopupFrame) {
           menuPopupFrame->CanAdjustEdges(
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -612,17 +612,17 @@ nsXULPopupManager::InitTriggerEvent(nsID
             presContext->GetRootPresContext();
           if (!rootDocPresContext)
             return;
           nsIFrame* rootDocumentRootFrame = rootDocPresContext->
               PresShell()->FrameManager()->GetRootFrame();
           if ((event->mClass == eMouseEventClass || 
                event->mClass == eMouseScrollEventClass ||
                event->mClass == eWheelEventClass) &&
-               !event->AsGUIEvent()->widget) {
+               !event->AsGUIEvent()->mWidget) {
             // no widget, so just use the client point if available
             nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
             nsIntPoint clientPt;
             mouseEvent->GetClientX(&clientPt.x);
             mouseEvent->GetClientY(&clientPt.y);
 
             // XXX this doesn't handle IFRAMEs in transforms
             nsPoint thisDocToRootDocOffset = presShell->FrameManager()->
@@ -1410,20 +1410,20 @@ nsXULPopupManager::FirePopupShowingEvent
   WidgetMouseEvent event(true, eXULPopupShowing, nullptr,
                          WidgetMouseEvent::eReal);
 
   // coordinates are relative to the root widget
   nsPresContext* rootPresContext =
     presShell->GetPresContext()->GetRootPresContext();
   if (rootPresContext) {
     rootPresContext->PresShell()->GetViewManager()->
-      GetRootWidget(getter_AddRefs(event.widget));
+      GetRootWidget(getter_AddRefs(event.mWidget));
   }
   else {
-    event.widget = nullptr;
+    event.mWidget = nullptr;
   }
 
   event.refPoint = mCachedMousePoint;
   event.mModifiers = mCachedModifiers;
   EventDispatcher::Dispatch(popup, presContext, &event, nullptr, &status);
 
   mCachedMousePoint = LayoutDeviceIntPoint(0, 0);
   mOpeningPopup = nullptr;
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -180,18 +180,22 @@ convert_stream_type_to_sl_stream(cubeb_s
   default:
     return 0xFFFFFFFF;
   }
 }
 #endif
 
 static void opensl_destroy(cubeb * ctx);
 
+
 #if defined(__ANDROID__)
 
+// B2G header file still contain the required function declarations.
+#ifndef MOZ_WIDGET_GONK
+
 #if (__ANDROID_API__ >= ANDROID_VERSION_LOLLIPOP)
 typedef int (system_property_get)(const char*, char*);
 
 static int
 __system_property_get(const char* name, char* value)
 {
   void* libc = dlopen("libc.so", RTLD_LAZY);
   if (!libc) {
@@ -204,16 +208,18 @@ static int
   if (func) {
     ret = func(name, value);
   }
   dlclose(libc);
   return ret;
 }
 #endif
 
+#endif // MOZ_WIDGET_GONK
+
 static int
 get_android_version(void)
 {
   char version_string[PROP_VALUE_MAX];
 
   memset(version_string, 0, PROP_VALUE_MAX);
 
   int len = __system_property_get("ro.build.version.sdk", version_string);
--- a/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in
+++ b/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in
@@ -1,10 +1,11 @@
         <activity
             android:name="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"
+            android:process=":search"
             android:launchMode="singleTop"
             android:taskAffinity="@ANDROID_PACKAGE_NAME@.SEARCH"
             android:icon="@drawable/search_launcher"
             android:label="@string/search_app_name"
             android:configChanges="orientation|screenSize"
             android:theme="@style/AppTheme">
             <intent-filter>
                 <action android:name="android.intent.action.ASSIST"/>
@@ -44,16 +45,17 @@
                 <action android:name="org.mozilla.widget.LAUNCH_NEW_TAB"/>
             </intent-filter>
 
             <meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info" />
         </receiver>
 
         <activity
             android:name="org.mozilla.search.SearchPreferenceActivity"
+            android:process=":search"
             android:logo="@drawable/search_launcher"
             android:label="@string/search_pref_title"
             android:parentActivityName="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"
             android:theme="@style/SettingsTheme" >
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"
                 android:value="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"/>
         </activity>
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -29,16 +29,19 @@ pref("security.ssl3.dhe_rsa_aes_256_sha"
 pref("security.ssl3.ecdhe_rsa_rc4_128_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_rc4_128_sha", true);
 pref("security.ssl3.rsa_aes_128_sha", true);
 pref("security.ssl3.rsa_aes_256_sha", true);
 pref("security.ssl3.rsa_des_ede3_sha", true);
 pref("security.ssl3.rsa_rc4_128_sha", true);
 pref("security.ssl3.rsa_rc4_128_md5", true);
 
+pref("security.content.signature.root_hash",
+     "97:E8:BA:9C:F1:2F:B3:DE:53:CC:42:A4:E6:57:7E:D6:4D:F4:93:C2:47:B4:14:FE:A0:36:81:8D:38:23:56:0E");
+
 pref("security.default_personal_cert",   "Ask Every Time");
 pref("security.remember_cert_checkbox_default_setting", true);
 pref("security.ask_for_password",        0);
 pref("security.password_lifetime",       30);
 
 pref("security.OCSP.enabled", 1);
 pref("security.OCSP.require", false);
 pref("security.OCSP.GET.enabled", false);
--- a/testing/firefox-ui/tests/puppeteer/manifest.ini
+++ b/testing/firefox-ui/tests/puppeteer/manifest.ini
@@ -8,13 +8,14 @@ tags = local
 [test_security.py]
 tags = remote
 [test_software_update.py]
 [test_utils.py]
 
 # UI tests
 [test_about_window.py]
 [test_menubar.py]
+[test_notifications.py]
 [test_page_info_window.py]
 [test_tabbar.py]
 [test_toolbars.py]
 tags = remote
 [test_windows.py]
new file mode 100644
index 0000000000000000000000000000000000000000..c8877b55dec371fa6417fc626ef1a6f3113cc2bc
GIT binary patch
literal 1552
zc$^FHW@Zs#U|`^2xLcX!&XKXBU5t@|;S&(^Fvu_@<>!|amlP!y=w%g$hHx@4I|ev~
zfpBRBHv=Qf3uXoeFtN7(bk<=50oU*Uy1c{uJeFQcbqa5EQfzhD{W56U@r_Mu3@@!v
z<o)^ml;)SM@4Q}|n_Dcg_kj0%p?Q|>-Zu)oD;`)ZNYONB-^7&Y;V;nT%v65;yzqYO
z_q=60Kb{MVNO-N&>f*ge^UliX*5iC^(~e)helD+ju_uR4M(m^)vvjUJda*>mHR;Wq
z<xg3vpYmig?GSu?N|?j#LU)h$+IIi#k9J&dUD@rcty2;j$>&+%CieU?*X$ndcc%jn
zM{qb^+O=wz%o+<mkEBIUHqLt-voK_;_F9dvXTD8jpJnq<?b6m~nyRr6f)sYCzmJr?
zWH5XE>1R(;{7-$}x3ABu>gUUso43^P{MWi=y!~wFzZEe%?^W2()VrU_xBnA=05EL1
z7(hTQBFmit39tjhHaVjxKQ~n$9IR_ZoWis)gEasiIUob#4KJhw0(lugEPyZ|BQ+-{
z9~eKmaFak7%_MDaouGnVjt~4?g{7VReP2pHedi3@5ZV!T%H!<Gli`;F1H8_k_xD`o
z6WX=)nHIAaTQ_s4Mr(SAlclQUO4pTLUILXXiY9PvKeFgb(E_dsA`A$>1&3$3Prjz3
zFArpcFhAUBdbx>tnQ5uTC19870bQks>9XYfypq(s5{2A6-6EjU#G;a%)Z$_VsOPv4
zL68Ov0{z15Lsh`EX#mv74YVgS52zz2N3SR)4Qz*ls8bjSquG%=`LrK6dH&?meltO6
zd86;*E4o4oVmbk;3AvLpH+)duw0z6c*M&ZDtecA7&9N@F4LtQV(DM`LHO|H1AC=BN
zGVNYeR9)>~<GMTaPu~r(DRO-6Ukav5-M(<NXy=khzt1)szv>mL_x_oYQ7-7dq`GM%
zL+P{7XWkwsotte=uhU#{u2%4OVat^5545zSz8G@U8&}61tzO-IFO=i$1n-#|>yGlt
zRE3+bWC`t<r8zf3zo=Vi&TXE>T8q7YIro&*hfZ7C9Uy(r-JzH@$GWtdLG$eDjhpyt
zH2Mo{m(Hu^kP$4oKK)IPYFBhUi;Kbw#f7skWaY_OhlyE8oqkuMY|`-6pmNi)d*K>(
ztn-?R8x~#smM5}hPvi5q%CD!}MOPS{op|xNuz7=duD0vZ<toqRQ!X5<U2OQt`N6aA
z9f=p2SGCl={9ZkG`Siw_na_3X`KtK+4o&F%$0>TEUe7T0!xg5}^&8$<h~4XPY@fEB
z=dB!*f#=2fiK<`svvluc4De=Tl4HhIz({}-5Rl2Rq!GkIEpAvL#SKQD0GWs@TS-7!
z0t{~*V}J(3GZ`x+YhX1DR~AEd-du!XNEr^Fskm|nvZ)qK448R^6_Qu*I2AK1ARD>>
cXedg?V1;B13<Fu&K$=*Aa5hk9JPU{i03S06YXATM
new file mode 100644
--- /dev/null
+++ b/testing/firefox-ui/tests/puppeteer/test_notifications.py
@@ -0,0 +1,77 @@
+# 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/.
+
+import os
+
+from marionette_driver import By
+from marionette_driver.errors import TimeoutException
+
+from firefox_ui_harness.testcases import FirefoxTestCase
+from firefox_puppeteer.ui.browser.notifications import (
+    AddOnInstallFailedNotification)
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestNotifications(FirefoxTestCase):
+
+    def setUp(self):
+        FirefoxTestCase.setUp(self)
+        # setting this pref prevents a notification from being displayed
+        # when e10s is enabled. see http://mzl.la/1TVNAXh
+        self.prefs.set_pref('browser.tabs.remote.force-enable', True)
+
+    def tearDown(self):
+        try:
+            if self.browser.notification is not None:
+                self.browser.notification.close()
+        finally:
+            FirefoxTestCase.tearDown(self)
+
+    def test_no_notification(self):
+        """No initial notifications are shown"""
+        self.assertIsNone(self.browser.notification)
+
+    def test_notification_with_origin(self):
+        """Trigger a notification with an origin"""
+        self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+        self.assertIsNotNone(self.browser.notification.origin)
+        self.assertIsNotNone(self.browser.notification.label)
+
+    def test_close_notification(self):
+        """Trigger and dismiss a notification"""
+        self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+        self.browser.notification.close()
+        self.assertIsNone(self.browser.notification)
+
+    def test_add_on_failed_notification(self):
+        """Trigger add-on failed notification using an unsigned add-on"""
+        self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+        self.assertIsInstance(self.browser.notification,
+                              AddOnInstallFailedNotification)
+
+    def test_wait_for_any_notification_timeout(self):
+        """Wait for a notification when one is not shown"""
+        message = 'No notification was shown'
+        with self.assertRaisesRegexp(TimeoutException, message):
+            self.browser.wait_for_notification()
+
+    def test_wait_for_specific_notification_timeout(self):
+        """Wait for a notification when one is not shown"""
+        message = 'AddOnInstallFailedNotification was not shown'
+        with self.assertRaisesRegexp(TimeoutException, message):
+            self.browser.wait_for_notification(AddOnInstallFailedNotification)
+
+    def test_wait_for_no_notification_timeout(self):
+        """Wait for no notification when one is shown"""
+        message = 'Unexpected notification shown'
+        self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+        with self.assertRaisesRegexp(TimeoutException, message):
+            self.browser.wait_for_notification(None)
+
+    def trigger_add_on_notification(self, add_on):
+        with self.marionette.using_context('content'):
+            self.marionette.navigate('file://{0}'.format(here))
+            self.marionette.find_element(By.LINK_TEXT, add_on).click()
+        self.browser.wait_for_notification()
--- a/testing/mozharness/configs/beetmover/repacks.yml.tmpl
+++ b/testing/mozharness/configs/beetmover/repacks.yml.tmpl
@@ -12,16 +12,19 @@ mapping:
       artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar
       s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar
     checksum:
       artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums
       s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums
     checksum_sig:
       artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums.asc
       s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc
+    xpi:
+      artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi
+      s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/xpi/{{ locale }}.xpi
 
   {% if platform == "win32" %}
     full_installer:
       artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe
       s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe
     stub_installer:
       artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe
       s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe
--- a/testing/mozharness/scripts/desktop_partner_repacks.py
+++ b/testing/mozharness/scripts/desktop_partner_repacks.py
@@ -104,17 +104,17 @@ class DesktopPartnerRepacks(ReleaseMixin
             self.fatal("repack_manifests_url not supplied.")
 
     def _pre_config_lock(self, rw_config):
         self.read_buildbot_config()
         if not self.buildbot_config:
             self.warning("Skipping buildbot properties overrides")
         else:
             props = self.buildbot_config["properties"]
-            for prop in ['version', 'build_number']:
+            for prop in ['version', 'build_number', 'revision']:
                 if props.get(prop):
                     self.info("Overriding %s with %s" % (prop, props[prop]))
                     self.config[prop] = props.get(prop)
 
         if self.config.get('require_buildprops', False) is True:
             if not self.buildbot_config:
                 self.fatal("Unable to load properties from file: %s" % self.config.get('buildbot_json_path'))
             buildbot_props = self.buildbot_config.get('properties', {})
@@ -187,16 +187,18 @@ class DesktopPartnerRepacks(ReleaseMixin
         if self.config.get('partner'):
             repack_cmd.extend(["--partner", self.config['partner']])
         if self.config.get('s3cfg'):
             repack_cmd.extend(["--s3cfg", self.config['s3cfg']])
         if self.config.get('hgroot'):
             repack_cmd.extend(["--hgroot", self.config['hgroot']])
         if self.config.get('hgrepo'):
             repack_cmd.extend(["--repo", self.config['hgrepo']])
+        if self.config.get('revision'):
+            repack_cmd.extend(["--tag", self.config["revision"]])
 
         return self.run_command(repack_cmd,
                                 cwd=self.query_abs_dirs()['abs_scripts_dir'])
 
 # main {{{
 if __name__ == '__main__':
     partner_repacks = DesktopPartnerRepacks()
     partner_repacks.run_and_exit()
--- a/testing/puppeteer/firefox/docs/index.rst
+++ b/testing/puppeteer/firefox/docs/index.rst
@@ -33,16 +33,17 @@ The following libraries are currently im
 future. Each library is available from an instance of the FirefoxTestCase class.
 
 .. toctree::
 
    ui/about_window/window
    ui/deck
    ui/menu
    ui/pageinfo/window
+   ui/browser/notifications
    ui/browser/tabbar
    ui/browser/toolbars
    ui/browser/window
    ui/update_wizard/dialog
    ui/windows
    api/appinfo
    api/keys
    api/l10n
new file mode 100644
--- /dev/null
+++ b/testing/puppeteer/firefox/docs/ui/browser/notifications.rst
@@ -0,0 +1,44 @@
+.. py:currentmodule:: firefox_puppeteer.ui.browser.notifications
+
+Notifications
+=============
+
+AddOnInstallBlockedNotification
+-------------------------------
+
+.. autoclass:: AddOnInstallBlockedNotification
+   :members:
+   :inherited-members:
+   :show-inheritance:
+
+AddOnInstallConfirmationNotification
+------------------------------------
+
+.. autoclass:: AddOnInstallConfirmationNotification
+   :members:
+   :inherited-members:
+   :show-inheritance:
+
+AddOnInstallCompleteNotification
+--------------------------------
+
+.. autoclass:: AddOnInstallCompleteNotification
+   :members:
+   :inherited-members:
+   :show-inheritance:
+
+AddOnInstallFailedNotification
+------------------------------
+
+.. autoclass:: AddOnInstallFailedNotification
+   :members:
+   :inherited-members:
+   :show-inheritance:
+
+AddOnProgressNotification
+-------------------------
+
+.. autoclass:: AddOnProgressNotification
+   :members:
+   :inherited-members:
+   :show-inheritance:
new file mode 100644
--- /dev/null
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/notifications.py
@@ -0,0 +1,84 @@
+# 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/.
+
+from abc import ABCMeta
+
+from marionette_driver import By
+
+from firefox_puppeteer.ui_base_lib import UIBaseLib
+
+
+class BaseNotification(UIBaseLib):
+    """Abstract base class for any kind of notification."""
+    __metaclass__ = ABCMeta
+
+    @property
+    def label(self):
+        """Provides access to the notification label.
+
+        :returns: The notification label.
+        """
+        return self.element.get_attribute('label')
+
+    @property
+    def origin(self):
+        """Provides access to the notification origin.
+
+        :returns: The notification origin.
+        """
+        return self.element.get_attribute('origin')
+
+    def close(self):
+        """Close the notification."""
+        self.element.find_element(
+            By.ANON_ATTRIBUTE, {'anonid': 'closebutton'}).click()
+
+
+class AddOnInstallBlockedNotification(BaseNotification):
+    """Add-on install blocked notification."""
+
+    def allow(self):
+        """Allow the add-on to be installed."""
+        self.element.find_element(
+            By.ANON_ATTRIBUTE, {'anonid': 'button'}).find_element(
+            By.ANON_ATTRIBUTE, {'anonid': 'button'}).click()
+
+
+class AddOnInstallConfirmationNotification(BaseNotification):
+    """Add-on install confirmation notification."""
+
+    @property
+    def add_on(self):
+        """Provides access to the add-on name.
+
+        :returns: The add-on name.
+        """
+        label = self.element.find_element(
+            By.CSS_SELECTOR, '#addon-install-confirmation-content label')
+        return label.get_attribute('value')
+
+    def cancel(self):
+        """Cancel installation of the add-on."""
+        self.element.find_element(
+            By.ID, 'addon-install-confirmation-cancel').click()
+
+    def install(self):
+        """Proceed with installation of the add-on."""
+        self.element.find_element(
+            By.ID, 'addon-install-confirmation-accept').click()
+
+
+class AddOnInstallCompleteNotification(BaseNotification):
+    """Add-on install complete notification."""
+    pass
+
+
+class AddOnInstallFailedNotification(BaseNotification):
+    """Add-on install failed notification."""
+    pass
+
+
+class AddOnProgressNotification(BaseNotification):
+    """Add-on progress notification."""
+    pass
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
@@ -1,22 +1,31 @@
 # 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/.
 
 import firefox_puppeteer.errors as errors
 
 from marionette_driver import By, Wait
-from marionette_driver.errors import NoSuchWindowException
+from marionette_driver.errors import (
+    NoSuchElementException,
+    NoSuchWindowException)
 from marionette_driver.keys import Keys
 
 from firefox_puppeteer.api.l10n import L10n
 from firefox_puppeteer.api.prefs import Preferences
 from firefox_puppeteer.decorators import use_class_as_property
 from firefox_puppeteer.ui.about_window.window import AboutWindow
+from firefox_puppeteer.ui.browser.notifications import (
+    AddOnInstallBlockedNotification,
+    AddOnInstallConfirmationNotification,
+    AddOnInstallCompleteNotification,
+    AddOnInstallFailedNotification,
+    AddOnProgressNotification,
+    BaseNotification)
 from firefox_puppeteer.ui.browser.tabbar import TabBar
 from firefox_puppeteer.ui.browser.toolbars import NavBar
 from firefox_puppeteer.ui.pageinfo.window import PageInfoWindow
 from firefox_puppeteer.ui.windows import BaseWindow, Windows
 import firefox_puppeteer.errors as errors
 
 
 class BrowserWindow(BaseWindow):
@@ -80,16 +89,50 @@ class BrowserWindow(BaseWindow):
 
         if not self._navbar:
             navbar = self.window_element.find_element(By.ID, 'nav-bar')
             self._navbar = NavBar(lambda: self.marionette, self, navbar)
 
         return self._navbar
 
     @property
+    def notification(self):
+        """Provides access to the currently displayed notification."""
+
+        notifications_map = {
+            'addon-install-blocked-notification': AddOnInstallBlockedNotification,
+            'addon-install-confirmation-notification': AddOnInstallConfirmationNotification,
+            'addon-install-complete-notification': AddOnInstallCompleteNotification,
+            'addon-install-failed-notification': AddOnInstallFailedNotification,
+            'addon-progress-notification': AddOnProgressNotification,
+        }
+
+        try:
+            notification = self.window_element.find_element(
+                By.CSS_SELECTOR, '#notification-popup popupnotification')
+        except NoSuchElementException:
+            return None  # no notification is displayed
+        notification_id = notification.get_attribute('id')
+        return notifications_map[notification_id](
+            lambda: self.marionette, self, notification)
+
+    def wait_for_notification(self, notification_class=BaseNotification):
+        """Waits for the specified notification to be displayed."""
+        if notification_class is None:
+            Wait(self.marionette).until(
+                lambda _: self.notification is None,
+                message='Unexpected notification shown.')
+        else:
+            message = '{0} was not shown.'.format(notification_class.__name__)
+            if notification_class is BaseNotification:
+                message = 'No notification was shown.'
+            Wait(self.marionette).until(lambda _: isinstance(
+                self.notification, notification_class), message=message)
+
+    @property
     def tabbar(self):
         """Provides access to the tab bar.
 
         See the :class:`~ui.browser.tabbar.TabBar` reference.
         """
         self.switch_to()
 
         if not self._tabbar:
old mode 100644
new mode 100755
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -414,16 +414,20 @@ class XPCShellTestsTests(unittest.TestCa
         self.log = StringIO()
         self.tempdir = tempfile.mkdtemp()
         self.utility_path = os.path.join(objdir, 'dist', 'bin')
         logger = structured.commandline.setup_logging("selftest%s" % id(self),
                                                       {},
                                                       {"tbpl": self.log})
         self.x = XPCShellTests(logger)
         self.x.harness_timeout = 15
+        self.symbols_path = None
+        candidate_path = os.path.join(build_obj.distdir, 'crashreporter-symbols')
+        if (os.path.isdir(candidate_path)):
+          self.symbols_path = candidate_path
 
     def tearDown(self):
         shutil.rmtree(self.tempdir)
 
     def writeFile(self, name, contents):
         """
         Write |contents| to a file named |name| in the temp directory,
         and return the full path to the file.
@@ -449,25 +453,24 @@ class XPCShellTestsTests(unittest.TestCa
                 testlines.extend(t[1:])
         self.manifest = self.writeFile("xpcshell.ini", """
 [DEFAULT]
 head =
 tail =
 
 """ + "\n".join(testlines))
 
-    def assertTestResult(self, expected, shuffle=False, verbose=False,
-                         symbolsPath=None):
+    def assertTestResult(self, expected, shuffle=False, verbose=False):
         """
         Assert that self.x.runTests with manifest=self.manifest
         returns |expected|.
         """
         self.assertEquals(expected,
                           self.x.runTests(xpcshellBin,
-                                          symbolsPath=symbolsPath,
+                                          symbolsPath=self.symbols_path,
                                           manifest=self.manifest,
                                           mozInfo=mozinfo.info,
                                           shuffle=shuffle,
                                           verbose=verbose,
                                           sequential=True,
                                           testingModulesDir=os.path.join(objdir, '_tests', 'modules'),
                                           utility_path=self.utility_path),
                           msg="""Tests should have %s, log:
@@ -527,35 +530,27 @@ tail =
         self.assertNotInLog(TEST_PASS_STRING)
 
     @unittest.skipIf(mozinfo.isWin or not mozinfo.info.get('debug'),
                      'We don\'t have a stack fixer on hand for windows.')
     def testAssertStack(self):
         """
         When an assertion is hit, we should produce a useful stack.
         """
-        # Passing symbolsPath will cause the stack fixer to use
-        # fix_stack_using_bpsyms and exercise the fileid utility in
-        # this test.
-        symbolsPath = None
-        candidate_path = os.path.join(build_obj.distdir, 'crashreporter-symbols')
-        if os.path.isdir(candidate_path):
-          symbolsPath = candidate_path
-
         self.writeFile("test_assert.js", '''
           add_test(function test_asserts_immediately() {
             Components.classes["@mozilla.org/xpcom/debug;1"]
                       .getService(Components.interfaces.nsIDebug2)
                       .assertion("foo", "assertion failed", "test.js", 1)
             run_next_test();
           });
         ''')
 
         self.writeManifest(["test_assert.js"])
-        self.assertTestResult(False, symbolsPath=symbolsPath)
+        self.assertTestResult(False)
 
         self.assertInLog("###!!! ASSERTION")
         log_lines = self.log.getvalue().splitlines()
         line_pat = "#\d\d:"
         unknown_pat = "#\d\d\: \?\?\?\[.* \+0x[a-f0-9]+\]"
         self.assertFalse(any(re.search(unknown_pat, line) for line in log_lines),
                          "An stack frame without symbols was found in\n%s" % pprint.pformat(log_lines))
         self.assertTrue(any(re.search(line_pat, line) for line in log_lines),
--- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm
+++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm
@@ -582,27 +582,27 @@ EventTargetParent.init();
 
 // This function returns a listener that will not fire on events where
 // the target is a remote xul:browser element itself. We'd rather let
 // the child process handle the event and pass it up via
 // EventTargetParent.
 var filteringListeners = new WeakMap();
 function makeFilteringListener(eventType, listener)
 {
-  if (filteringListeners.has(listener)) {
-    return filteringListeners.get(listener);
-  }
-
   // Some events are actually targeted at the <browser> element
   // itself, so we only handle the ones where know that won't happen.
   let eventTypes = ["mousedown", "mouseup", "click"];
   if (eventTypes.indexOf(eventType) == -1) {
     return listener;
   }
 
+  if (filteringListeners.has(listener)) {
+    return filteringListeners.get(listener);
+  }
+
   function filter(event) {
     let target = event.originalTarget;
     if (target instanceof Ci.nsIDOMXULElement &&
         target.localName == "browser" &&
         target.isRemoteBrowser) {
       return;
     }
 
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -170,22 +170,20 @@
           <body>
           <![CDATA[
             if (this.type == "scrubber") {
                 this.Utils.log("--- dragStateChanged: " + isDragging + " ---");
                 this.isDragging = isDragging;
                 if (isDragging) {
                     this.wasPausedBeforeDrag = this.Utils.video.paused;
                     this.isDraggingComplete = false;
-                    this.previousPlaybackRate = this.Utils.video.playbackRate;
                     this.Utils.video.pause();
                 } else if (!this.wasPausedBeforeDrag && !this.isDraggingComplete) {
                     this.isDraggingComplete = true;
                     // After the drag ends, resume playing.
-                    this.Utils.video.playbackRate = this.previousPlaybackRate;
                     this.Utils.video.play();
                 } else {
                     this.isDraggingComplete = true;
                 }
             }
           ]]>
           </body>
       </method>
@@ -1018,17 +1016,16 @@
                 },
 
                 _triggeredByControls: false,
 
                 togglePause : function () {
                     if (this.video.paused || this.video.ended) {
                         this._triggeredByControls = true;
                         this.hideClickToPlay();
-                        this.video.playbackRate = this.video.defaultPlaybackRate;
                         this.video.play();
                     } else {
                         this.video.pause();
                     }
 
                     // We'll handle style changes in the event listener for
                     // the "play" and "pause" events, same as if content
                     // script was controlling video playback.
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -1118,26 +1118,26 @@ nsView::RequestRepaint()
     presShell->ScheduleViewManagerFlush();
   }
 }
 
 nsEventStatus
 nsView::HandleEvent(WidgetGUIEvent* aEvent,
                     bool aUseAttachedEvents)
 {
-  NS_PRECONDITION(nullptr != aEvent->widget, "null widget ptr");
+  NS_PRECONDITION(nullptr != aEvent->mWidget, "null widget ptr");
 
   nsEventStatus result = nsEventStatus_eIgnore;
   nsView* view;
   if (aUseAttachedEvents) {
-    nsIWidgetListener* listener = aEvent->widget->GetAttachedWidgetListener();
+    nsIWidgetListener* listener = aEvent->mWidget->GetAttachedWidgetListener();
     view = listener ? listener->GetView() : nullptr;
   }
   else {
-    view = GetViewFor(aEvent->widget);
+    view = GetViewFor(aEvent->mWidget);
   }
 
   if (view) {
     RefPtr<nsViewManager> vm = view->GetViewManager();
     vm->DispatchEvent(aEvent, view, &result);
   }
 
   return result;
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -495,46 +495,46 @@ public:
  ******************************************************************************/
 
 class WidgetGUIEvent : public WidgetEvent
 {
 protected:
   WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
                  EventClassID aEventClassID)
     : WidgetEvent(aIsTrusted, aMessage, aEventClassID)
-    , widget(aWidget)
+    , mWidget(aWidget)
   {
   }
 
   WidgetGUIEvent()
   {
   }
 
 public:
   virtual WidgetGUIEvent* AsGUIEvent() override { return this; }
 
   WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
     : WidgetEvent(aIsTrusted, aMessage, eGUIEventClass)
-    , widget(aWidget)
+    , mWidget(aWidget)
   {
   }
 
   virtual WidgetEvent* Duplicate() const override
   {
     MOZ_ASSERT(mClass == eGUIEventClass,
                "Duplicate() must be overridden by sub class");
     // Not copying widget, it is a weak reference.
     WidgetGUIEvent* result = new WidgetGUIEvent(false, mMessage, nullptr);
     result->AssignGUIEventData(*this, true);
     result->mFlags = mFlags;
     return result;
   }
 
-  /// Originator of the event
-  nsCOMPtr<nsIWidget> widget;
+  // Originator of the event
+  nsCOMPtr<nsIWidget> mWidget;
 
   /*
    * Explanation for this PluginEvent class:
    *
    * WidgetGUIEvent's mPluginEvent member used to be a void* pointer,
    * used to reference external, OS-specific data structures.
    *
    * That void* pointer wasn't serializable by itself, causing
@@ -587,17 +587,17 @@ public:
     }
 
     void Clear()
     {
       mBuffer.Clear();
     }
   };
 
-  /// Event for NPAPI plugin
+  // Event for NPAPI plugin
   PluginEvent mPluginEvent;
 
   void AssignGUIEventData(const WidgetGUIEvent& aEvent, bool aCopyTargets)
   {
     AssignEventData(aEvent, aCopyTargets);
 
     // widget should be initialized with the constructor.
 
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -841,17 +841,17 @@ ContentCacheInParent::OnCompositionEvent
      this, ToChar(aEvent.mMessage),
      NS_ConvertUTF16toUTF8(aEvent.mData).get(), aEvent.mData.Length(),
      aEvent.mRanges ? aEvent.mRanges->Length() : 0, mPendingEventsNeedingAck,
      GetBoolName(mIsComposing), mCommitStringByRequest));
 
   // We must be able to simulate the selection because
   // we might not receive selection updates in time
   if (!mIsComposing) {
-    if (aEvent.widget && aEvent.widget->PluginHasFocus()) {
+    if (aEvent.mWidget && aEvent.mWidget->PluginHasFocus()) {
       // If focus is on plugin, we cannot get selection range
       mCompositionStart = 0;
     } else {
       mCompositionStart = mSelection.StartOffset();
     }
   }
 
   mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -303,17 +303,17 @@ PuppetWidget::InitEvent(WidgetGUIEvent& 
   }
   event.mTime = PR_Now() / 1000;
 }
 
 NS_IMETHODIMP
 PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
-  debug_DumpEvent(stdout, event->widget, event, "PuppetWidget", 0);
+  debug_DumpEvent(stdout, event->mWidget, event, "PuppetWidget", 0);
 #endif
 
   MOZ_ASSERT(!mChild || mChild->mWindowType == eWindowType_popup,
              "Unexpected event dispatch!");
 
   AutoCacheNativeKeyCommands autoCache(this);
   if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) {
     WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
--- a/widget/TouchEvents.h
+++ b/widget/TouchEvents.h
@@ -102,17 +102,17 @@ public:
     , direction(0)
     , delta(0.0)
     , clickCount(0)
   {
   }
 
   WidgetSimpleGestureEvent(const WidgetSimpleGestureEvent& aOther)
     : WidgetMouseEventBase(aOther.IsTrusted(), aOther.mMessage,
-                           aOther.widget, eSimpleGestureEventClass)
+                           aOther.mWidget, eSimpleGestureEventClass)
     , allowedDirections(aOther.allowedDirections)
     , direction(aOther.direction)
     , delta(aOther.delta)
     , clickCount(0)
   {
   }
 
   virtual WidgetEvent* Duplicate() const override
@@ -162,17 +162,17 @@ public:
   virtual WidgetTouchEvent* AsTouchEvent() override { return this; }
 
   WidgetTouchEvent()
   {
     MOZ_COUNT_CTOR(WidgetTouchEvent);
   }
 
   WidgetTouchEvent(const WidgetTouchEvent& aOther)
-    : WidgetInputEvent(aOther.IsTrusted(), aOther.mMessage, aOther.widget,
+    : WidgetInputEvent(aOther.IsTrusted(), aOther.mMessage, aOther.mWidget,
                        eTouchEventClass)
   {
     MOZ_COUNT_CTOR(WidgetTouchEvent);
     mModifiers = aOther.mModifiers;
     mTime = aOther.mTime;
     mTimeStamp = aOther.mTimeStamp;
     mTouches.AppendElements(aOther.mTouches);
     mFlags.mCancelable = mMessage != eTouchCancel;
--- a/widget/android/NativeJSContainer.cpp
+++ b/widget/android/NativeJSContainer.cpp
@@ -34,26 +34,16 @@ bool CheckThread()
     if (!NS_IsMainThread()) {
         jni::ThrowException("java/lang/IllegalThreadStateException",
                             "Not on Gecko thread");
         return false;
     }
     return true;
 }
 
-bool
-CheckJSCall(bool result)
-{
-    if (!result) {
-        jni::ThrowException("java/lang/UnsupportedOperationException",
-                            "JSAPI call failed");
-    }
-    return result;
-}
-
 template<class C, typename T> bool
 CheckJNIArgument(const jni::Ref<C, T>& arg)
 {
     if (!arg) {
         jni::ThrowException("java/lang/IllegalArgumentException",
                             "Null argument");
     }
     return !!arg;
@@ -124,16 +114,26 @@ class NativeJSContainerImpl final
     {
         if (!mJSObject) {
             jni::ThrowException("java/lang/NullPointerException",
                                 "Null JSObject");
         }
         return !!mJSObject;
     }
 
+    bool CheckJSCall(bool result) const
+    {
+        if (!result) {
+            JS_ClearPendingException(mJSContext);
+            jni::ThrowException("java/lang/UnsupportedOperationException",
+                                "JSAPI call failed");
+        }
+        return result;
+    }
+
     // Check that a JS Value contains a particular property type as indicaed by
     // the property's InValue method (e.g. StringProperty::InValue).
     bool CheckProperty(bool (Self::*InValue)(JS::HandleValue) const,
                        JS::HandleValue val) const
     {
         if (!(this->*InValue)(val)) {
             // XXX this can happen when converting a double array inside a
             // Bundle, because double arrays can be misidentified as an int
@@ -430,27 +430,31 @@ class NativeJSContainerImpl final
             return false;
         }
         JS::RootedObject obj(mJSContext, &val.toObject());
         bool isArray;
         uint32_t length = 0;
         if (!JS_IsArrayObject(mJSContext, obj, &isArray) ||
             !isArray ||
             !JS_GetArrayLength(mJSContext, obj, &length)) {
+            JS_ClearPendingException(mJSContext);
             return false;
         }
         if (!length) {
             // Empty arrays are always okay.
             return true;
         }
         // We only check to see the first element is the target type. If the
         // array has mixed types, we'll throw an error during actual conversion.
         JS::RootedValue element(mJSContext);
-        return JS_GetElement(mJSContext, obj, 0, &element) &&
-               (this->*Prop::InValue)(element);
+        if (!JS_GetElement(mJSContext, obj, 0, &element)) {
+            JS_ClearPendingException(mJSContext);
+            return false;
+        }
+        return (this->*Prop::InValue)(element);
     }
 
     template<class Prop> typename Prop::NativeArray
     ArrayFromValue(JS::HandleValue val)
     {
         JS::RootedObject obj(mJSContext, &val.toObject());
         uint32_t length = 0;
         if (!CheckJSCall(JS_GetArrayLength(mJSContext, obj, &length))) {
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -3096,17 +3096,17 @@ nsWindow::GeckoViewSupport::OnImeReplace
                         status == nsEventStatus_eConsumeNoDefault) {
                     MOZ_ASSERT(i > 0 &&
                             mIMEKeyEvents[i - 1]->mMessage == eKeyDown);
                     // The previous key down event resulted in eConsumeNoDefault
                     // so we should not dispatch the current key press event.
                     continue;
                 }
                 // widget for duplicated events is initially nullptr.
-                event->widget = &window;
+                event->mWidget = &window;
                 window.DispatchEvent(event, status);
             }
             mIMEKeyEvents.Clear();
             return;
         }
 
         {
             WidgetCompositionEvent event(true, eCompositionStart, &window);
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1431,17 +1431,17 @@ nsresult nsChildView::ConfigureChildren(
   return NS_OK;
 }
 
 // Invokes callback and ProcessEvent methods on Event Listener object
 NS_IMETHODIMP nsChildView::DispatchEvent(WidgetGUIEvent* event,
                                          nsEventStatus& aStatus)
 {
 #ifdef DEBUG
-  debug_DumpEvent(stdout, event->widget, event, "something", 0);
+  debug_DumpEvent(stdout, event->mWidget, event, "something", 0);
 #endif
 
   NS_ASSERTION(!(mTextInputHandler && mTextInputHandler->IsIMEComposing() &&
                  event->HasKeyEventMessage()),
     "Any key events should not be fired during IME composing");
 
   if (event->mFlags.mIsSynthesizedForTests) {
     WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
@@ -1456,21 +1456,22 @@ NS_IMETHODIMP nsChildView::DispatchEvent
   nsIWidgetListener* listener = mWidgetListener;
 
   // If the listener is NULL, check if the parent is a popup. If it is, then
   // this child is the popup content view attached to a popup. Get the
   // listener from the parent popup instead.
   nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(mParentWidget ? mParentWidget : this);
   if (!listener && mParentWidget) {
     if (mParentWidget->WindowType() == eWindowType_popup) {
-      // Check just in case event->widget isn't this widget
-      if (event->widget)
-        listener = event->widget->GetWidgetListener();
+      // Check just in case event->mWidget isn't this widget
+      if (event->mWidget) {
+        listener = event->mWidget->GetWidgetListener();
+      }
       if (!listener) {
-        event->widget = mParentWidget;
+        event->mWidget = mParentWidget;
         listener = mParentWidget->GetWidgetListener();
       }
     }
   }
 
   if (listener)
     aStatus = listener->HandleEvent(event, mUseAttachedEvents);
 
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -1873,24 +1873,21 @@ NS_IMETHODIMP nsCocoaWindow::GetSheetWin
 }
 
 // Invokes callback and ProcessEvent methods on Event Listener object
 NS_IMETHODIMP 
 nsCocoaWindow::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
 {
   aStatus = nsEventStatus_eIgnore;
 
-  nsIWidget* aWidget = event->widget;
-  NS_IF_ADDREF(aWidget);
+  nsCOMPtr<nsIWidget> kungFuDeathGrip(event->mWidget);
 
   if (mWidgetListener)
     aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents);
 
-  NS_IF_RELEASE(aWidget);
-
   return NS_OK;
 }
 
 // aFullScreen should be the window's mInFullScreenMode. We don't have access to that
 // from here, so we need to pass it in. mInFullScreenMode should be the canonical
 // indicator that a window is currently full screen and it makes sense to keep
 // all sizemode logic here.
 static nsSizeMode
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -138,17 +138,17 @@ nsWindow::DispatchKeyInput(WidgetKeyboar
 {
     if (!gFocusedWindow) {
         return nsEventStatus_eIgnore;
     }
 
     gFocusedWindow->UserActivity();
 
     nsEventStatus status;
-    aEvent.widget = gFocusedWindow;
+    aEvent.mWidget = gFocusedWindow;
     gFocusedWindow->DispatchEvent(&aEvent, status);
     return status;
 }
 
 /*static*/ void
 nsWindow::DispatchTouchInput(MultiTouchInput& aInput)
 {
     APZThreadUtils::AssertOnControllerThread();
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -550,17 +550,17 @@ nsWindow::MaybeDispatchResized()
         DispatchResized();
     }
 }
 
 nsresult
 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
-    debug_DumpEvent(stdout, aEvent->widget, aEvent,
+    debug_DumpEvent(stdout, aEvent->mWidget, aEvent,
                     "something", 0);
 #endif
     aStatus = nsEventStatus_eIgnore;
     nsIWidgetListener* listener =
         mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
     if (listener) {
       aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
     }
@@ -6555,26 +6555,26 @@ nsWindow::GetDragInfo(WidgetMouseEvent* 
 #endif
 
     // find the top-level window
     gdk_window = gdk_window_get_toplevel(gdk_window);
     MOZ_ASSERT(gdk_window,
                "gdk_window_get_toplevel should not return null");
     *aWindow = gdk_window;
 
-    if (!aMouseEvent->widget) {
+    if (!aMouseEvent->mWidget) {
         return false;
     }
 
     // FIXME: It would be nice to have the widget position at the time
     // of the event, but it's relatively unlikely that the widget has
     // moved since the mousedown.  (On the other hand, it's quite likely
     // that the mouse has moved, which is why we use the mouse position
     // from the event.)
-    LayoutDeviceIntPoint offset = aMouseEvent->widget->WidgetToScreenOffset();
+    LayoutDeviceIntPoint offset = aMouseEvent->mWidget->WidgetToScreenOffset();
     *aRootX = aMouseEvent->refPoint.x + offset.x;
     *aRootY = aMouseEvent->refPoint.y + offset.y;
 
     return true;
 }
 
 NS_IMETHODIMP
 nsWindow::BeginMoveDrag(WidgetMouseEvent* aEvent)
--- a/widget/nsBaseFilePicker.cpp
+++ b/widget/nsBaseFilePicker.cpp
@@ -41,18 +41,17 @@ LocalFileToDirectoryOrBlob(nsPIDOMWindow
 {
   if (aIsDirectory) {
 #ifdef DEBUG
     bool isDir;
     aFile->IsDirectory(&isDir);
     MOZ_ASSERT(isDir);
 #endif
 
-    RefPtr<Directory> directory =
-      Directory::Create(aWindow, aFile, Directory::eDOMRootDirectory);
+    RefPtr<Directory> directory = Directory::Create(aWindow, aFile);
     MOZ_ASSERT(directory);
 
     directory.forget(aResult);
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(aWindow, aFile);
   blob.forget(aResult);
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1281,16 +1281,17 @@ void nsBaseWidget::CreateCompositor(int 
     shadowManager = mCompositorBridgeChild->SendPLayerTransactionConstructor(
       backendHints, 0, &textureFactoryIdentifier, &success);
   }
 
   ShadowLayerForwarder* lf = lm->AsShadowForwarder();
 
   if (!success || !lf) {
     NS_WARNING("Failed to create an OMT compositor.");
+    mAPZC = nullptr;
     DestroyCompositor();
     mLayerManager = nullptr;
     mCompositorBridgeChild = nullptr;
     mCompositorBridgeParent = nullptr;
     mCompositorVsyncDispatcher = nullptr;
     return;
   }
 
--- a/widget/nsFilePickerProxy.cpp
+++ b/widget/nsFilePickerProxy.cpp
@@ -169,18 +169,17 @@ nsFilePickerProxy::Recv__delete__(const 
     nsCOMPtr<nsIFile> file;
     NS_ConvertUTF16toUTF8 path(aData.get_InputDirectory().directoryPath());
     nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return true;
     }
 
     RefPtr<Directory> directory =
-      Directory::Create(mParent->GetCurrentInnerWindow(), file,
-                        Directory::eDOMRootDirectory);
+      Directory::Create(mParent->GetCurrentInnerWindow(), file);
     MOZ_ASSERT(directory);
 
     OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
     element->SetAsDirectory() = directory;
   }
 
   if (mCallback) {
     mCallback->Done(aResult);
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -676,17 +676,17 @@ nsWindow::GetNativeData(uint32_t aDataTy
     LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType));
     return nullptr;
 }
 
 NS_IMETHODIMP
 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
-    debug_DumpEvent(stdout, aEvent->widget, aEvent,
+    debug_DumpEvent(stdout, aEvent->mWidget, aEvent,
                     "something", 0);
 #endif
 
     aStatus = nsEventStatus_eIgnore;
 
     // send it to the standard callback
     if (mWidgetListener) {
         aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -816,17 +816,17 @@ LayoutDeviceIntPoint nsWindow::WidgetToS
     return offset;
 }
 
 NS_IMETHODIMP
 nsWindow::DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
                         nsEventStatus& aStatus)
 {
   aStatus = nsEventStatus_eIgnore;
-  nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(aEvent->widget);
+  nsCOMPtr<nsIWidget> kungFuDeathGrip(aEvent->mWidget);
 
   if (mWidgetListener)
     aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP_(void)
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3861,17 +3861,17 @@ nsWindow::CurrentMessageWidgetEventTime(
 
 // Main event dispatch. Invokes callback and ProcessEvent method on
 // Event Listener object. Part of nsIWidget.
 NS_IMETHODIMP nsWindow::DispatchEvent(WidgetGUIEvent* event,
                                       nsEventStatus& aStatus)
 {
 #ifdef WIDGET_DEBUG_OUTPUT
   debug_DumpEvent(stdout,
-                  event->widget,
+                  event->mWidget,
                   event,
                   "something",
                   (int32_t) mWnd);
 #endif // WIDGET_DEBUG_OUTPUT
 
   aStatus = nsEventStatus_eIgnore;
 
   // Top level windows can have a view attached which requires events be sent
@@ -5368,16 +5368,26 @@ nsWindow::ProcessMessage(UINT msg, WPARA
                                            nullptr);
         }
       }
       break;
     }
 
     case WM_MOVING:
       FinishLiveResizing(MOVING);
+      if (WinUtils::IsPerMonitorDPIAware()) {
+        // Sometimes, we appear to miss a WM_DPICHANGED message while moving
+        // a window around. Therefore, call ChangedDPI and ResetLayout here,
+        // which causes the prescontext and appshell window management code to
+        // check the appUnitsPerDevPixel value and current widget size, and
+        // refresh them if necessary. If nothing has changed, these calls will
+        // return without actually triggering any extra reflow or painting.
+        ChangedDPI();
+        ResetLayout();
+      }
       break;
 
     case WM_ENTERSIZEMOVE:
     {
       if (mResizeState == NOT_RESIZING) {
         mResizeState = IN_SIZEMOVE;
       }
       break;
@@ -6919,16 +6929,17 @@ nsWindow::OnDPIChanged(int32_t x, int32_
         width = std::min(width, availWidth);
         height = std::min(height, availHeight);
       }
     }
 
     Resize(x, y, width, height, true);
   }
   ChangedDPI();
+  ResetLayout();
 }
 
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: IME management and accessibility
  **
  ** Handles managing IME input and accessibility.
--- a/xpcom/base/nsWindowsHelpers.h
+++ b/xpcom/base/nsWindowsHelpers.h
@@ -207,25 +207,112 @@ public:
   static void Release(RawRef aDevMode)
   {
     if (aDevMode != Void()) {
       ::HeapFree(::GetProcessHeap(), 0, aDevMode);
     }
   }
 };
 
+
+// HGLOBAL is just a typedef of HANDLE which nsSimpleRef has a specialization of,
+// that means having a nsAutoRefTraits specialization for HGLOBAL is useless.
+// Therefore we create a wrapper class for HGLOBAL to make nsAutoRefTraits and
+// nsAutoRef work as intention.
+class nsHGLOBAL {
+public:
+  nsHGLOBAL(HGLOBAL hGlobal) : m_hGlobal(hGlobal)
+  {
+  }
+
+  operator HGLOBAL() const
+  {
+    return m_hGlobal;
+  }
+
+private:
+  HGLOBAL m_hGlobal;
+};
+
+
+template<>
+class nsAutoRefTraits<nsHGLOBAL>
+{
+public:
+  typedef nsHGLOBAL RawRef;
+  static RawRef Void()
+  {
+    return nullptr;
+  }
+
+  static void Release(RawRef hGlobal)
+  {
+    ::GlobalFree(hGlobal);
+  }
+};
+
+
+// Because Printer's HANDLE uses ClosePrinter and we already have nsAutoRef<HANDLE>
+// which uses CloseHandle so we need to create a wrapper class for HANDLE to have
+// another specialization for nsAutoRefTraits.
+class nsHPRINTER {
+public:
+  nsHPRINTER(HANDLE hPrinter) : m_hPrinter(hPrinter)
+  {
+  }
+
+  operator HANDLE() const
+  {
+    return m_hPrinter;
+  }
+
+  HANDLE* operator&()
+  {
+    return &m_hPrinter;
+  }
+
+private:
+  HANDLE m_hPrinter;
+};
+
+
+// winspool.h header has AddMonitor macro, it conflicts with AddMonitor member
+// function in TaskbarPreview.cpp and TaskbarTabPreview.cpp. Beside, we only
+// need ClosePrinter here for Release function, so having its prototype is enough.
+extern "C" BOOL WINAPI ClosePrinter(HANDLE hPrinter);
+
+
+template<>
+class nsAutoRefTraits<nsHPRINTER>
+{
+public:
+  typedef nsHPRINTER RawRef;
+  static RawRef Void()
+  {
+    return nullptr;
+  }
+
+  static void Release(RawRef hPrinter)
+  {
+    ::ClosePrinter(hPrinter);
+  }
+};
+
+
 typedef nsAutoRef<HKEY> nsAutoRegKey;
 typedef nsAutoRef<HDC> nsAutoHDC;
 typedef nsAutoRef<HBRUSH> nsAutoBrush;
 typedef nsAutoRef<HRGN> nsAutoRegion;
 typedef nsAutoRef<HBITMAP> nsAutoBitmap;
 typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle;
 typedef nsAutoRef<HANDLE> nsAutoHandle;
 typedef nsAutoRef<HMODULE> nsModuleHandle;
 typedef nsAutoRef<DEVMODEW*> nsAutoDevMode;
+typedef nsAutoRef<nsHGLOBAL> nsAutoGlobalMem;
+typedef nsAutoRef<nsHPRINTER> nsAutoPrinter;
 
 namespace {
 
 // Construct a path "<system32>\<aModule>". return false if the output buffer
 // is too small.
 // Note: If the system path cannot be found, or doesn't fit in the output buffer
 // with the module name, we will just ignore the system path and output the
 // module name alone;