merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 11 Dec 2015 11:38:17 +0100
changeset 276191 754b4805a65c
parent 276096 0dd42501bbe6 (current diff)
parent 276190 672a8b656e19 (diff)
child 276198 48aaaf45934f
child 276220 e056ab829313
child 276293 d74d9d3c2598
push id29784
push usercbook@mozilla.com
push date2015-12-11 10:38 +0000
treeherdermozilla-central@754b4805a65c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone45.0a1
first release with
nightly linux32
754b4805a65c / 45.0a1 / 20151211030207 / files
nightly linux64
754b4805a65c / 45.0a1 / 20151211030207 / files
nightly mac
754b4805a65c / 45.0a1 / 20151211030207 / files
nightly win32
754b4805a65c / 45.0a1 / 20151211030207 / files
nightly win64
754b4805a65c / 45.0a1 / 20151211030207 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/events/IMEStateManager.cpp
js/src/tests/ecma_6/Class/derivedConstructorDisabled.js
mobile/android/app/mobile.js
modules/libpref/init/all.js
widget/IMEData.h
widget/windows/WinIMEHandler.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1002,56 +1002,26 @@ pref("dom.downloads.max_retention_days",
 //
 // To prevent SD card DoS attacks via downloads we disable background handling.
 //
 pref("security.exthelperapp.disable_background_handling", true);
 
 // Inactivity time in milliseconds after which we shut down the OS.File worker.
 pref("osfile.reset_worker_delay", 5000);
 
-// APZC preferences.
-#ifdef MOZ_WIDGET_GONK
-pref("apz.allow_zooming", true);
-#endif
-
-// Gaia relies heavily on scroll events for now, so lets fire them
-// more often than the default value (100).
-pref("apz.pan_repaint_interval", 16);
-
 // APZ physics settings, tuned by UX designers
+pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking
 pref("apz.fling_curve_function_x1", "0.41");
 pref("apz.fling_curve_function_y1", "0.0");
 pref("apz.fling_curve_function_x2", "0.80");
 pref("apz.fling_curve_function_y2", "1.0");
 pref("apz.fling_curve_threshold_inches_per_ms", "0.01");
 pref("apz.fling_friction", "0.0019");
 pref("apz.max_velocity_inches_per_ms", "0.07");
-pref("apz.touch_start_tolerance", "0.1");
-
-#ifdef MOZ_WIDGET_GONK
-pref("apz.touch_move_tolerance", "0.03");
-#endif
-
-// Tweak default displayport values to reduce the risk of running out of
-// memory when zooming in
-pref("apz.x_skate_size_multiplier", "1.25");
-pref("apz.y_skate_size_multiplier", "1.5");
-pref("apz.x_stationary_size_multiplier", "1.5");
-pref("apz.y_stationary_size_multiplier", "1.8");
-pref("apz.enlarge_displayport_when_clipped", true);
-// Use "sticky" axis locking
-pref("apz.axis_lock.mode", 2);
-
-// Overscroll-related settings
 pref("apz.overscroll.enabled", true);
-pref("apz.overscroll.stretch_factor", "0.35");
-pref("apz.overscroll.spring_stiffness", "0.0018");
-pref("apz.overscroll.spring_friction", "0.015");
-pref("apz.overscroll.stop_distance_threshold", "5.0");
-pref("apz.overscroll.stop_velocity_threshold", "0.01");
 
 // For event-regions based hit-testing
 pref("layout.event-regions.enabled", true);
 
 // This preference allows FirefoxOS apps (and content, I think) to force
 // the use of software (instead of hardware accelerated) 2D canvases by
 // creating a context like this:
 //
--- a/b2g/components/AboutServiceWorkers.jsm
+++ b/b2g/components/AboutServiceWorkers.jsm
@@ -24,27 +24,22 @@ function debug(aMsg) {
 
 function serializeServiceWorkerInfo(aServiceWorkerInfo) {
   if (!aServiceWorkerInfo) {
     throw new Error("Invalid service worker information");
   }
 
   let result = {};
 
-  Object.keys(aServiceWorkerInfo).forEach(property => {
-    if (typeof aServiceWorkerInfo[property] == "function") {
-      return;
-    }
-    if (property === "principal") {
-      result.principal = {
-        origin: aServiceWorkerInfo.principal.originNoSuffix,
-        originAttributes: aServiceWorkerInfo.principal.originAttributes
-      };
-      return;
-    }
+  result.principal = {
+    origin: aServiceWorkerInfo.principal.originNoSuffix,
+    originAttributes: aServiceWorkerInfo.principal.originAttributes
+  };
+
+  ["scope", "scriptSpec"].forEach(property => {
     result[property] = aServiceWorkerInfo[property];
   });
 
   return result;
 }
 
 
 this.AboutServiceWorkers = {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -756,17 +756,17 @@
                 if (this.mBrowser.userTypedClear > 0 ||
                     ((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
                      aLocation.spec != "about:blank") ||
                      aFlags && Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
                   this.mBrowser.userTypedValue = null;
                 }
 
                 // If the browser was playing audio, we should remove the playing state.
-                if (this.mTab.hasAttribute("soundplaying")) {
+                if (this.mTab.hasAttribute("soundplaying") && this.mBrowser.lastURI != aLocation) {
                   this.mTab.removeAttribute("soundplaying");
                   this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
                 }
 
                 // If the browser was previously muted, we should restore the muted state.
                 if (this.mTab.hasAttribute("muted")) {
                   this.mTab.linkedBrowser.mute();
                 }
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -319,17 +319,16 @@ support-files = fxa_profile_handler.sjs
 skip-if = e10s # Bug 863514 - no gesture support.
 [browser_getshortcutoruri.js]
 [browser_hide_removing.js]
 [browser_homeDrop.js]
 skip-if = buildapp == 'mulet'
 [browser_identity_UI.js]
 [browser_insecureLoginForms.js]
 [browser_keywordBookmarklets.js]
-skip-if = e10s # Bug 1102025 - different principals for the bookmarklet only in e10s mode (unclear if test or 'real' issue)
 [browser_keywordSearch.js]
 [browser_keywordSearch_postData.js]
 [browser_lastAccessedTab.js]
 skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
 [browser_locationBarCommand.js]
 skip-if = os == "linux" # Linux: Intermittent failures, bug 917535
 [browser_locationBarExternalLoad.js]
 [browser_menuButtonFitts.js]
--- a/browser/base/content/test/general/browser_keywordBookmarklets.js
+++ b/browser/base/content/test/general/browser_keywordBookmarklets.js
@@ -7,26 +7,46 @@ add_task(function* test_keyword_bookmark
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   registerCleanupFunction (function* () {
     gBrowser.removeTab(tab);
     yield PlacesUtils.bookmarks.remove(bm);
   });
   yield promisePageShow();
   let originalPrincipal = gBrowser.contentPrincipal;
 
+  function getPrincipalURI() {
+    return ContentTask.spawn(tab.linkedBrowser, null, function() {
+      return content.document.nodePrincipal.URI.spec;
+    });
+  }
+
+  let originalPrincipalURI = yield getPrincipalURI();
+
   yield PlacesUtils.keywords.insert({ keyword: "bm", url: "javascript:1;" })
 
   // Enter bookmarklet keyword in the URL bar
   gURLBar.value = "bm";
   gURLBar.focus();
   EventUtils.synthesizeKey("VK_RETURN", {});
 
   yield promisePageShow();
 
-  ok(gBrowser.contentPrincipal.equals(originalPrincipal), "javascript bookmarklet should inherit principal");
+  let newPrincipalURI = yield getPrincipalURI();
+  is(newPrincipalURI, originalPrincipalURI, "content has the same principal");
+
+  // In e10s, null principals don't round-trip so the same null principal sent
+  // from the child will be a new null principal. Verify that this is the
+  // case.
+  if (tab.linkedBrowser.isRemoteBrowser) {
+    ok(originalPrincipal.isNullPrincipal && gBrowser.contentPrincipal.isNullPrincipal,
+       "both principals should be null principals in the parent");
+  } else {
+    ok(gBrowser.contentPrincipal.equals(originalPrincipal),
+       "javascript bookmarklet should inherit principal");
+  }
 });
 
 function* promisePageShow() {
   return new Promise(resolve => {
     gBrowser.selectedBrowser.addEventListener("pageshow", function listen() {
       gBrowser.selectedBrowser.removeEventListener("pageshow", listen);
       resolve();
     });
--- a/configure.in
+++ b/configure.in
@@ -4219,17 +4219,16 @@ cairo-uikit)
     AC_DEFINE(MOZ_WIDGET_UIKIT)
     LDFLAGS="$LDFLAGS -framework UIKit -lobjc"
     TK_CFLAGS="-DNO_X11"
     TK_LIBS='-Wl,-framework,Foundation -Wl,-framework,CoreFoundation -Wl,-framework,CoreGraphics -Wl,-framework,CoreText -Wl,-framework,AVFoundation -Wl,-framework,AudioToolbox -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo -Wl,-framework,OpenGLES -Wl,-framework,QuartzCore'
     CFLAGS="$CFLAGS $TK_CFLAGS"
     CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
     MOZ_USER_DIR="Mozilla"
     MOZ_FS_LAYOUT=bundle
-    AC_DEFINE(MOZ_SINGLE_PROCESS_APZ)
     ;;
 
 cairo-android)
     AC_DEFINE(MOZ_WIDGET_ANDROID)
     MOZ_WIDGET_TOOLKIT=android
     MOZ_PDF_PRINTING=1
     MOZ_INSTRUMENT_EVENT_LOOP=1
     ;;
@@ -4793,21 +4792,18 @@ fi
 dnl ========================================================
 dnl = Enable the C++ async pan/zoom code instead of the Java version
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(android-apz,
 [  --enable-android-apz      Switch to C++ pan/zoom code],
     MOZ_ANDROID_APZ=1,
     MOZ_ANDROID_APZ=)
 if test -n "$MOZ_ANDROID_APZ"; then
-    dnl Do this if defined in confvars.sh
-    AC_DEFINE(MOZ_ANDROID_APZ)
-    if test -z "$MOZ_B2GDROID"; then
-      AC_DEFINE(MOZ_SINGLE_PROCESS_APZ)
-    fi
+     dnl Do this if defined in confvars.sh
+     AC_DEFINE(MOZ_ANDROID_APZ)
 fi
 
 dnl ========================================================
 dnl = Disable WebSMS backend
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(websms-backend,
 [  --disable-websms-backend
                            Disable WebSMS backend],
--- a/dom/apps/OfflineCacheInstaller.jsm
+++ b/dom/apps/OfflineCacheInstaller.jsm
@@ -224,17 +224,17 @@ function installCache(app) {
     return;
 
   let cacheManifest = cacheDir.clone();
   cacheManifest.append('manifest.appcache');
   if (!cacheManifest.exists())
     return;
 
   let principal =
-    Services.scriptSecurityManager.createCodebasePrincipal(app.origin, {appId: aApp.localId});
+    Services.scriptSecurityManager.createCodebasePrincipal(app.origin, {appId: app.localId});
 
   // If the build has been correctly configured, this should not happen!
   // If we install the cache anyway, it won't be updateable. If we don't install
   // it, the application won't be useable offline.
   let metadataLoaded;
   if (!resourcesMetadata.exists()) {
     // Not debug, since this is something that should be logged always!
     dump("OfflineCacheInstaller: App " + app.appId + " does have an app cache" +
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7504,17 +7504,19 @@ nsContentUtils::TransferableToIPCTransfe
             // constructor before processing our response, which would crash. In
             // that case, hope that the caller is nsClipboardProxy::GetData,
             // called from editor and send over images as raw data.
             if (aInSyncMessage) {
               nsAutoCString type;
               if (IsFileImage(file, type)) {
                 IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
                 item->flavor() = type;
-                SlurpFileToString(file, item->data());
+                nsAutoCString data;
+                SlurpFileToString(file, data);
+                item->data() = data;
               }
 
               continue;
             }
 
             blobImpl = new BlobImplFile(file, false);
             ErrorResult rv;
             // Ensure that file data is cached no that the content process
@@ -7664,21 +7666,20 @@ nsContentUtils::GetButtonsFlagForButton(
   }
 }
 
 LayoutDeviceIntPoint
 nsContentUtils::ToWidgetPoint(const CSSPoint& aPoint,
                               const nsPoint& aOffset,
                               nsPresContext* aPresContext)
 {
-  nsPoint point = CSSPoint::ToAppUnits(aPoint) + aOffset;
-#if defined(MOZ_SINGLE_PROCESS_APZ)
-  point = point.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
-#endif
-  return LayoutDeviceIntPoint::FromAppUnitsRounded(point, aPresContext->AppUnitsPerDevPixel());
+  return LayoutDeviceIntPoint::FromAppUnitsRounded(
+    (CSSPoint::ToAppUnits(aPoint) +
+    aOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution()),
+    aPresContext->AppUnitsPerDevPixel());
 }
 
 nsView*
 nsContentUtils::GetViewToDispatchEvent(nsPresContext* presContext,
                                        nsIPresShell** presShell)
 {
   if (presContext && presShell) {
     *presShell = presContext->PresShell();
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -281,18 +281,17 @@ NS_CreateJSTimeoutHandler(JSContext *aCx
     new nsJSScriptTimeoutHandler(aCx, aWindow, aFunction, args, aError);
   return aError.Failed() ? nullptr : handler.forget();
 }
 
 already_AddRefed<nsIScriptTimeoutHandler>
 NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
                           const nsAString& aExpression, ErrorResult& aError)
 {
-  ErrorResult rv;
   bool allowEval = false;
   RefPtr<nsJSScriptTimeoutHandler> handler =
-    new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, rv);
-  if (rv.Failed() || !allowEval) {
+    new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, aError);
+  if (aError.Failed() || !allowEval) {
     return nullptr;
   }
 
   return handler.forget();
 }
--- a/dom/base/test/browser_bug593387.js
+++ b/dom/base/test/browser_bug593387.js
@@ -1,65 +1,70 @@
 /*
  * Test for bug 593387
  * Loads a chrome document in a content docshell and then inserts a
  * X-Frame-Options: DENY iframe into the document and verifies that the document
  * loads. The policy we are enforcing is outlined here:
  * https://bugzilla.mozilla.org/show_bug.cgi?id=593387#c17
 */
-var newBrowser;
 
-function test() {
-  waitForExplicitFinish();
+add_task(function* test() {
+  yield BrowserTestUtils.withNewTab({ gBrowser,
+                                      url: "chrome://global/content/mozilla.xhtml" },
+                                     function* (newBrowser) {
+    // NB: We load the chrome:// page in the parent process.
+    yield testXFOFrameInChrome(newBrowser);
 
-  var newTab = gBrowser.addTab();
-  gBrowser.selectedTab = newTab;
-  newBrowser = gBrowser.getBrowserForTab(newTab);
-  //alert(newBrowser.contentWindow);
+    // Run next test (try the same with a content top-level context)
+    yield BrowserTestUtils.loadURI(newBrowser, "http://example.com/");
+    yield BrowserTestUtils.browserLoaded(newBrowser);
 
-  newBrowser.addEventListener("load", testXFOFrameInChrome, true);
-  newBrowser.contentWindow.location = "chrome://global/content/mozilla.xhtml";
-}
+    yield ContentTask.spawn(newBrowser, null, testXFOFrameInContent);
+  });
+});
 
-function testXFOFrameInChrome() {
-  newBrowser.removeEventListener("load", testXFOFrameInChrome, true);
-
+function testXFOFrameInChrome(newBrowser) {
   // Insert an iframe that specifies "X-Frame-Options: DENY" and verify
   // that it loads, since the top context is chrome
+  var deferred = {};
+  deferred.promise = new Promise((resolve) => {
+    deferred.resolve = resolve;
+  });
+
   var frame = newBrowser.contentDocument.createElement("iframe");
   frame.src = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny";
-  frame.addEventListener("load", function() {
-    frame.removeEventListener("load", arguments.callee, true);
+  frame.addEventListener("load", function loaded() {
+    frame.removeEventListener("load", loaded, true);
 
     // Test that the frame loaded
     var test = this.contentDocument.getElementById("test");
     is(test.tagName, "H1", "wrong element type");
     is(test.textContent, "deny", "wrong textContent");
-    
-    // Run next test (try the same with a content top-level context)
-    newBrowser.addEventListener("load", testXFOFrameInContent, true);
-    newBrowser.contentWindow.location = "http://example.com/";  
+    deferred.resolve();
   }, true);
 
   newBrowser.contentDocument.body.appendChild(frame);
+  return deferred.promise;
 }
 
-function testXFOFrameInContent() {
-  newBrowser.removeEventListener("load", testXFOFrameInContent, true);
-
+function testXFOFrameInContent(newBrowser) {
   // Insert an iframe that specifies "X-Frame-Options: DENY" and verify that it
   // is blocked from loading since the top browsing context is another site
-  var frame = newBrowser.contentDocument.createElement("iframe");
+  var deferred = {};
+  deferred.promise = new Promise((resolve) => {
+    deferred.resolve = resolve;
+  });
+
+  var frame = content.document.createElement("iframe");
   frame.src = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny";
-  frame.addEventListener("load", function() {
-    frame.removeEventListener("load", arguments.callee, true);
+  frame.addEventListener("load", function loaded() {
+    frame.removeEventListener("load", loaded, true);
 
     // Test that the frame DID NOT load
     var test = this.contentDocument.getElementById("test");
-    is(test, undefined, "should be about:blank");
+    is(test, null, "should be about:blank");
 
-    // Finalize the test
-    gBrowser.removeCurrentTab();
-    finish();
+    deferred.resolve();
   }, true);
 
-  newBrowser.contentDocument.body.appendChild(frame);
+  content.document.body.appendChild(frame);
+  return deferred.promise;
 }
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2482,54 +2482,69 @@ CanvasRenderingContext2D::UpdateFilter()
       gfxRect(0, 0, mWidth, mHeight),
       CurrentState().filterAdditionalImages);
 }
 
 //
 // rects
 //
 
-// bug 1074733
-// The canvas spec does not forbid rects with negative w or h, so given
-// corners (x, y), (x+w, y), (x+w, y+h), and (x, y+h) we must generate
-// the appropriate rect by flipping negative dimensions. This prevents
-// draw targets from receiving "empty" rects later on.
-static void
-NormalizeRect(double& aX, double& aY, double& aWidth, double& aHeight)
-{
+static bool
+ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight)
+{
+
+  // bug 1018527
+  // The values of canvas API input are in double precision, but Moz2D APIs are
+  // using float precision. Bypass canvas API calls when the input is out of
+  // float precision to avoid precision problem
+  if (!std::isfinite((float)aX) | !std::isfinite((float)aY) |
+      !std::isfinite((float)aWidth) | !std::isfinite((float)aHeight)) {
+    return false;
+  }
+
+  // bug 1074733
+  // The canvas spec does not forbid rects with negative w or h, so given
+  // corners (x, y), (x+w, y), (x+w, y+h), and (x, y+h) we must generate
+  // the appropriate rect by flipping negative dimensions. This prevents
+  // draw targets from receiving "empty" rects later on.
   if (aWidth < 0) {
     aWidth = -aWidth;
     aX -= aWidth;
   }
   if (aHeight < 0) {
     aHeight = -aHeight;
     aY -= aHeight;
   }
+  return true;
 }
 
 void
 CanvasRenderingContext2D::ClearRect(double x, double y, double w,
                                     double h)
 {
-  NormalizeRect(x, y, w, h);
+  if(!ValidateRect(x, y, w, h)) {
+    return;
+  }
 
   EnsureTarget();
 
   mTarget->ClearRect(gfx::Rect(x, y, w, h));
 
   RedrawUser(gfxRect(x, y, w, h));
 }
 
 void
 CanvasRenderingContext2D::FillRect(double x, double y, double w,
                                    double h)
 {
   const ContextState &state = CurrentState();
 
-  NormalizeRect(x, y, w, h);
+  if(!ValidateRect(x, y, w, h)) {
+    return;
+  }
 
   if (state.patternStyles[Style::FILL]) {
     CanvasPattern::RepeatMode repeat =
       state.patternStyles[Style::FILL]->mRepeat;
     // In the FillRect case repeat modes are easy to deal with.
     bool limitx = repeat == CanvasPattern::RepeatMode::NOREPEAT || repeat == CanvasPattern::RepeatMode::REPEATY;
     bool limity = repeat == CanvasPattern::RepeatMode::NOREPEAT || repeat == CanvasPattern::RepeatMode::REPEATX;
 
@@ -2594,17 +2609,20 @@ CanvasRenderingContext2D::StrokeRect(dou
 {
   const ContextState &state = CurrentState();
 
   gfx::Rect bounds;
 
   if (!w && !h) {
     return;
   }
-  NormalizeRect(x, y, w, h);
+
+  if(!ValidateRect(x, y, w, h)) {
+    return;
+  }
 
   EnsureTarget();
   if (!IsTargetValid()) {
     return;
   }
 
   if (NeedToCalculateBounds()) {
     bounds = gfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f,
@@ -4370,18 +4388,20 @@ CanvasRenderingContext2D::DrawImage(cons
 {
   if (mDrawObserver) {
     mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
   }
 
   MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6);
 
   if (optional_argc == 6) {
-    NormalizeRect(sx, sy, sw, sh);
-    NormalizeRect(dx, dy, dw, dh);
+    if (!ValidateRect(sx, sy, sw, sh) ||
+        !ValidateRect(dx, dy, dw, dh)) {
+      return;
+    }
   }
 
   RefPtr<SourceSurface> srcSurf;
   gfx::IntSize imgSize;
 
   Element* element = nullptr;
 
   EnsureTarget();
--- a/dom/canvas/test/test_canvas.html
+++ b/dom/canvas/test/test_canvas.html
@@ -21531,16 +21531,30 @@ ctx.fillStyle = '#0f0';
 ctx.fillRect(0, 0, 100, 50);
 isPixel(ctx, 50,25, 0,255,0,255, 0);
 
 
 }
 
 </script>
 
+<!-- [[[ test_2d.clearRect.testdoubleprecision.html ]]] -->
+
+<p>Canvas test: 2d.clearRect.testdoubleprecision</p>
+<canvas id="c690" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<script>
+
+function test_2d_clearRect_testdoubleprecision() {
+  var canvas = document.getElementById('c690');
+  ctx = canvas.getContext('2d');
+  ctx.setTransform(1, 1, 1, 1, 0, 0);
+  ctx.clearRect(-1.79e+308, 0, 1.79e+308, 8);
+}
+</script>
+
 <script>
 
 function asyncTestsDone() {
 	if (isDone_test_2d_drawImage_animated_apng &&
 		isDone_test_2d_pattern_animated_gif &&
 		isDone_test_2d_drawImage_animated_gif) {
 		SimpleTest.finish();
 	} else {
@@ -24830,17 +24844,23 @@ try {
   ok(false, "unexpected exception thrown in: test_2d_transformation_reset_transform");
  }
  try {
   // run this test last since it replaces the getContext method
   test_type_replace();
  } catch (e) {
   ok(false, "unexpected exception thrown in: test_type_replace");
  }
- 
+ try {
+   test_2d_clearRect_testdoubleprecision();
+ } catch(e) {
+   throw e;
+   ok(false, "unexpected exception thrown in: test_2d_clearRect_testdoubleprecision");
+ }
+
  //run the asynchronous tests
  try {
   test_2d_drawImage_animated_apng();
  } catch (e) {
   ok(false, "unexpected exception thrown in: test_2d_drawImage_animated_apng");
  }
  try {
   test_2d_drawImage_animated_gif();
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -930,21 +930,19 @@ Event::GetScreenCoords(nsPresContext* aP
   WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
   if (!aPresContext || !(guiEvent && guiEvent->widget)) {
     return CSSIntPoint(aPoint.x, aPoint.y);
   }
 
   nsPoint pt =
     LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
-#if defined(MOZ_SINGLE_PROCESS_APZ)
   if (aPresContext->PresShell()) {
-    pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
+    pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
   }
-#endif
 
   pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(),
                                       aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
   return CSSPixel::FromAppUnitsRounded(pt);
 }
 
 // static
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -755,25 +755,27 @@ EventStateManager::PreHandleEvent(nsPres
   case eBeforeKeyUp:
   case eKeyUp:
   case eAfterKeyUp:
     {
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
 
-      // NOTE: Don't refer TextComposition::IsComposing() since DOM Level 3
-      //       Events defines that KeyboardEvent.isComposing is true when it's
+      // NOTE: Don't refer TextComposition::IsComposing() since UI Events
+      //       defines that KeyboardEvent.isComposing is true when it's
       //       dispatched after compositionstart and compositionend.
       //       TextComposition::IsComposing() is false even before
       //       compositionend if there is no composing string.
-      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
+      //       And also don't expose other document's composition state.
+      //       A native IME context is typically shared by multiple documents.
+      //       So, don't use GetTextCompositionFor(nsIWidget*) here.
       RefPtr<TextComposition> composition =
-        IMEStateManager::GetTextCompositionFor(keyEvent);
-      keyEvent->mIsComposing = !!composition;
+        IMEStateManager::GetTextCompositionFor(aPresContext);
+      aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
     }
     break;
   case eWheel:
   case eWheelOperationStart:
   case eWheelOperationEnd:
     {
       NS_ASSERTION(aEvent->mFlags.mIsTrusted,
                    "Untrusted wheel event shouldn't be here");
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1139,37 +1139,47 @@ IMEStateManager::DispatchCompositionEven
                    bool aIsSynthesized)
 {
   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={ message=%s, "
+     "aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
+     "mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
+     "mOriginProcessID=0x%X }, widget(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()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
      GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
      GetBoolName(aIsSynthesized), tabParent.get()));
 
   if (!aCompositionEvent->mFlags.mIsTrusted ||
       aCompositionEvent->mFlags.mPropagationStopped) {
     return;
   }
 
   MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionUpdate,
              "compositionupdate event shouldn't be dispatched manually");
 
   EnsureTextCompositionArray();
 
   RefPtr<TextComposition> composition =
-    sTextCompositions->GetCompositionFor(aCompositionEvent->widget);
+    sTextCompositions->GetCompositionFor(aCompositionEvent);
   if (!composition) {
     // If synthesized event comes after delayed native composition events
     // for request of commit or cancel, we should ignore it.
     if (NS_WARN_IF(aIsSynthesized)) {
       return;
     }
     MOZ_LOG(sISMLog, LogLevel::Debug,
       ("ISM:   IMEStateManager::DispatchCompositionEvent(), "
@@ -1273,18 +1283,28 @@ void
 IMEStateManager::OnCompositionEventDiscarded(
                    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, mFlags={ mIsTrusted=%s } })",
+     "mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
+     "mOriginProcessID=0x%X }, widget(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()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
 
   if (!aCompositionEvent->mFlags.mIsTrusted) {
     return;
   }
 
   // Ignore compositionstart for now because sTextCompositions may not have
   // been created yet.
@@ -1644,16 +1664,32 @@ IMEStateManager::GetTextCompositionFor(n
   }
   RefPtr<TextComposition> textComposition =
     sTextCompositions->GetCompositionFor(aWidget);
   return textComposition.forget();
 }
 
 // static
 already_AddRefed<TextComposition>
-IMEStateManager::GetTextCompositionFor(WidgetGUIEvent* aGUIEvent)
+IMEStateManager::GetTextCompositionFor(
+                   const WidgetCompositionEvent* aCompositionEvent)
 {
-  MOZ_ASSERT(aGUIEvent->AsCompositionEvent() || aGUIEvent->AsKeyboardEvent(),
-    "aGUIEvent has to be WidgetCompositionEvent or WidgetKeyboardEvent");
-  return GetTextCompositionFor(aGUIEvent->widget);
+  if (!sTextCompositions) {
+    return nullptr;
+  }
+  RefPtr<TextComposition> textComposition =
+    sTextCompositions->GetCompositionFor(aCompositionEvent);
+  return textComposition.forget();
+}
+
+// static
+already_AddRefed<TextComposition>
+IMEStateManager::GetTextCompositionFor(nsPresContext* aPresContext)
+{
+  if (!sTextCompositions) {
+    return nullptr;
+  }
+  RefPtr<TextComposition> textComposition =
+    sTextCompositions->GetCompositionFor(aPresContext);
+  return textComposition.forget();
 }
 
 } // namespace mozilla
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -176,21 +176,27 @@ public:
   /**
    * Get TextComposition from widget.
    */
   static already_AddRefed<TextComposition>
     GetTextCompositionFor(nsIWidget* aWidget);
 
   /**
    * Returns TextComposition instance for the event.
-   *
-   * @param aGUIEvent Should be a composition event which is being dispatched.
    */
   static already_AddRefed<TextComposition>
-    GetTextCompositionFor(WidgetGUIEvent* aGUIEvent);
+    GetTextCompositionFor(const WidgetCompositionEvent* aCompositionEvent);
+
+  /**
+   * Returns TextComposition instance for the pres context.
+   * Be aware, even if another pres context which shares native IME context with
+   * specified pres context has composition, this returns nullptr.
+   */
+  static already_AddRefed<TextComposition>
+    GetTextCompositionFor(nsPresContext* aPresContext);
 
   /**
    * Send a notification to IME.  It depends on the IME or platform spec what
    * will occur (or not occur).
    */
   static nsresult NotifyIME(const IMENotification& aNotification,
                             nsIWidget* aWidget,
                             bool aOriginIsRemote = false);
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -34,50 +34,44 @@ bool TextComposition::sHandlingSelection
 
 TextComposition::TextComposition(nsPresContext* aPresContext,
                                  nsINode* aNode,
                                  TabParent* aTabParent,
                                  WidgetCompositionEvent* aCompositionEvent)
   : mPresContext(aPresContext)
   , mNode(aNode)
   , mTabParent(aTabParent)
-  , mNativeContext(
-      aCompositionEvent->widget->GetInputContext().mNativeIMEContext)
+  , mNativeContext(aCompositionEvent->mNativeIMEContext)
   , mCompositionStartOffset(0)
   , mCompositionTargetOffset(0)
   , mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
   , mIsComposing(false)
   , mIsEditorHandlingEvent(false)
   , mIsRequestingCommit(false)
   , mIsRequestingCancel(false)
   , mRequestedToCommitOrCancel(false)
   , mWasNativeCompositionEndEventDiscarded(false)
   , mAllowControlCharacters(
       Preferences::GetBool("dom.compositionevent.allow_control_characters",
                            false))
 {
+  MOZ_ASSERT(aCompositionEvent->mNativeIMEContext.IsValid());
 }
 
 void
 TextComposition::Destroy()
 {
   mPresContext = nullptr;
   mNode = nullptr;
   mTabParent = nullptr;
   // TODO: If the editor is still alive and this is held by it, we should tell
   //       this being destroyed for cleaning up the stuff.
 }
 
 bool
-TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
-{
-  return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
-}
-
-bool
 TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const
 {
   return !Destroyed() && aWidget && !aWidget->Destroyed() &&
          mPresContext->GetPresShell() &&
          !mPresContext->GetPresShell()->IsDestroying();
 }
 
 bool
@@ -109,16 +103,17 @@ TextComposition::CloneAndDispatchAs(
   MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
              "Should be called only when it's safe to dispatch an event");
 
   WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted,
                                           aMessage, aCompositionEvent->widget);
   compositionEvent.time = aCompositionEvent->time;
   compositionEvent.timeStamp = aCompositionEvent->timeStamp;
   compositionEvent.mData = aCompositionEvent->mData;
+  compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
   compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
   compositionEvent.mFlags.mIsSynthesizedForTests =
     aCompositionEvent->mFlags.mIsSynthesizedForTests;
 
   nsEventStatus dummyStatus = nsEventStatus_eConsumeNoDefault;
   nsEventStatus* status = aStatus ? aStatus : &dummyStatus;
   if (aMessage == eCompositionUpdate) {
     mLastData = compositionEvent.mData;
@@ -608,32 +603,34 @@ TextComposition::CompositionEventDispatc
     return NS_OK; // cannot dispatch any events anymore
   }
 
   RefPtr<nsPresContext> presContext = mTextComposition->mPresContext;
   nsEventStatus status = nsEventStatus_eIgnore;
   switch (mEventMessage) {
     case eCompositionStart: {
       WidgetCompositionEvent compStart(true, eCompositionStart, widget);
+      compStart.mNativeIMEContext = mTextComposition->mNativeContext;
       WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
       ContentEventHandler handler(presContext);
       handler.OnQuerySelectedText(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compStart.mData = selectedText.mReply.mString;
       compStart.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compStart, &status, nullptr,
                                                 mIsSynthesizedEvent);
       break;
     }
     case eCompositionChange:
     case eCompositionCommitAsIs:
     case eCompositionCommit: {
       WidgetCompositionEvent compEvent(true, mEventMessage, widget);
+      compEvent.mNativeIMEContext = mTextComposition->mNativeContext;
       if (mEventMessage != eCompositionCommitAsIs) {
         compEvent.mData = mData;
       }
       compEvent.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compEvent, &status, nullptr,
                                                 mIsSynthesizedEvent);
@@ -645,27 +642,36 @@ TextComposition::CompositionEventDispatc
   return NS_OK;
 }
 
 /******************************************************************************
  * TextCompositionArray
  ******************************************************************************/
 
 TextCompositionArray::index_type
-TextCompositionArray::IndexOf(nsIWidget* aWidget)
+TextCompositionArray::IndexOf(const NativeIMEContext& aNativeIMEContext)
 {
+  if (!aNativeIMEContext.IsValid()) {
+    return NoIndex;
+  }
   for (index_type i = Length(); i > 0; --i) {
-    if (ElementAt(i - 1)->MatchesNativeContext(aWidget)) {
+    if (ElementAt(i - 1)->GetNativeIMEContext() == aNativeIMEContext) {
       return i - 1;
     }
   }
   return NoIndex;
 }
 
 TextCompositionArray::index_type
+TextCompositionArray::IndexOf(nsIWidget* aWidget)
+{
+  return IndexOf(aWidget->GetNativeIMEContext());
+}
+
+TextCompositionArray::index_type
 TextCompositionArray::IndexOf(nsPresContext* aPresContext)
 {
   for (index_type i = Length(); i > 0; --i) {
     if (ElementAt(i - 1)->GetPresContext() == aPresContext) {
       return i - 1;
     }
   }
   return NoIndex;
@@ -689,16 +695,37 @@ TextCompositionArray::GetCompositionFor(
   index_type i = IndexOf(aWidget);
   if (i == NoIndex) {
     return nullptr;
   }
   return ElementAt(i);
 }
 
 TextComposition*
+TextCompositionArray::GetCompositionFor(
+                        const WidgetCompositionEvent* aCompositionEvent)
+{
+  index_type i = IndexOf(aCompositionEvent->mNativeIMEContext);
+  if (i == NoIndex) {
+    return nullptr;
+  }
+  return ElementAt(i);
+}
+
+TextComposition*
+TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext)
+{
+  index_type i = IndexOf(aPresContext);
+  if (i == NoIndex) {
+    return nullptr;
+  }
+  return ElementAt(i);
+}
+
+TextComposition*
 TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext,
                                            nsINode* aNode)
 {
   index_type i = IndexOf(aPresContext, aNode);
   if (i == NoIndex) {
     return nullptr;
   }
   return ElementAt(i);
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -71,17 +71,20 @@ public:
   nsIWidget* GetWidget() const
   {
     return mPresContext ? mPresContext->GetRootWidget() : nullptr;
   }
   // Returns true if the composition is started with synthesized event which
   // came from nsDOMWindowUtils.
   bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
 
-  bool MatchesNativeContext(nsIWidget* aWidget) const;
+  const widget::NativeIMEContext& GetNativeIMEContext() const
+  {
+    return mNativeContext;
+  }
 
   /**
    * This is called when IMEStateManager stops managing the instance.
    */
   void Destroy();
 
   /**
    * Request to commit (or cancel) the composition to IME.  This method should
@@ -186,17 +189,17 @@ private:
   RefPtr<TabParent> mTabParent;
 
   // This is the clause and caret range information which is managed by
   // the focused editor.  This may be null if there is no clauses or caret.
   RefPtr<TextRangeArray> mRanges;
 
   // mNativeContext stores a opaque pointer.  This works as the "ID" for this
   // composition.  Don't access the instance, it may not be available.
-  void* mNativeContext;
+  widget::NativeIMEContext mNativeContext;
 
   // mEditorWeak is a weak reference to the focused editor handling composition.
   nsWeakPtr mEditorWeak;
 
   // mLastData stores the data attribute of the latest composition event (except
   // the compositionstart event).
   nsString mLastData;
 
@@ -395,21 +398,29 @@ private:
  * compositions in the process.  If the instance is it, each TextComposition
  * in the array can be destroyed by calling some methods of itself.
  */
 
 class TextCompositionArray final :
   public nsAutoTArray<RefPtr<TextComposition>, 2>
 {
 public:
+  // Looking for per native IME context.
+  index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
   index_type IndexOf(nsIWidget* aWidget);
+
+  TextComposition* GetCompositionFor(nsIWidget* aWidget);
+  TextComposition* GetCompositionFor(
+                     const WidgetCompositionEvent* aCompositionEvent);
+
+  // Looking for per nsPresContext
   index_type IndexOf(nsPresContext* aPresContext);
   index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
 
-  TextComposition* GetCompositionFor(nsIWidget* aWidget);
+  TextComposition* GetCompositionFor(nsPresContext* aPresContext);
   TextComposition* GetCompositionFor(nsPresContext* aPresContext,
                                      nsINode* aNode);
   TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
                                            nsIContent* aContent);
 };
 
 } // namespace mozilla
 
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4975,32 +4975,32 @@ HTMLMediaElement::GetTopLevelPrincipal()
   }
   principal = doc->NodePrincipal();
   return principal.forget();
 }
 #endif // MOZ_EME
 
 NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
 {
-   MOZ_ASSERT(mAudioChannelAgent);
+  MOZ_ASSERT(mAudioChannelAgent);
 
   if (!OwnerDoc()->GetInnerWindow()) {
     return NS_OK;
   }
   bool captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured();
 
   if (captured != mAudioCapturedByWindow) {
     if (captured) {
       mAudioCapturedByWindow = true;
       nsCOMPtr<nsPIDOMWindow> window =
         do_QueryInterface(OwnerDoc()->GetParentObject());
       uint64_t id = window->WindowID();
       MediaStreamGraph* msg =
         MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
-                                      AudioChannel::Normal);
+                                      mAudioChannel);
 
       if (GetSrcMediaStream()) {
         mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());
       } else {
         RefPtr<DOMMediaStream> stream = CaptureStreamInternal(false, msg);
         mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetPlaybackStream());
       }
     } else {
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -230,30 +230,29 @@ parent:
      * Notifies chrome to position change
      *
      *  contentCache Cache of content
      */
     prio(urgent) async NotifyIMEPositionChange(ContentCache contentCache,
                                                IMENotification notification);
 
     /**
-     * Instructs chrome to end any pending composition
+     * Requests chrome to commit or cancel composition of IME.
      *
-     *  cancel       true if composition should be cancelled
-     *  noCompositionEvent   true if no composition event is fired by commit or
-     *                       cancel
-     *  composition  Text to commit before ending the composition
+     *  cancel                Set true if composition should be cancelled.
      *
-     *  if cancel is true,
-     *    widget should return empty string for composition
-     *  if cancel is false,
-     *    widget should return the current composition text
+     *  isCommitted           Returns true if the request causes composition
+     *                        being committed synchronously.
+     *  committedString       Returns committed string.  The may be non-empty
+     *                        string even if cancel is true because IME may
+     *                        try to restore selected string which was
+     *                        replaced with the composition.
      */
-    prio(urgent) sync EndIMEComposition(bool cancel)
-                        returns (bool noCompositionEvent, nsString composition);
+    prio(urgent) sync RequestIMEToCommitComposition(bool cancel)
+                        returns (bool isCommitted, nsString committedString);
 
     /**
      * OnEventNeedingAckHandled() is called after a child process dispatches a
      * composition event or a selection event which is sent from the parent
      * process.
      *
      * message      The message value of the handled event.
      */
@@ -291,18 +290,17 @@ parent:
      * Indicate, based on the current state, that some commands are enabled and
      * some are disabled.
      */
     EnableDisableCommands(nsString action,
                           nsCString[] enabledCommands,
                           nsCString[] disabledCommands);
 
     prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
-                                                 int32_t IMEOpen,
-                                                 intptr_t NativeIMEContext);
+                                                 int32_t IMEOpen);
 
     prio(urgent) async SetInputContext(int32_t IMEEnabled,
                                        int32_t IMEOpen,
                                        nsString type,
                                        nsString inputmode,
                                        nsString actionHint,
                                        int32_t cause,
                                        int32_t focusChange);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2316,26 +2316,29 @@ TabParent::GetTabIdFrom(nsIDocShell *doc
 RenderFrameParent*
 TabParent::GetRenderFrame()
 {
   PRenderFrameParent* p = LoneManagedOrNull(ManagedPRenderFrameParent());
   return static_cast<RenderFrameParent*>(p);
 }
 
 bool
-TabParent::RecvEndIMEComposition(const bool& aCancel,
-                                 bool* aNoCompositionEvent,
-                                 nsString* aComposition)
+TabParent::RecvRequestIMEToCommitComposition(const bool& aCancel,
+                                             bool* aIsCommitted,
+                                             nsString* aCommittedString)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
+    *aIsCommitted = false;
     return true;
   }
-  *aNoCompositionEvent =
-    !mContentCache.RequestToCommitComposition(widget, aCancel, *aComposition);
+
+  *aIsCommitted =
+    mContentCache.RequestIMEToCommitComposition(widget, aCancel,
+                                                *aCommittedString);
   return true;
 }
 
 bool
 TabParent::RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
                               const int32_t& aPanelX, const int32_t& aPanelY,
                               nsString* aCommitted)
 {
@@ -2358,31 +2361,28 @@ TabParent::RecvSetPluginFocused(const bo
     return true;
   }
   widget->SetPluginFocused((bool&)aFocused);
   return true;
 }
 
 bool
 TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
-                               int32_t* aIMEOpen,
-                               intptr_t* aNativeIMEContext)
+                               int32_t* aIMEOpen)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aIMEEnabled = IMEState::DISABLED;
     *aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-    *aNativeIMEContext = 0;
     return true;
   }
 
   InputContext context = widget->GetInputContext();
   *aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
   *aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
-  *aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
   return true;
 }
 
 bool
 TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
                                const int32_t& aIMEOpen,
                                const nsString& aType,
                                const nsString& aInputmode,
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -182,27 +182,26 @@ public:
     virtual bool RecvNotifyIMESelection(const ContentCache& aContentCache,
                                         const widget::IMENotification& aEventMessage) override;
     virtual bool RecvUpdateContentCache(const ContentCache& aContentCache) override;
     virtual bool RecvNotifyIMEMouseButtonEvent(const widget::IMENotification& aEventMessage,
                                                bool* aConsumedByIME) override;
     virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
                                              const widget::IMENotification& aEventMessage) override;
     virtual bool RecvOnEventNeedingAckHandled(const EventMessage& aMessage) override;
-    virtual bool RecvEndIMEComposition(const bool& aCancel,
-                                       bool* aNoCompositionEvent,
-                                       nsString* aComposition) override;
+    virtual bool RecvRequestIMEToCommitComposition(const bool& aCancel,
+                                                   bool* aIsCommitted,
+                                                   nsString* aCommittedString) override;
     virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
                                     const int32_t& aPanelX,
                                     const int32_t& aPanelY,
                                     nsString* aCommitted) override;
     virtual bool RecvSetPluginFocused(const bool& aFocused) override;
     virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
-                                     int32_t* aIMEOpen,
-                                     intptr_t* aNativeIMEContext) override;
+                                     int32_t* aIMEOpen) override;
     virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
                                      const int32_t& aIMEOpen,
                                      const nsString& aType,
                                      const nsString& aInputmode,
                                      const nsString& aActionHint,
                                      const int32_t& aCause,
                                      const int32_t& aFocusChange) override;
     virtual bool RecvRequestFocus(const bool& aCanRaise) override;
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2107,58 +2107,67 @@ MediaDecoderStateMachine::SeekCompleted(
     // seekTime is bounded in suitable duration. See Bug 1112438.
     int64_t videoStart = video ? video->mTime : seekTime;
     int64_t audioStart = audio ? audio->mTime : seekTime;
     newCurrentTime = std::min(audioStart, videoStart);
   } else {
     newCurrentTime = video ? video->mTime : seekTime;
   }
 
-  if (mDecodingFirstFrame) {
-    // We were resuming from dormant, or initiated a seek early.
-    // We can fire loadeddata now.
-    FinishDecodeFirstFrame();
-  }
-
   // Change state to DECODING or COMPLETED now. SeekingStopped will
   // call MediaDecoderStateMachine::Seek to reset our state to SEEKING
   // if we need to seek again.
 
   bool isLiveStream = mResource->IsLiveStream();
+  State nextState;
   if (mPendingSeek.Exists()) {
     // A new seek target came in while we were processing the old one. No rest
     // for the seeking.
     DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING");
-    SetState(DECODER_STATE_SEEKING);
+    nextState = DECODER_STATE_SEEKING;
   } else if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
     // Seeked to end of media, move to COMPLETED state. Note we don't do
     // this when playing a live stream, since the end of media will advance
     // once we download more data!
     DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime);
     // Explicitly set our state so we don't decode further, and so
     // we report playback ended to the media element.
-    SetState(DECODER_STATE_COMPLETED);
-    DispatchDecodeTasksIfNeeded();
+    nextState = DECODER_STATE_COMPLETED;
   } else {
     DECODER_LOG("Changed state from SEEKING (to %lld) to DECODING", seekTime);
+    nextState = DECODER_STATE_DECODING;
+  }
+
+  // We want to resolve the seek request prior finishing the first frame
+  // to ensure that the seeked event is fired prior loadeded.
+  mCurrentSeek.Resolve(nextState == DECODER_STATE_COMPLETED, __func__);
+
+  if (mDecodingFirstFrame) {
+    // We were resuming from dormant, or initiated a seek early.
+    // We can fire loadeddata now.
+    FinishDecodeFirstFrame();
+  }
+
+  if (nextState == DECODER_STATE_DECODING) {
     StartDecoding();
+  } else {
+    SetState(nextState);
   }
 
   // Ensure timestamps are up to date.
   UpdatePlaybackPositionInternal(newCurrentTime);
 
   // Try to decode another frame to detect if we're at the end...
   DECODER_LOG("Seek completed, mCurrentPosition=%lld", mCurrentPosition.Ref());
 
   // Reset quick buffering status. This ensures that if we began the
   // seek while quick-buffering, we won't bypass quick buffering mode
   // if we need to buffer after the seek.
   mQuickBuffering = false;
 
-  mCurrentSeek.Resolve(mState == DECODER_STATE_COMPLETED, __func__);
   ScheduleStateMachine();
 
   if (video) {
     mMediaSink->Redraw();
     mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
   }
 }
 
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -76,16 +76,18 @@ skip-if = ((os == "win" && os_version ==
 [test_SeekableBeforeEndOfStream.html]
 [test_SeekableBeforeEndOfStream_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_SeekableBeforeEndOfStreamSplit.html]
 [test_SeekableBeforeEndOfStreamSplit_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_SeekNoData_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
+[test_SeekedEvent_mp4.html]
+skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_SeekTwice_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_Sequence_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_SetModeThrows.html]
 [test_SplitAppendDelay.html]
 [test_SplitAppendDelay_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/test/test_SeekedEvent_mp4.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>MSE: Check that seeked event is fired prior loadeddata</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="mediasource.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+runWithMSE(function(ms, el) {
+  el.controls = true;
+  el._seeked = false;
+  el._loadeddata = false;
+  el._playing = false;
+  el.addEventListener("seeked", function() {
+    ok(true, "got seeked event");
+    is(el._loadeddata, false, "can't have received loadeddata prior seeked");
+    is(el._playing, false, "can't be playing prior seeked");
+    el._seeked = true;
+  });
+  el.addEventListener("loadeddata", function() {
+    ok(true, "got loadeddata event");
+    is(el._seeked, true, "must have received seeked prior loadeddata");
+    is(el._playing, false, "can't be playing prior playing");
+    el._loadeddata = true;
+  });
+  el.addEventListener("playing", function() {
+    ok(true, "got playing");
+    is(el._seeked, true, "must have received seeked prior playing");
+    is(el._loadeddata, true, "must have received loadeddata prior playing");
+    el._playing = true;
+  });
+  once(ms, 'sourceopen').then(function() {
+    ok(true, "Receive a sourceopen event");
+    var videosb = ms.addSourceBuffer("video/mp4");
+    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+    fetchAndLoad(videosb, 'bipbop/bipbop_video', ['init'], '.mp4')
+    .then(once.bind(null, el, "loadedmetadata"))
+    .then(function() {
+      el.play();
+      videosb.timestampOffset = 2;
+      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+      // Load [2, 3.606).
+      var promises = [];
+      promises.push(once(el, "play"));
+      promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', ['1'], '.m4s'));
+      return Promise.all(promises);
+    })
+    .then(function() {
+      return fetchAndLoad(videosb, 'bipbop/bipbop_video', ['2'], '.m4s');
+    })
+    .then(function() {
+      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+      el.currentTime = 2;
+      var promises = [];
+      promises.push(once(el, "seeked"));
+      promises.push(once(el, "playing"));
+      return Promise.all(promises);
+    })
+    .then(function() {
+      ok(true, "completed seek");
+      SimpleTest.finish();
+    });
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -17,16 +17,18 @@
 extern "C" {
 #include "opus/opus_multistream.h"
 }
 #include "mozilla/TimeStamp.h"
 #include "VorbisUtils.h"
 #include "MediaMetadataManager.h"
 #include "nsISeekableStream.h"
 #include "gfx2DGlue.h"
+#include "mozilla/Telemetry.h"
+#include "nsPrintfCString.h"
 
 using namespace mozilla::gfx;
 using namespace mozilla::media;
 
 namespace mozilla {
 
 // On B2G estimate the buffered ranges rather than calculating them explicitly.
 // This prevents us doing I/O on the main thread, which is prohibited in B2G.
@@ -143,16 +145,27 @@ OggReader::OggReader(AbstractMediaDecode
   MOZ_COUNT_CTOR(OggReader);
   memset(&mTheoraInfo, 0, sizeof(mTheoraInfo));
 }
 
 OggReader::~OggReader()
 {
   ogg_sync_clear(&mOggState);
   MOZ_COUNT_DTOR(OggReader);
+  if (HasAudio() || HasVideo()) {
+    // If we were able to initialize our decoders, report whether we encountered
+    // a chained stream or not.
+    ReentrantMonitorAutoEnter mon(mMonitor);
+    bool isChained = mIsChained;
+    nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
+      LOG(LogLevel::Debug, (nsPrintfCString("Reporting telemetry MEDIA_OGG_LOADED_IS_CHAINED=%d", isChained).get()));
+      Telemetry::Accumulate(Telemetry::ID::MEDIA_OGG_LOADED_IS_CHAINED, isChained);
+    });
+    AbstractThread::MainThread()->Dispatch(task.forget());
+  }
 }
 
 nsresult OggReader::Init() {
   int ret = ogg_sync_init(&mOggState);
   NS_ENSURE_TRUE(ret == 0, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
@@ -699,20 +712,23 @@ bool OggReader::DecodeAudioData()
     // file while trying to decode, so inform the audio queue that there'll
     // be no more samples.
     return false;
   }
 
   return true;
 }
 
-void OggReader::SetChained(bool aIsChained) {
+void OggReader::SetChained() {
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
-    mIsChained = aIsChained;
+    if (mIsChained) {
+      return;
+    }
+    mIsChained = true;
   }
   mOnMediaNotSeekable.Notify();
 }
 
 bool OggReader::ReadOggChain()
 {
   bool chained = false;
   OpusState* newOpusState = nullptr;
@@ -795,17 +811,17 @@ bool OggReader::ReadOggChain()
     mInfo.mAudio.mRate = newOpusState->mRate;
     mInfo.mAudio.mChannels = newOpusState->mChannels;
 
     chained = true;
     tags = newOpusState->GetTags();
   }
 
   if (chained) {
-    SetChained(true);
+    SetChained();
     {
       auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate;
       mTimedMetadataEvent.Notify(
         TimedMetadata(media::TimeUnit::FromMicroseconds(t),
                       Move(tags),
                       nsAutoPtr<MediaInfo>(new MediaInfo(mInfo))));
     }
     return true;
@@ -1134,17 +1150,17 @@ int64_t OggReader::RangeEndTime(int64_t 
     int serial = ogg_page_serialno(&page);
 
     OggCodecState* codecState = nullptr;
     codecState = mCodecStore.Get(serial);
     if (!codecState) {
       // This page is from a bitstream which we haven't encountered yet.
       // It's probably from a new "link" in a "chained" ogg. Don't
       // bother even trying to find a duration...
-      SetChained(true);
+      SetChained();
       endTime = -1;
       break;
     }
 
     int64_t t = codecState->Time(granulepos);
     if (t != -1) {
       endTime = t;
     }
@@ -1908,17 +1924,17 @@ media::TimeIntervals OggReader::GetBuffe
         startOffset += page.header_len + page.body_len;
         continue;
       }
       else {
         // Page is for a stream we don't know about (possibly a chained
         // ogg), return OK to abort the finding any further ranges. This
         // prevents us searching through the rest of the media when we
         // may not be able to extract timestamps from it.
-        SetChained(true);
+        SetChained();
         return buffered;
       }
     }
 
     if (startTime != -1) {
       // We were able to find a start time for that range, see if we can
       // find an end time.
       int64_t endTime = RangeEndTime(startOffset, endOffset, true);
--- a/dom/media/ogg/OggReader.h
+++ b/dom/media/ogg/OggReader.h
@@ -247,17 +247,17 @@ private:
   // succeeds.
   bool ReadHeaders(OggCodecState* aState);
 
   // Reads the next link in the chain.
   bool ReadOggChain();
 
   // Set this media as being a chain and notifies the state machine that the
   // media is no longer seekable.
-  void SetChained(bool aIsChained);
+  void SetChained();
 
   // Returns the next Ogg packet for an bitstream/codec state. Returns a
   // pointer to an ogg_packet on success, or nullptr if the read failed.
   // The caller is responsible for deleting the packet and its |packet| field.
   ogg_packet* NextOggPacket(OggCodecState* aCodecState);
 
   // Fills aTracks with the serial numbers of each active stream, for use by
   // various SkeletonState functions.
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -275,31 +275,33 @@ D3D9DXVA2Manager::Init(nsACString& aFail
                                            D3DDEVTYPE_HAL,
                                            (D3DFORMAT)MAKEFOURCC('N','V','1','2'),
                                            D3DFMT_X8R8G8B8);
   if (!SUCCEEDED(hr)) {
     aFailureReason = nsPrintfCString("CheckDeviceFormatConversion failed with error %X", hr);
     return hr;
   }
 
-  // Create D3D9DeviceEx.
+  // Create D3D9DeviceEx. We pass null HWNDs here even though the documentation
+  // suggests that one of them should not be. At this point in time Chromium
+  // does the same thing for video acceleration.
   D3DPRESENT_PARAMETERS params = {0};
   params.BackBufferWidth = 1;
   params.BackBufferHeight = 1;
   params.BackBufferFormat = D3DFMT_UNKNOWN;
   params.BackBufferCount = 1;
   params.SwapEffect = D3DSWAPEFFECT_DISCARD;
-  params.hDeviceWindow = ::GetShellWindow();
+  params.hDeviceWindow = nullptr;
   params.Windowed = TRUE;
   params.Flags = D3DPRESENTFLAG_VIDEO;
 
   RefPtr<IDirect3DDevice9Ex> device;
   hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
                               D3DDEVTYPE_HAL,
-                              ::GetShellWindow(),
+                              nullptr,
                               D3DCREATE_FPU_PRESERVE |
                               D3DCREATE_MULTITHREADED |
                               D3DCREATE_MIXED_VERTEXPROCESSING,
                               &params,
                               nullptr,
                               getter_AddRefs(device));
   if (!SUCCEEDED(hr)) {
     aFailureReason = nsPrintfCString("CreateDeviceEx failed with error %X", hr);
--- a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm
+++ b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm
@@ -74,28 +74,38 @@ SpeechTaskCallback::OnCancel()
 }
 
 NS_IMETHODIMP
 SpeechTaskCallback::OnPause()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   [mSpeechSynthesizer pauseSpeakingAtBoundary:NSSpeechImmediateBoundary];
+  if (!mTask) {
+    // When calling pause() on child porcess, it may not receive end event
+    // from chrome process yet.
+    return NS_ERROR_FAILURE;
+  }
   mTask->DispatchPause(GetTimeDurationFromStart(), mCurrentIndex);
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP
 SpeechTaskCallback::OnResume()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   [mSpeechSynthesizer continueSpeaking];
+  if (!mTask) {
+    // When calling resume() on child porcess, it may not receive end event
+    // from chrome process yet.
+    return NS_ERROR_FAILURE;
+  }
   mTask->DispatchResume(GetTimeDurationFromStart(), mCurrentIndex);
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP
 SpeechTaskCallback::OnVolumeChanged(float aVolume)
@@ -115,23 +125,29 @@ SpeechTaskCallback::GetTimeDurationFromS
   TimeDuration duration = TimeStamp::Now() - mStartingTime;
   return duration.ToMilliseconds();
 }
 
 void
 SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex)
 {
   mCurrentIndex = aIndex;
+  if (!mTask) {
+    return;
+  }
   mTask->DispatchBoundary(NS_LITERAL_STRING("word"),
                           GetTimeDurationFromStart(), mCurrentIndex);
 }
 
 void
 SpeechTaskCallback::OnError(uint32_t aIndex)
 {
+  if (!mTask) {
+    return;
+  }
   mTask->DispatchError(GetTimeDurationFromStart(), aIndex);
 }
 
 void
 SpeechTaskCallback::OnDidFinishSpeaking()
 {
   mTask->DispatchEnd(GetTimeDurationFromStart(), mCurrentIndex);
   // no longer needed
--- a/dom/media/webspeech/synth/windows/SapiService.cpp
+++ b/dom/media/webspeech/synth/windows/SapiService.cpp
@@ -71,26 +71,36 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(SapiCall
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SapiCallback)
 
 NS_IMETHODIMP
 SapiCallback::OnPause()
 {
   if (FAILED(mSapiClient->Pause())) {
     return NS_ERROR_FAILURE;
   }
+  if (!mTask) {
+    // When calling pause() on child porcess, it may not receive end event
+    // from chrome process yet.
+    return NS_ERROR_FAILURE;
+  }
   mTask->DispatchPause(GetTickCount() - mStartingTime, mCurrentIndex);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SapiCallback::OnResume()
 {
   if (FAILED(mSapiClient->Resume())) {
     return NS_ERROR_FAILURE;
   }
+  if (!mTask) {
+    // When calling resume() on child porcess, it may not receive end event
+    // from chrome process yet.
+    return NS_ERROR_FAILURE;
+  }
   mTask->DispatchResume(GetTickCount() - mStartingTime, mCurrentIndex);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SapiCallback::OnCancel()
 {
   // After cancel, mCurrentIndex may be updated.
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -120,16 +120,17 @@ PluginInstanceParent::PluginInstancePare
     : mParent(parent)
     , mSurrogate(PluginAsyncSurrogate::Cast(npp))
     , mUseSurrogate(true)
     , mNPP(npp)
     , mNPNIface(npniface)
     , mIsWhitelistedForShumway(false)
     , mWindowType(NPWindowTypeWindow)
     , mDrawingModel(kDefaultDrawingModel)
+    , mLastRecordedDrawingModel(-1)
     , mFrameID(0)
 #if defined(OS_WIN)
     , mPluginHWND(nullptr)
     , mChildPluginHWND(nullptr)
     , mChildPluginsParentHWND(nullptr)
     , mPluginWndProc(nullptr)
     , mNestedEventState(false)
 #endif // defined(XP_WIN)
@@ -804,16 +805,18 @@ PluginInstanceParent::SetCurrentImage(Im
 {
     MOZ_ASSERT(IsUsingDirectDrawing());
     ImageContainer::NonOwningImage holder(aImage);
     holder.mFrameID = ++mFrameID;
 
     nsAutoTArray<ImageContainer::NonOwningImage,1> imageList;
     imageList.AppendElement(holder);
     mImageContainer->SetCurrentImages(imageList);
+
+    RecordDrawingModel();
 }
 
 bool
 PluginInstanceParent::RecvShowDirectDXGISurface(const WindowsHandle& handle,
                                                  const gfx::IntRect& dirty)
 {
 #if defined(XP_WIN)
     RefPtr<D3D11SurfaceHolder> surface;
@@ -968,16 +971,17 @@ PluginInstanceParent::RecvShow(const NPR
     }
 
     mFrontSurface = surface;
     RecvNPN_InvalidateRect(updatedRect);
 
     PLUGIN_LOG_DEBUG(("   (RecvShow invalidated for surface %p)",
                       mFrontSurface.get()));
 
+    RecordDrawingModel();
     return true;
 }
 
 nsresult
 PluginInstanceParent::AsyncSetWindow(NPWindow* aWindow)
 {
     NPRemoteWindow window;
     mWindowType = aWindow->type;
@@ -1375,16 +1379,17 @@ PluginInstanceParent::NPP_SetWindow(cons
     window.visualID = ws_info->visual ? ws_info->visual->visualid : 0;
     window.colormap = ws_info->colormap;
 #endif
 
     if (!CallNPP_SetWindow(window)) {
         return NPERR_GENERIC_ERROR;
     }
 
+    RecordDrawingModel();
     return NPERR_NO_ERROR;
 }
 
 NPError
 PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
                                    void* _retval)
 {
     switch (aVariable) {
@@ -2358,8 +2363,33 @@ PluginInstanceParent::Cast(NPP aInstance
 
     if (aSurrogate) {
         *aSurrogate = resolver->GetAsyncSurrogate();
     }
 
     return instancePtr;
 }
 
+void
+PluginInstanceParent::RecordDrawingModel()
+{
+    int mode = -1;
+    switch (mWindowType) {
+    case NPWindowTypeWindow:
+        // We use 0=windowed since there is no specific NPDrawingModel value.
+        mode = 0;
+        break;
+    case NPWindowTypeDrawable:
+        mode = mDrawingModel + 1;
+        break;
+    default:
+        MOZ_ASSERT_UNREACHABLE("bad window type");
+        return;
+    }
+
+    if (mode == mLastRecordedDrawingModel) {
+        return;
+    }
+    MOZ_ASSERT(mode >= 0);
+
+    Telemetry::Accumulate(Telemetry::PLUGIN_DRAWING_MODEL, mode);
+    mLastRecordedDrawingModel = mode;
+}
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -371,27 +371,35 @@ private:
     bool InternalGetValueForNPObject(NPNVariable aVariable,
                                      PPluginScriptableObjectParent** aValue,
                                      NPError* aResult);
 
     nsPluginInstanceOwner* GetOwner();
 
     void SetCurrentImage(layers::Image* aImage);
 
+    // Update Telemetry with the current drawing model.
+    void RecordDrawingModel();
+
 private:
     PluginModuleParent* mParent;
     RefPtr<PluginAsyncSurrogate> mSurrogate;
     bool mUseSurrogate;
     NPP mNPP;
     const NPNetscapeFuncs* mNPNIface;
     nsCString mSrcAttribute;
     bool mIsWhitelistedForShumway;
     NPWindowType mWindowType;
     int16_t mDrawingModel;
 
+    // Since plugins may request different drawing models to find a compatible
+    // one, we only record the drawing model after a SetWindow call and if the
+    // drawing model has changed.
+    int mLastRecordedDrawingModel;
+
     nsDataHashtable<nsPtrHashKey<NPObject>, PluginScriptableObjectParent*> mScriptableObjects;
 
     // This is used to tell the compositor that it should invalidate the ImageLayer.
     uint32_t mFrameID;
 
 #if defined(XP_WIN)
     // Note: DXGI 1.1 surface handles are global across all processes, and are not
     // marshaled. As long as we haven't freed a texture its handle should be valid
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -149,16 +149,19 @@ partial interface Document {
   // Gecko extensions?
                 attribute EventHandler onwheel;
                 attribute EventHandler oncopy;
                 attribute EventHandler oncut;
                 attribute EventHandler onpaste;
                 attribute EventHandler onbeforescriptexecute;
                 attribute EventHandler onafterscriptexecute;
 
+                [Pref="dom.select_events.enabled"]
+                attribute EventHandler onselectionchange;
+
   /**
    * True if this document is synthetic : stand alone image, video, audio file,
    * etc.
    */
   [Func="IsChromeOrXBL"] readonly attribute boolean mozSyntheticDocument;
   /**
    * Returns the script element whose script is currently being processed.
    *
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -1982,24 +1982,24 @@ nsEditor::RestorePreservedSelection(Sele
 void
 nsEditor::StopPreservingSelection()
 {
   mRangeUpdater.DropSelectionState(mSavedSel);
   mSavedSel.MakeEmpty();
 }
 
 void
-nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent)
+nsEditor::EnsureComposition(mozilla::WidgetCompositionEvent* aCompositionEvent)
 {
   if (mComposition) {
     return;
   }
   // The compositionstart event must cause creating new TextComposition
   // instance at being dispatched by IMEStateManager.
-  mComposition = IMEStateManager::GetTextCompositionFor(aEvent);
+  mComposition = IMEStateManager::GetTextCompositionFor(aCompositionEvent);
   if (!mComposition) {
     MOZ_CRASH("IMEStateManager doesn't return proper composition");
   }
   mComposition->StartHandlingComposition(this);
 }
 
 nsresult
 nsEditor::BeginIMEComposition(WidgetCompositionEvent* aCompositionEvent)
--- a/editor/libeditor/nsEditor.h
+++ b/editor/libeditor/nsEditor.h
@@ -408,17 +408,17 @@ protected:
     // regardless of DOM. Also, check to see if spell check should be skipped or not.
     return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() && !ShouldSkipSpellCheck();
   }
 
   /**
    * EnsureComposition() should be called by composition event handlers.  This
    * tries to get the composition for the event and set it to mComposition.
    */
-  void EnsureComposition(mozilla::WidgetGUIEvent* aEvent);
+  void EnsureComposition(mozilla::WidgetCompositionEvent* aCompositionEvent);
 
   nsresult GetSelection(int16_t aSelectionType, nsISelection** aSelection);
 
 public:
 
   /** All editor operations which alter the doc should be prefaced
    *  with a call to StartOperation, naming the action and direction */
   NS_IMETHOD StartOperation(EditAction opID,
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2214,17 +2214,17 @@ void AsyncPanZoomController::HandlePanni
 
     if (fabs(aPanDistance.x) > breakThreshold || fabs(aPanDistance.y) > breakThreshold) {
       if (mState == PANNING_LOCKED_X) {
         if (!IsCloseToHorizontal(angle, gfxPrefs::APZAxisBreakoutAngle())) {
           mY.SetAxisLocked(false);
           SetState(PANNING);
         }
       } else if (mState == PANNING_LOCKED_Y) {
-        if (!IsCloseToVertical(angle, gfxPrefs::APZAxisLockAngle())) {
+        if (!IsCloseToVertical(angle, gfxPrefs::APZAxisBreakoutAngle())) {
           mX.SetAxisLocked(false);
           SetState(PANNING);
         }
       }
     }
   }
 }
 
--- a/gfx/layers/apz/test/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/layers/apz/test/gtest/TestAsyncPanZoomController.cpp
@@ -543,21 +543,22 @@ Pan(const RefPtr<InputReceiver>& aTarget
     MockContentControllerDelayed* aMcc,
     const ScreenPoint& aTouchStart,
     const ScreenPoint& aTouchEnd,
     bool aKeepFingerDown = false,
     nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
     nsEventStatus (*aOutEventStatuses)[4] = nullptr,
     uint64_t* aOutInputBlockId = nullptr)
 {
-  // Reduce the touch start tolerance to a tiny value.
+  // Reduce the touch start and move tolerance to a tiny value.
   // We can't use a scoped pref because this value might be read at some later
   // time when the events are actually processed, rather than when we deliver
   // them.
   gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f);
+  gfxPrefs::SetAPZTouchMoveTolerance(0.0f);
   const int OVERCOME_TOUCH_TOLERANCE = 1;
 
   const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
 
   // Even if the caller doesn't care about the block id, we need it to set the
   // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
   uint64_t blockId;
   if (!aOutInputBlockId) {
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -410,68 +410,74 @@ APZCCallbackHelper::GetRootContentDocume
     }
     context = context->GetToplevelContentDocumentPresContext();
     if (!context) {
         return nullptr;
     }
     return context->PresShell();
 }
 
+static nsIPresShell*
+GetRootDocumentPresShell(nsIContent* aContent)
+{
+    nsIDocument* doc = aContent->GetComposedDoc();
+    if (!doc) {
+        return nullptr;
+    }
+    nsIPresShell* shell = doc->GetShell();
+    if (!shell) {
+        return nullptr;
+    }
+    nsPresContext* context = shell->GetPresContext();
+    if (!context) {
+        return nullptr;
+    }
+    context = context->GetRootPresContext();
+    if (!context) {
+        return nullptr;
+    }
+    return context->PresShell();
+}
+
 CSSPoint
 APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
                                            const ScrollableLayerGuid& aGuid)
 {
     CSSPoint input = aInput;
     if (aGuid.mScrollId == FrameMetrics::NULL_SCROLL_ID) {
         return input;
     }
-
     nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
     if (!content) {
         return input;
     }
 
-#if !defined(MOZ_SINGLE_PROCESS_APZ)
     // First, scale inversely by the root content document's pres shell
     // resolution to cancel the scale-to-resolution transform that the
     // compositor adds to the layer with the pres shell resolution. The points
     // sent to Gecko by APZ don't have this transform unapplied (unlike other
     // compositor-side transforms) because APZ doesn't know about it.
-    if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
+    if (nsIPresShell* shell = GetRootDocumentPresShell(content)) {
         input = input / shell->GetResolution();
     }
-#endif
 
-    // Apply the callback-transform.
+    // Now apply the callback-transform.
     // XXX: technically we need to walk all the way up the layer tree from the layer
     // represented by |aGuid.mScrollId| up to the root of the layer tree and apply
     // the input transforms at each level in turn. However, it is quite difficult
     // to do this given that the structure of the layer tree may be different from
     // the structure of the content tree. Also it may be impossible to do correctly
     // at this point because there are other CSS transforms and such interleaved in
     // between so applying the inputTransforms all in a row at the end may leave
     // some things transformed improperly. In practice we should rarely hit scenarios
     // where any of this matters, so I'm skipping it for now and just doing the single
     // transform for the layer that the input hit.
-
     void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
     if (property) {
         CSSPoint delta = (*static_cast<CSSPoint*>(property));
-
-#if defined(MOZ_SINGLE_PROCESS_APZ)
-        // The delta is in root content document coordinate space while the
-        // aInput point is in root document coordinate space so convert the
-        // delta to root document space before adding it to the aInput point.
-        float resolution = 1.0f;
-        if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
-            resolution = shell->GetResolution();
-        }
-        delta.x = delta.x * resolution;
-        delta.y = delta.y * resolution;
-#endif // MOZ_SINGLE_PROCESS_APZ
         input += delta;
     }
     return input;
 }
 
 LayoutDeviceIntPoint
 APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
                                            const ScrollableLayerGuid& aGuid,
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -142,26 +142,24 @@ ChromeProcessController::HandleDoubleTap
   }
 
   nsCOMPtr<nsIDocument> document = GetRootContentDocument(aGuid.mScrollId);
   if (!document.get()) {
     return;
   }
 
   CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
-#if defined(MOZ_SINGLE_PROCESS_APZ)
   // CalculateRectToZoomTo performs a hit test on the frame associated with the
   // Root Content Document. Unfortunately that frame does not know about the
   // resolution of the document and so we must remove it before calculating
   // the zoomToRect.
   nsIPresShell* presShell = document->GetShell();
   const float resolution = presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f;
   point.x = point.x / resolution;
   point.y = point.y / resolution;
-#endif // MOZ_SINGLE_PROCESS_APZ
   CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
 
   uint32_t presShellId;
   FrameMetrics::ViewID viewId;
   if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
       document->GetDocumentElement(), &presShellId, &viewId)) {
     mAPZCTreeManager->ZoomToRect(
       ScrollableLayerGuid(aGuid.mLayersId, presShellId, viewId), zoomToRect);
--- a/ipc/glue/Transport_posix.cpp
+++ b/ipc/glue/Transport_posix.cpp
@@ -4,16 +4,18 @@
 /* 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 <unistd.h>
 
 #include <string>
 
+#include "base/eintr_wrapper.h"
+
 #include "chrome/common/child_process_info.h"
 
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/ipc/FileDescriptor.h"
 
 using namespace std;
 
 using base::ProcessHandle;
@@ -36,16 +38,18 @@ CreateTransport(base::ProcessId aProcIdO
     return NS_ERROR_TRANSPORT_INIT;
   }
 
   // The Transport closes these fds when it goes out of scope, so we
   // dup them here
   fd1 = dup(fd1);
   fd2 = dup(fd2);
   if (fd1 < 0 || fd2 < 0) {
+    HANDLE_EINTR(close(fd1));
+    HANDLE_EINTR(close(fd2));
     return NS_ERROR_DUPLICATE_HANDLE;
   }
 
   aOne->mFd = base::FileDescriptor(fd1, true/*close after sending*/);
   aTwo->mFd = base::FileDescriptor(fd2, true/*close after sending*/);
   return NS_OK;
 }
 
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -548,17 +548,16 @@ DynamicallyLinkModule(JSContext* cx, con
             if (!ValidateGlobalVariable(cx, module, global, importVal))
                 return false;
             break;
           case AsmJSModule::Global::FFI:
             if (!ValidateFFI(cx, global, importVal, &ffis))
                 return false;
             break;
           case AsmJSModule::Global::ArrayView:
-          case AsmJSModule::Global::SharedArrayView:
           case AsmJSModule::Global::ArrayViewCtor:
             if (!ValidateArrayView(cx, global, globalVal))
                 return false;
             break;
           case AsmJSModule::Global::ByteLength:
             if (!ValidateByteLength(cx, globalVal))
                 return false;
             break;
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -95,17 +95,17 @@ enum AsmJSSimdOperation
 //
 // NB: this means that AsmJSModule must be GC-safe.
 class AsmJSModule
 {
   public:
     class Global
     {
       public:
-        enum Which { Variable, FFI, ArrayView, ArrayViewCtor, SharedArrayView, MathBuiltinFunction,
+        enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
                      AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation, ByteLength };
         enum VarInitKind { InitConstant, InitImport };
         enum ConstantKind { GlobalConstant, MathConstant };
 
       private:
         struct Pod {
             Which which_;
             union {
@@ -184,27 +184,23 @@ class AsmJSModule
             MOZ_ASSERT(pod.which_ == FFI);
             return pod.u.ffiIndex_;
         }
         // When a view is created from an imported constructor:
         //   var I32 = stdlib.Int32Array;
         //   var i32 = new I32(buffer);
         // the second import has nothing to validate and thus has a null field.
         PropertyName* maybeViewName() const {
-            MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == SharedArrayView || pod.which_ == ArrayViewCtor);
+            MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
             return name_;
         }
         Scalar::Type viewType() const {
-            MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == SharedArrayView || pod.which_ == ArrayViewCtor);
+            MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
             return pod.u.viewType_;
         }
-        void makeViewShared() {
-            MOZ_ASSERT(pod.which_ == ArrayView);
-            pod.which_ = SharedArrayView;
-        }
         PropertyName* mathName() const {
             MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
             return name_;
         }
         PropertyName* atomicsName() const {
             MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
             return name_;
         }
@@ -905,30 +901,28 @@ class AsmJSModule
     bool addFFI(PropertyName* field, uint32_t* ffiIndex) {
         MOZ_ASSERT(!isFinished());
         if (pod.numFFIs_ == UINT32_MAX)
             return false;
         Global g(Global::FFI, field);
         g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++;
         return globals_.append(g);
     }
-    bool addArrayView(Scalar::Type vt, PropertyName* maybeField, bool isSharedView) {
+    bool addArrayView(Scalar::Type vt, PropertyName* maybeField) {
         MOZ_ASSERT(!isFinished());
-        MOZ_ASSERT(!pod.hasArrayView_ || (pod.isSharedView_ == isSharedView));
         pod.hasArrayView_ = true;
-        pod.isSharedView_ = isSharedView;
+        pod.isSharedView_ = false;
         Global g(Global::ArrayView, maybeField);
         g.pod.u.viewType_ = vt;
         return globals_.append(g);
     }
-    bool addArrayViewCtor(Scalar::Type vt, PropertyName* field, bool isSharedView) {
+    bool addArrayViewCtor(Scalar::Type vt, PropertyName* field) {
         MOZ_ASSERT(!isFinished());
         MOZ_ASSERT(field);
-        MOZ_ASSERT(!pod.isSharedView_ || isSharedView);
-        pod.isSharedView_ = isSharedView;
+        pod.isSharedView_ = false;
         Global g(Global::ArrayViewCtor, field);
         g.pod.u.viewType_ = vt;
         return globals_.append(g);
     }
     bool addByteLength() {
         MOZ_ASSERT(!isFinished());
         Global g(Global::ByteLength, nullptr);
         return globals_.append(g);
@@ -973,29 +967,19 @@ class AsmJSModule
         return globals_.append(g);
     }
     unsigned numGlobals() const {
         return globals_.length();
     }
     Global& global(unsigned i) {
         return globals_[i];
     }
-    bool isValidViewSharedness(bool shared) const {
-        if (pod.hasArrayView_)
-            return pod.isSharedView_ == shared;
-        return !pod.isSharedView_ || shared;
-    }
     void setViewsAreShared() {
         if (pod.hasArrayView_)
             pod.isSharedView_ = true;
-        for (size_t i=0 ; i < globals_.length() ; i++) {
-            Global& g = globals_[i];
-            if (g.which() == Global::ArrayView)
-                g.makeViewShared();
-        }
     }
 
     /*************************************************************************/
     // These functions are called while parsing/compiling function bodies:
 
     bool hasArrayView() const {
         return pod.hasArrayView_;
     }
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -1009,17 +1009,16 @@ class MOZ_STACK_CLASS ModuleValidator
                 uint32_t globalDataOffset_;
                 NumLit literalValue_;
             } varOrConst;
             uint32_t funcIndex_;
             uint32_t funcPtrTableIndex_;
             uint32_t ffiIndex_;
             struct {
                 Scalar::Type viewType_;
-                bool isSharedView_;
             } viewInfo;
             AsmJSMathBuiltinFunction mathBuiltinFunc_;
             AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
             AsmJSSimdType simdCtorType_;
             struct {
                 AsmJSSimdType type_;
                 AsmJSSimdOperation which_;
             } simdOp;
@@ -1067,24 +1066,16 @@ class MOZ_STACK_CLASS ModuleValidator
         }
         bool isAnyArrayView() const {
             return which_ == ArrayView || which_ == ArrayViewCtor;
         }
         Scalar::Type viewType() const {
             MOZ_ASSERT(isAnyArrayView());
             return u.viewInfo.viewType_;
         }
-        bool viewIsSharedView() const {
-            MOZ_ASSERT(isAnyArrayView());
-            return u.viewInfo.isSharedView_;
-        }
-        void setViewIsSharedView() {
-            MOZ_ASSERT(isAnyArrayView());
-            u.viewInfo.isSharedView_ = true;
-        }
         bool isMathFunction() const {
             return which_ == MathBuiltinFunction;
         }
         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
             MOZ_ASSERT(which_ == MathBuiltinFunction);
             return u.mathBuiltinFunc_;
         }
         bool isAtomicsFunction() const {
@@ -1397,28 +1388,26 @@ class MOZ_STACK_CLASS ModuleValidator
         Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
         Global* global = validationLifo_.new_<Global>(which);
         if (!global)
             return false;
         global->u.varOrConst.globalDataOffset_ = globalDataOffset;
         global->u.varOrConst.type_ = Type::var(importType).which();
         return globals_.putNew(varName, global);
     }
-    bool addArrayView(PropertyName* varName, Scalar::Type vt, PropertyName* maybeField,
-                      bool isSharedView)
+    bool addArrayView(PropertyName* varName, Scalar::Type vt, PropertyName* maybeField)
     {
         if (!arrayViews_.append(ArrayView(varName, vt)))
             return false;
         Global* global = validationLifo_.new_<Global>(Global::ArrayView);
         if (!global)
             return false;
-        if (!module().addArrayView(vt, maybeField, isSharedView))
+        if (!module().addArrayView(vt, maybeField))
             return false;
         global->u.viewInfo.viewType_ = vt;
-        global->u.viewInfo.isSharedView_ = isSharedView;
         return globals_.putNew(varName, global);
     }
     bool addMathBuiltinFunction(PropertyName* varName, AsmJSMathBuiltinFunction func,
                                 PropertyName* fieldName)
     {
         if (!module().addMathBuiltinFunction(func, fieldName))
             return false;
         Global* global = validationLifo_.new_<Global>(Global::MathBuiltinFunction);
@@ -1492,24 +1481,23 @@ class MOZ_STACK_CLASS ModuleValidator
         module().addChangeHeap(mask, min, max);
         Global* global = validationLifo_.new_<Global>(Global::ChangeHeap);
         if (!global)
             return false;
         global->u.changeHeap.srcBegin_ = fn->pn_pos.begin;
         global->u.changeHeap.srcEnd_ = fn->pn_pos.end;
         return globals_.putNew(name, global);
     }
-    bool addArrayViewCtor(PropertyName* varName, Scalar::Type vt, PropertyName* fieldName, bool isSharedView) {
+    bool addArrayViewCtor(PropertyName* varName, Scalar::Type vt, PropertyName* fieldName) {
         Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
         if (!global)
             return false;
-        if (!module().addArrayViewCtor(vt, fieldName, isSharedView))
+        if (!module().addArrayViewCtor(vt, fieldName))
             return false;
         global->u.viewInfo.viewType_ = vt;
-        global->u.viewInfo.isSharedView_ = isSharedView;
         return globals_.putNew(varName, global);
     }
     bool addFFI(PropertyName* varName, PropertyName* field) {
         Global* global = validationLifo_.new_<Global>(Global::FFI);
         if (!global)
             return false;
         uint32_t index;
         if (!module().addFFI(field, &index))
@@ -1607,16 +1595,20 @@ class MOZ_STACK_CLASS ModuleValidator
     }
     bool tryRequireHeapLengthToBeAtLeast(uint32_t len) {
         return module().tryRequireHeapLengthToBeAtLeast(len);
     }
     uint32_t minHeapLength() const {
         return module().minHeapLength();
     }
 
+    bool usesSharedMemory() const {
+        return atomicsPresent_;
+    }
+
     // Error handling.
     bool hasAlreadyFailed() const {
         return !!errorString_;
     }
 
     bool failOffset(uint32_t offset, const char* str) {
         MOZ_ASSERT(!hasAlreadyFailed());
         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
@@ -1735,24 +1727,18 @@ class MOZ_STACK_CLASS ModuleValidator
         if (SimdOperationNameMap::Ptr p = standardLibrarySimdOpNames_.lookup(name)) {
             *op = p->value();
             return true;
         }
         return false;
     }
 
     void startFunctionBodies() {
-        if (atomicsPresent_) {
-            for (GlobalMap::Range r = globals_.all() ; !r.empty() ; r.popFront()) {
-                Global* g = r.front().value();
-                if (g->isAnyArrayView())
-                    g->setViewIsSharedView();
-            }
+        if (atomicsPresent_)
             module().setViewsAreShared();
-        }
     }
 };
 
 } // namespace
 
 /*****************************************************************************/
 // Numeric literal utilities
 
@@ -2467,20 +2453,19 @@ CheckGlobalVariableInitImport(ModuleVali
     ValType coerceTo;
     ParseNode* coercedExpr;
     if (!CheckTypeAnnotation(m, initNode, &coerceTo, &coercedExpr))
         return false;
     return CheckGlobalVariableImportExpr(m, varName, coerceTo, coercedExpr, isConst);
 }
 
 static bool
-IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type, bool* shared)
+IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type)
 {
     JSAtomState& names = m.cx()->names();
-    *shared = false;
     if (name == names.Int8Array) {
         *type = Scalar::Int8;
     } else if (name == names.Uint8Array) {
         *type = Scalar::Uint8;
     } else if (name == names.Int16Array) {
         *type = Scalar::Int16;
     } else if (name == names.Uint16Array) {
         *type = Scalar::Uint16;
@@ -2521,50 +2506,45 @@ CheckNewArrayView(ModuleValidator& m, Pr
     PropertyName* bufferName = m.module().bufferArgumentName();
     if (!bufferName)
         return m.fail(newExpr, "cannot create array view without an asm.js heap parameter");
 
     ParseNode* ctorExpr = ListHead(newExpr);
 
     PropertyName* field;
     Scalar::Type type;
-    bool shared = false;
     if (ctorExpr->isKind(PNK_DOT)) {
         ParseNode* base = DotBase(ctorExpr);
 
         if (!IsUseOfName(base, globalName))
             return m.failName(base, "expecting '%s.*Array", globalName);
 
         field = DotMember(ctorExpr);
-        if (!IsArrayViewCtorName(m, field, &type, &shared))
+        if (!IsArrayViewCtorName(m, field, &type))
             return m.fail(ctorExpr, "could not match typed array name");
     } else {
         if (!ctorExpr->isKind(PNK_NAME))
             return m.fail(ctorExpr, "expecting name of imported array view constructor");
 
         PropertyName* globalName = ctorExpr->name();
         const ModuleValidator::Global* global = m.lookupGlobal(globalName);
         if (!global)
             return m.failName(ctorExpr, "%s not found in module global scope", globalName);
 
         if (global->which() != ModuleValidator::Global::ArrayViewCtor)
             return m.failName(ctorExpr, "%s must be an imported array view constructor", globalName);
 
         field = nullptr;
         type = global->viewType();
-        shared = global->viewIsSharedView();
     }
 
     if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
         return false;
 
-    if (!m.module().isValidViewSharedness(shared))
-        return m.failName(ctorExpr, "%s has different sharedness than previous view constructors", globalName);
-
-    return m.addArrayView(varName, type, field, shared);
+    return m.addArrayView(varName, type, field);
 }
 
 static bool
 IsSimdTypeName(ModuleValidator& m, PropertyName* name, AsmJSSimdType* type)
 {
     if (name == m.cx()->names().int32x4) {
         *type = AsmJSSimdType_int32x4;
         return true;
@@ -2690,22 +2670,18 @@ CheckGlobalDotImport(ModuleValidator& m,
         if (field == m.cx()->names().NaN)
             return m.addGlobalConstant(varName, GenericNaN(), field);
         if (field == m.cx()->names().Infinity)
             return m.addGlobalConstant(varName, PositiveInfinity<double>(), field);
         if (field == m.cx()->names().byteLength)
             return m.addByteLength(varName);
 
         Scalar::Type type;
-        bool shared = false;
-        if (IsArrayViewCtorName(m, field, &type, &shared)) {
-            if (!m.module().isValidViewSharedness(shared))
-                return m.failName(initNode, "'%s' has different sharedness than previous view constructors", field);
-            return m.addArrayViewCtor(varName, type, field, shared);
-        }
+        if (IsArrayViewCtorName(m, field, &type))
+            return m.addArrayViewCtor(varName, type, field);
 
         return m.failName(initNode, "'%s' is not a standard constant or typed array name", field);
     }
 
     if (base->name() == m.module().importArgumentName())
         return m.addFFI(varName, field);
 
     const ModuleValidator::Global* global = m.lookupGlobal(base->name());
@@ -6782,16 +6758,22 @@ CheckModule(ExclusiveContext* cx, AsmJSP
     if (!CheckModuleProcessingDirectives(m))
         return false;
 
     if (!CheckModuleGlobals(m))
         return false;
 
     m.startFunctionBodies();
 
+#if !defined(ENABLE_SHARED_ARRAY_BUFFER)
+    if (m.usesSharedMemory())
+        return m.failOffset(m.parser().tokenStream.currentToken().pos.begin,
+                            "shared memory and atomics not supported by this build");
+#endif
+
     if (!CheckFunctions(m))
         return false;
 
     if (!CheckFuncPtrTables(m))
         return false;
 
     if (!CheckModuleReturn(m))
         return false;
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -99,17 +99,18 @@ class FunctionCompiler
             return false;
 
         for (ABIArgIter<LifoSig::ArgVector> i(args); !i.done(); i++) {
             MAsmJSParameter* ins = MAsmJSParameter::New(alloc(), *i, i.mirType());
             curBlock_->add(ins);
             curBlock_->initSlot(info().localSlot(i.index()), ins);
             if (!mirGen_.ensureBallast())
                 return false;
-            localTypes_.append(args[i.index()]);
+            if (!localTypes_.append(args[i.index()]))
+                return false;
         }
 
         for (unsigned i = 0; i < func_.numVarInits(); i++) {
             Val v = func_.varInit(i);
             MInstruction* ins = nullptr;
             switch (v.type()) {
               case ValType::I32:
                 ins = MConstant::NewAsmJS(alloc(), Int32Value(v.i32()), MIRType_Int32);
@@ -129,17 +130,18 @@ class FunctionCompiler
                 ins = MSimdConstant::New(alloc(), SimdConstant::CreateX4(v.f32x4()), MIRType_Float32x4);
                 break;
             }
 
             curBlock_->add(ins);
             curBlock_->initSlot(info().localSlot(firstVarSlot + i), ins);
             if (!mirGen_.ensureBallast())
                 return false;
-            localTypes_.append(v.type());
+            if (!localTypes_.append(v.type()))
+                return false;
         }
 
         return true;
     }
 
     void checkPostconditions()
     {
         MOZ_ASSERT(loopStack_.empty());
@@ -1124,22 +1126,30 @@ class FunctionCompiler
     }
 
     bool joinSwitch(MBasicBlock* switchBlock, const BlockVector& cases, MBasicBlock* defaultBlock)
     {
         size_t pos = breakableStack_.popCopy();
         if (!switchBlock)
             return true;
         MTableSwitch* mir = switchBlock->lastIns()->toTableSwitch();
-        size_t defaultIndex = mir->addDefault(defaultBlock);
+        size_t defaultIndex;
+        if (!mir->addDefault(defaultBlock, &defaultIndex))
+            return false;
         for (unsigned i = 0; i < cases.length(); i++) {
-            if (!cases[i])
-                mir->addCase(defaultIndex);
-            else
-                mir->addCase(mir->addSuccessor(cases[i]));
+            if (!cases[i]) {
+                if (!mir->addCase(defaultIndex))
+                    return false;
+            } else {
+                size_t caseIndex;
+                if (!mir->addSuccessor(cases[i], &caseIndex))
+                    return false;
+                if (!mir->addCase(caseIndex))
+                    return false;
+            }
         }
         if (curBlock_) {
             MBasicBlock* next;
             if (!newBlock(curBlock_, &next))
                 return false;
             curBlock_->end(MGoto::New(alloc(), next));
             curBlock_ = next;
         }
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -233,22 +233,16 @@ EvalKernel(JSContext* cx, const CallArgs
     AssertInnerizedScopeChain(cx, *scopeobj);
 
     Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global());
     if (!GlobalObject::isRuntimeCodeGenEnabled(cx, scopeObjGlobal)) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL);
         return false;
     }
 
-    if (evalType == DIRECT_EVAL && caller.script()->isDerivedClassConstructor()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DISABLED_DERIVED_CLASS,
-                             "direct eval");
-        return false;
-    }
-
     // ES5 15.1.2.1 step 1.
     if (args.length() < 1) {
         args.rval().setUndefined();
         return true;
     }
     if (!args[0].isString()) {
         args.rval().set(args[0]);
         return true;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2778,69 +2778,73 @@ BytecodeEmitter::emitNameIncDec(ParseNod
         return false;
     if (post && !emit1(JSOP_POP))              // RESULT
         return false;
 
     return true;
 }
 
 bool
-BytecodeEmitter::emitElemOperands(ParseNode* pn, JSOp op)
+BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
 {
     MOZ_ASSERT(pn->isArity(PN_BINARY));
 
     if (!emitTree(pn->pn_left))
         return false;
 
-    if (op == JSOP_CALLELEM && !emit1(JSOP_DUP))
-        return false;
+    if (opts == EmitElemOption::IncDec) {
+        if (!emit1(JSOP_CHECKOBJCOERCIBLE))
+            return false;
+    } else if (opts == EmitElemOption::Call) {
+        if (!emit1(JSOP_DUP))
+            return false;
+    }
 
     if (!emitTree(pn->pn_right))
         return false;
 
-    bool isSetElem = op == JSOP_SETELEM || op == JSOP_STRICTSETELEM;
-    if (isSetElem && !emit2(JSOP_PICK, 2))
-        return false;
-    return true;
-}
-
-bool
-BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
+    if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 2))
+        return false;
+    return true;
+}
+
+bool
+BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
 {
     MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper());
 
     // The ordering here is somewhat screwy. We need to evaluate the propval
     // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
     // Since JSOP_THIS might throw in derived class constructors, we cannot
     // just push it earlier as the receiver. We have to swap it down instead.
 
     if (!emitTree(pn->pn_right))
         return false;
 
     // We need to convert the key to an object id first, so that we do not do
     // it inside both the GETELEM and the SETELEM.
-    if (opts == SuperElem_IncDec && !emit1(JSOP_TOID))
+    if (opts == EmitElemOption::IncDec && !emit1(JSOP_TOID))
         return false;
 
     if (!emitGetThisForSuperBase(pn->pn_left))
         return false;
 
-    if (opts == SuperElem_Call) {
+    if (opts == EmitElemOption::Call) {
         if (!emit1(JSOP_SWAP))
             return false;
 
         // We need another |this| on top, also
         if (!emitDupAt(1))
             return false;
     }
 
     if (!emit1(JSOP_SUPERBASE))
         return false;
 
-    if (opts == SuperElem_Set && !emit2(JSOP_PICK, 3))
+    if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
         return false;
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitElemOpBase(JSOp op)
 {
@@ -2849,27 +2853,33 @@ BytecodeEmitter::emitElemOpBase(JSOp op)
 
     checkTypeSet(op);
     return true;
 }
 
 bool
 BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op)
 {
-    return emitElemOperands(pn, op) && emitElemOpBase(op);
+    EmitElemOption opts = EmitElemOption::Get;
+    if (op == JSOP_CALLELEM)
+        opts = EmitElemOption::Call;
+    else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
+        opts = EmitElemOption::Set;
+
+    return emitElemOperands(pn, opts) && emitElemOpBase(op);
 }
 
 bool
 BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
 {
-    SuperElemOptions opts = SuperElem_Get;
+    EmitElemOption opts = EmitElemOption::Get;
     if (isCall)
-        opts = SuperElem_Call;
+        opts = EmitElemOption::Call;
     else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
-        opts = SuperElem_Set;
+        opts = EmitElemOption::Set;
 
     if (!emitSuperElemOperands(pn, opts))
         return false;
     if (!emitElemOpBase(op))
         return false;
 
     if (isCall && !emit1(JSOP_SWAP))
         return false;
@@ -2880,20 +2890,20 @@ BytecodeEmitter::emitSuperElemOp(ParseNo
 bool
 BytecodeEmitter::emitElemIncDec(ParseNode* pn)
 {
     MOZ_ASSERT(pn->pn_kid->isKind(PNK_ELEM));
 
     bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
 
     if (isSuper) {
-        if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec))
+        if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
             return false;
     } else {
-        if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
+        if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec))
             return false;
     }
 
     bool post;
     JSOp binop = GetIncDecInfo(pn->getKind(), &post);
 
     JSOp getOp;
     if (isSuper) {
@@ -3460,20 +3470,44 @@ BytecodeEmitter::emitSetThis(ParseNode* 
     if (!emitTree(pn->pn_right))
         return false;
 
     if (!bindNameToSlot(name))
         return false;
 
     JSOp setOp = name->getOp();
 
+    // Handle the eval case. Only accept the strict variant, as eval in a
+    // derived class constructor must be strict.
+    if (setOp == JSOP_STRICTSETNAME) {
+        if (!emitAtomOp(name, JSOP_GETNAME))
+            return false;
+        if (!emit1(JSOP_CHECKTHISREINIT))
+            return false;
+        if (!emit1(JSOP_POP))
+            return false;
+
+        if (!emitAtomOp(name, JSOP_BINDNAME))
+            return false;
+        if (!emit1(JSOP_SWAP))
+            return false;
+
+        return emitAtomOp(name, setOp);
+    }
+
     JSOp getOp;
     switch (setOp) {
-      case JSOP_SETLOCAL:      getOp = JSOP_GETLOCAL;      break;
-      case JSOP_SETALIASEDVAR: getOp = JSOP_GETALIASEDVAR; break;
+      case JSOP_SETLOCAL:
+        getOp = JSOP_GETLOCAL;
+        setOp = JSOP_INITLEXICAL;
+        break;
+      case JSOP_SETALIASEDVAR:
+        getOp = JSOP_GETALIASEDVAR;
+        setOp = JSOP_INITALIASEDLEXICAL;
+        break;
       default: MOZ_CRASH("Unexpected op");
     }
 
     // First, get the original |this| and throw if we already initialized it.
     if (!emitVarOp(name, getOp))
         return false;
     if (!emit1(JSOP_CHECKTHISREINIT))
         return false;
@@ -4374,23 +4408,35 @@ BytecodeEmitter::emitVariables(ParseNode
         } else if (binding->isKind(PNK_ASSIGN)) {
             /*
              * A destructuring initialiser assignment preceded by var will
              * never occur to the left of 'in' in a for-in loop.  As with 'for
              * (var x = i in o)...', this will cause the entire 'var [a, b] =
              * i' to be hoisted out of the loop.
              */
             MOZ_ASSERT(binding->isOp(JSOP_NOP));
-            MOZ_ASSERT(emitOption != DefineVars && emitOption != AnnexB);
-
-            /*
-             * To allow the front end to rewrite var f = x; as f = x; when a
-             * function f(){} precedes the var, detect simple name assignment
-             * here and initialize the name.
-             */
+            MOZ_ASSERT(emitOption != DefineVars);
+            MOZ_ASSERT_IF(emitOption == AnnexB, binding->pn_left->isKind(PNK_NAME));
+
+            // To allow the front end to rewrite |var f = x;| as |f = x;| when a
+            // |function f(){}| precedes the var, detect simple name assignment
+            // here and initialize the name.
+            //
+            // There is a corner case where a function declaration synthesizes
+            // an Annex B declaration, which in turn gets rewritten later as a
+            // simple assignment due to hoisted function declaration of the
+            // same name. For example,
+            //
+            // {
+            //   // Synthesizes an Annex B declaration because no 'f' binding
+            //   // yet exists. This later gets rewritten as an assignment when
+            //   // the outer function 'f' gets hoisted.
+            //   function f() {}
+            // }
+            // function f() {}
             if (binding->pn_left->isKind(PNK_NAME)) {
                 if (!emitSingleVariable(pn, binding->pn_left, binding->pn_right, emitOption))
                     return false;
             } else {
                 ParseNode* initializer = binding->pn_left;
                 if (!emitDestructuringDecls(pn->getOp(), initializer))
                     return false;
 
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -514,17 +514,18 @@ struct BytecodeEmitter
     bool emitPropOp(ParseNode* pn, JSOp op);
     bool emitPropIncDec(ParseNode* pn);
 
     bool emitComputedPropertyName(ParseNode* computedPropName);
 
     // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
     // opcode onto the stack in the right order. In the case of SETELEM, the
     // value to be assigned must already be pushed.
-    bool emitElemOperands(ParseNode* pn, JSOp op);
+    enum class EmitElemOption { Get, Set, Call, IncDec };
+    bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
 
     bool emitElemOpBase(JSOp op);
     bool emitElemOp(ParseNode* pn, JSOp op);
     bool emitElemIncDec(ParseNode* pn);
 
     bool emitCatch(ParseNode* pn);
     bool emitIf(ParseNode* pn);
     bool emitWith(ParseNode* pn);
@@ -649,17 +650,16 @@ struct BytecodeEmitter
     //
     // Please refer the comment above emitSpread for additional information about
     // stack convention.
     bool emitForOf(StmtType type, ParseNode* pn);
 
     bool emitClass(ParseNode* pn);
     bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false);
     bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
-    enum SuperElemOptions { SuperElem_Get, SuperElem_Set, SuperElem_Call, SuperElem_IncDec };
-    bool emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts = SuperElem_Get);
+    bool emitSuperElemOperands(ParseNode* pn, EmitElemOption opts = EmitElemOption::Get);
     bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
 };
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* frontend_BytecodeEmitter_h */
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -120,18 +120,22 @@ MarkUsesAsHoistedLexical(ParseNode* pn)
 void
 SharedContext::computeAllowSyntax(JSObject* staticScope)
 {
     for (StaticScopeIter<CanGC> it(context, staticScope); !it.done(); it++) {
         if (it.type() == StaticScopeIter<CanGC>::Function && !it.fun().isArrow()) {
             // Any function supports new.target.
             allowNewTarget_ = true;
             allowSuperProperty_ = it.fun().allowSuperProperty();
-            if (it.maybeFunctionBox())
+            if (it.maybeFunctionBox()) {
                 superScopeAlreadyNeedsHomeObject_ = it.maybeFunctionBox()->needsHomeObject();
+                allowSuperCall_ = it.maybeFunctionBox()->isDerivedClassConstructor();
+            } else {
+                allowSuperCall_ = it.fun().isDerivedClassConstructor();
+            }
             break;
         }
     }
 }
 
 void
 SharedContext::computeThisBinding(JSObject* staticScope)
 {
@@ -7465,21 +7469,16 @@ Parser<ParseHandler>::assignExpr(InHandl
         tokenStream.seek(start);
         if (!abortIfSyntaxParser())
             return null();
 
         TokenKind ignored;
         if (!tokenStream.peekToken(&ignored, TokenStream::Operand))
             return null();
 
-        if (pc->sc->isFunctionBox() && pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
-            report(ParseError, false, null(), JSMSG_DISABLED_DERIVED_CLASS, "arrow functions");
-            return null();
-        }
-
         Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator);
         if (!arrowFunc)
             return null();
 
         if (isBlock) {
             // This arrow function could be a non-trailing member of a comma
             // expression or a semicolon terminating a full expression.  If so,
             // the next token is that comma/semicolon, gotten with None:
@@ -8885,17 +8884,17 @@ Parser<ParseHandler>::memberExpr(YieldHa
             nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
             if (!nextMember)
                 return null();
         } else if ((allowCallSyntax && tt == TOK_LP) ||
                    tt == TOK_TEMPLATE_HEAD ||
                    tt == TOK_NO_SUBS_TEMPLATE)
         {
             if (handler.isSuperBase(lhs)) {
-                if (!pc->sc->isFunctionBox() || !pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
+                if (!pc->sc->allowSuperCall()) {
                     report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
                     return null();
                 }
 
                 if (tt != TOK_LP) {
                     report(ParseError, false, null(), JSMSG_BAD_SUPER);
                     return null();
                 }
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -197,31 +197,33 @@ class SharedContext
     bool localStrict;
     bool extraWarnings;
 
   private:
     ThisBinding thisBinding_;
 
     bool allowNewTarget_;
     bool allowSuperProperty_;
+    bool allowSuperCall_;
     bool inWith_;
     bool needsThisTDZChecks_;
     bool superScopeAlreadyNeedsHomeObject_;
 
   public:
     SharedContext(ExclusiveContext* cx, Directives directives,
                   bool extraWarnings)
       : context(cx),
         anyCxFlags(),
         strictScript(directives.strict()),
         localStrict(false),
         extraWarnings(extraWarnings),
         thisBinding_(ThisBinding::Global),
         allowNewTarget_(false),
         allowSuperProperty_(false),
+        allowSuperCall_(false),
         inWith_(false),
         needsThisTDZChecks_(false),
         superScopeAlreadyNeedsHomeObject_(false)
     { }
 
     // The unfortunate reason that staticScope() is a virtual is because
     // GlobalSharedContext and FunctionBox have different lifetimes.
     // GlobalSharedContexts are stack allocated and thus may use RootedObject
@@ -239,16 +241,17 @@ class SharedContext
     bool isModuleBox() { return isObjectBox() && toObjectBox()->isModuleBox(); }
     inline ModuleBox* asModuleBox();
     bool isGlobalContext() { return !toObjectBox(); }
 
     ThisBinding thisBinding()          const { return thisBinding_; }
 
     bool allowNewTarget()              const { return allowNewTarget_; }
     bool allowSuperProperty()          const { return allowSuperProperty_; }
+    bool allowSuperCall()              const { return allowSuperCall_; }
     bool inWith()                      const { return inWith_; }
     bool needsThisTDZChecks()          const { return needsThisTDZChecks_; }
 
     void markSuperScopeNeedsHomeObject();
 
     bool hasExplicitUseStrict()        const { return anyCxFlags.hasExplicitUseStrict; }
     bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
     bool hasDebuggerStatement()        const { return anyCxFlags.hasDebuggerStatement; }
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -872,23 +872,25 @@ TokenStream::getDirective(bool isMultili
             getChar();
             // Debugging directives can occur in both single- and multi-line
             // comments. If we're currently inside a multi-line comment, we also
             // need to recognize multi-line comment terminators.
             if (isMultiline && c == '*' && peekChar() == '/') {
                 ungetChar('*');
                 break;
             }
-            tokenbuf.append(c);
+            if (!tokenbuf.append(c))
+                return false;
         }
 
-        if (tokenbuf.empty())
+        if (tokenbuf.empty()) {
             // The directive's URL was missing, but this is not quite an
             // exception that we should stop and drop everything for.
             return true;
+        }
 
         size_t length = tokenbuf.length();
 
         *destination = cx->make_pod_array<char16_t>(length + 1);
         if (!*destination)
             return false;
 
         PodCopy(destination->get(), tokenbuf.begin(), length);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/gating.js
@@ -0,0 +1,33 @@
+// Check gating of shared memory features in asm.js (bug 1171540,
+// bug 1231624).
+//
+// In asm.js, importing any atomic is a signal that shared memory is
+// being used.  If an atomic is imported, and if shared memory is
+// disabled in the build or in the run then a type error should be
+// signaled for the module at the end of the declaration section and
+// the module should not be an asm.js module.
+
+if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
+    quit(0);
+
+// This code is not run, we only care whether it compiles as asm.js.
+
+function module_a(stdlib, foreign, heap) {
+    "use asm";
+
+    var i32a = new stdlib.Int32Array(heap);
+    var ld = stdlib.Atomics.load;
+
+    // There should be a type error around this line if shared memory
+    // is not enabled.
+
+    function do_load() {
+	var v = 0;
+	v = ld(i32a, 0)|0;	// It's not actually necessary to use the atomic op
+	return v|0;
+    }
+
+    return { load: do_load };
+}
+
+assertEq(isAsmJSModule(module_a), !!this.SharedArrayBuffer);
--- a/js/src/jit-test/tests/basic/bug984766.js
+++ b/js/src/jit-test/tests/basic/bug984766.js
@@ -1,15 +1,17 @@
 
 for (var i = 0; i < 10; i++) {
   x = new ArrayBuffer(4)
   x.f = (function() {})
   new Uint16Array(x).set(JSON.parse)
   gcslice()
 }
 
+if (!this.SharedArrayBuffer)
+  quit(0);
 
 for (var i = 0; i < 10; i++) {
   x = new SharedArrayBuffer(4)
   x.f = (function() {})
   new Uint16Array(x).set(JSON.parse)
   gcslice()
 }
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -3583,49 +3583,71 @@ BaselineCompiler::emit_JSOP_RETRVAL()
         masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
         masm.bind(&done);
     }
 
     return emitReturn();
 }
 
-typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue,
-                       MutableHandleValue);
+typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, MutableHandleValue);
 static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation);
 
 bool
 BaselineCompiler::emit_JSOP_TOID()
 {
     // Load index in R0, but keep values on the stack for the decompiler.
     frame.syncStack(0);
     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
 
     // No-op if index is int32.
     Label done;
     masm.branchTestInt32(Assembler::Equal, R0, &done);
 
     prepareVMCall();
 
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
-
     pushArg(R0);
-    pushArg(R1);
     pushArg(ImmPtr(pc));
     pushArg(ImmGCPtr(script));
 
     if (!callVM(ToIdInfo))
         return false;
 
     masm.bind(&done);
     frame.pop(); // Pop index.
     frame.push(R0);
     return true;
 }
 
+typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
+static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible);
+
+bool
+BaselineCompiler::emit_JSOP_CHECKOBJCOERCIBLE()
+{
+    frame.syncStack(0);
+    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+
+    Label fail, done;
+
+    masm.branchTestUndefined(Assembler::Equal, R0, &fail);
+    masm.branchTestNull(Assembler::NotEqual, R0, &done);
+
+    masm.bind(&fail);
+    prepareVMCall();
+
+    pushArg(R0);
+
+    if (!callVM(ThrowObjectCoercibleInfo))
+        return false;
+
+    masm.bind(&done);
+    return true;
+}
+
 typedef JSString* (*ToStringFn)(JSContext*, HandleValue);
 static const VMFunction ToStringInfo = FunctionInfo<ToStringFn>(ToStringSlow);
 
 bool
 BaselineCompiler::emit_JSOP_TOSTRING()
 {
     // Keep top stack value in R0.
     frame.popRegsAndSync(1);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -214,17 +214,18 @@ namespace jit {
     _(JSOP_SUPERCALL)          \
     _(JSOP_SPREADSUPERCALL)    \
     _(JSOP_THROWSETCONST)      \
     _(JSOP_THROWSETALIASEDCONST) \
     _(JSOP_INITHIDDENPROP_GETTER) \
     _(JSOP_INITHIDDENPROP_SETTER) \
     _(JSOP_INITHIDDENELEM)     \
     _(JSOP_INITHIDDENELEM_GETTER) \
-    _(JSOP_INITHIDDENELEM_SETTER)
+    _(JSOP_INITHIDDENELEM_SETTER) \
+    _(JSOP_CHECKOBJCOERCIBLE)
 
 class BaselineCompiler : public BaselineCompilerSpecific
 {
     FixedList<Label>            labels_;
     NonAssertingLabel           return_;
     NonAssertingLabel           postBarrierSlot_;
 
     // Native code offset right before the scope chain is initialized.
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -2764,16 +2764,21 @@ DoSetElemFallback(JSContext* cx, Baselin
     } else if (op == JSOP_INITELEM_INC) {
         if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
             return false;
     } else {
         if (!SetObjectElement(cx, obj, index, rhs, JSOp(*pc) == JSOP_STRICTSETELEM, script, pc))
             return false;
     }
 
+    // Don't try to attach stubs that wish to be hidden. We don't know how to
+    // have different enumerability in the stubs for the moment.
+    if (op == JSOP_INITHIDDENELEM)
+        return true;
+
     // Overwrite the object on the stack (pushed for the decompiler) with the rhs.
     MOZ_ASSERT(stack[2] == objv);
     stack[2] = rhs;
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -9056,32 +9056,31 @@ CodeGenerator::visitOutOfLineTypeOfV(Out
     masm.passABIArg(output);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::TypeOfObjectOperation));
     masm.storeCallResult(output);
     restoreVolatile(output);
 
     masm.jump(ool->rejoin());
 }
 
-typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue,
+typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
                        MutableHandleValue);
 static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation);
 
 void
 CodeGenerator::visitToIdV(LToIdV* lir)
 {
     Label notInt32;
     FloatRegister temp = ToFloatRegister(lir->tempFloat());
     const ValueOperand out = ToOutValue(lir);
     ValueOperand index = ToValue(lir, LToIdV::Index);
 
     OutOfLineCode* ool = oolCallVM(ToIdInfo, lir,
                                    ArgList(ImmGCPtr(current->mir()->info().script()),
                                            ImmPtr(lir->mir()->resumePoint()->pc()),
-                                           ToValue(lir, LToIdV::Object),
                                            ToValue(lir, LToIdV::Index)),
                                    StoreValueTo(out));
 
     Register tag = masm.splitTagForTest(index);
 
     masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
     masm.moveValue(index, out);
     masm.jump(ool->rejoin());
@@ -10364,16 +10363,32 @@ CodeGenerator::visitCheckReturn(LCheckRe
     Label bail, noChecks;
     masm.branchTestObject(Assembler::Equal, returnValue, &noChecks);
     masm.branchTestUndefined(Assembler::NotEqual, returnValue, &bail);
     masm.branchTestMagicValue(Assembler::Equal, thisValue, JS_UNINITIALIZED_LEXICAL, &bail);
     bailoutFrom(&bail, ins->snapshot());
     masm.bind(&noChecks);
 }
 
+typedef bool (*ThrowObjCoercibleFn)(JSContext*, HandleValue);
+static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo<ThrowObjCoercibleFn>(ThrowObjectCoercible);
+
+void
+CodeGenerator::visitCheckObjCoercible(LCheckObjCoercible* ins)
+{
+    ValueOperand checkValue = ToValue(ins, LCheckObjCoercible::CheckValue);
+    Label fail, done;
+    masm.branchTestNull(Assembler::Equal, checkValue, &fail);
+    masm.branchTestUndefined(Assembler::NotEqual, checkValue, &done);
+    masm.bind(&fail);
+    pushArg(checkValue);
+    callVM(ThrowObjectCoercibleInfo, ins);
+    masm.bind(&done);
+}
+
 void
 CodeGenerator::visitRandom(LRandom* ins)
 {
     using mozilla::non_crypto::XorShift128PlusRNG;
 
     FloatRegister output = ToFloatRegister(ins->output());
     Register tempReg = ToRegister(ins->temp0());
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -340,16 +340,17 @@ class CodeGenerator : public CodeGenerat
     void visitAsmJSVoidReturn(LAsmJSVoidReturn* ret);
     void visitLexicalCheck(LLexicalCheck* ins);
     void visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins);
     void visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins);
     void visitDebugger(LDebugger* ins);
     void visitNewTarget(LNewTarget* ins);
     void visitArrowNewTarget(LArrowNewTarget* ins);
     void visitCheckReturn(LCheckReturn* ins);
+    void visitCheckObjCoercible(LCheckObjCoercible* ins);
 
     void visitCheckOverRecursed(LCheckOverRecursed* lir);
     void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
 
     void visitInterruptCheckImplicit(LInterruptCheckImplicit* ins);
     void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
 
     void visitUnboxFloatingPoint(LUnboxFloatingPoint* lir);
--- a/js/src/jit/ExecutableAllocator.h
+++ b/js/src/jit/ExecutableAllocator.h
@@ -349,19 +349,20 @@ class ExecutableAllocator
 
         // Create a new allocator
         ExecutablePool* pool = createPool(largeAllocSize);
         if (!pool)
             return nullptr;
         // At this point, local |pool| is the owner.
 
         if (m_smallPools.length() < maxSmallPools) {
-            // We haven't hit the maximum number of live pools;  add the new pool.
-            m_smallPools.append(pool);
-            pool->addRef();
+            // We haven't hit the maximum number of live pools; add the new pool.
+            // If append() OOMs, we just return an unshared allocator.
+            if (m_smallPools.append(pool))
+                pool->addRef();
         } else {
             // Find the pool with the least space.
             int iMin = 0;
             for (size_t i = 1; i < m_smallPools.length(); i++) {
                 if (m_smallPools[i]->available() <
                     m_smallPools[iMin]->available())
                 {
                     iMin = i;
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -129,17 +129,19 @@ class LinearSum
         constant_(0)
     {
     }
 
     LinearSum(const LinearSum& other)
       : terms_(other.terms_.allocPolicy()),
         constant_(other.constant_)
     {
-        terms_.appendAll(other.terms_);
+        AutoEnterOOMUnsafeRegion oomUnsafe;
+        if (!terms_.appendAll(other.terms_))
+            oomUnsafe.crash("LinearSum::LinearSum");
     }
 
     // These return false on an integer overflow, and afterwards the sum must
     // not be used.
     bool multiply(int32_t scale);
     bool add(const LinearSum& other, int32_t scale = 1);
     bool add(SimpleLinearSum other, int32_t scale = 1);
     bool add(MDefinition* term, int32_t scale);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -610,17 +610,18 @@ IonBuilder::analyzeNewLoopTypes(MBasicBl
 
             // Update the most recent header for this loop encountered, in case
             // new types flow to the phis and the loop is processed at least
             // three times.
             loopHeaders_[i].header = entry;
             return true;
         }
     }
-    loopHeaders_.append(LoopHeader(start, entry));
+    if (!loopHeaders_.append(LoopHeader(start, entry)))
+        return false;
 
     jsbytecode* last = nullptr;
     jsbytecode* earlier = nullptr;
     for (jsbytecode* pc = start; pc != end; earlier = last, last = pc, pc += GetBytecodeLength(pc)) {
         uint32_t slot;
         if (*pc == JSOP_SETLOCAL)
             slot = info().localSlot(GET_LOCALNO(pc));
         else if (*pc == JSOP_SETARG)
@@ -2093,16 +2094,19 @@ IonBuilder::inspectOpcode(JSOp op)
             return pushConstant(UndefinedValue());
 
         // Just fall through to the unsupported bytecode case.
         break;
 
       case JSOP_NEWTARGET:
         return jsop_newtarget();
 
+      case JSOP_CHECKOBJCOERCIBLE:
+        return jsop_checkobjcoercible();
+
 #ifdef DEBUG
       case JSOP_PUSHBLOCKSCOPE:
       case JSOP_FRESHENBLOCKSCOPE:
       case JSOP_POPBLOCKSCOPE:
         // These opcodes are currently unhandled by Ion, but in principle
         // there's no reason they couldn't be.  Whenever this happens, OSR will
         // have to consider that JSOP_FRESHENBLOCK mutates the scope chain --
         // right now it caches the scope chain in MBasicBlock::scopeChain().
@@ -3414,18 +3418,22 @@ IonBuilder::tableSwitch(JSOp op, jssrcno
 
     // Create MIR instruction
     MTableSwitch* tableswitch = MTableSwitch::New(alloc(), ins, low, high);
 
     // Create default case
     MBasicBlock* defaultcase = newBlock(current, defaultpc);
     if (!defaultcase)
         return ControlStatus_Error;
-    tableswitch->addDefault(defaultcase);
-    tableswitch->addBlock(defaultcase);
+
+    if (!tableswitch->addDefault(defaultcase))
+        return ControlStatus_Error;
+
+    if (!tableswitch->addBlock(defaultcase))
+        return ControlStatus_Error;
 
     // Create cases
     jsbytecode* casepc = nullptr;
     for (int i = 0; i < high-low+1; i++) {
         casepc = pc + GET_JUMP_OFFSET(pc2);
 
         MOZ_ASSERT(casepc >= pc && casepc <= exitpc);
         MBasicBlock* caseblock;
@@ -3443,24 +3451,32 @@ IonBuilder::tableSwitch(JSOp op, jssrcno
                 return ControlStatus_Error;
         } else {
             // If this is an actual case (not filled gap),
             // add this block to the list that still needs to get processed.
             caseblock = newBlock(current, casepc);
             if (!caseblock)
                 return ControlStatus_Error;
 
-            tableswitch->addBlock(caseblock);
+            if (!tableswitch->addBlock(caseblock))
+                return ControlStatus_Error;
+
             // Add constant to indicate which case this is for use by
             // processNextTableSwitchCase.
             MConstant* constant = MConstant::New(alloc(), Int32Value(i + low));
             caseblock->add(constant);
         }
 
-        tableswitch->addCase(tableswitch->addSuccessor(caseblock));
+        size_t caseIndex;
+        if (!tableswitch->addSuccessor(caseblock, &caseIndex))
+            return ControlStatus_Error;
+
+        if (!tableswitch->addCase(caseIndex))
+            return ControlStatus_Error;
+
         pc2 += JUMP_OFFSET_LEN;
     }
 
     // Move defaultcase to the end, to maintain RPO.
     graph().moveBlockToEnd(defaultcase);
 
     MOZ_ASSERT(tableswitch->numCases() == (uint32_t)(high - low + 1));
     MOZ_ASSERT(tableswitch->numSuccessors() > 0);
@@ -5384,17 +5400,17 @@ IonBuilder::selectInliningTargets(const 
                 if (totalSize > optimizationInfo().inlineMaxBytecodePerCallSite(offThread))
                     inlineable = false;
             }
         } else {
             // Non-function targets are not supported by polymorphic inlining.
             inlineable = false;
         }
 
-        choiceSet.append(inlineable);
+        choiceSet.infallibleAppend(inlineable);
         if (inlineable)
             *numInlineable += 1;
     }
 
     // If optimization tracking is turned on and one of the inlineable targets
     // is a native, track the type info of the call. Most native inlinings
     // depend on the types of the arguments and the return value.
     if (isOptimizationTrackingEnabled()) {
@@ -5876,17 +5892,18 @@ IonBuilder::inlineCalls(CallInfo& callIn
         }
 
         // inlineSingleCall() changed |current| to the inline return block.
         MBasicBlock* inlineReturnBlock = current;
         setCurrent(dispatchBlock);
 
         // Connect the inline path to the returnBlock.
         ObjectGroup* funcGroup = target->isSingleton() ? nullptr : target->group();
-        dispatch->addCase(target, funcGroup, inlineBlock);
+        if (!dispatch->addCase(target, funcGroup, inlineBlock))
+            return false;
 
         MDefinition* retVal = inlineReturnBlock->peek(-1);
         retPhi->addInput(retVal);
         inlineReturnBlock->end(MGoto::New(alloc(), returnBlock));
         if (!returnBlock->addPredecessorWithoutPhis(inlineReturnBlock))
             return false;
     }
 
@@ -10304,16 +10321,41 @@ IonBuilder::jsop_rest()
     // elements added.
     MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, index);
     current->add(initLength);
 
     current->push(array);
     return true;
 }
 
+bool
+IonBuilder::jsop_checkobjcoercible()
+{
+    MDefinition* toCheck = current->peek(-1);
+
+    if (!toCheck->mightBeType(MIRType_Undefined) &&
+        !toCheck->mightBeType(MIRType_Null))
+    {
+        toCheck->setImplicitlyUsedUnchecked();
+        return true;
+    }
+
+    MOZ_ASSERT(toCheck->type() == MIRType_Value ||
+               toCheck->type() == MIRType_Null  ||
+               toCheck->type() == MIRType_Undefined);
+
+    // If we want to squeeze more perf here, we can throw without checking,
+    // if IsNullOrUndefined(toCheck->type()). Since this is a failure case,
+    // it should be OK.
+    MCheckObjCoercible* check = MCheckObjCoercible::New(alloc(), current->pop());
+    current->add(check);
+    current->push(check);
+    return resumeAfter(check);
+}
+
 uint32_t
 IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed)
 {
     if (!types || types->unknownObject()) {
         trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
         return UINT32_MAX;
     }
 
@@ -13016,17 +13058,17 @@ IonBuilder::jsop_typeof()
 bool
 IonBuilder::jsop_toid()
 {
     // No-op if the index is an integer.
     if (current->peek(-1)->type() == MIRType_Int32)
         return true;
 
     MDefinition* index = current->pop();
-    MToId* ins = MToId::New(alloc(), current->peek(-1), index);
+    MToId* ins = MToId::New(alloc(), index);
 
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -733,16 +733,17 @@ class IonBuilder
     bool jsop_iterend();
     bool jsop_in();
     bool jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType);
     bool jsop_instanceof();
     bool jsop_getaliasedvar(ScopeCoordinate sc);
     bool jsop_setaliasedvar(ScopeCoordinate sc);
     bool jsop_debugger();
     bool jsop_newtarget();
+    bool jsop_checkobjcoercible();
 
     /* Inlining. */
 
     enum InliningStatus
     {
         InliningStatus_Error,
         InliningStatus_NotInlined,
         InliningStatus_WarmUpCountTooLow,
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1092,18 +1092,17 @@ LIRGenerator::visitTypeOf(MTypeOf* ins)
     useBox(lir, LTypeOfV::Input, opd);
     define(lir, ins);
 }
 
 void
 LIRGenerator::visitToId(MToId* ins)
 {
     LToIdV* lir = new(alloc()) LToIdV(tempDouble());
-    useBox(lir, LToIdV::Object, ins->lhs());
-    useBox(lir, LToIdV::Index, ins->rhs());
+    useBox(lir, LToIdV::Index, ins->input());
     defineBox(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitBitNot(MBitNot* ins)
 {
     MDefinition* input = ins->getOperand(0);
@@ -4326,16 +4325,29 @@ LIRGenerator::visitCheckReturn(MCheckRet
     LCheckReturn* lir = new(alloc()) LCheckReturn();
     useBoxAtStart(lir, LCheckReturn::ReturnValue, retVal);
     useBoxAtStart(lir, LCheckReturn::ThisValue, thisVal);
     assignSnapshot(lir, Bailout_BadDerivedConstructorReturn);
     add(lir, ins);
     redefine(ins, retVal);
 }
 
+void
+LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins)
+{
+    MDefinition* checkVal = ins->checkValue();
+    MOZ_ASSERT(checkVal->type() == MIRType_Value);
+
+    LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible();
+    useBoxAtStart(lir, LCheckObjCoercible::CheckValue, checkVal);
+    redefine(ins, checkVal);
+    add(lir, ins);
+    assignSafepoint(lir, ins);
+}
+
 static void
 SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
 {
     Fprinter& out = JitSpewPrinter();
     out.printf("Current resume point %p details:\n", (void*)resumePoint);
     out.printf("    frame count: %u\n", resumePoint->frameCount());
 
     if (ins) {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -305,14 +305,15 @@ class LIRGenerator : public LIRGenerator
     void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins);
     void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins);
     void visitDebugger(MDebugger* ins);
     void visitNewTarget(MNewTarget* ins);
     void visitArrowNewTarget(MArrowNewTarget* ins);
     void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
     void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
     void visitCheckReturn(MCheckReturn* ins);
+    void visitCheckObjCoercible(MCheckObjCoercible* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Lowering_h */
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2531,21 +2531,21 @@ class MTableSwitch final
   public:
     INSTRUCTION_HEADER(TableSwitch)
     static MTableSwitch* New(TempAllocator& alloc, MDefinition* ins, int32_t low, int32_t high);
 
     size_t numSuccessors() const override {
         return successors_.length();
     }
 
-    size_t addSuccessor(MBasicBlock* successor) {
+    bool addSuccessor(MBasicBlock* successor, size_t* index) {
         MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2));
         MOZ_ASSERT(!successors_.empty());
-        successors_.append(successor);
-        return successors_.length() - 1;
+        *index = successors_.length();
+        return successors_.append(successor);
     }
 
     MBasicBlock* getSuccessor(size_t i) const override {
         MOZ_ASSERT(i < numSuccessors());
         return successors_[i];
     }
 
     void replaceSuccessor(size_t i, MBasicBlock* successor) override {
@@ -2576,33 +2576,34 @@ class MTableSwitch final
     MBasicBlock* getCase(size_t i) const {
         return getSuccessor(cases_[i]);
     }
 
     size_t numCases() const {
         return high() - low() + 1;
     }
 
-    size_t addDefault(MBasicBlock* block) {
+    bool addDefault(MBasicBlock* block, size_t* index = nullptr) {
         MOZ_ASSERT(successors_.empty());
-        successors_.append(block);
-        return 0;
-    }
-
-    void addCase(size_t successorIndex) {
-        cases_.append(successorIndex);
+        if (index)
+            *index = 0;
+        return successors_.append(block);
+    }
+
+    bool addCase(size_t successorIndex) {
+        return cases_.append(successorIndex);
     }
 
     MBasicBlock* getBlock(size_t i) const {
         MOZ_ASSERT(i < numBlocks());
         return blocks_[i];
     }
 
-    void addBlock(MBasicBlock* block) {
-        blocks_.append(block);
+    bool addBlock(MBasicBlock* block) {
+        return blocks_.append(block);
     }
 
     MDefinition* getOperand(size_t index) const override {
         MOZ_ASSERT(index == 0);
         return operand_.producer();
     }
 
     size_t numOperands() const override {
@@ -5366,30 +5367,30 @@ class MTypeOf
 
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return true;
     }
 };
 
 class MToId
-  : public MBinaryInstruction,
+  : public MUnaryInstruction,
     public BoxInputsPolicy::Data
 {
-    MToId(MDefinition* object, MDefinition* index)
-      : MBinaryInstruction(object, index)
+    explicit MToId(MDefinition* index)
+      : MUnaryInstruction(index)
     {
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(ToId)
 
-    static MToId* New(TempAllocator& alloc, MDefinition* object, MDefinition* index) {
-        return new(alloc) MToId(object, index);
+    static MToId* New(TempAllocator& alloc, MDefinition* index) {
+        return new(alloc) MToId(index);
     }
 };
 
 class MBinaryBitwiseInstruction
   : public MBinaryInstruction,
     public BitwisePolicy::Data
 {
   protected:
@@ -10641,18 +10642,18 @@ class MDispatchInstruction
     MBasicBlock* getSuccessor(size_t i) const final override {
         MOZ_ASSERT(i < numSuccessors());
         if (i == map_.length())
             return fallback_;
         return map_[i].block;
     }
 
   public:
-    void addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
-        map_.append(Entry(func, funcGroup, block));
+    bool addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
+        return map_.append(Entry(func, funcGroup, block));
     }
     uint32_t numCases() const {
         return map_.length();
     }
     JSFunction* getCase(uint32_t i) const {
         return map_[i].func;
     }
     ObjectGroup* getCaseObjectGroup(uint32_t i) const {
@@ -13360,16 +13361,39 @@ class MDebugger : public MNullaryInstruc
   public:
     INSTRUCTION_HEADER(Debugger)
 
     static MDebugger* New(TempAllocator& alloc) {
         return new(alloc) MDebugger();
     }
 };
 
+class MCheckObjCoercible
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MCheckObjCoercible(MDefinition* toCheck)
+      : MUnaryInstruction(toCheck)
+    {
+        setGuard();
+        setResultType(MIRType_Value);
+        setResultTypeSet(toCheck->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(CheckObjCoercible)
+    static MCheckObjCoercible* New(TempAllocator& alloc, MDefinition* toCheck) {
+        return new(alloc) MCheckObjCoercible(toCheck);
+    }
+
+    MDefinition* checkValue() {
+        return getOperand(0);
+    }
+};
+
 class MAsmJSNeg
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
     MAsmJSNeg(MDefinition* op, MIRType type)
       : MUnaryInstruction(op)
     {
         setResultType(type);
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -274,17 +274,18 @@ namespace jit {
     _(AsmJSAtomicBinopHeap)                                                 \
     _(UnknownValue)                                                         \
     _(LexicalCheck)                                                         \
     _(ThrowRuntimeLexicalError)                                             \
     _(GlobalNameConflictsCheck)                                             \
     _(Debugger)                                                             \
     _(NewTarget)                                                            \
     _(ArrowNewTarget)                                                       \
-    _(CheckReturn)
+    _(CheckReturn)                                                          \
+    _(CheckObjCoercible)
 
 // Forward declarations of MIR types.
 #define FORWARD_DECLARE(op) class M##op;
  MIR_OPCODE_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
 class MDefinitionVisitor // interface i.e. pure abstract class
 {
--- a/js/src/jit/RegisterAllocator.h
+++ b/js/src/jit/RegisterAllocator.h
@@ -60,28 +60,34 @@ struct AllocationIntegrityState
         Vector<LDefinition, 0, SystemAllocPolicy> temps;
         Vector<LDefinition, 1, SystemAllocPolicy> outputs;
 
         InstructionInfo()
         { }
 
         InstructionInfo(const InstructionInfo& o)
         {
-            inputs.appendAll(o.inputs);
-            temps.appendAll(o.temps);
-            outputs.appendAll(o.outputs);
+            AutoEnterOOMUnsafeRegion oomUnsafe;
+            if (!inputs.appendAll(o.inputs) ||
+                !temps.appendAll(o.temps) ||
+                !outputs.appendAll(o.outputs))
+            {
+                oomUnsafe.crash("InstructionInfo::InstructionInfo");
+            }
         }
     };
     Vector<InstructionInfo, 0, SystemAllocPolicy> instructions;
 
     struct BlockInfo {
         Vector<InstructionInfo, 5, SystemAllocPolicy> phis;
         BlockInfo() {}
         BlockInfo(const BlockInfo& o) {
-            phis.appendAll(o.phis);
+            AutoEnterOOMUnsafeRegion oomUnsafe;
+            if (!phis.appendAll(o.phis))
+                oomUnsafe.crash("BlockInfo::BlockInfo");
         }
     };
     Vector<BlockInfo, 0, SystemAllocPolicy> blocks;
 
     Vector<LDefinition*, 20, SystemAllocPolicy> virtualRegisters;
 
     // Describes a correspondence that should hold at the end of a block.
     // The value which was written to vreg in the original LIR should be
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1306,16 +1306,25 @@ ThrowBadDerivedReturn(JSContext* cx, Han
 }
 
 bool
 BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
 {
     return ThrowUninitializedThis(cx, frame);
 }
 
+
+bool
+ThrowObjectCoercible(JSContext* cx, HandleValue v)
+{
+    MOZ_ASSERT(v.isUndefined() || v.isNull());
+    MOZ_ALWAYS_FALSE(ToObjectSlow(cx, v, false));
+    return false;
+}
+
 bool
 BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
 {
     return GetFunctionThis(cx, frame, res);
 }
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -733,14 +733,16 @@ IonMarkFunction(MIRType type)
 }
 
 bool ObjectIsCallable(JSObject* obj);
 
 bool ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber);
 bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
 bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
 
+bool ThrowObjectCoercible(JSContext* cx, HandleValue v);
+
 bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1271,28 +1271,27 @@ class LTypeOfV : public LInstructionHelp
         return getTemp(0);
     }
 
     MTypeOf* mir() const {
         return mir_->toTypeOf();
     }
 };
 
-class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1>
+class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
 {
   public:
     LIR_HEADER(ToIdV)
 
     explicit LToIdV(const LDefinition& temp)
     {
         setTemp(0, temp);
     }
 
-    static const size_t Object = 0;
-    static const size_t Index = BOX_PIECES;
+    static const size_t Index = 0;
 
     MToId* mir() const {
         return mir_->toToId();
     }
 
     const LDefinition* tempFloat() {
         return getTemp(0);
     }
@@ -7392,12 +7391,20 @@ class LCheckReturn : public LCallInstruc
 {
   public:
     static const size_t ReturnValue = 0;
     static const size_t ThisValue = BOX_PIECES;
 
     LIR_HEADER(CheckReturn)
 };
 
+class LCheckObjCoercible : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+  public:
+    static const size_t CheckValue = 0;
+
+    LIR_HEADER(CheckObjCoercible)
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_LIR_shared_h */
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -362,11 +362,12 @@
     _(AssertResultV)                \
     _(AssertResultT)                \
     _(LexicalCheck)                 \
     _(ThrowRuntimeLexicalError)     \
     _(GlobalNameConflictsCheck)     \
     _(Debugger)                     \
     _(NewTarget)                    \
     _(ArrowNewTarget)               \
-    _(CheckReturn)
+    _(CheckReturn)                  \
+    _(CheckObjCoercible)
 
 #endif /* jit_shared_LOpcodes_shared_h */
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -100,17 +100,16 @@ MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA,      2
 MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value")
 MSG_DEF(JSMSG_CANT_SET_PROTO,          0, JSEXN_TYPEERR, "can't set prototype of this object")
 MSG_DEF(JSMSG_CANT_SET_PROTO_OF,       1, JSEXN_TYPEERR, "can't set prototype of {0}")
 MSG_DEF(JSMSG_CANT_SET_PROTO_CYCLE,    0, JSEXN_TYPEERR, "can't set prototype: it would cause a prototype chain cycle")
 MSG_DEF(JSMSG_INVALID_ARG_TYPE,        3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
 MSG_DEF(JSMSG_TERMINATED,              1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
 MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL,     1, JSEXN_TYPEERR, "{0}.prototype is not an object or null")
 MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
-MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS,  1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors")
 MSG_DEF(JSMSG_UNINITIALIZED_THIS,      1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor")
 MSG_DEF(JSMSG_BAD_DERIVED_RETURN,      1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")
 
 // JSON
 MSG_DEF(JSMSG_JSON_BAD_PARSE,          3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
 MSG_DEF(JSMSG_JSON_CYCLIC_VALUE,       1, JSEXN_TYPEERR, "cyclic {0} value")
 
 // Runtime errors
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -8,17 +8,16 @@
  * JS math package.
  */
 
 #include "jsmath.h"
 
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/unused.h"
 
 #include <algorithm>  // for std::max
 #include <fcntl.h>
 
 #ifdef XP_UNIX
 # include <unistd.h>
 #endif
 
@@ -797,20 +796,25 @@ GenerateSeed(uint64_t* seedBuffer, size_
     }
 
 #elif defined(XP_UNIX)
     int fd = open("/dev/urandom", O_RDONLY);
     MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom?!");
     if (fd >= 0) {
         ssize_t size = length * sizeof(seedBuffer[0]);
         ssize_t nread = read(fd, (char *) seedBuffer, size);
+        close(fd);
         MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
-        mozilla::Unused << nread;
-        close(fd);
+        if (nread == size)
+            return;
     }
+
+    // Use PRMJ_Now() if we couldn't read from /dev/urandom.
+    for (size_t i = 0; i < length; i++)
+        seedBuffer[i] = PRMJ_Now();
 #else
 # error "Platform needs to implement random_generateSeed()"
 #endif
 }
 
 void
 js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed)
 {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2226,21 +2226,22 @@ js::LookupNameUnqualified(JSContext* cx,
         if (!LookupProperty(cx, scope, id, &pobj, &shape))
             return false;
         if (shape)
             break;
     }
 
     // See note above RuntimeLexicalErrorObject.
     if (pobj == scope) {
-        if (IsUninitializedLexicalSlot(scope, shape)) {
+        if (name != cx->names().dotThis && IsUninitializedLexicalSlot(scope, shape)) {
             scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_UNINITIALIZED_LEXICAL);
             if (!scope)
                 return false;
         } else if (scope->is<ScopeObject>() && !scope->is<DeclEnvObject>() && !shape->writable()) {
+            MOZ_ASSERT(name != cx->names().dotThis);
             scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_BAD_CONST_ASSIGN);
             if (!scope)
                 return false;
         }
     }
 
     objp.set(scope);
     return true;
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalBinding.js
@@ -0,0 +1,19 @@
+// Make sure it doesn't matter when we make the arrow function
+var test = `
+
+new class extends class { } {
+    constructor() {
+        let arrow = () => this;
+        assertThrowsInstanceOf(arrow, ReferenceError);
+        super();
+        assertEq(arrow(), this);
+    }
+}();
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalClosed.js
@@ -0,0 +1,18 @@
+var test = `
+
+new class extends class { } {
+    constructor() {
+        let a1 = () => this;
+        let a2 = (() => super());
+        assertThrowsInstanceOf(a1, ReferenceError);
+        assertEq(a2(), a1());
+    }
+}();
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalEscape.js
@@ -0,0 +1,20 @@
+var test = `
+
+let arrow;
+
+class foo extends class { } {
+    constructor() {
+        arrow = () => this;
+        super();
+    }
+}
+
+assertEq(new foo(), arrow());
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalEscapeUninitialized.js
@@ -0,0 +1,45 @@
+var test = `
+
+let superArrow;
+let thisArrow;
+
+let thisStash;
+
+class base {
+    constructor() {
+        // We run this constructor twice as part of the double init check
+        if (!thisStash)
+            thisStash = {prop:45};
+        return thisStash;
+    }
+}
+
+class foo extends base {
+    constructor() {
+        superArrow = (()=>super());
+        thisArrow = ()=>this;
+    }
+}
+
+// Populate the arrow function saves. Since we never invoke super(), we throw
+assertThrowsInstanceOf(()=>new foo(), ReferenceError);
+
+// No |this| binding in the closure, yet
+assertThrowsInstanceOf(thisArrow, ReferenceError);
+
+// call super()
+superArrow();
+
+// Can't call it twice
+assertThrowsInstanceOf(superArrow, ReferenceError);
+
+// Oh look, |this| is populated, now.
+assertEq(thisArrow(), thisStash);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalGetThis.js
@@ -0,0 +1,17 @@
+var test = `
+
+new class extends class { } {
+    constructor() {
+        super();
+        assertEq(this, (()=>this)());
+        assertEq(this, eval("this"));
+    }
+}();
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalNestedSuperCall.js
@@ -0,0 +1,41 @@
+var test = `
+
+new class extends class { } {
+    constructor() {
+        (()=>eval("super()"))();
+        assertEq(this, eval("this"));
+        assertEq(this, (()=>this)());
+    }
+}();
+
+new class extends class { } {
+    constructor() {
+        (()=>(()=>super())())();
+        assertEq(this, eval("this"));
+        assertEq(this, (()=>this)());
+    }
+}();
+
+new class extends class { } {
+    constructor() {
+        eval("(()=>super())()");
+        assertEq(this, eval("this"));
+        assertEq(this, (()=>this)());
+    }
+}();
+
+new class extends class { } {
+    constructor() {
+        eval("eval('super()')");
+        assertEq(this, eval("this"));
+        assertEq(this, (()=>this)());
+    }
+}();
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/derivedConstructorArrowEvalSuperCall.js
@@ -0,0 +1,25 @@
+var test = `
+
+new class extends class { } {
+    constructor() {
+        assertEq(eval("super(); this"), this);
+        assertEq(this, eval("this"));
+        assertEq(this, (()=>this)());
+    }
+}();
+
+new class extends class { } {
+    constructor() {
+        (()=>super())();
+        assertEq(this, eval("this"));
+        assertEq(this, (()=>this)());
+    }
+}();
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
deleted file mode 100644
--- a/js/src/tests/ecma_6/Class/derivedConstructorDisabled.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell)
-
-var test = `
-
-class base {
-    constructor() {
-        eval('');
-        (()=>0)();
-    }
-}
-
-class derived extends base {
-    constructor() {
-        eval('');
-    }
-}
-
-// Make sure eval and arrows are still valid in non-derived constructors.
-new base();
-
-
-// Eval throws in derived class constructors, in both class expressions and
-// statements.
-assertThrowsInstanceOf((() => new derived()), InternalError);
-assertThrowsInstanceOf((() => new class extends base { constructor() { eval('') } }()), InternalError);
-
-var g = newGlobal();
-var dbg = Debugger(g);
-dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); };
-
-g.eval("new class foo extends null { constructor() { debugger; return {}; } }()");
-`;
-
-if (classesEnabled())
-    eval(test);
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superPropIncDecElem.js
@@ -0,0 +1,31 @@
+var test = `
+
+// #1
+function base() { }
+
+base.prototype = {
+    test() {
+        --super[1];
+    }
+}
+
+var d = new base();
+d.test();
+
+// #2
+class test2 {
+    test() {
+        super[1]++;
+    }
+}
+
+var d = new test2();
+d.test()
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-same-name.js
@@ -0,0 +1,7 @@
+{
+  function f() { return "inner"; }
+}
+
+function f() { return "outer"; }
+
+reportCompare(f(), "inner");
--- a/js/src/tests/js1_8_5/reflect-parse/classes.js
+++ b/js/src/tests/js1_8_5/reflect-parse/classes.js
@@ -127,19 +127,16 @@ function testClasses() {
     assertClass("class NAME { constructor() { }; static [\"prototype\"]() { } }",
                 [ctorPlaceholder, emptyCPNMethod("prototype", true)]);
 
     /* Constructor */
     // Allow default constructors
     assertClass("class NAME { }", []);
     assertClass("class NAME extends null { }", [], lit(null));
 
-    // For now, disallow arrow functions in derived class constructors
-    assertClassError("class NAME extends null { constructor() { (() => 0); }", InternalError);
-
     // Derived class constructor must have curly brackets
     assertClassError("class NAME extends null {  constructor() 1 }", SyntaxError);
 
     // It is an error to have two methods named constructor, but not other
     // names, regardless if one is an accessor or a generator or static.
     assertClassError("class NAME { constructor() { } constructor(a) { } }", SyntaxError);
     let methods = [["method() { }", simpleMethod("method", "method", false)],
                    ["*method() { }", simpleMethod("method", "method", true)],
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4368,18 +4368,18 @@ Debugger::setupTraceLogger(JSContext* cx
             args.rval().setBoolean(false);
             return true;
         }
 
         RootedValue v(cx);
         if (!GetProperty(cx, obj, obj, ids[i], &v))
             return false;
 
-        textIds.append(textId);
-        values.append(ToBoolean(v));
+        textIds.infallibleAppend(textId);
+        values.infallibleAppend(ToBoolean(v));
     }
 
     MOZ_ASSERT(ids.length() == textIds.length());
     MOZ_ASSERT(textIds.length() == values.length());
 
     for (size_t i = 0; i < textIds.length(); i++) {
         if (values[i])
             TraceLogEnableTextId(cx, textIds[i]);
@@ -6719,23 +6719,16 @@ DebuggerGenericEval(JSContext* cx, const
                     EvalBindings evalWithBindings, HandleValue bindings, HandleValue options,
                     MutableHandleValue vp, Debugger* dbg, HandleObject scope,
                     ScriptFrameIter* iter)
 {
     /* Either we're specifying the frame, or a global. */
     MOZ_ASSERT_IF(iter, !scope);
     MOZ_ASSERT_IF(!iter, scope && IsGlobalLexicalScope(scope));
 
-    if (iter && iter->script()->isDerivedClassConstructor()) {
-        MOZ_ASSERT(iter->isFunctionFrame() && iter->calleeTemplate()->isClassConstructor());
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DISABLED_DERIVED_CLASS,
-                             "debugger eval");
-        return false;
-    }
-
     /* Check the first argument, the eval code string. */
     if (!code.isString()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
                              fullMethodName, "string", InformalValueTypeName(code));
         return false;
     }
     RootedLinearString linear(cx, code.toString()->ensureLinear(cx));
     if (!linear)
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -422,35 +422,40 @@ js::EnqueuePendingParseTasksAfterGC(JSRu
     GlobalHelperThreadState::ParseTaskVector newTasks;
     {
         AutoLockHelperThreadState lock;
         GlobalHelperThreadState::ParseTaskVector& waiting = HelperThreadState().parseWaitingOnGC();
 
         for (size_t i = 0; i < waiting.length(); i++) {
             ParseTask* task = waiting[i];
             if (task->runtimeMatches(rt)) {
-                newTasks.append(task);
+                AutoEnterOOMUnsafeRegion oomUnsafe;
+                if (!newTasks.append(task))
+                    oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
                 HelperThreadState().remove(waiting, &i);
             }
         }
     }
 
     if (newTasks.empty())
         return;
 
     // This logic should mirror the contents of the !activeGCInAtomsZone()
     // branch in StartOffThreadParseScript:
 
     for (size_t i = 0; i < newTasks.length(); i++)
         newTasks[i]->activate(rt);
 
     AutoLockHelperThreadState lock;
 
-    for (size_t i = 0; i < newTasks.length(); i++)
-        HelperThreadState().parseWorklist().append(newTasks[i]);
+    {
+        AutoEnterOOMUnsafeRegion oomUnsafe;
+        if (!HelperThreadState().parseWorklist().appendAll(newTasks))
+            oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
+    }
 
     HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
 }
 
 static const uint32_t kDefaultHelperStackSize = 2048 * 1024;
 static const uint32_t kDefaultHelperStackQuota = 1800 * 1024;
 
 // TSan enforces a minimum stack size that's just slightly larger than our
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -199,16 +199,20 @@ FetchName(JSContext* cx, HandleObject ob
             MOZ_ASSERT(shape->hasSlot());
             vp.set(obj2->as<NativeObject>().getSlot(shape->slot()));
         } else {
             if (!NativeGetExistingProperty(cx, normalized, obj2.as<NativeObject>(), shape, vp))
                 return false;
         }
     }
 
+    // We do our own explicit checking for |this|
+    if (name == cx->names().dotThis)
+        return true;
+
     // NAME operations are the slow paths already, so unconditionally check
     // for uninitialized lets.
     return CheckUninitializedLexical(cx, name, vp);
 }
 
 inline bool
 FetchNameNoGC(JSObject* pobj, Shape* shape, MutableHandleValue vp)
 {
@@ -386,28 +390,24 @@ NegOperation(JSContext* cx, HandleScript
             return false;
         res.setNumber(-d);
     }
 
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
-ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue objval,
-              HandleValue idval, MutableHandleValue res)
+ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval,
+              MutableHandleValue res)
 {
     if (idval.isInt32()) {
         res.set(idval);
         return true;
     }
 
-    JSObject* obj = ToObjectFromStack(cx, objval);
-    if (!obj)
-        return false;
-
     RootedId id(cx);
     if (!ToPropertyKey(cx, idval, &id))
         return false;
 
     res.set(IdToValue(id));
     return true;
 }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1735,17 +1735,16 @@ CASE(EnableInterruptsPseudoOpcode)
     DISPATCH_TO(op);
 }
 
 /* Various 1-byte no-ops. */
 CASE(JSOP_NOP)
 CASE(JSOP_UNUSED14)
 CASE(JSOP_UNUSED65)
 CASE(JSOP_BACKPATCH)
-CASE(JSOP_UNUSED163)
 CASE(JSOP_UNUSED177)
 CASE(JSOP_UNUSED178)
 CASE(JSOP_UNUSED179)
 CASE(JSOP_UNUSED180)
 CASE(JSOP_UNUSED181)
 CASE(JSOP_UNUSED182)
 CASE(JSOP_UNUSED183)
 CASE(JSOP_UNUSED187)
@@ -2417,20 +2416,19 @@ END_CASE(JSOP_DELELEM)
 
 CASE(JSOP_TOID)
 {
     /*
      * Increment or decrement requires use to lookup the same property twice,
      * but we need to avoid the observable stringification the second time.
      * There must be an object value below the id, which will not be popped.
      */
-    ReservedRooted<Value> objval(&rootValue0, REGS.sp[-2]);
     ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
     MutableHandleValue res = REGS.stackHandleAt(-1);
-    if (!ToIdOperation(cx, script, REGS.pc, objval, idval, res))
+    if (!ToIdOperation(cx, script, REGS.pc, idval, res))
         goto error;
 }
 END_CASE(JSOP_TOID)
 
 CASE(JSOP_TYPEOFEXPR)
 CASE(JSOP_TYPEOF)
 {
     REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
@@ -3227,20 +3225,17 @@ CASE(JSOP_GETLOCAL)
         assertSameCompartmentDebugOnly(cx, REGS.sp[-1]);
 }
 END_CASE(JSOP_GETLOCAL)
 
 CASE(JSOP_SETLOCAL)
 {
     uint32_t i = GET_LOCALNO(REGS.pc);
 
-    // Derived class constructors store the TDZ Value in the .this slot
-    // before a super() call.
-    MOZ_ASSERT_IF(!script->isDerivedClassConstructor(),
-                  !IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
+    MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
 
     REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
 }
 END_CASE(JSOP_SETLOCAL)
 
 CASE(JSOP_DEFVAR)
 {
     /* ES5 10.5 step 8 (with subsequent errata). */
@@ -3888,16 +3883,24 @@ CASE(JSOP_CLASSCONSTRUCTOR)
     JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
                                                      nullptr);
     if (!constructor)
         goto error;
     PUSH_OBJECT(*constructor);
 }
 END_CASE(JSOP_CLASSCONSTRUCTOR)
 
+CASE(JSOP_CHECKOBJCOERCIBLE)
+{
+    ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
+    if (checkVal.isNullOrUndefined() && !ToObjectFromStack(cx, checkVal))
+        goto error;
+}
+END_CASE(JSOP_CHECKOBJCOERCIBLE)
+
 DEFAULT()
 {
     char numBuf[12];
     JS_snprintf(numBuf, sizeof numBuf, "%d", *REGS.pc);
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                          JSMSG_BAD_BYTECODE, numBuf);
     goto error;
 }
@@ -4832,19 +4835,16 @@ js::ReportRuntimeRedeclaration(JSContext
     }
 }
 
 bool
 js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
 {
     RootedFunction fun(cx, frame.callee());
 
-    MOZ_ASSERT(fun->isClassConstructor());
-    MOZ_ASSERT(fun->nonLazyScript()->isDerivedClassConstructor());
-
     const char* name = "anonymous";
     JSAutoByteString str;
     if (fun->atom()) {
         if (!AtomToPrintableString(cx, fun->atom(), &str))
             return false;
         name = str.ptr();
     }
 
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1663,17 +1663,24 @@ 1234567890123456789012345678901234567890
      * Throws if a binding with the same name already exists on the scope, or
      * if a var binding with the same name exists on the global.
      *   Category: Variables and Scopes
      *   Type: Variables
      *   Operands: uint32_t nameIndex
      *   Stack: =>
      */ \
     macro(JSOP_DEFLET,        162,"deflet",     NULL,     5,  0,  0,  JOF_ATOM) \
-    macro(JSOP_UNUSED163,     163,"unused163",  NULL,     1,  0,  1,  JOF_BYTE) \
+    /*
+     * Throw if the value on the stack is not coerscible to an object (is |null| or |undefined|).
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: val => val
+     */ \
+    macro(JSOP_CHECKOBJCOERCIBLE, 163, "checkobjcoercible", NULL, 1,  1,  1, JOF_BYTE) \
     /*
      * Find the function to invoke with |super()| on the scope chain.
      *
      *   Category: Variables and Scopes
      *   Type: Super
      *   Operands:
      *   Stack: => superFun
      */ \
@@ -2117,25 +2124,22 @@ 1234567890123456789012345678901234567890
      *   Category: Variables and Scopes
      *   Type: Arguments
      *   Operands:
      *   Stack: => rest
      */ \
     macro(JSOP_REST,          224, "rest",         NULL,  1,  0,  1,  JOF_BYTE|JOF_TYPESET) \
     \
     /*
-     * First, throw a TypeError if baseValue is null or undefined. Then,
-     * replace the top-of-stack value propertyNameValue with
-     * ToPropertyKey(propertyNameValue). This opcode implements ES6 12.3.2.1
-     * steps 7-10.  It is also used to implement computed property names; in
-     * that case, baseValue is always an object, so the first step is a no-op.
+     * Replace the top-of-stack value propertyNameValue with
+     * ToPropertyKey(propertyNameValue).
      *   Category: Literals
      *   Type: Object
      *   Operands:
-     *   Stack: baseValue, propertyNameValue => baseValue, propertyKey
+     *   Stack: propertyNameValue => propertyKey
      */ \
     macro(JSOP_TOID,          225, "toid",         NULL,  1,  1,  1,  JOF_BYTE) \
     \
     /*
      * Pushes the implicit 'this' value for calls to the associated name onto
      * the stack.
      *   Category: Variables and Scopes
      *   Type: This
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -301,18 +301,20 @@ JSRuntime::init(uint32_t maxbytes, uint3
     if (!atomsZone || !atomsZone->init(true))
         return false;
 
     JS::CompartmentOptions options;
     ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
     if (!atomsCompartment || !atomsCompartment->init(nullptr))
         return false;
 
-    gc.zones.append(atomsZone.get());
-    atomsZone->compartments.append(atomsCompartment.get());
+    if (!gc.zones.append(atomsZone.get()))
+        return false;
+    if (!atomsZone->compartments.append(atomsCompartment.get()))
+        return false;
 
     atomsCompartment->setIsSystem(true);
 
     atomsZone.forget();
     this->atomsCompartment_ = atomsCompartment.forget();
 
     if (!symbolRegistry_.init())
         return false;
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -948,17 +948,17 @@ class ClonedBlockObject : public BlockOb
 // (i.e. JSOP_SETNAME), we emit an accompanying, preceding JSOP_BINDNAME which
 // finds the right scope on which to set the name. Moreover, when the name on
 // the scope is an uninitialized lexical, we cannot throw eagerly, as the spec
 // demands that the error be thrown after evaluating the RHS of
 // assignments. Instead, this sentinel scope object is pushed on the stack.
 // Attempting to access anything on this scope throws the appropriate
 // ReferenceError.
 //
-// ES6 'const' bindings induce a runtime assignment when assigned to outside
+// ES6 'const' bindings induce a runtime error when assigned to outside
 // of initialization, regardless of strictness.
 class RuntimeLexicalErrorObject : public ScopeObject
 {
     static const unsigned ERROR_SLOT = 1;
 
   public:
     static const unsigned RESERVED_SLOTS = 2;
     static const Class class_;
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3870,17 +3870,21 @@ TypeNewScript::rollbackPartiallyInitiali
     if (!initializerList)
         return false;
 
     bool found = false;
 
     RootedFunction function(cx, this->function());
     Vector<uint32_t, 32> pcOffsets(cx);
     for (ScriptFrameIter iter(cx); !iter.done(); ++iter) {
-        pcOffsets.append(iter.script()->pcToOffset(iter.pc()));
+        {
+            AutoEnterOOMUnsafeRegion oomUnsafe;
+            if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
+                oomUnsafe.crash("rollbackPartiallyInitializedObjects");
+        }
 
         if (!iter.isConstructing() || !iter.matchCallee(cx, function))
             continue;
 
         // Derived class constructors initialize their this-binding later and
         // we shouldn't run the definite properties analysis on them.
         MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
 
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 327;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 329;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 425,
+static_assert(JSErr_Limit == 424,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext* cx)
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -4570,23 +4570,19 @@ nsDisplayResolution::~nsDisplayResolutio
 #endif
 
 void
 nsDisplayResolution::HitTest(nsDisplayListBuilder* aBuilder,
                              const nsRect& aRect,
                              HitTestState* aState,
                              nsTArray<nsIFrame*> *aOutFrames)
 {
-#if defined(MOZ_SINGLE_PROCESS_APZ)
   nsIPresShell* presShell = mFrame->PresContext()->PresShell();
   nsRect rect = aRect.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
   mList.HitTest(aBuilder, rect, aState, aOutFrames);
-#else
-  mList.HitTest(aBuilder, aRect, aState, aOutFrames);
-#endif // MOZ_SINGLE_PROCESS_APZ
 }
 
 already_AddRefed<Layer>
 nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
                                 LayerManager* aManager,
                                 const ContainerLayerParameters& aContainerParameters) {
   nsIPresShell* presShell = mFrame->PresContext()->PresShell();
   ContainerLayerParameters containerParameters(
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1411,17 +1411,22 @@ public:
    * resolution bounds are sane, and the resolution of this was
    * actually updated.
    *
    * The resolution defaults to 1.0.
    */
   virtual nsresult SetResolution(float aResolution) = 0;
   float GetResolution() { return mResolution.valueOr(1.0); }
   virtual float GetCumulativeResolution() = 0;
-  virtual float GetCumulativeScaleResolution() = 0;
+
+  /**
+   * Calculate the cumulative scale resolution from this document up to
+   * but not including the root document.
+   */
+  virtual float GetCumulativeNonRootScaleResolution() = 0;
 
   /**
    * Was the current resolution set by the user or just default initialized?
    */
   bool IsResolutionSet() { return mResolution.isSome(); }
 
   /**
    * Similar to SetResolution() but also increases the scale of the content
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2016,19 +2016,17 @@ nsLayoutUtils::GetEventCoordinatesRelati
     if (frameWidget && frameWidget == aWidget) {
       // Special case this cause it happens a lot.
       // This also fixes bug 664707, events in the extra-special case of select
       // dropdown popups that are transformed.
       nsPresContext* presContext = aFrame->PresContext();
       nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x),
                  presContext->DevPixelsToAppUnits(aPoint.y));
       pt = pt - view->ViewToWidgetOffset();
-#if defined(MOZ_SINGLE_PROCESS_APZ)
-      pt = pt.RemoveResolution(presContext->PresShell()->GetCumulativeScaleResolution());
-#endif // MOZ_SINGLE_PROCESS_APZ
+      pt = pt.RemoveResolution(presContext->PresShell()->GetCumulativeNonRootScaleResolution());
       return pt;
     }
   }
 
   /* If we walk up the frame tree and discover that any of the frames are
    * transformed, we need to do extra work to convert from the global
    * space to the local space.
    */
@@ -2054,22 +2052,20 @@ nsLayoutUtils::GetEventCoordinatesRelati
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
   // Convert from root document app units to app units of the document aFrame
   // is in.
   int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
   int32_t localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
   widgetToView = widgetToView.ScaleToOtherAppUnits(rootAPD, localAPD);
-#if defined(MOZ_SINGLE_PROCESS_APZ)
   nsIPresShell* shell = aFrame->PresContext()->PresShell();
 
   // XXX Bug 1224748 - Update nsLayoutUtils functions to correctly handle nsPresShell resolution
-  widgetToView = widgetToView.RemoveResolution(shell->GetCumulativeScaleResolution());
-#endif
+  widgetToView = widgetToView.RemoveResolution(shell->GetCumulativeNonRootScaleResolution());
 
   /* If we encountered a transform, we can't do simple arithmetic to figure
    * out how to convert back to aFrame's coordinates and must use the CTM.
    */
   if (transformFound || aFrame->IsSVGText()) {
     return TransformRootPointToFrame(aFrame, widgetToView);
   }
 
@@ -2807,20 +2803,18 @@ nsLayoutUtils::TranslateViewToWidget(nsP
                                      nsIWidget* aWidget)
 {
   nsPoint viewOffset;
   nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
   if (!viewWidget) {
     return LayoutDeviceIntPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   }
 
-  nsPoint pt = aPt + viewOffset;
-#if defined(MOZ_SINGLE_PROCESS_APZ)
-  pt = pt.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
-#endif // MOZ_SINGLE_PROCESS_APZ
+  nsPoint pt = (aPt +
+  viewOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
   LayoutDeviceIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(pt.x),
                                             aPresContext->AppUnitsToDevPixels(pt.y));
   return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget);
 }
 
 // Combine aNewBreakType with aOrigBreakType, but limit the break types
 // to NS_STYLE_CLEAR_LEFT, RIGHT, BOTH.
 uint8_t
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5325,23 +5325,26 @@ float PresShell::GetCumulativeResolution
   float resolution = GetResolution();
   nsPresContext* parentCtx = GetPresContext()->GetParentPresContext();
   if (parentCtx) {
     resolution *= parentCtx->PresShell()->GetCumulativeResolution();
   }
   return resolution;
 }
 
-float PresShell::GetCumulativeScaleResolution()
+float PresShell::GetCumulativeNonRootScaleResolution()
 {
   float resolution = 1.0;
   nsIPresShell* currentShell = this;
   while (currentShell) {
-    resolution *=  currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
-    nsPresContext* parentCtx = currentShell->GetPresContext()->GetParentPresContext();
+    nsPresContext* currentCtx = currentShell->GetPresContext();
+    if (currentCtx != currentCtx->GetRootPresContext()) {
+      resolution *=  currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
+    }
+    nsPresContext* parentCtx = currentCtx->GetParentPresContext();
     if (parentCtx) {
       currentShell = parentCtx->PresShell();
     } else {
       currentShell = nullptr;
     }
   }
   return resolution;
 }
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -213,17 +213,17 @@ public:
   virtual nsresult SetResolution(float aResolution) override {
     return SetResolutionImpl(aResolution, /* aScaleToResolution = */ false);
   }
   virtual nsresult SetResolutionAndScaleTo(float aResolution) override {
     return SetResolutionImpl(aResolution, /* aScaleToResolution = */ true);
   }
   virtual bool ScaleToResolution() const override;
   virtual float GetCumulativeResolution() override;
-  virtual float GetCumulativeScaleResolution() override;
+  virtual float GetCumulativeNonRootScaleResolution() override;
 
   //nsIViewObserver interface
 
   virtual void Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
                      uint32_t aFlags) override;
   virtual nsresult HandleEvent(nsIFrame* aFrame,
                                mozilla::WidgetGUIEvent* aEvent,
                                bool aDontRetargetEvents,
--- a/layout/base/tests/chrome/chrome.ini
+++ b/layout/base/tests/chrome/chrome.ini
@@ -15,16 +15,17 @@ support-files =
   passpointerevents_dynamically_window.html
   printpreview_bug396024_helper.xul
   printpreview_bug482976_helper.xul
   printpreview_helper.xul
   transformed_scrolling_repaints_3_window.html
   file_bug1018265.xul
 
 [test_bug370436.html]
+skip-if = buildapp == 'b2g'
 [test_bug396367-1.html]
 [test_bug396367-2.html]
 [test_bug420499.xul]
 skip-if = buildapp == 'b2g'
 [test_bug458898.html]
 skip-if = buildapp == 'b2g'
 [test_bug495648.xul]
 skip-if = buildapp == 'b2g'
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -437,22 +437,20 @@ nsSubDocumentFrame::BuildDisplayList(nsD
           dirty = rootScrollableFrame->ExpandRectToNearlyVisible(dirty);
         }
       }
     }
 
     aBuilder->EnterPresShell(subdocRootFrame,
                              pointerEventsNone && !passPointerEventsToChildren);
 
-#if defined(MOZ_SINGLE_PROCESS_APZ)
     if (!haveDisplayPort) {
       // Remove nsPresShell resolution
       dirty = dirty.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
     }
-#endif
   } else {
     dirty = aDirtyRect;
   }
 
   DisplayListClipState::AutoSaveRestore clipState(aBuilder);
   if (ShouldClipSubdocument()) {
     clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
   }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -551,22 +551,30 @@ pref("editor.singleLine.pasteNewlines", 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with EventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.async-video.enabled", true);
+
 #ifdef MOZ_ANDROID_APZ
 pref("layers.async-pan-zoom.enabled", true);
-pref("apz.axis_lock.mode", 1);
-pref("apz.fling_stop_on_tap_threshold", "0.08");
+// APZ physics settings, copied from B2G
+pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking
+pref("apz.fling_curve_function_x1", "0.41");
+pref("apz.fling_curve_function_y1", "0.0");
+pref("apz.fling_curve_function_x2", "0.80");
+pref("apz.fling_curve_function_y2", "1.0");
+pref("apz.fling_curve_threshold_inches_per_ms", "0.01");
+pref("apz.fling_friction", "0.0019");
+pref("apz.max_velocity_inches_per_ms", "0.07");
 #endif
-pref("apz.allow_zooming", true);
+
 pref("layers.progressive-paint", true);
 pref("layers.low-precision-buffer", true);
 pref("layers.low-precision-resolution", "0.25");
 pref("layers.low-precision-opacity", "1.0");
 // We want to limit layers for two reasons:
 // 1) We can't scroll smoothly if we have to many draw calls
 // 2) Pages that have too many layers consume too much memory and crash.
 // By limiting the number of layers on mobile we're making the main thread
--- a/mobile/android/b2gdroid/app/b2gdroid.js
+++ b/mobile/android/b2gdroid/app/b2gdroid.js
@@ -537,31 +537,30 @@ pref("editor.singleLine.pasteNewlines", 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with EventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.async-video.enabled", true);
+
 #ifdef MOZ_ANDROID_APZ
 pref("layers.async-pan-zoom.enabled", true);
-pref("apz.allow_zooming", true);
-// Use "sticky" axis locking
-pref("apz.axis_lock.mode", 2);
 // APZ physics settings, tuned by UX designers
+pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking
 pref("apz.fling_curve_function_x1", "0.41");
 pref("apz.fling_curve_function_y1", "0.0");
 pref("apz.fling_curve_function_x2", "0.80");
 pref("apz.fling_curve_function_y2", "1.0");
 pref("apz.fling_curve_threshold_inches_per_ms", "0.01");
 pref("apz.fling_friction", "0.0019");
 pref("apz.max_velocity_inches_per_ms", "0.07");
-pref("apz.touch_start_tolerance", "0.1");
 #endif
+
 pref("layers.progressive-paint", true);
 pref("layers.low-precision-buffer", true);
 pref("layers.low-precision-resolution", "0.25");
 pref("layers.low-precision-opacity", "1.0");
 // We want to limit layers for two reasons:
 // 1) We can't scroll smoothly if we have to many draw calls
 // 2) Pages that have too many layers consume too much memory and crash.
 // By limiting the number of layers on mobile we're making the main thread
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
@@ -232,16 +232,21 @@ public class LayerView extends ScrollVie
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             requestFocus();
         }
         event.offsetLocation(0, -mSurfaceTranslation);
 
         if (mToolbarAnimator != null && mToolbarAnimator.onInterceptTouchEvent(event)) {
             return true;
         }
+        if (AppConstants.MOZ_ANDROID_APZ && !mGeckoIsReady) {
+            // If gecko isn't loaded yet, don't try sending events to the
+            // native code because it's just going to crash
+            return true;
+        }
         if (mPanZoomController != null && mPanZoomController.onTouchEvent(event)) {
             return true;
         }
         return sendEventToGecko(event);
     }
 
     @Override
     public boolean onHoverEvent(MotionEvent event) {
@@ -259,16 +264,21 @@ public class LayerView extends ScrollVie
         return sendEventToGecko(event);
     }
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if (AndroidGamepadManager.handleMotionEvent(event)) {
             return true;
         }
+        if (AppConstants.MOZ_ANDROID_APZ && !mGeckoIsReady) {
+            // If gecko isn't loaded yet, don't try sending events to the
+            // native code because it's just going to crash
+            return true;
+        }
         if (mPanZoomController != null && mPanZoomController.onMotionEvent(event)) {
             return true;
         }
         return false;
     }
 
     @Override
     protected void onAttachedToWindow() {
@@ -365,16 +375,21 @@ public class LayerView extends ScrollVie
     }
 
     public void setIsRTL(boolean aIsRTL) {
         mLayerClient.setIsRTL(aIsRTL);
     }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (AppConstants.MOZ_ANDROID_APZ && !mGeckoIsReady) {
+            // If gecko isn't loaded yet, don't try sending events to the
+            // native code because it's just going to crash
+            return true;
+        }
         if (mPanZoomController != null && mPanZoomController.onKeyEvent(event)) {
             return true;
         }
         return false;
     }
 
     public void requestRender() {
         if (mListener != null) {
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java
@@ -87,20 +87,27 @@ class NativePanZoomController implements
     private native void init();
     private native boolean handleTouchEvent(GeckoEvent event);
     private native void handleMotionEvent(GeckoEvent event);
 
     @Override
     public native void destroy();
     @Override
     public native boolean getRedrawHint();
+
     @Override
-    public native void setOverScrollMode(int overscrollMode);
+    public void setOverScrollMode(int overscrollMode) {
+        // FIXME implement this
+    }
+
     @Override
-    public native int getOverScrollMode();
+    public int getOverScrollMode() {
+        // FIXME implement this
+        return 0;
+    }
 
     @WrapForJNI(allowMultithread = true, stubName = "RequestContentRepaintWrapper")
     private void requestContentRepaint(float x, float y, float width, float height, float resolution) {
         mTarget.forceRedraw(new DisplayPortMetrics(x, y, x + width, y + height, resolution));
     }
 
     @Override
     public void setOverscrollHandler(final Overscroll listener) {
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -531,16 +531,20 @@ pref("media.video-queue.send-to-composit
 pref("media.video_stats.enabled", true);
 
 // Weather we allow AMD switchable graphics
 pref("layers.amd-switchable-gfx.enabled", true);
 
 // Whether to use async panning and zooming
 pref("layers.async-pan-zoom.enabled", false);
 
+#ifdef MOZ_WIDGET_UIKIT
+pref("layers.async-pan-zoom.enabled", true);
+#endif
+
 // Whether to enable event region building during painting
 pref("layout.event-regions.enabled", false);
 
 // APZ preferences. For documentation/details on what these prefs do, check
 // gfx/layers/apz/src/AsyncPanZoomController.cpp.
 pref("apz.allow_checkerboarding", true);
 pref("apz.allow_zooming", false);
 
@@ -562,68 +566,64 @@ pref("apz.fling_accel_base_mult", "1.0")
 pref("apz.fling_accel_interval_ms", 500);
 pref("apz.fling_accel_supplemental_mult", "1.0");
 pref("apz.fling_curve_function_x1", "0.0");
 pref("apz.fling_curve_function_y1", "0.0");
 pref("apz.fling_curve_function_x2", "1.0");
 pref("apz.fling_curve_function_y2", "1.0");
 pref("apz.fling_curve_threshold_inches_per_ms", "-1.0");
 pref("apz.fling_friction", "0.002");
+pref("apz.fling_repaint_interval", 16);
 pref("apz.fling_stop_on_tap_threshold", "0.05");
 pref("apz.fling_stopped_threshold", "0.01");
 pref("apz.highlight_checkerboarded_areas", false);
 pref("apz.max_velocity_inches_per_ms", "-1.0");
 pref("apz.max_velocity_queue_size", 5);
 pref("apz.min_skate_speed", "1.0");
 pref("apz.minimap.enabled", false);
 pref("apz.num_paint_duration_samples", 3);
 pref("apz.overscroll.enabled", false);
 pref("apz.overscroll.min_pan_distance_ratio", "1.0");
-pref("apz.overscroll.stretch_factor", "0.5");
-pref("apz.overscroll.spring_stiffness", "0.001");
 pref("apz.overscroll.spring_friction", "0.015");
+pref("apz.overscroll.spring_stiffness", "0.0018");
 pref("apz.overscroll.stop_distance_threshold", "5.0");
 pref("apz.overscroll.stop_velocity_threshold", "0.01");
+pref("apz.overscroll.stretch_factor", "0.35");
+pref("apz.pan_repaint_interval", 16);
 
 // Whether to print the APZC tree for debugging
 pref("apz.printtree", false);
 
+pref("apz.smooth_scroll_repaint_interval", 16);
 pref("apz.test.logging_enabled", false);
-pref("apz.touch_start_tolerance", "0.2222222");  // 0.2222222 came from 1.0/4.5
-pref("apz.touch_move_tolerance", "0.0");
+pref("apz.touch_start_tolerance", "0.1");
+pref("apz.touch_move_tolerance", "0.03");
 pref("apz.use_paint_duration", true);
 pref("apz.velocity_bias", "1.0");
 pref("apz.velocity_relevance_time_ms", 150);
-pref("apz.x_stationary_size_multiplier", "3.0");
-pref("apz.y_stationary_size_multiplier", "3.5");
 pref("apz.x_skate_highmem_adjust", "0.0");
 pref("apz.y_skate_highmem_adjust", "0.0");
-pref("apz.zoom_animation_duration_ms", 250);
-
-#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
-// Desktop prefs
-pref("apz.fling_repaint_interval", 16);
-pref("apz.smooth_scroll_repaint_interval", 16);
-pref("apz.pan_repaint_interval", 16);
 pref("apz.x_skate_size_multiplier", "2.5");
 pref("apz.y_skate_size_multiplier", "3.5");
-#else
+pref("apz.x_stationary_size_multiplier", "3.0");
+pref("apz.y_stationary_size_multiplier", "3.5");
+pref("apz.zoom_animation_duration_ms", 250);
+
+#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
 // Mobile prefs
+pref("apz.allow_zooming", true);
+pref("apz.enlarge_displayport_when_clipped", true);
 pref("apz.fling_repaint_interval", 75);
 pref("apz.smooth_scroll_repaint_interval", 75);
-pref("apz.pan_repaint_interval", 250);
 pref("apz.x_skate_size_multiplier", "1.25");
 pref("apz.y_skate_size_multiplier", "1.5");
 pref("apz.x_stationary_size_multiplier", "1.5");
 pref("apz.y_stationary_size_multiplier", "1.8");
 #endif
 
-// APZ testing (bug 961289)
-pref("apz.test.logging_enabled", false);
-
 #ifdef XP_MACOSX
 // Whether to run in native HiDPI mode on machines with "Retina"/HiDPI display;
 //   <= 0 : hidpi mode disabled, display will just use pixel-based upscaling
 //   == 1 : hidpi supported if all screens share the same backingScaleFactor
 //   >= 2 : hidpi supported even with mixed backingScaleFactors (somewhat broken)
 pref("gfx.hidpi.enabled", 2);
 #endif
 
@@ -2584,17 +2584,17 @@ pref("dom.ipc.plugins.unloadTimeoutSecs"
 // channels until some remaining bugs are resolved.
 #ifdef E10S_TESTING_ONLY
 pref("dom.ipc.plugins.asyncInit.enabled", false);
 #else
 pref("dom.ipc.plugins.asyncInit.enabled", true);
 #endif
 
 // Allow the AsyncDrawing mode to be used for plugins.
-pref("dom.ipc.plugins.asyncdrawing.enabled", false);
+pref("dom.ipc.plugins.asyncdrawing.enabled", true);
 
 pref("dom.ipc.processCount", 1);
 
 // Enable caching of Moz2D Path objects for SVG geometry elements
 pref("svg.path-caching.enabled", true);
 
 // Enable the use of display-lists for SVG hit-testing and painting.
 pref("svg.display-lists.hit-testing.enabled", true);
@@ -3168,19 +3168,16 @@ pref("plugin.scan.Quicktime", "5.0");
 
 // Locate and scan the Window Media Player installation directory for plugins with a minimum version
 pref("plugin.scan.WindowsMediaPlayer", "7.0");
 
 // Locate plugins by the directories specified in the Windows registry for PLIDs
 // Which is currently HKLM\Software\MozillaPlugins\xxxPLIDxxx\Path
 pref("plugin.scan.plid.all", true);
 
-// Allow the new AsyncDrawing mode to be used for plugins.
-pref("plugin.allow.asyncdrawing", false);
-
 // Help Windows NT, 2000, and XP dialup a RAS connection
 // when a network address is unreachable.
 pref("network.autodial-helper.enabled", true);
 
 // Switch the keyboard layout per window
 pref("intl.keyboard.per_window_layout", false);
 
 #ifdef NS_ENABLE_TSF
@@ -4314,20 +4311,16 @@ pref("layers.tiles.adjust", true);
 // Set the default values, and then override per-platform as needed
 pref("layers.offmainthreadcomposition.enabled", true);
 // Compositor target frame rate. NOTE: If vsync is enabled the compositor
 // frame rate will still be capped.
 // -1 -> default (match layout.frame_rate or 60 FPS)
 // 0  -> full-tilt mode: Recomposite even if not transaction occured.
 pref("layers.offmainthreadcomposition.frame-rate", -1);
 
-#ifdef MOZ_WIDGET_UIKIT
-pref("layers.async-pan-zoom.enabled", true);
-#endif
-
 #ifdef XP_MACOSX
 pref("layers.enable-tiles", true);
 pref("layers.tile-width", 512);
 pref("layers.tile-height", 512);
 pref("layers.tiled-drawtarget.enabled", true);
 pref("layers.tiles.edge-padding", false);
 #endif
 
--- a/mozglue/android/jni-stubs.inc
+++ b/mozglue/android/jni-stubs.inc
@@ -737,54 +737,16 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint);
 #endif
 
 #ifdef JNI_STUBS
 
-typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode_t)(JNIEnv *, jobject, jint);
-static Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode;
-extern "C" NS_EXPORT void MOZ_JNICALL
-Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(JNIEnv * arg0, jobject arg1, jint arg2) {
-    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode) {
-        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
-                       "JNI Function called before it was loaded");
-        return ;
-    }
-     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(arg0, arg1, arg2);
-}
-#endif
-
-#ifdef JNI_BINDINGS
-  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode);
-#endif
-
-#ifdef JNI_STUBS
-
-typedef jint (*Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode_t)(JNIEnv *, jobject);
-static Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode;
-extern "C" NS_EXPORT jint MOZ_JNICALL
-Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv * arg0, jobject arg1) {
-    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode) {
-        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
-                       "JNI Function called before it was loaded");
-        return 0;
-    }
-    return f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(arg0, arg1);
-}
-#endif
-
-#ifdef JNI_BINDINGS
-  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode);
-#endif
-
-#ifdef JNI_STUBS
-
 typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_setIsLongpressEnabled_t)(JNIEnv *, jobject, jboolean);
 static Java_org_mozilla_gecko_gfx_NativePanZoomController_setIsLongpressEnabled_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setIsLongpressEnabled;
 extern "C" NS_EXPORT void MOZ_JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_setIsLongpressEnabled(JNIEnv * arg0, jobject arg1, jboolean arg2) {
     if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setIsLongpressEnabled) {
         arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
                        "JNI Function called before it was loaded");
         return ;
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -55,25 +55,42 @@ var XULAppInfoFactory = {
     appInfo.QueryInterface(iid);
     if (outer != null) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return appInfo.QueryInterface(iid);
   }
 };
 
+// we need to ensure we setup revocation data before certDB, or we'll start with
+// no revocation.txt in the profile
+var profile = do_get_profile();
+
+// Write out an empty blocklist.xml file to the profile to ensure nothing
+// is blocklisted by default
+var blockFile = profile.clone();
+blockFile.append("blocklist.xml");
+var stream = Cc["@mozilla.org/network/file-output-stream;1"]
+               .createInstance(Ci.nsIFileOutputStream);
+stream.init(blockFile,
+  FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
+  FileUtils.PERMS_FILE, 0);
+
+var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+           "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">\n" +
+           "</blocklist>\n";
+stream.write(data, data.length);
+stream.close();
+
 var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
 registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
                           XULAPPINFO_CONTRACTID, XULAppInfoFactory);
 
-// we need to ensure we setup revocation data before certDB, or we'll start with
-// no revocation.txt in the profile
-var profile = do_get_profile();
 var revocations = profile.clone();
 revocations.append("revocations.txt");
 if (!revocations.exists()) {
   let existing = do_get_file("test_onecrl/sample_revocations.txt", false);
   existing.copyTo(profile,"revocations.txt");
 }
 
 var certDB = Cc["@mozilla.org/security/x509certdb;1"]
@@ -130,17 +147,17 @@ var blocklists = {
   "/updatedBlocklist/" : updatedBlocklist
 }
 
 function serveResponse(request, response) {
   do_print("Serving for path " + request.path + "\n");
   response.write(blocklists[request.path]);
 }
 
-for (path in blocklists) {
+for (var path in blocklists) {
   testserver.registerPathHandler(path, serveResponse);
 }
 
 // start the test server
 testserver.start(-1);
 var port = testserver.identity.primaryPort;
 
 // Setup the addonManager
@@ -215,17 +232,16 @@ function check_revocations_txt_contents(
   inputStream.QueryInterface(Ci.nsILineInputStream);
   let contents = "";
   let hasmore = false;
   do {
     var line = {};
     hasmore = inputStream.readLine(line);
     contents = contents + (contents.length == 0 ? "" : "\n") + line.value;
   } while (hasmore);
-
   equal(contents, expected, "revocations.txt should be as expected");
 }
 
 function run_test() {
   // import the certificates we need
   load_cert("test-ca", "CTu,CTu,CTu");
   load_cert("test-int", ",,");
   load_cert("other-test-ca", "CTu,CTu,CTu");
--- a/testing/marionette/transport/marionette_transport/transport.py
+++ b/testing/marionette/transport/marionette_transport/transport.py
@@ -123,25 +123,16 @@ class TcpTransport(object):
         self.protocol = 1
         self.application_type = None
         self.last_id = 0
         self.expected_responses = []
 
         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.sock.settimeout(self.socket_timeout)
 
-    def _recv_n_bytes(self, n):
-        data = ""
-        while len(data) < n:
-            chunk = self.sock.recv(n - len(data))
-            if chunk == "":
-                break
-            data += chunk
-        return data
-
     def _unmarshal(self, packet):
         msg = None
 
         # protocol 3 and above
         if self.protocol >= 3:
             typ = int(packet[1])
             if typ == Command.TYPE:
                 msg = Command.from_msg(packet)
--- a/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-move-element-test.html.ini
+++ b/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-move-element-test.html.ini
@@ -1,8 +1,9 @@
 [attached-callback-move-element-test.html]
   type: testharness
+  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1231029 https://bugzilla.mozilla.org/show_bug.cgi?id=1231031 https://bugzilla.mozilla.org/show_bug.cgi?id=1183023
   [Test attached callback if moving custom element from document without browsing context to document with browsing context]
     expected: FAIL
 
   [Test attached callback if moving custom element from document with browsing context to document with browsing context]
     expected: FAIL
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -6280,16 +6280,23 @@
     "cpp_guard": "MOZ_RUST_MP4PARSE"
   },
   "MEDIA_WMF_DECODE_ERROR": {
     "expires_in_version": "50",
     "kind": "enumerated",
     "n_values": 256,
     "description": "WMF media decoder error or success (0) codes."
   },
+  "MEDIA_OGG_LOADED_IS_CHAINED": {
+    "alert_emails": ["cpearce@mozilla.com"],
+    "expires_in_version": "53",
+    "kind": "boolean",
+    "description": "Whether Ogg audio/video encountered are chained or not.",
+    "bug_numbers": [1230295]
+  },
   "VIDEO_CAN_CREATE_AAC_DECODER": {
     "alert_emails": ["cpearce@mozilla.com"],
     "expires_in_version": "50",
     "kind": "boolean",
     "description": "Whether at startup we report we can playback MP4 (AAC) audio. This is single value is recorded at every startup.",
     "releaseChannelCollection": "opt-out"
   },
   "VIDEO_CAN_CREATE_H264_DECODER": {
@@ -10165,10 +10172,18 @@
     "description": "The number of ICE connections which immediately failed (0) vs. reached at least checking state (1)."
   },
   "YOUTUBE_REWRITABLE_EMBED_SEEN": {
     "alert_emails": ["cpeterson@mozilla.com"],
     "expires_in_version": "48",
     "kind": "flag",
     "bug_numbers": [1229971],
     "description": "Flag activated whenever a rewritable youtube flash embed is seen during a session."
+  },
+  "PLUGIN_DRAWING_MODEL": {
+    "alert_emails": ["danderson@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "bug_numbers": [1229961],
+    "n_values": 12,
+    "description": "Plugin drawing model. 0 when windowed, otherwise NPDrawingModel + 1."
   }
 }
--- a/toolkit/mozapps/extensions/internal/PluginProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/PluginProvider.jsm
@@ -444,17 +444,17 @@ PluginWrapper.prototype = {
     let libs = [];
     for (let tag of pluginFor(this).tags)
       libs.push(tag.filename);
     return libs;
   },
 
   get pluginFullpath() {
     let paths = [];
-    for (let tag of aTags)
+    for (let tag of pluginFor(this).tags)
       paths.push(tag.fullpath);
     return paths;
   },
 
   get pluginMimeTypes() {
     let types = [];
     for (let tag of pluginFor(this).tags) {
       let mimeTypes = tag.getMimeTypes({});
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -443,21 +443,20 @@ ContentCacheInChild::SetSelection(nsIWid
 }
 
 /*****************************************************************************
  * mozilla::ContentCacheInParent
  *****************************************************************************/
 
 ContentCacheInParent::ContentCacheInParent()
   : ContentCache()
+  , mCommitStringByRequest(nullptr)
   , mCompositionStart(UINT32_MAX)
-  , mCompositionEventsDuringRequest(0)
   , mPendingEventsNeedingAck(0)
   , mIsComposing(false)
-  , mRequestedToCommitOrCancelComposition(false)
 {
 }
 
 void
 ContentCacheInParent::AssignContent(const ContentCache& aOther,
                                     const IMENotification* aNotification)
 {
   mText = aOther.mText;
@@ -822,58 +821,44 @@ ContentCacheInParent::GetCaretRect(uint3
 
 bool
 ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
 {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCacheInParent: 0x%p OnCompositionEvent(aEvent={ "
      "mMessage=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), "
      "mPendingEventsNeedingAck=%u, mIsComposing=%s, "
-     "mRequestedToCommitOrCancelComposition=%s",
+     "mCommitStringByRequest=0x%p",
      this, ToChar(aEvent.mMessage),
      NS_ConvertUTF16toUTF8(aEvent.mData).get(), aEvent.mData.Length(),
      aEvent.mRanges ? aEvent.mRanges->Length() : 0, mPendingEventsNeedingAck,
-     GetBoolName(mIsComposing),
-     GetBoolName(mRequestedToCommitOrCancelComposition)));
-
-  if (!aEvent.CausesDOMTextEvent()) {
-    MOZ_ASSERT(aEvent.mMessage == eCompositionStart);
-    mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
-    mCompositionStart = mSelection.StartOffset();
-    // XXX What's this case??
-    if (mRequestedToCommitOrCancelComposition) {
-      mCommitStringByRequest = aEvent.mData;
-      mCompositionEventsDuringRequest++;
-      return false;
-    }
-    mPendingEventsNeedingAck++;
-    return true;
-  }
-
-  // XXX Why do we ignore following composition events here?
-  //     TextComposition must handle following events correctly!
-
-  // During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
-  // widget usually sends a eCompositionChange event to finalize or
-  // clear the composition, respectively.
-  // Because the event will not reach content in time, we intercept it
-  // here and pass the text as the DidRequestToCommitOrCancelComposition()
-  // return value.
-  if (mRequestedToCommitOrCancelComposition) {
-    mCommitStringByRequest = aEvent.mData;
-    mCompositionEventsDuringRequest++;
-    return false;
-  }
+     GetBoolName(mIsComposing), mCommitStringByRequest));
 
   // We must be able to simulate the selection because
   // we might not receive selection updates in time
   if (!mIsComposing) {
     mCompositionStart = mSelection.StartOffset();
   }
+
   mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
+
+  // During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
+  // widget usually sends a eCompositionChange and/or eCompositionCommit event
+  // to finalize or clear the composition, respectively.  In this time,
+  // we need to intercept all composition events here and pass the commit
+  // string for returning to the remote process as a result of
+  // RequestIMEToCommitComposition().  Then, eCommitComposition event will
+  // be dispatched with the committed string in the remote process internally.
+  if (mCommitStringByRequest) {
+    MOZ_ASSERT(aEvent.mMessage == eCompositionChange ||
+               aEvent.mMessage == eCompositionCommit);
+    *mCommitStringByRequest = aEvent.mData;
+    return false;
+  }
+
   mPendingEventsNeedingAck++;
   return true;
 }
 
 void
 ContentCacheInParent::OnSelectionEvent(
                         const WidgetSelectionEvent& aSelectionEvent)
 {
@@ -907,39 +892,73 @@ ContentCacheInParent::OnEventNeedingAckH
   MOZ_RELEASE_ASSERT(mPendingEventsNeedingAck > 0);
   if (--mPendingEventsNeedingAck) {
     return;
   }
 
   FlushPendingNotifications(aWidget);
 }
 
-uint32_t
-ContentCacheInParent::RequestToCommitComposition(nsIWidget* aWidget,
-                                                 bool aCancel,
-                                                 nsAString& aLastString)
+bool
+ContentCacheInParent::RequestIMEToCommitComposition(nsIWidget* aWidget,
+                                                    bool aCancel,
+                                                    nsAString& aCommittedString)
 {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCacheInParent: 0x%p RequestToCommitComposition(aWidget=%p, "
-     "aCancel=%s), mIsComposing=%s, mRequestedToCommitOrCancelComposition=%s, "
-     "mCompositionEventsDuringRequest=%u",
+     "aCancel=%s), mIsComposing=%s, mCommitStringByRequest=%p",
      this, aWidget, GetBoolName(aCancel), GetBoolName(mIsComposing),
-     GetBoolName(mRequestedToCommitOrCancelComposition),
-     mCompositionEventsDuringRequest));
+     mCommitStringByRequest));
+
+  MOZ_ASSERT(!mCommitStringByRequest);
 
-  mRequestedToCommitOrCancelComposition = true;
-  mCompositionEventsDuringRequest = 0;
+  RefPtr<TextComposition> composition =
+    IMEStateManager::GetTextCompositionFor(aWidget);
+  if (NS_WARN_IF(!composition)) {
+    MOZ_LOG(sContentCacheLog, LogLevel::Warning,
+      ("  ContentCacheInParent: 0x%p RequestToCommitComposition(), "
+       "does nothing due to no composition", this));
+    return false;
+  }
+
+  mCommitStringByRequest = &aCommittedString;
 
   aWidget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
                                                REQUEST_TO_COMMIT_COMPOSITION));
 
-  mRequestedToCommitOrCancelComposition = false;
-  aLastString = mCommitStringByRequest;
-  mCommitStringByRequest.Truncate(0);
-  return mCompositionEventsDuringRequest;
+  mCommitStringByRequest = nullptr;
+
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("  ContentCacheInParent: 0x%p RequestToCommitComposition(), "
+     "mIsComposing=%s, the composition %s committed synchronously",
+     this, GetBoolName(mIsComposing),
+     composition->Destroyed() ? "WAS" : "has NOT been"));
+
+  if (!composition->Destroyed()) {
+    // When the composition isn't committed synchronously, the remote process's
+    // TextComposition instance will synthesize commit events and wait to
+    // receive delayed composition events.  When TextComposition instances both
+    // in this process and the remote process will be destroyed when delayed
+    // composition events received. TextComposition instance in the parent
+    // process will dispatch following composition events and be destroyed
+    // normally. On the other hand, TextComposition instance in the remote
+    // process won't dispatch following composition events and will be
+    // destroyed by IMEStateManager::DispatchCompositionEvent().
+    return false;
+  }
+
+  // When the composition is committed synchronously, the commit string will be
+  // returned to the remote process. Then, PuppetWidget will dispatch
+  // eCompositionCommit event with the returned commit string (i.e., the value
+  // is aCommittedString of this method).  Finally, TextComposition instance in
+  // the remote process will be destroyed by
+  // IMEStateManager::DispatchCompositionEvent() at receiving the
+  // eCompositionCommit event (Note that TextComposition instance in this
+  // process was already destroyed).
+  return true;
 }
 
 void
 ContentCacheInParent::MaybeNotifyIME(nsIWidget* aWidget,
                                      const IMENotification& aNotification)
 {
   if (!mPendingEventsNeedingAck) {
     IMEStateManager::NotifyIME(aNotification, aWidget, true);
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -320,61 +320,59 @@ public:
    *
    * WARNING: This may send notifications to IME.  That might cause destroying
    *          TabParent or aWidget.  Therefore, the caller must not destroy
    *          this instance during a call of this method.
    */
   void OnEventNeedingAckHandled(nsIWidget* aWidget, EventMessage aMessage);
 
   /**
-   * RequestToCommitComposition() requests to commit or cancel composition to
-   * the widget.  If it's handled synchronously, this returns the number of
-   * composition events after that.
+   * RequestIMEToCommitComposition() requests aWidget to commit or cancel
+   * composition.  If it's handled synchronously, this returns true.
    *
    * @param aWidget     The widget to be requested to commit or cancel
    *                    the composition.
    * @param aCancel     When the caller tries to cancel the composition, true.
    *                    Otherwise, i.e., tries to commit the composition, false.
-   * @param aLastString The last composition string before requesting to
-   *                    commit or cancel composition.
-   * @return            The count of composition events ignored after a call of
-   *                    WillRequestToCommitOrCancelComposition().
+   * @param aCommittedString    The committed string (i.e., the last data of
+   *                            dispatched composition events during requesting
+   *                            IME to commit composition.
+   * @return            Whether the composition is actually committed
+   *                    synchronously.
    */
-  uint32_t RequestToCommitComposition(nsIWidget* aWidget,
-                                      bool aCancel,
-                                      nsAString& aLastString);
+  bool RequestIMEToCommitComposition(nsIWidget* aWidget,
+                                     bool aCancel,
+                                     nsAString& aCommittedString);
 
   /**
    * MaybeNotifyIME() may notify IME of the notification.  If child process
    * hasn't been handled all sending events yet, this stores the notification
    * and flush it later.
    */
   void MaybeNotifyIME(nsIWidget* aWidget,
                       const IMENotification& aNotification);
 
 private:
   IMENotification mPendingSelectionChange;
   IMENotification mPendingTextChange;
   IMENotification mPendingLayoutChange;
   IMENotification mPendingCompositionUpdate;
 
-  // This is commit string which is caused by our request.
-  nsString mCommitStringByRequest;
+  // This is not nullptr only while the instance is requesting IME to
+  // composition.  Then, data value of dispatched composition events should
+  // be stored into the instance.
+  nsAString* mCommitStringByRequest;
   // Start offset of the composition string.
   uint32_t mCompositionStart;
-  // Count of composition events during requesting commit or cancel the
-  // composition.
-  uint32_t mCompositionEventsDuringRequest;
   // mPendingEventsNeedingAck is increased before sending a composition event or
   // a selection event and decreased after they are received in the child
   // process.
   uint32_t mPendingEventsNeedingAck;
 
   bool mIsComposing;
-  bool mRequestedToCommitOrCancelComposition;
 
   bool GetCaretRect(uint32_t aOffset, LayoutDeviceIntRect& aCaretRect) const;
   bool GetTextRect(uint32_t aOffset,
                    LayoutDeviceIntRect& aTextRect) const;
   bool GetUnionTextRects(uint32_t aOffset,
                          uint32_t aLength,
                          LayoutDeviceIntRect& aUnionTextRect) const;
 
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -5,16 +5,18 @@
 
 #ifndef mozilla_widget_IMEData_h_
 #define mozilla_widget_IMEData_h_
 
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsStringGlue.h"
 
+class nsIWidget;
+
 namespace mozilla {
 
 class WritingMode;
 
 } // namespace mozilla
 
 /**
  * Preference for receiving IME updates
@@ -218,21 +220,68 @@ struct IMEState final
   // a plain text editor whose ime-mode is "disabled" or a windowless plugin
   // has focus.
   bool MaybeEditable() const
   {
     return IsEditable() || mEnabled == PLUGIN;
   }
 };
 
+// NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context.
+// If there can be only one IME composition in a process, this can be used.
+#define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
+  (reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
+
+struct NativeIMEContext final
+{
+  // Pointer to native IME context.  Typically this is the result of
+  // nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process.
+  // See also NS_ONLY_ONE_NATIVE_IME_CONTEXT.
+  uintptr_t mRawNativeIMEContext;
+  // Process ID of the origin of mNativeIMEContext.
+  uint64_t mOriginProcessID;
+
+  NativeIMEContext()
+  {
+    Init(nullptr);
+  }
+
+  explicit NativeIMEContext(nsIWidget* aWidget)
+  {
+    Init(aWidget);
+  }
+
+  bool IsValid() const
+  {
+    return mRawNativeIMEContext &&
+           mOriginProcessID != static_cast<uintptr_t>(-1);
+  }
+
+  void Init(nsIWidget* aWidget);
+  void InitWithRawNativeIMEContext(const void* aRawNativeIMEContext)
+  {
+    InitWithRawNativeIMEContext(const_cast<void*>(aRawNativeIMEContext));
+  }
+  void InitWithRawNativeIMEContext(void* aRawNativeIMEContext);
+
+  bool operator==(const NativeIMEContext& aOther) const
+  {
+    return mRawNativeIMEContext == aOther.mRawNativeIMEContext &&
+           mOriginProcessID == aOther.mOriginProcessID;
+  }
+  bool operator!=(const NativeIMEContext& aOther) const
+  {
+    return !(*this == aOther);
+  }
+};
+
 struct InputContext final
 {
   InputContext()
-    : mNativeIMEContext(nullptr)
-    , mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
+    : mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
     , mMayBeIMEUnaware(false)
   {
   }
 
   bool IsPasswordEditor() const
   {
     return mHTMLInputType.LowerCaseEqualsLiteral("password");
   }
@@ -243,21 +292,16 @@ struct InputContext final
   nsString mHTMLInputType;
 
   /* The type of the inputmode */
   nsString mHTMLInputInputmode;
 
   /* A hint for the action that is performed when the input is submitted */
   nsString mActionHint;
 
-  /* Native IME context for the widget.  This doesn't come from the argument of
-     SetInputContext().  If there is only one context in the process, this may
-     be nullptr. */
-  void* mNativeIMEContext;
-
   /**
    * mOrigin indicates whether this focus event refers to main or remote
    * content.
    */
   enum Origin
   {
     // Adjusting focus of content on the main process
     ORIGIN_MAIN,
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -74,19 +74,19 @@ const size_t PuppetWidget::kMaxDimension
 
 NS_IMPL_ISUPPORTS_INHERITED0(PuppetWidget, nsBaseWidget)
 
 PuppetWidget::PuppetWidget(TabChild* aTabChild)
   : mTabChild(aTabChild)
   , mMemoryPressureObserver(nullptr)
   , mDPI(-1)
   , mDefaultScale(-1)
-  , mNativeKeyCommandsValid(false)
   , mCursorHotspotX(0)
   , mCursorHotspotY(0)
+  , mNativeKeyCommandsValid(false)
 {
   MOZ_COUNT_CTOR(PuppetWidget);
 
   mSingleLineCommands.SetCapacity(4);
   mMultiLineCommands.SetCapacity(4);
   mRichTextCommands.SetCapacity(4);
 }
 
@@ -156,16 +156,21 @@ PuppetWidget::CreateChild(const LayoutDe
            NS_SUCCEEDED(widget->Create(isPopup ? nullptr: this, nullptr, aRect,
                                        aInitData))) ?
           widget.forget() : nullptr);
 }
 
 NS_IMETHODIMP
 PuppetWidget::Destroy()
 {
+  if (mOnDestroyCalled) {
+    return NS_OK;
+  }
+  mOnDestroyCalled = true;
+
   Base::OnDestroy();
   Base::Destroy();
   mPaintTask.Revoke();
   if (mMemoryPressureObserver) {
     mMemoryPressureObserver->Remove();
   }
   mMemoryPressureObserver = nullptr;
   mChild = nullptr;
@@ -314,16 +319,34 @@ PuppetWidget::DispatchEvent(WidgetGUIEve
   AutoCacheNativeKeyCommands autoCache(this);
   if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) {
     WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
     if (keyEvent) {
       mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent);
     }
   }
 
+  if (event->mClass == eCompositionEventClass) {
+    // Store the latest native IME context of parent process's widget or
+    // TextEventDispatcher if it's in this process.
+    WidgetCompositionEvent* compositionEvent = event->AsCompositionEvent();
+#ifdef DEBUG
+    if (mNativeIMEContext.IsValid() &&
+        mNativeIMEContext != compositionEvent->mNativeIMEContext) {
+      RefPtr<TextComposition> composition =
+        IMEStateManager::GetTextCompositionFor(this);
+      MOZ_ASSERT(!composition,
+        "When there is composition caused by old native IME context, "
+        "composition events caused by different native IME context are not "
+        "allowed");
+    }
+#endif // #ifdef DEBUG
+    mNativeIMEContext = compositionEvent->mNativeIMEContext;
+  }
+
   aStatus = nsEventStatus_eIgnore;
 
   if (GetCurrentWidgetListener()) {
     aStatus = GetCurrentWidgetListener()->HandleEvent(event, mUseAttachedEvents);
   }
 
   return NS_OK;
 }
@@ -563,50 +586,72 @@ PuppetWidget::GetLayerManager(PLayerTran
   }
   if (aAllowRetaining) {
     *aAllowRetaining = true;
   }
   return mLayerManager;
 }
 
 nsresult
-PuppetWidget::IMEEndComposition(bool aCancel)
+PuppetWidget::RequestIMEToCommitComposition(bool aCancel)
 {
-#ifndef MOZ_CROSS_PROCESS_IME
-  return NS_OK;
-#endif
-
-  nsEventStatus status;
-  bool noCompositionEvent = true;
-  WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this);
-  InitEvent(compositionCommitEvent, nullptr);
-  // SendEndIMEComposition is always called since ResetInputState
-  // should always be called even if we aren't composing something.
-  if (!mTabChild ||
-      !mTabChild->SendEndIMEComposition(aCancel, &noCompositionEvent,
-                                        &compositionCommitEvent.mData)) {
+#ifdef MOZ_CROSS_PROCESS_IME
+  if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
 
-  if (noCompositionEvent) {
+  MOZ_ASSERT(!Destroyed());
+
+  // There must not be composition which is caused by the PuppetWidget instance.
+  if (NS_WARN_IF(!mNativeIMEContext.IsValid())) {
+    return NS_OK;
+  }
+
+  RefPtr<TextComposition> composition =
+    IMEStateManager::GetTextCompositionFor(this);
+  // This method shouldn't be called when there is no text composition instance.
+  if (NS_WARN_IF(!composition)) {
     return NS_OK;
   }
 
+  bool isCommitted = false;
+  nsAutoString committedString;
+  if (NS_WARN_IF(!mTabChild->SendRequestIMEToCommitComposition(
+                               aCancel, &isCommitted, &committedString))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // If the composition wasn't committed synchronously, we need to wait async
+  // composition events for destroying the TextComposition instance.
+  if (!isCommitted) {
+    return NS_OK;
+  }
+
+  // Dispatch eCompositionCommit event.
+  WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this);
+  InitEvent(compositionCommitEvent, nullptr);
+  compositionCommitEvent.mData = committedString;
+  nsEventStatus status = nsEventStatus_eIgnore;
   DispatchEvent(&compositionCommitEvent, status);
+
+  // NOTE: PuppetWidget might be destroyed already.
+
+#endif // #ifdef MOZ_CROSS_PROCESS_IME
+
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
 {
   switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
-      return IMEEndComposition(false);
+      return RequestIMEToCommitComposition(false);
     case REQUEST_TO_CANCEL_COMPOSITION:
-      return IMEEndComposition(true);
+      return RequestIMEToCommitComposition(true);
     case NOTIFY_IME_OF_FOCUS:
     case NOTIFY_IME_OF_BLUR:
       return NotifyIMEOfFocusChange(aIMENotification);
     case NOTIFY_IME_OF_SELECTION_CHANGE:
       return NotifyIMEOfSelectionChange(aIMENotification);
     case NOTIFY_IME_OF_TEXT_CHANGE:
       return NotifyIMEOfTextChange(aIMENotification);
     case NOTIFY_IME_OF_COMPOSITION_UPDATE:
@@ -670,25 +715,30 @@ PuppetWidget::GetInputContext()
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return InputContext();
 #endif
 
   InputContext context;
   if (mTabChild) {
     int32_t enabled, open;
-    intptr_t nativeIMEContext;
-    mTabChild->SendGetInputContext(&enabled, &open, &nativeIMEContext);
+    // TODO: This is too expensive. PuppetWidget should cache IMEState.
+    mTabChild->SendGetInputContext(&enabled, &open);
     context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled);
     context.mIMEState.mOpen = static_cast<IMEState::Open>(open);
-    context.mNativeIMEContext = reinterpret_cast<void*>(nativeIMEContext);
   }
   return context;
 }
 
+NS_IMETHODIMP_(NativeIMEContext)
+PuppetWidget::GetNativeIMEContext()
+{
+  return mNativeIMEContext;
+}
+
 nsresult
 PuppetWidget::NotifyIMEOfFocusChange(const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
@@ -1116,16 +1166,18 @@ PuppetWidget::GetNativeData(uint32_t aDa
       mTabChild->SendGetWidgetNativeData(&nativeData);
     }
     return (void*)nativeData;
   }
   case NS_NATIVE_WIDGET:
   case NS_NATIVE_DISPLAY:
     // These types are ignored (see bug 1183828).
     break;
+  case NS_RAW_NATIVE_IME_CONTEXT:
+    MOZ_CRASH("You need to call GetNativeIMEContext() instead");
   case NS_NATIVE_WINDOW:
   case NS_NATIVE_PLUGIN_PORT:
   case NS_NATIVE_GRAPHIC:
   case NS_NATIVE_SHELLWIDGET:
   default:
     NS_WARNING("nsWindow::GetNativeData called with bad value");
     break;
   }
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -174,16 +174,17 @@ public:
   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                   LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                   bool* aAllowRetaining = nullptr) override;
 
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction) override;
   NS_IMETHOD_(InputContext) GetInputContext() override;
+  NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext() override;
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
 
   NS_IMETHOD SetCursor(nsCursor aCursor) override;
   NS_IMETHOD SetCursor(imgIContainer* aCursor,
                        uint32_t aHotspotX, uint32_t aHotspotY) override;
 
   virtual void ClearCachedCursor() override;
 
@@ -249,28 +250,25 @@ public:
   virtual nsresult SynthesizeNativeTouchTap(ScreenIntPoint aPointerScreenPoint,
                                             bool aLongTap,
                                             nsIObserver* aObserver) override;
   virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver) override;
   virtual uint32_t GetMaxTouchPoints() const override;
 
   virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
 protected:
-  bool mEnabled;
-  bool mVisible;
-
   virtual nsresult NotifyIMEInternal(
                      const IMENotification& aIMENotification) override;
 
 private:
   nsresult Paint();
 
   void SetChild(PuppetWidget* aChild);
 
-  nsresult IMEEndComposition(bool aCancel);
+  nsresult RequestIMEToCommitComposition(bool aCancel);
   nsresult NotifyIMEOfFocusChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfSelectionChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfCompositionUpdate(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfMouseButtonEvent(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfPositionChange(const IMENotification& aIMENotification);
 
   bool CacheEditorRect();
@@ -317,31 +315,43 @@ private:
   nsRevocableEventPtr<PaintTask> mPaintTask;
   RefPtr<MemoryPressureObserver> mMemoryPressureObserver;
   // XXX/cjones: keeping this around until we teach LayerManager to do
   // retained-content-only transactions
   RefPtr<DrawTarget> mDrawTarget;
   // IME
   nsIMEUpdatePreference mIMEPreferenceOfParent;
   InputContext mInputContext;
+  // mNativeIMEContext is initialized when this dispatches every composition
+  // event both from parent process's widget and TextEventDispatcher in same
+  // process.  If it hasn't been started composition yet, this isn't necessary
+  // for XP code since there is no TextComposition instance which is caused by
+  // the PuppetWidget instance.
+  NativeIMEContext mNativeIMEContext;
   ContentCacheInChild mContentCache;
-  bool mNeedIMEStateInit;
 
   // The DPI of the screen corresponding to this widget
   float mDPI;
   double mDefaultScale;
 
   // Precomputed answers for ExecuteNativeKeyBinding
-  bool mNativeKeyCommandsValid;
   InfallibleTArray<mozilla::CommandInt> mSingleLineCommands;
   InfallibleTArray<mozilla::CommandInt> mMultiLineCommands;
   InfallibleTArray<mozilla::CommandInt> mRichTextCommands;
 
   nsCOMPtr<imgIContainer> mCustomCursor;
   uint32_t mCursorHotspotX, mCursorHotspotY;
+
+protected:
+  bool mEnabled;
+  bool mVisible;
+
+private:
+  bool mNeedIMEStateInit;
+  bool mNativeKeyCommandsValid;
 };
 
 struct AutoCacheNativeKeyCommands
 {
   explicit AutoCacheNativeKeyCommands(PuppetWidget* aWidget)
     : mWidget(aWidget)
   {
     mSavedValid = mWidget->mNativeKeyCommandsValid;
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -129,16 +129,27 @@ TextEventDispatcher::GetState() const
 }
 
 void
 TextEventDispatcher::InitEvent(WidgetGUIEvent& aEvent) const
 {
   aEvent.time = PR_IntervalNow();
   aEvent.refPoint = LayoutDeviceIntPoint(0, 0);
   aEvent.mFlags.mIsSynthesizedForTests = mForTests;
+  if (aEvent.mClass != eCompositionEventClass) {
+    return;
+  }
+  // Currently, we should set special native IME context when composition
+  // events are dispatched from PuppetWidget since PuppetWidget may have not
+  // known actual native IME context yet and it caches native IME context
+  // when it dispatches every WidgetCompositionEvent.
+  if (XRE_IsContentProcess()) {
+    aEvent.AsCompositionEvent()->
+      mNativeIMEContext.InitWithRawNativeIMEContext(mWidget);
+  }
 }
 
 nsresult
 TextEventDispatcher::DispatchEvent(nsIWidget* aWidget,
                                    WidgetGUIEvent& aEvent,
                                    nsEventStatus& aStatus)
 {
   MOZ_ASSERT(!aEvent.AsInputEvent(), "Use DispatchInputEvent()");
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -361,16 +361,17 @@ public:
   virtual WidgetCompositionEvent* AsCompositionEvent() override
   {
     return this;
   }
 
   WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
                          nsIWidget* aWidget)
     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass)
+    , mNativeIMEContext(aWidget)
     , mOriginalMessage(eVoidEvent)
   {
     // XXX compositionstart is cancelable in draft of DOM3 Events.
     //     However, it doesn't make sense for us, we cannot cancel composition
     //     when we send compositionstart event.
     mFlags.mCancelable = false;
   }
 
@@ -388,16 +389,20 @@ public:
 
   // The composition string or the commit string.  If the instance is a
   // compositionstart event, this is initialized with selected text by
   // TextComposition automatically.
   nsString mData;
 
   RefPtr<TextRangeArray> mRanges;
 
+  // mNativeIMEContext stores the native IME context which causes the
+  // composition event.
+  widget::NativeIMEContext mNativeIMEContext;
+
   // If the instance is a clone of another event, mOriginalMessage stores
   // the another event's mMessage.
   EventMessage mOriginalMessage;
 
   void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
                                   bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -398,28 +398,14 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
 {
     // FIXME implement this
     return true;
 }
 
 NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(JNIEnv* env, jobject instance, jint overscrollMode)
-{
-    // FIXME implement this
-}
-
-NS_EXPORT jint JNICALL
-Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env, jobject instance)
-{
-    // FIXME implement this
-    return 0;
-}
-
-
-NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_setIsLongpressEnabled(JNIEnv* env, jobject instance, jboolean isLongpressEnabled)
 {
     APZCTreeManager::SetLongTapEnabled(isLongpressEnabled);
 }
 
 }
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1258,16 +1258,21 @@ nsWindow::GetNativeData(uint32_t aDataTy
 {
     switch (aDataType) {
         // used by GLContextProviderEGL, nullptr is EGL_DEFAULT_DISPLAY
         case NS_NATIVE_DISPLAY:
             return nullptr;
 
         case NS_NATIVE_WIDGET:
             return (void *) this;
+
+        case NS_RAW_NATIVE_IME_CONTEXT:
+            // We assume that there is only one context per process on Android
+            return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
+
     }
 
     return nullptr;
 }
 
 void
 nsWindow::OnMouseEvent(AndroidGeckoEvent *ae)
 {
@@ -2239,18 +2244,16 @@ nsWindow::Natives::SetInputContext(const
     });
 }
 
 InputContext
 nsWindow::Natives::GetInputContext()
 {
     InputContext context = mInputContext;
     context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-    // We assume that there is only one context per process on Android
-    context.mNativeIMEContext = nullptr;
     return context;
 }
 
 void
 nsWindow::Natives::OnImeSynchronize()
 {
     if (!mIMEMaskEventsCount) {
         FlushIMEChanges();
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -679,16 +679,27 @@ void* nsChildView::GetNativeData(uint32_
 
     case NS_NATIVE_OFFSETX:
       retVal = 0;
       break;
 
     case NS_NATIVE_OFFSETY:
       retVal = 0;
       break;
+
+    case NS_RAW_NATIVE_IME_CONTEXT:
+      retVal = [mView inputContext];
+      // If input context isn't available on this widget, we should set |this|
+      // instead of nullptr since if this returns nullptr, IMEStateManager
+      // cannot manage composition with TextComposition instance.  Although,
+      // this case shouldn't occur.
+      if (NS_WARN_IF(!retVal)) {
+        retVal = this;
+      }
+      break;
   }
 
   return retVal;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
 }
 
 #pragma mark -
@@ -1764,23 +1775,16 @@ nsChildView::GetInputContext()
         break;
       }
       // If mTextInputHandler is null, set CLOSED instead...
       MOZ_FALLTHROUGH;
     default:
       mInputContext.mIMEState.mOpen = IMEState::CLOSED;
       break;
   }
-  mInputContext.mNativeIMEContext = [mView inputContext];
-  // If input context isn't available on this widget, we should set |this|
-  // instead of nullptr since nullptr means that the platform has only one
-  // context per process.
-  if (!mInputContext.mNativeIMEContext) {
-    mInputContext.mNativeIMEContext = this;
-  }
   return mInputContext;
 }
 
 NS_IMETHODIMP
 nsChildView::AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
   return mTextInputHandler->AttachNativeKeyEvent(aEvent);
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -360,26 +360,16 @@ public:
     void SetMenuBar(nsMenuBarX* aMenuBar);
     nsMenuBarX *GetMenuBar();
 
     NS_IMETHOD_(void) SetInputContext(
                         const InputContext& aContext,
                         const InputContextAction& aAction) override;
     NS_IMETHOD_(InputContext) GetInputContext() override
     {
-      NSView* view = mWindow ? [mWindow contentView] : nil;
-      if (view) {
-        mInputContext.mNativeIMEContext = [view inputContext];
-      }
-      // If inputContext isn't available on this window, returns this window's
-      // pointer since nullptr means the platform has only one context per
-      // process.
-      if (!mInputContext.mNativeIMEContext) {
-        mInputContext.mNativeIMEContext = this;
-      }
       return mInputContext;
     }
     NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
                         NativeKeyBindingsType aType,
                         const mozilla::WidgetKeyboardEvent& aEvent,
                         DoCommandCallback aCallback,
                         void* aCallbackData) override;
 
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -587,16 +587,30 @@ void* nsCocoaWindow::GetNativeData(uint3
       retVal = mWindow;
       break;
       
     case NS_NATIVE_GRAPHIC:
       // There isn't anything that makes sense to return here,
       // and it doesn't matter so just return nullptr.
       NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a top-level window!");
       break;
+    case NS_RAW_NATIVE_IME_CONTEXT: {
+      NSView* view = mWindow ? [mWindow contentView] : nil;
+      if (view) {
+        retVal = [view inputContext];
+      }
+      // If inputContext isn't available on this window, return this window's
+      // pointer instead of nullptr since if this returns nullptr,
+      // IMEStateManager cannot manage composition with TextComposition
+      // instance.  Although, this case shouldn't occur.
+      if (NS_WARN_IF(!retVal)) {
+        retVal = this;
+      }
+      break;
+    }
   }
 
   return retVal;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
 }
 
 bool nsCocoaWindow::IsVisible() const
--- a/widget/gonk/nsClipboard.cpp
+++ b/widget/gonk/nsClipboard.cpp
@@ -115,23 +115,22 @@ nsClipboard::SetData(nsITransferable *aT
 
         nsAutoString utf16string;
         wideString->GetData(utf16string);
         mClipboard->SetHTML(utf16string);
       } else if (!imageAdded && // image is added only once to the clipboard.
                  (flavorStr.EqualsLiteral(kNativeImageMime) ||
                   flavorStr.EqualsLiteral(kPNGImageMime) ||
                   flavorStr.EqualsLiteral(kJPEGImageMime) ||
-                  flavorStr.EqualsLiteral(kJPGImageMime) ||
-                  flavorStr.EqualsLiteral(kGIFImageMime))) {
-        // image/[png|jpeg|jpg|gif] or application/x-moz-nativeimage
+                  flavorStr.EqualsLiteral(kJPGImageMime))) {
+        // image/[png|jpeg|jpg] or application/x-moz-nativeimage
 
         // Look through our transfer data for the image.
         static const char* const imageMimeTypes[] = {
-          kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime, kGIFImageMime };
+          kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime };
 
         nsCOMPtr<nsISupportsInterfacePointer> imgPtr;
         for (uint32_t i = 0; !imgPtr && i < ArrayLength(imageMimeTypes); ++i) {
           aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len);
           imgPtr = do_QueryInterface(clip);
         }
         if (!imgPtr) {
           continue;
@@ -254,21 +253,20 @@ nsClipboard::GetData(nsITransferable *aT
         uint32_t len = mClipboard->GetHTML().Length() * sizeof(char16_t);
         rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           continue;
         }
         break;
       }
 
-      // image/[png|jpeg|jpg|gif]
+      // image/[png|jpeg|jpg]
       if ((flavorStr.EqualsLiteral(kPNGImageMime) ||
            flavorStr.EqualsLiteral(kJPEGImageMime) ||
-           flavorStr.EqualsLiteral(kJPGImageMime) ||
-           flavorStr.EqualsLiteral(kGIFImageMime)) &&
+           flavorStr.EqualsLiteral(kJPGImageMime)) &&
           mClipboard->HasImage() ) {
         // Get image buffer from clipboard.
         RefPtr<gfx::DataSourceSurface> image = mClipboard->GetImage();
 
         // Encode according to MIME type.
         RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, image->GetSize());
         nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable));
         nsCOMPtr<imgITools> imgTool = do_GetService(NS_IMGTOOLS_CID);
@@ -323,18 +321,17 @@ nsClipboard::HasDataMatchingFlavors(cons
         continue;
       }
       if (!strcmp(flavor, kUnicodeMime) && mClipboard->HasText()) {
         *aHasType = true;
       } else if (!strcmp(flavor, kHTMLMime) && mClipboard->HasHTML()) {
         *aHasType = true;
       } else if (!strcmp(flavor, kJPEGImageMime) ||
                  !strcmp(flavor, kJPGImageMime) ||
-                 !strcmp(flavor, kPNGImageMime) ||
-                 !strcmp(flavor, kGIFImageMime)) {
+                 !strcmp(flavor, kPNGImageMime)) {
         // We will encode the image into any format you want, so we don't
         // need to check each specific format
         if (mClipboard->HasImage()) {
           *aHasType = true;
         }
       }
     }
   } else {
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -534,16 +534,19 @@ void*
 nsWindow::GetNativeData(uint32_t aDataType)
 {
     switch (aDataType) {
     case NS_NATIVE_WINDOW:
         // Called before primary display's EGLSurface creation.
         return mScreen->GetNativeWindow();
     case NS_NATIVE_OPENGL_CONTEXT:
         return mScreen->GetGLContext().take();
+    case NS_RAW_NATIVE_IME_CONTEXT:
+        // There is only one IME context on Gonk.
+        return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
     }
 
     return nullptr;
 }
 
 void
 nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
 {
@@ -577,18 +580,16 @@ nsWindow::SetInputContext(const InputCon
                           const InputContextAction& aAction)
 {
     mInputContext = aContext;
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
-    // There is only one IME context on Gonk.
-    mInputContext.mNativeIMEContext = nullptr;
     return mInputContext;
 }
 
 NS_IMETHODIMP
 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
 {
     return NS_OK;
 }
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1732,16 +1732,25 @@ nsWindow::GetNativeData(uint32_t aDataTy
 
     case NS_NATIVE_SHELLWIDGET:
         return GetToplevelWidget();
 
     case NS_NATIVE_SHAREABLE_WINDOW:
         return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
     case NS_NATIVE_PLUGIN_OBJECT_PTR:
         return (void *) mPluginNativeWindow;
+    case NS_RAW_NATIVE_IME_CONTEXT:
+        // If IME context isn't available on this widget, we should set |this|
+        // instead of nullptr since if we return nullptr, IMEStateManager
+        // cannot manage composition with TextComposition instance.  Although,
+        // this case shouldn't occur.
+        if (NS_WARN_IF(!mIMContext)) {
+            return this;
+        }
+        return mIMContext.get();
     default:
         NS_WARNING("nsWindow::GetNativeData called with bad value");
         return nullptr;
     }
 }
 
 void
 nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
@@ -6290,23 +6299,18 @@ nsWindow::SetInputContext(const InputCon
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
   InputContext context;
   if (!mIMContext) {
       context.mIMEState.mEnabled = IMEState::DISABLED;
       context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-      // If IME context isn't available on this widget, we should set |this|
-      // instead of nullptr since nullptr means that the platform has only one
-      // context per process.
-      context.mNativeIMEContext = this;
   } else {
       context = mIMContext->GetInputContext();
-      context.mNativeIMEContext = mIMContext;
   }
   return context;
 }
 
 nsIMEUpdatePreference
 nsWindow::GetIMEUpdatePreference()
 {
     if (!mIMContext) {
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -48,16 +48,17 @@
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/VsyncDispatcher.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZEventState.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/ChromeProcessController.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/Services.h"
 #include "mozilla/Snprintf.h"
 #include "nsRefPtrHashtable.h"
 #include "TouchEvents.h"
 #include "WritingModes.h"
 #include "InputData.h"
@@ -81,16 +82,17 @@ static int32_t gNumWidgets;
 #endif
 
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 static nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>* sPluginWidgetList;
 #endif
 
 nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
 
+using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::ipc;
 using namespace mozilla::widget;
 using namespace mozilla;
 using base::Thread;
 
 nsIContent* nsBaseWidget::mLastRollup = nullptr;
 // Global user preference for disabling native theme. Used
@@ -2074,20 +2076,60 @@ nsIWidget::SnapshotWidgetOnScreen()
                   gfx::Rect(gfx::Point(), gfx::Size(size)),
                   gfx::Rect(gfx::Point(), gfx::Size(size)),
                   gfx::DrawSurfaceOptions(gfx::Filter::POINT));
 
   forwarder->DestroySharedSurface(&surface);
   return dt->Snapshot();
 }
 
+NS_IMETHODIMP_(nsIWidget::NativeIMEContext)
+nsIWidget::GetNativeIMEContext()
+{
+  return NativeIMEContext(this);
+}
+
 namespace mozilla {
 namespace widget {
 
 void
+NativeIMEContext::Init(nsIWidget* aWidget)
+{
+  if (!aWidget) {
+    mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
+    mOriginProcessID = static_cast<uint64_t>(-1);
+    return;
+  }
+  if (!XRE_IsContentProcess()) {
+    mRawNativeIMEContext = reinterpret_cast<uintptr_t>(
+      aWidget->GetNativeData(NS_RAW_NATIVE_IME_CONTEXT));
+    mOriginProcessID = 0;
+    return;
+  }
+  // If this is created in a child process, aWidget is an instance of
+  // PuppetWidget which doesn't support NS_RAW_NATIVE_IME_CONTEXT.
+  // Instead of that PuppetWidget::GetNativeIMEContext() returns cached
+  // native IME context of the parent process.
+  *this = aWidget->GetNativeIMEContext();
+}
+
+void
+NativeIMEContext::InitWithRawNativeIMEContext(void* aRawNativeIMEContext)
+{
+  if (NS_WARN_IF(!aRawNativeIMEContext)) {
+    mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
+    mOriginProcessID = static_cast<uint64_t>(-1);
+    return;
+  }
+  mRawNativeIMEContext = reinterpret_cast<uintptr_t>(aRawNativeIMEContext);
+  mOriginProcessID =
+    XRE_IsContentProcess() ? ContentChild::GetSingleton()->GetID() : 0;
+}
+
+void
 IMENotification::TextChangeDataBase::MergeWith(
                    const IMENotification::TextChangeDataBase& aOther)
 {
   MOZ_ASSERT(aOther.IsValid(),
              "Merging data must store valid data");
   MOZ_ASSERT(aOther.mStartOffset <= aOther.mRemovedEndOffset,
              "end of removed text must be same or larger than start");
   MOZ_ASSERT(aOther.mStartOffset <= aOther.mAddedEndOffset,
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -539,29 +539,31 @@ template<>
 struct ParamTraits<mozilla::WidgetCompositionEvent>
 {
   typedef mozilla::WidgetCompositionEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
     WriteParam(aMsg, aParam.mData);
+    WriteParam(aMsg, aParam.mNativeIMEContext);
     bool hasRanges = !!aParam.mRanges;
     WriteParam(aMsg, hasRanges);
     if (hasRanges) {
       WriteParam(aMsg, *aParam.mRanges.get());
     }
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     bool hasRanges;
     if (!ReadParam(aMsg, aIter,
                    static_cast<mozilla::WidgetGUIEvent*>(aResult)) ||
         !ReadParam(aMsg, aIter, &aResult->mData) ||
+        !ReadParam(aMsg, aIter, &aResult->mNativeIMEContext) ||
         !ReadParam(aMsg, aIter, &hasRanges)) {
       return false;
     }
 
     if (!hasRanges) {
       aResult->mRanges = nullptr;
     } else {
       aResult->mRanges = new mozilla::TextRangeArray();
@@ -677,16 +679,34 @@ struct ParamTraits<nsIMEUpdatePreference
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mWantUpdates);
   }
 };
 
 template<>
+struct ParamTraits<mozilla::widget::NativeIMEContext>
+{
+  typedef mozilla::widget::NativeIMEContext paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mRawNativeIMEContext);
+    WriteParam(aMsg, aParam.mOriginProcessID);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mRawNativeIMEContext) &&
+           ReadParam(aMsg, aIter, &aResult->mOriginProcessID);
+  }
+};
+
+template<>
 struct ParamTraits<mozilla::widget::IMENotification::Point>
 {
   typedef mozilla::widget::IMENotification::Point paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mX);
     WriteParam(aMsg, aParam.mY);
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -99,17 +99,24 @@ typedef void* nsNativeWidget;
 #define NS_NATIVE_SCREEN      9
 // The toplevel GtkWidget containing this nsIWidget:
 #define NS_NATIVE_SHELLWIDGET 10
 // Has to match to NPNVnetscapeWindow, and shareable across processes
 // HWND on Windows and XID on X11
 #define NS_NATIVE_SHAREABLE_WINDOW 11
 #define NS_NATIVE_OPENGL_CONTEXT   12
 // See RegisterPluginWindowForRemoteUpdates
-#define NS_NATIVE_PLUGIN_ID            13
+#define NS_NATIVE_PLUGIN_ID        13
+// This is available only with GetNativeData() in parent process.  Anybody
+// shouldn't access this pointer as a valid pointer since the result may be
+// special value like NS_ONLY_ONE_NATIVE_IME_CONTEXT.  So, the result is just
+// an identifier of distinguishing a text composition is caused by which native
+// IME context.  Note that the result is only valid in the process.  So,
+// XP code should use nsIWidget::GetNativeIMEContext() instead of using this.
+#define NS_RAW_NATIVE_IME_CONTEXT  14
 #ifdef XP_MACOSX
 #define NS_NATIVE_PLUGIN_PORT_QD    100
 #define NS_NATIVE_PLUGIN_PORT_CG    101
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
@@ -118,18 +125,18 @@ typedef void* nsNativeWidget;
 #define NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW 105
 #endif
 #if defined(MOZ_WIDGET_GTK)
 // set/get nsPluginNativeWindowGtk, e10s specific
 #define NS_NATIVE_PLUGIN_OBJECT_PTR    104
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0xd953b7a1, 0x6981, 0x4ed7, \
-  { 0xbc, 0xf0, 0xed, 0x96, 0x70, 0xee, 0x23, 0x28 } }
+{ 0xaaa79c8d, 0xc99d, 0x4fe1, \
+  { 0xa5, 0x11, 0xd3, 0xeb, 0xb1, 0x61, 0x9e, 0x26 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -324,16 +331,17 @@ class nsIWidget : public nsISupports {
     typedef mozilla::layers::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
     typedef mozilla::layers::ZoomConstraints ZoomConstraints;
     typedef mozilla::widget::IMEMessage IMEMessage;
     typedef mozilla::widget::IMENotification IMENotification;
     typedef mozilla::widget::IMEState IMEState;
     typedef mozilla::widget::InputContext InputContext;
     typedef mozilla::widget::InputContextAction InputContextAction;
+    typedef mozilla::widget::NativeIMEContext NativeIMEContext;
     typedef mozilla::widget::SizeConstraints SizeConstraints;
     typedef mozilla::widget::TextEventDispatcher TextEventDispatcher;
     typedef mozilla::CompositorVsyncDispatcher CompositorVsyncDispatcher;
     typedef mozilla::LayoutDeviceIntMargin LayoutDeviceIntMargin;
     typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
     typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
     typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
     typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
@@ -1786,16 +1794,23 @@ public:
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction) = 0;
 
     /*
      * Get current input context.
      */
     NS_IMETHOD_(InputContext) GetInputContext() = 0;
 
+    /**
+     * Get native IME context.  This is different from GetNativeData() with
+     * NS_RAW_NATIVE_IME_CONTEXT, the result is unique even if in a remote
+     * process.
+     */
+    NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext();
+
     /*
      * Given a WidgetKeyboardEvent, this method synthesizes a corresponding
      * native (OS-level) event for it. This method allows tests to simulate
      * keystrokes that trigger native key bindings (which require a native
      * event).
      */
     NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) = 0;
 
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -659,16 +659,20 @@ nsWindow::GetNativeData(uint32_t aDataTy
 #endif
         break;
     }
     case NS_NATIVE_PLUGIN_PORT:
     case NS_NATIVE_GRAPHIC:
     case NS_NATIVE_SHELLWIDGET: {
         break;
     }
+    case NS_RAW_NATIVE_IME_CONTEXT:
+        // Our qt widget looks like using only one context per process.
+        // However, it's better to set the context's pointer.
+        return qApp->inputMethod();
     default:
         NS_WARNING("nsWindow::GetNativeData called with bad value");
         return nullptr;
     }
     LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType));
     return nullptr;
 }
 
@@ -711,20 +715,16 @@ nsWindow::SetInputContext(const InputCon
             break;
     }
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
     mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-    // Our qt widget looks like using only one context per process.
-    // However, it's better to set the context's pointer.
-    mInputContext.mNativeIMEContext = qApp->inputMethod();
-
     return mInputContext;
 }
 
 NS_IMETHODIMP
 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
 {
     NS_PRECONDITION(aNewParent, "");
 
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -831,17 +831,16 @@ nsWindow::SetInputContext(const InputCon
 {
     //TODO: actually show VKB
     mInputContext = aContext;
 }
 
 NS_IMETHODIMP_(mozilla::widget::InputContext)
 nsWindow::GetInputContext()
 {
-    mInputContext.mNativeIMEContext = nullptr;
     return mInputContext;
 }
 
 void
 nsWindow::SetBackgroundColor(const nscolor &aColor)
 {
     mNativeView.backgroundColor = [UIColor colorWithRed:NS_GET_R(aColor)
                                    green:NS_GET_G(aColor)
@@ -874,16 +873,20 @@ void* nsWindow::GetNativeData(uint32_t a
 
     case NS_NATIVE_OFFSETY:
       retVal = 0;
       break;
 
     case NS_NATIVE_PLUGIN_PORT:
         // not implemented
         break;
+
+    case NS_RAW_NATIVE_IME_CONTEXT:
+      retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
+      break;
   }
 
   return retVal;
 }
 
 CGFloat
 nsWindow::BackingScaleFactor()
 {
--- a/widget/windows/IMMHandler.cpp
+++ b/widget/windows/IMMHandler.cpp
@@ -181,16 +181,40 @@ IMEContext::IMEContext(HWND aWnd)
 }
 
 IMEContext::IMEContext(nsWindow* aWindow)
   : mWnd(aWindow->GetWindowHandle())
   , mIMC(::ImmGetContext(aWindow->GetWindowHandle()))
 {
 }
 
+void
+IMEContext::Init(HWND aWnd)
+{
+  Clear();
+  mWnd = aWnd;
+  mIMC = ::ImmGetContext(mWnd);
+}
+
+void
+IMEContext::Init(nsWindow* aWindow)
+{
+  Init(aWindow->GetWindowHandle());
+}
+
+void
+IMEContext::Clear()
+{
+  if (mWnd && mIMC) {
+    ::ImmReleaseContext(mWnd, mIMC);
+  }
+  mWnd = nullptr;
+  mIMC = nullptr;
+}
+
 /******************************************************************************
  * IMMHandler
  ******************************************************************************/
 
 static UINT sWM_MSIME_MOUSE = 0; // mouse message for MSIME 98/2000
 
 WritingMode IMMHandler::sWritingModeOfCompositionFont;
 nsString IMMHandler::sIMEName;
--- a/widget/windows/IMMHandler.h
+++ b/widget/windows/IMMHandler.h
@@ -21,32 +21,39 @@ class nsWindow;
 namespace mozilla {
 namespace widget {
 
 struct MSGResult;
 
 class IMEContext final
 {
 public:
+  IMEContext()
+    : mWnd(nullptr)
+    , mIMC(nullptr)
+  {
+  }
+
   explicit IMEContext(HWND aWnd);
   explicit IMEContext(nsWindow* aWindow);
 
   ~IMEContext()
   {
-    if (mIMC) {
-      ::ImmReleaseContext(mWnd, mIMC);
-      mIMC = nullptr;
-    }
+    Clear();
   }
 
   HIMC get() const
   {
     return mIMC;
   }
 
+  void Init(HWND aWnd);
+  void Init(nsWindow* aWindow);
+  void Clear();
+
   bool IsValid() const
   {
     return !!mIMC;
   }
 
   void SetOpenState(bool aOpen) const
   {
     if (!mIMC) {
@@ -85,21 +92,16 @@ public:
       return false;
     }
     ::ImmReleaseContext(mWnd, mIMC);
     mIMC = nullptr;
     return true;
   }
 
 protected:
-  IMEContext()
-  {
-    MOZ_CRASH("Don't create IMEContext without window handle");
-  }
-
   IMEContext(const IMEContext& aOther)
   {
     MOZ_CRASH("Don't copy IMEContext");
   }
 
   HWND mWnd;
   HIMC mIMC;
 };
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -89,18 +89,41 @@ IMEHandler::Terminate()
   }
 #endif // #ifdef NS_ENABLE_TSF
 
   IMMHandler::Terminate();
 }
 
 // static
 void*
-IMEHandler::GetNativeData(uint32_t aDataType)
+IMEHandler::GetNativeData(nsWindow* aWindow, uint32_t aDataType)
 {
+  if (aDataType == NS_RAW_NATIVE_IME_CONTEXT) {
+#ifdef NS_ENABLE_TSF
+    if (IsTSFAvailable()) {
+      return TSFTextStore::GetThreadManager();
+    }
+#endif // #ifdef NS_ENABLE_TSF
+    IMEContext context(aWindow);
+    if (context.IsValid()) {
+      return context.get();
+    }
+    // If IMC isn't associated with the window, IME is disabled on the window
+    // now.  In such case, we should return default IMC instead.
+    const IMEContext& defaultIMC = aWindow->DefaultIMC();
+    if (defaultIMC.IsValid()) {
+      return defaultIMC.get();
+    }
+    // If there is no default IMC, we should return the pointer to the window
+    // since if we return nullptr, IMEStateManager cannot manage composition
+    // with TextComposition instance.  This is possible if no IME is installed,
+    // but composition may occur with dead key sequence.
+    return aWindow;
+  }
+
 #ifdef NS_ENABLE_TSF
   void* result = TSFTextStore::GetNativeData(aDataType);
   if (!result || !(*(static_cast<void**>(result)))) {
     return nullptr;
   }
   // XXX During the TSF module test, sIsInTSFMode must be true.  After that,
   //     the value should be restored but currently, there is no way for that.
   //     When the TSF test is enabled again, we need to fix this.  Perhaps,
@@ -379,24 +402,21 @@ IMEHandler::SetInputContext(nsWindow* aW
   }
 
   bool enable = WinUtils::IsIMEEnabled(aInputContext);
   bool adjustOpenState = (enable &&
     aInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE);
   bool open = (adjustOpenState &&
     aInputContext.mIMEState.mOpen == IMEState::OPEN);
 
-  aInputContext.mNativeIMEContext = nullptr;
-
 #ifdef NS_ENABLE_TSF
   // Note that even while a plugin has focus, we need to notify TSF of that.
   if (sIsInTSFMode) {
     TSFTextStore::SetInputContext(aWindow, aInputContext, aAction);
     if (IsTSFAvailable()) {
-      aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager();
       if (sIsIMMEnabled) {
         // Associate IME context for IMM-IMEs.
         AssociateIMEContext(aWindow, enable);
       } else if (oldInputContext.mIMEState.mEnabled == IMEState::PLUGIN) {
         // Disassociate the IME context from the window when plugin loses focus
         // in pure TSF mode.
         AssociateIMEContext(aWindow, false);
       }
@@ -412,25 +432,16 @@ IMEHandler::SetInputContext(nsWindow* aW
 #endif // #ifdef NS_ENABLE_TSF
 
   AssociateIMEContext(aWindow, enable);
 
   IMEContext context(aWindow);
   if (adjustOpenState) {
     context.SetOpenState(open);
   }
-
-  if (aInputContext.mNativeIMEContext) {
-    return;
-  }
-
-  // The old InputContext must store the default IMC or old TextStore.
-  // When IME context is disassociated from the window, use it.
-  aInputContext.mNativeIMEContext = enable ?
-    static_cast<void*>(context.get()) : oldInputContext.mNativeIMEContext;
 }
 
 // static
 void
 IMEHandler::AssociateIMEContext(nsWindow* aWindow, bool aEnable)
 {
   IMEContext context(aWindow);
   if (aEnable) {
@@ -451,35 +462,29 @@ IMEHandler::InitInputContext(nsWindow* a
   // For a11y, the default enabled state should be 'enabled'.
   aInputContext.mIMEState.mEnabled = IMEState::ENABLED;
 
 #ifdef NS_ENABLE_TSF
   if (sIsInTSFMode) {
     TSFTextStore::SetInputContext(aWindow, aInputContext,
       InputContextAction(InputContextAction::CAUSE_UNKNOWN,
                          InputContextAction::GOT_FOCUS));
-    aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager();
-    MOZ_ASSERT(aInputContext.mNativeIMEContext);
     // IME context isn't necessary in pure TSF mode.
     if (!sIsIMMEnabled) {
       AssociateIMEContext(aWindow, false);
     }
     return;
   }
 #endif // #ifdef NS_ENABLE_TSF
 
-  // NOTE: mNativeIMEContext may be null if IMM module isn't installed.
+#ifdef DEBUG
+  // NOTE: IMC may be null if IMM module isn't installed.
   IMEContext context(aWindow);
-  aInputContext.mNativeIMEContext = static_cast<void*>(context.get());
-  MOZ_ASSERT(aInputContext.mNativeIMEContext || !CurrentKeyboardLayoutHasIME());
-  // If no IME context is available, we should set the widget's pointer since
-  // nullptr indicates there is only one context per process on the platform.
-  if (!aInputContext.mNativeIMEContext) {
-    aInputContext.mNativeIMEContext = static_cast<void*>(aWindow);
-  }
+  MOZ_ASSERT(context.IsValid() || !CurrentKeyboardLayoutHasIME());
+#endif // #ifdef DEBUG
 }
 
 #ifdef DEBUG
 // static
 bool
 IMEHandler::CurrentKeyboardLayoutHasIME()
 {
 #ifdef NS_ENABLE_TSF
--- a/widget/windows/WinIMEHandler.h
+++ b/widget/windows/WinIMEHandler.h
@@ -29,19 +29,19 @@ struct MSGResult;
  */
 class IMEHandler final
 {
 public:
   static void Initialize();
   static void Terminate();
 
   /**
-   * Returns TSF related native data.
+   * Returns TSF related native data or native IME context.
    */
-  static void* GetNativeData(uint32_t aDataType);
+  static void* GetNativeData(nsWindow* aWindow, uint32_t aDataType);
 
   /**
    * ProcessRawKeyMessage() message is called before calling TranslateMessage()
    * and DispatchMessage().  If this returns true, the message is consumed.
    * Then, caller must not perform TranslateMessage() nor DispatchMessage().
    */
   static bool ProcessRawKeyMessage(const MSG& aMsg);
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -651,16 +651,17 @@ nsWindow::Create(nsIWidget* aParent,
   // Starting with Windows XP, a process always runs within a terminal services
   // session. In order to play nicely with RDP, fast user switching, and the
   // lock screen, we should be handling WM_WTSSESSION_CHANGE. We must register
   // our HWND in order to receive this message.
   DebugOnly<BOOL> wtsRegistered = ::WTSRegisterSessionNotification(mWnd,
                                                        NOTIFY_FOR_THIS_SESSION);
   NS_ASSERTION(wtsRegistered, "WTSRegisterSessionNotification failed!\n");
 
+  mDefaultIMC.Init(this);
   IMEHandler::InitInputContext(this, mInputContext);
 
   // If the internal variable set by the config.trim_on_minimize pref has not
   // been initialized, and if this is the hidden window (conveniently created
   // before any visible windows, and after the profile has been initialized),
   // do some initialization work.
   if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
     // Our internal trim prevention logic is effective on 2K/XP at maintaining
@@ -3144,20 +3145,21 @@ void* nsWindow::GetNativeData(uint32_t a
       // XXX:  This is sleezy!!  Remember to Release the DC after using it!
 #ifdef MOZ_XUL
       return (void*)(eTransparencyTransparent == mTransparencyMode) ?
         mMemoryDC : ::GetDC(mWnd);
 #else
       return (void*)::GetDC(mWnd);
 #endif
 
+    case NS_RAW_NATIVE_IME_CONTEXT:
     case NS_NATIVE_TSF_THREAD_MGR:
     case NS_NATIVE_TSF_CATEGORY_MGR:
     case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
-      return IMEHandler::GetNativeData(aDataType);
+      return IMEHandler::GetNativeData(this, aDataType);
 
     default:
       break;
   }
 
   return nullptr;
 }
 
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -39,16 +39,18 @@
 #include "oleacc.h"
 #include "mozilla/a11y/Accessible.h"
 #endif
 
 #include "nsUXThemeData.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIIdleServiceInternal.h"
 
+#include "IMMHandler.h"
+
 /**
  * Forward class definitions
  */
 
 class nsNativeDragTarget;
 class nsIRollupListener;
 class imgIContainer;
 
@@ -66,16 +68,17 @@ struct MSGResult;
 class nsWindow : public nsWindowBase
 {
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::widget::WindowHook WindowHook;
   typedef mozilla::widget::TaskbarWindowPreview TaskbarWindowPreview;
   typedef mozilla::widget::NativeKey NativeKey;
   typedef mozilla::widget::MSGResult MSGResult;
+  typedef mozilla::widget::IMEContext IMEContext;
 
 public:
   nsWindow();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   friend class nsWindowGfx;
 
@@ -287,16 +290,18 @@ public:
 
   bool                    const DestroyCalled() { return mDestroyCalled; }
 
   bool IsPopup();
   virtual bool ShouldUseOffMainThreadCompositing();
 
   bool CaptureWidgetOnScreen(RefPtr<mozilla::gfx::DrawTarget> aDT);
 
+  const IMEContext& DefaultIMC() const { return mDefaultIMC; }
+
 protected:
   virtual ~nsWindow();
 
   virtual void WindowUsesOMTC() override;
   virtual void RegisterTouchWindow() override;
 
   virtual nsresult NotifyIMEInternal(
                      const IMENotification& aIMENotification) override;
@@ -467,16 +472,17 @@ protected:
 protected:
   nsCOMPtr<nsIWidget>   mParent;
   nsIntSize             mLastSize;
   nsIntPoint            mLastPoint;
   HWND                  mWnd;
   HWND                  mTransitionWnd;
   WNDPROC               mPrevWndProc;
   HBRUSH                mBrush;
+  IMEContext            mDefaultIMC;
   bool                  mIsTopWidgetWindow;
   bool                  mInDtor;
   bool                  mIsVisible;
   bool                  mUnicodeWidget;
   bool                  mPainting;
   bool                  mTouchWindow;
   bool                  mDisplayPanFeedback;
   bool                  mHideChrome;