Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 23 Dec 2014 13:19:37 -0500
changeset 221108 29426cc277cbb8944802c12e3c0d2455961d6d23
parent 221107 cddde1da19ae6fff0b46aca7708de7f878a978e4 (current diff)
parent 221092 44344099d1193b50caabab1153b8a9198e2daec0 (diff)
child 221109 3d3e53c0b21ad1c12c61f251d9f87828ac5f8ad8
push id28010
push userkwierso@gmail.com
push dateWed, 24 Dec 2014 00:29:29 +0000
treeherdermozilla-central@8b881bea204a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team. a=merge
testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-test.html.ini
testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/detached-callback-move-element-test.html.ini
--- a/accessible/xpcom/xpcAccessible.cpp
+++ b/accessible/xpcom/xpcAccessible.cpp
@@ -18,16 +18,17 @@
 #include "nsIPersistentProperties2.h"
 
 using namespace mozilla::a11y;
 
 NS_IMETHODIMP
 xpcAccessible::GetParent(nsIAccessible** aParent)
 {
   NS_ENSURE_ARG_POINTER(aParent);
+  *aParent = nullptr;
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   NS_IF_ADDREF(*aParent = ToXPC(Intl()->Parent()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -141,47 +142,62 @@ xpcAccessible::GetChildren(nsIArray** aC
   NS_ADDREF(*aChildren = children);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetIndexInParent(int32_t* aIndexInParent)
 {
   NS_ENSURE_ARG_POINTER(aIndexInParent);
+  *aIndexInParent = -1;
+
+  if (!Intl())
+    return NS_ERROR_FAILURE;
 
   *aIndexInParent = Intl()->IndexInParent();
   return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetDOMNode(nsIDOMNode** aDOMNode)
 {
   NS_ENSURE_ARG_POINTER(aDOMNode);
   *aDOMNode = nullptr;
 
+  if (!Intl())
+    return NS_ERROR_FAILURE;
+
   nsINode* node = Intl()->GetNode();
   if (node)
     CallQueryInterface(node, aDOMNode);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetDocument(nsIAccessibleDocument** aDocument)
 {
   NS_ENSURE_ARG_POINTER(aDocument);
+  *aDocument = nullptr;
+
+  if (!Intl())
+    return NS_ERROR_FAILURE;
 
   NS_IF_ADDREF(*aDocument = ToXPCDocument(Intl()->Document()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetRootDocument(nsIAccessibleDocument** aRootDocument)
 {
   NS_ENSURE_ARG_POINTER(aRootDocument);
+  *aRootDocument = nullptr;
+
+  if (!Intl())
+    return NS_ERROR_FAILURE;
 
   NS_IF_ADDREF(*aRootDocument = ToXPCDocument(Intl()->RootAccessible()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetRole(uint32_t* aRole)
 {
@@ -194,17 +210,17 @@ xpcAccessible::GetRole(uint32_t* aRole)
   *aRole = Intl()->Role();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetState(uint32_t* aState, uint32_t* aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
-  
+
   if (!Intl())
     nsAccUtils::To32States(states::DEFUNCT, aState, aExtraState);
   else
     nsAccUtils::To32States(Intl()->State(), aState, aExtraState);
 
   return NS_OK;
 }
 
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "b60aedd37a5ccdb71893d31761988bcc17a82676", 
+    "revision": "51051a09cdd5b1a3c6d2edcc9dd718823adabb59", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -34,36 +34,51 @@ class DiagnosticsMatcher {
 public:
   DiagnosticsMatcher();
 
   ASTConsumerPtr makeASTConsumer() {
     return astMatcher.newASTConsumer();
   }
 
 private:
-  class StackClassChecker : public MatchFinder::MatchCallback {
+  class ScopeChecker : public MatchFinder::MatchCallback {
   public:
+    enum Scope {
+      eLocal,
+      eGlobal
+    };
+    ScopeChecker(Scope scope_) :
+      scope(scope_) {}
     virtual void run(const MatchFinder::MatchResult &Result);
     void noteInferred(QualType T, DiagnosticsEngine &Diag);
+  private:
+    Scope scope;
   };
 
   class NonHeapClassChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
     void noteInferred(QualType T, DiagnosticsEngine &Diag);
   };
 
   class ArithmeticArgChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
-  StackClassChecker stackClassChecker;
+  class TrivialCtorDtorChecker : public MatchFinder::MatchCallback {
+  public:
+    virtual void run(const MatchFinder::MatchResult &Result);
+  };
+
+  ScopeChecker stackClassChecker;
+  ScopeChecker globalClassChecker;
   NonHeapClassChecker nonheapClassChecker;
   ArithmeticArgChecker arithmeticArgChecker;
+  TrivialCtorDtorChecker trivialCtorDtorChecker;
   MatchFinder astMatcher;
 };
 
 namespace {
 
 bool isInIgnoredNamespace(const Decl *decl) {
   const DeclContext *DC = decl->getDeclContext()->getEnclosingNamespaceContext();
   const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
@@ -231,17 +246,18 @@ public:
 /**
  * Where classes may be allocated. Regular classes can be allocated anywhere,
  * non-heap classes on the stack or as static variables, and stack classes only
  * on the stack. Note that stack classes subsumes non-heap classes.
  */
 enum ClassAllocationNature {
   RegularClass = 0,
   NonHeapClass = 1,
-  StackClass = 2
+  StackClass = 2,
+  GlobalClass = 3
 };
 
 /// A cached data of whether classes are stack classes, non-heap classes, or
 /// neither.
 DenseMap<const CXXRecordDecl *,
   std::pair<const Decl *, ClassAllocationNature> > inferredAllocCauses;
 
 ClassAllocationNature getClassAttrs(QualType T);
@@ -250,16 +266,19 @@ ClassAllocationNature getClassAttrs(CXXR
   // Normalize so that D points to the definition if it exists. If it doesn't,
   // then we can't allocate it anyways.
   if (!D->hasDefinition())
     return RegularClass;
   D = D->getDefinition();
   // Base class: anyone with this annotation is obviously a stack class
   if (MozChecker::hasCustomAnnotation(D, "moz_stack_class"))
     return StackClass;
+  // Base class: anyone with this annotation is obviously a global class
+  if (MozChecker::hasCustomAnnotation(D, "moz_global_class"))
+    return GlobalClass;
 
   // See if we cached the result.
   DenseMap<const CXXRecordDecl *,
     std::pair<const Decl *, ClassAllocationNature> >::iterator it =
     inferredAllocCauses.find(D);
   if (it != inferredAllocCauses.end()) {
     return it->second.second;
   }
@@ -278,30 +297,37 @@ ClassAllocationNature getClassAttrs(CXXR
   // going.
   for (CXXRecordDecl::base_class_iterator base = D->bases_begin(),
        e = D->bases_end(); base != e; ++base) {
     ClassAllocationNature super = getClassAttrs(base->getType());
     if (super == StackClass) {
       inferredAllocCauses[D] = std::make_pair(
         base->getType()->getAsCXXRecordDecl(), StackClass);
       return StackClass;
+    } else if (super == GlobalClass) {
+      inferredAllocCauses[D] = std::make_pair(
+        base->getType()->getAsCXXRecordDecl(), GlobalClass);
+      return GlobalClass;
     } else if (super == NonHeapClass) {
       inferredAllocCauses[D] = std::make_pair(
         base->getType()->getAsCXXRecordDecl(), NonHeapClass);
       type = NonHeapClass;
     }
   }
 
   // Maybe it has a member which is a stack class.
   for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end();
        field != e; ++field) {
     ClassAllocationNature fieldType = getClassAttrs(field->getType());
     if (fieldType == StackClass) {
       inferredAllocCauses[D] = std::make_pair(*field, StackClass);
       return StackClass;
+    } else if (fieldType == GlobalClass) {
+      inferredAllocCauses[D] = std::make_pair(*field, GlobalClass);
+      return GlobalClass;
     } else if (fieldType == NonHeapClass) {
       inferredAllocCauses[D] = std::make_pair(*field, NonHeapClass);
       type = NonHeapClass;
     }
   }
 
   return type;
 }
@@ -319,16 +345,22 @@ namespace clang {
 namespace ast_matchers {
 
 /// This matcher will match any class with the stack class assertion or an
 /// array of such classes.
 AST_MATCHER(QualType, stackClassAggregate) {
   return getClassAttrs(Node) == StackClass;
 }
 
+/// This matcher will match any class with the global class assertion or an
+/// array of such classes.
+AST_MATCHER(QualType, globalClassAggregate) {
+  return getClassAttrs(Node) == GlobalClass;
+}
+
 /// This matcher will match any class with the stack class assertion or an
 /// array of such classes.
 AST_MATCHER(QualType, nonheapClassAggregate) {
   return getClassAttrs(Node) == NonHeapClass;
 }
 
 /// This matcher will match any function declaration that is declared as a heap
 /// allocator.
@@ -337,16 +369,22 @@ AST_MATCHER(FunctionDecl, heapAllocator)
 }
 
 /// This matcher will match any declaration that is marked as not accepting
 /// arithmetic expressions in its arguments.
 AST_MATCHER(Decl, noArithmeticExprInArgs) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_no_arith_expr_in_arg");
 }
 
+/// This matcher will match any C++ class that is marked as having a trivial
+/// constructor and destructor.
+AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) {
+  return MozChecker::hasCustomAnnotation(&Node, "moz_trivial_ctor_dtor");
+}
+
 /// This matcher will match all arithmetic binary operators.
 AST_MATCHER(BinaryOperator, binaryArithmeticOperator) {
   BinaryOperatorKind opcode = Node.getOpcode();
   return opcode == BO_Mul ||
          opcode == BO_Div ||
          opcode == BO_Rem ||
          opcode == BO_Add ||
          opcode == BO_Sub ||
@@ -388,40 +426,55 @@ bool isPlacementNew(const CXXNewExpr *ex
   if (expr->getNumPlacementArgs() == 0)
     return false;
   if (MozChecker::hasCustomAnnotation(expr->getOperatorNew(),
       "moz_heap_allocator"))
     return false;
   return true;
 }
 
-DiagnosticsMatcher::DiagnosticsMatcher() {
+DiagnosticsMatcher::DiagnosticsMatcher()
+  : stackClassChecker(ScopeChecker::eLocal),
+    globalClassChecker(ScopeChecker::eGlobal)
+{
   // Stack class assertion: non-local variables of a stack class are forbidden
   // (non-localness checked in the callback)
   astMatcher.addMatcher(varDecl(hasType(stackClassAggregate())).bind("node"),
     &stackClassChecker);
   // Stack class assertion: new stack class is forbidden (unless placement new)
   astMatcher.addMatcher(newExpr(hasType(pointerType(
       pointee(stackClassAggregate())
     ))).bind("node"), &stackClassChecker);
+  // Global class assertion: non-global variables of a global class are forbidden
+  // (globalness checked in the callback)
+  astMatcher.addMatcher(varDecl(hasType(globalClassAggregate())).bind("node"),
+    &globalClassChecker);
+  // Global class assertion: new global class is forbidden
+  astMatcher.addMatcher(newExpr(hasType(pointerType(
+      pointee(globalClassAggregate())
+    ))).bind("node"), &globalClassChecker);
   // Non-heap class assertion: new non-heap class is forbidden (unless placement
   // new)
   astMatcher.addMatcher(newExpr(hasType(pointerType(
       pointee(nonheapClassAggregate())
     ))).bind("node"), &nonheapClassChecker);
 
-  // Any heap allocation function that returns a non-heap or a stack class is
-  // definitely doing something wrong
+  // Any heap allocation function that returns a non-heap or a stack class or
+  // a global class is definitely doing something wrong
   astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
       returns(pointerType(pointee(nonheapClassAggregate()))))))).bind("node"),
     &nonheapClassChecker);
   astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
       returns(pointerType(pointee(stackClassAggregate()))))))).bind("node"),
     &stackClassChecker);
 
+  astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
+      returns(pointerType(pointee(globalClassAggregate()))))))).bind("node"),
+    &globalClassChecker);
+
   astMatcher.addMatcher(callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
           anyOf(
               hasDescendant(binaryOperator(allOf(binaryArithmeticOperator(),
                   hasLHS(hasDescendant(declRefExpr())),
                   hasRHS(hasDescendant(declRefExpr()))
               )).bind("node")),
               hasDescendant(unaryOperator(allOf(unaryArithmeticOperator(),
                   hasUnaryOperand(allOf(hasType(builtinType()),
@@ -438,70 +491,91 @@ DiagnosticsMatcher::DiagnosticsMatcher()
               )).bind("node")),
               hasDescendant(unaryOperator(allOf(unaryArithmeticOperator(),
                   hasUnaryOperand(allOf(hasType(builtinType()),
                                         anyOf(hasDescendant(declRefExpr()), declRefExpr())))
               )).bind("node"))
           )
       )).bind("call"),
     &arithmeticArgChecker);
+
+  astMatcher.addMatcher(recordDecl(hasTrivialCtorDtor()).bind("node"),
+    &trivialCtorDtorChecker);
 }
 
-void DiagnosticsMatcher::StackClassChecker::run(
+void DiagnosticsMatcher::ScopeChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
     DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
+  unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID(
+    DiagnosticIDs::Error, "variable of type %0 only valid as global");
+  unsigned errorID = (scope == eGlobal) ? globalID : stackID;
   if (const VarDecl *d = Result.Nodes.getNodeAs<VarDecl>("node")) {
-    // Ignore the match if it's a local variable.
-    if (d->hasLocalStorage())
-      return;
+    if (scope == eLocal) {
+      // Ignore the match if it's a local variable.
+      if (d->hasLocalStorage())
+        return;
+    } else if (scope == eGlobal) {
+      // Ignore the match if it's a global variable or a static member of a
+      // class.  The latter is technically not in the global scope, but for the
+      // use case of classes that intend to avoid introducing static
+      // initializers that is fine.
+      if (d->hasGlobalStorage() && !d->isStaticLocal())
+        return;
+    }
 
-    Diag.Report(d->getLocation(), stackID) << d->getType();
+    Diag.Report(d->getLocation(), errorID) << d->getType();
     noteInferred(d->getType(), Diag);
   } else if (const CXXNewExpr *expr =
       Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
     // If it's placement new, then this match doesn't count.
-    if (isPlacementNew(expr))
+    if (scope == eLocal && isPlacementNew(expr))
       return;
-    Diag.Report(expr->getStartLoc(), stackID) << expr->getAllocatedType();
+    Diag.Report(expr->getStartLoc(), errorID) << expr->getAllocatedType();
     noteInferred(expr->getAllocatedType(), Diag);
   } else if (const CallExpr *expr =
       Result.Nodes.getNodeAs<CallExpr>("node")) {
     QualType badType = expr->getCallReturnType()->getPointeeType();
-    Diag.Report(expr->getLocStart(), stackID) << badType;
+    Diag.Report(expr->getLocStart(), errorID) << badType;
     noteInferred(badType, Diag);
   }
 }
 
-void DiagnosticsMatcher::StackClassChecker::noteInferred(QualType T,
+void DiagnosticsMatcher::ScopeChecker::noteInferred(QualType T,
     DiagnosticsEngine &Diag) {
   unsigned inheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
     DiagnosticIDs::Note,
-    "%0 is a stack class because it inherits from a stack class %1");
+    "%0 is a %2 class because it inherits from a %2 class %1");
   unsigned memberID = Diag.getDiagnosticIDs()->getCustomDiagID(
     DiagnosticIDs::Note,
-    "%0 is a stack class because member %1 is a stack class %2");
+    "%0 is a %3 class because member %1 is a %3 class %2");
+  const char* attribute = (scope == eGlobal) ?
+    "moz_global_class" : "moz_stack_class";
+  const char* type = (scope == eGlobal) ?
+    "global" : "stack";
 
-  // Find the CXXRecordDecl that is the stack class of interest
+  // Find the CXXRecordDecl that is the local/global class of interest
   while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
     T = arrTy->getElementType();
   CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
 
   // Direct result, we're done.
-  if (MozChecker::hasCustomAnnotation(clazz, "moz_stack_class"))
+  if (MozChecker::hasCustomAnnotation(clazz, attribute))
     return;
 
   const Decl *cause = inferredAllocCauses[clazz].first;
   if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(cause)) {
-    Diag.Report(clazz->getLocation(), inheritsID) << T << CRD->getDeclName();
+    Diag.Report(clazz->getLocation(), inheritsID) <<
+      T << CRD->getDeclName() << type;
   } else if (const FieldDecl *FD = dyn_cast<FieldDecl>(cause)) {
-    Diag.Report(FD->getLocation(), memberID) << T << FD << FD->getType();
+    Diag.Report(FD->getLocation(), memberID) <<
+      T << FD << FD->getType() << type;
   }
-  
+
   // Recursively follow this back.
   noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
 }
 
 void DiagnosticsMatcher::NonHeapClassChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
@@ -556,16 +630,29 @@ void DiagnosticsMatcher::ArithmeticArgCh
   const Expr *expr = Result.Nodes.getNodeAs<Expr>("node");
   if (const CallExpr *call = Result.Nodes.getNodeAs<CallExpr>("call")) {
     Diag.Report(expr->getLocStart(), errorID) << call->getDirectCallee();
   } else if (const CXXConstructExpr *ctr = Result.Nodes.getNodeAs<CXXConstructExpr>("call")) {
     Diag.Report(expr->getLocStart(), errorID) << ctr->getConstructor();
   }
 }
 
+void DiagnosticsMatcher::TrivialCtorDtorChecker::run(
+    const MatchFinder::MatchResult &Result) {
+  DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
+  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error, "class %0 must have trivial constructors and destructors");
+  const CXXRecordDecl *node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
+
+  bool badCtor = !node->hasTrivialDefaultConstructor();
+  bool badDtor = !node->hasTrivialDestructor();
+  if (badCtor || badDtor)
+    Diag.Report(node->getLocStart(), errorID) << node;
+}
+
 class MozCheckAction : public PluginASTAction {
 public:
   ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {
 #if CLANG_VERSION_FULL >= 306
     std::unique_ptr<MozChecker> checker(make_unique<MozChecker>(CI));
 
     std::vector<std::unique_ptr<ASTConsumer>> consumers;
     consumers.push_back(std::move(checker));
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestGlobalClass.cpp
@@ -0,0 +1,52 @@
+#define MOZ_GLOBAL_CLASS __attribute__((annotate("moz_global_class")))
+#include <stddef.h>
+
+struct MOZ_GLOBAL_CLASS Global {
+  int i;
+  void *operator new(size_t x) throw() { return 0; }
+  void *operator new(size_t blah, char *buffer) { return buffer; }
+};
+
+template <class T>
+struct MOZ_GLOBAL_CLASS TemplateClass {
+  T i;
+};
+
+void gobble(void *) { }
+
+void misuseGlobalClass(int len) {
+  Global notValid; // expected-error {{variable of type 'Global' only valid as global}}
+  Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}}
+  static Global valid; // expected-error {{variable of type 'Global' only valid as global}}
+  static Global alsoValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}}
+
+  gobble(&valid);
+  gobble(&notValid);
+  gobble(&alsoValid[0]);
+
+  gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}}
+  gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}}
+  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}}
+  gobble(len <= 5 ? &valid : new Global); // expected-error {{variable of type 'Global' only valid as global}}
+
+  char buffer[sizeof(Global)];
+  gobble(new (buffer) Global); // expected-error {{variable of type 'Global' only valid as global}}
+}
+
+Global valid;
+struct RandomClass {
+  Global nonstaticMember; // expected-note {{'RandomClass' is a global class because member 'nonstaticMember' is a global class 'Global'}}
+  static Global staticMember;
+};
+struct MOZ_GLOBAL_CLASS RandomGlobalClass {
+  Global nonstaticMember;
+  static Global staticMember;
+};
+
+struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global class because it inherits from a global class 'Global'}}
+struct MOZ_GLOBAL_CLASS GoodInherit : Global {};
+
+void misuseGlobalClassEvenMore(int len) {
+  BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}}
+  RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}}
+}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp
@@ -0,0 +1,58 @@
+#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
+
+struct MOZ_TRIVIAL_CTOR_DTOR EmptyClass{};
+
+template <class T>
+struct MOZ_TRIVIAL_CTOR_DTOR TemplateEmptyClass{};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedCtor { // expected-error {{class 'BadUserDefinedCtor' must have trivial constructors and destructors}}
+  BadUserDefinedCtor() {}
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedDtor { // expected-error {{class 'BadUserDefinedDtor' must have trivial constructors and destructors}}
+  ~BadUserDefinedDtor() {}
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualDtor { // expected-error {{class 'BadVirtualDtor' must have trivial constructors and destructors}}
+  virtual ~BadVirtualDtor() {}
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMember { // expected-error {{class 'BadVirtualMember' must have trivial constructors and destructors}}
+  virtual void f();
+};
+
+void foo();
+struct MOZ_TRIVIAL_CTOR_DTOR BadNonEmptyCtorDtor { // expected-error {{class 'BadNonEmptyCtorDtor' must have trivial constructors and destructors}}
+  BadNonEmptyCtorDtor() { foo(); }
+  ~BadNonEmptyCtorDtor() { foo(); }
+};
+
+struct NonTrivialCtor {
+  NonTrivialCtor() { foo(); }
+};
+
+struct NonTrivialDtor {
+  ~NonTrivialDtor() { foo(); }
+};
+
+struct VirtualMember {
+  virtual void f();
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInBase : NonTrivialCtor { // expected-error {{class 'BadNonTrivialCtorInBase' must have trivial constructors and destructors}}
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInBase : NonTrivialDtor { // expected-error {{class 'BadNonTrivialDtorInBase' must have trivial constructors and destructors}}
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInMember { // expected-error {{class 'BadNonTrivialCtorInMember' must have trivial constructors and destructors}}
+  NonTrivialCtor m;
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInMember { // expected-error {{class 'BadNonTrivialDtorInMember' must have trivial constructors and destructors}}
+  NonTrivialDtor m;
+};
+
+struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMemberInMember { // expected-error {{class 'BadVirtualMemberInMember' must have trivial constructors and destructors}}
+  VirtualMember m;
+};
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -2,16 +2,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SOURCES += [
     'TestBadImplicitConversionCtor.cpp',
     'TestCustomHeap.cpp',
+    'TestGlobalClass.cpp',
     'TestMustOverride.cpp',
     'TestNoArithmeticExprInArgument.cpp',
     'TestNonHeapClass.cpp',
     'TestStackClass.cpp',
+    'TestTrivialCtorDtor.cpp',
 ]
 
 DISABLE_STL_WRAPPING = True
 NO_VISIBILITY_FLAGS = True
--- a/configure.in
+++ b/configure.in
@@ -2269,18 +2269,27 @@ ia64*-hpux*)
             LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT"
             if test -z "$DEVELOPER_OPTIONS"; then
                 LDFLAGS="$LDFLAGS -RELEASE"
             fi
         fi
         dnl For profile-guided optimization
         PROFILE_GEN_CFLAGS="-GL"
         PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
-        PROFILE_USE_CFLAGS="-GL"
-        PROFILE_USE_LDFLAGS="-LTCG:PGOPTIMIZE"
+        dnl XXX: PGO builds can fail with warnings treated as errors,
+        dnl specifically "no profile data available" appears to be
+        dnl treated as an error sometimes. This might be a consequence
+        dnl of using WARNINGS_AS_ERRORS in some modules, combined
+        dnl with the linker doing most of the work in the whole-program
+        dnl optimization/PGO case. I think it's probably a compiler bug,
+        dnl but we work around it here.
+        PROFILE_USE_CFLAGS="-GL -wd4624 -wd4952"
+        dnl XXX: should be -LTCG:PGOPTIMIZE, but that fails on libxul.
+        dnl Probably also a compiler bug, but what can you do?
+        PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE"
         LDFLAGS="$LDFLAGS -DYNAMICBASE"
         dnl Minimum reqiurement of Gecko is VS2010 or later which supports
         dnl both SSSE3 and SSE4.1.
         HAVE_TOOLCHAIN_SUPPORT_MSSSE3=1
         HAVE_TOOLCHAIN_SUPPORT_MSSE4_1=1
         if test "$_CC_SUITE" -ge "11"; then
             dnl allow AVX2 code from VS2012
             HAVE_X86_AVX2=1
--- a/docshell/base/nsDefaultURIFixup.cpp
+++ b/docshell/base/nsDefaultURIFixup.cpp
@@ -1091,16 +1091,23 @@ nsDefaultURIFixup::KeywordURIFixup(const
     else if ((firstDotLoc == uint32_t(kNotFound) ||
               (foundDots == 1 && (firstDotLoc == 0 || firstDotLoc == aURIString.Length() - 1))) &&
               firstColonLoc == uint32_t(kNotFound) && firstQMarkLoc == uint32_t(kNotFound)) {
 
         if (isValidAsciiHost && IsDomainWhitelisted(asciiHost, firstDotLoc)) {
             return NS_OK;
         }
 
+        // ... unless there are no dots, and a slash, and alpha characters, and this is a valid host:
+        if (firstDotLoc == uint32_t(kNotFound) && lastSlashLoc != uint32_t(kNotFound) &&
+            hasAsciiAlpha && isValidAsciiHost) {
+            return NS_OK;
+        }
+
+
         // If we get here, we don't have a valid URI, or we did but the
         // host is not whitelisted, so we do a keyword search *anyway*:
         rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, aPostData);
     }
     return rv;
 }
 
 bool nsDefaultURIFixup::IsDomainWhitelisted(const nsAutoCString aAsciiHost,
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -371,16 +371,24 @@ let testcases = [ {
     input: "5+2",
     fixedURI: "http://5+2/",
     alternateURI: "http://www.5+2.com/",
     keywordLookup: true,
     protocolChange: true,
     affectedByWhitelist: true,
     affectedByDNSForSingleHosts: true,
   }, {
+    input: "5/2",
+    fixedURI: "http://5/2",
+    alternateURI: "http://www.5.com/2",
+    keywordLookup: true,
+    protocolChange: true,
+    affectedByWhitelist: true,
+    affectedByDNSForSingleHosts: true,
+  }, {
     input: "moz ?.::%27",
     keywordLookup: true,
     protocolChange: true
   }, {
     input: "mozilla.com/?q=search",
     fixedURI: "http://mozilla.com/?q=search",
     alternateURI: "http://www.mozilla.com/?q=search",
     protocolChange: true
@@ -443,16 +451,42 @@ let testcases = [ {
     affectedByWhitelist: true
   }, {
     input: "??mozilla",
     fixedURI: "http:///??mozilla",
     alternateURI: "http://www..com/??mozilla",
     keywordLookup: true,
     protocolChange: true,
     affectedByWhitelist: true
+  }, {
+    input: "mozilla/",
+    fixedURI: "http://mozilla/",
+    alternateURI: "http://www.mozilla.com/",
+    protocolChange: true,
+    affectedByWhitelist: true,
+  }, {
+    input: "mozilla",
+    fixedURI: "http://mozilla/",
+    alternateURI: "http://www.mozilla.com/",
+    protocolChange: true,
+    keywordLookup: true,
+    affectedByWhitelist: true,
+    affectedByDNSForSingleHosts: true,
+  }, {
+    input: "mozilla5/2",
+    fixedURI: "http://mozilla5/2",
+    alternateURI: "http://www.mozilla5.com/2",
+    protocolChange: true,
+    affectedByWhitelist: true,
+  }, {
+    input: "mozilla/foo",
+    fixedURI: "http://mozilla/foo",
+    alternateURI: "http://www.mozilla.com/foo",
+    protocolChange: true,
+    affectedByWhitelist: true,
   }];
 
 if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
   testcases.push({
     input: "C:\\some\\file.txt",
     fixedURI: "file:///C:/some/file.txt",
     protocolChange: true,
   });
@@ -462,20 +496,18 @@ if (Services.appinfo.OS.toLowerCase().st
     alternateURI: "http://www.mozilla.com/",
     protocolChange: true,
     affectedByWhitelist: true,
   });
   testcases.push({
     input: "mozilla\\",
     fixedURI: "http://mozilla/",
     alternateURI: "http://www.mozilla.com/",
-    keywordLookup: true,
     protocolChange: true,
     affectedByWhitelist: true,
-    affectedByDNSForSingleHosts: true,
   });
 } else {
   testcases.push({
     input: "/some/file.txt",
     fixedURI: "file:///some/file.txt",
     protocolChange: true,
   });
   testcases.push({
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1456,17 +1456,19 @@ Element::BindToTree(nsIDocument* aDocume
 
     // We no longer need to track the subtree pointer (and in fact we'll assert
     // if we do this any later).
     ClearSubtreeRootPointer();
 
     // Being added to a document.
     SetInDocument();
 
-    if (GetCustomElementData()) {
+    // Attached callback must be enqueued whenever custom element is inserted into a
+    // document and this document has a browsing context.
+    if (GetCustomElementData() && aDocument->GetDocShell()) {
       // Enqueue an attached callback for the custom element.
       aDocument->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
     }
 
     // Unset this flag since we now really are in a document.
     UnsetFlags(NODE_FORCE_XBL_BINDINGS |
                // And clear the lazy frame construction bits.
                NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
@@ -1668,17 +1670,19 @@ Element::UnbindFromTree(bool aDeep, bool
     if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && !GetShadowRoot()) {
       nsContentUtils::AddScriptRunner(
         new RemoveFromBindingManagerRunnable(document->BindingManager(), this,
                                              document));
     }
 
     document->ClearBoxObjectFor(this);
 
-    if (GetCustomElementData()) {
+    // Detached must be enqueued whenever custom element is removed from
+    // the document and this document has a browsing context.
+    if (GetCustomElementData() && document->GetDocShell()) {
       // Enqueue a detached callback for the custom element.
       document->EnqueueLifecycleCallback(nsIDocument::eDetached, this);
     }
   }
 
   // Ensure that CSS transitions don't continue on an element at a
   // different place in the tree (even if reinserted before next
   // animation refresh).
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -440,23 +440,37 @@ Registry::~Registry()
 }
 
 void
 CustomElementCallback::Call()
 {
   ErrorResult rv;
   switch (mType) {
     case nsIDocument::eCreated:
+    {
       // For the duration of this callback invocation, the element is being created
       // flag must be set to true.
       mOwnerData->mElementIsBeingCreated = true;
+
+      // The callback hasn't actually been invoked yet, but we need to flip
+      // this now in order to enqueue the attached callback. This is a spec
+      // bug (w3c bug 27437).
       mOwnerData->mCreatedCallbackInvoked = true;
+
+      // If ELEMENT is in a document and this document has a browsing context,
+      // enqueue attached callback for ELEMENT.
+      nsIDocument* document = mThisObject->GetUncomposedDoc();
+      if (document && document->GetDocShell()) {
+        document->EnqueueLifecycleCallback(nsIDocument::eAttached, mThisObject);
+      }
+
       static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
       mOwnerData->mElementIsBeingCreated = false;
       break;
+    }
     case nsIDocument::eAttached:
       static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv);
       break;
     case nsIDocument::eDetached:
       static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv);
       break;
     case nsIDocument::eAttributeChanged:
       static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject,
@@ -5419,68 +5433,69 @@ nsIDocument::CreateElement(const nsAStri
                   nullptr, mDefaultElementType, getter_AddRefs(content));
   if (rv.Failed()) {
     return nullptr;
   }
   return dont_AddRef(content.forget().take()->AsElement());
 }
 
 void
-nsDocument::SwizzleCustomElement(Element* aElement,
-                                 const nsAString& aTypeExtension,
-                                 uint32_t aNamespaceID,
-                                 ErrorResult& rv)
-{
-  nsCOMPtr<nsIAtom> typeAtom(do_GetAtom(aTypeExtension));
+nsDocument::SetupCustomElement(Element* aElement,
+                               uint32_t aNamespaceID,
+                               const nsAString* aTypeExtension)
+{
+  if (!mRegistry) {
+    return;
+  }
+
   nsCOMPtr<nsIAtom> tagAtom = aElement->Tag();
-  if (!mRegistry || tagAtom == typeAtom) {
-    return;
+  nsCOMPtr<nsIAtom> typeAtom = aTypeExtension ?
+    do_GetAtom(*aTypeExtension) : tagAtom;
+
+  if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
+    // Custom element setup in the parser happens after the "is"
+    // attribute is added.
+    aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
   }
 
   CustomElementDefinition* data;
   CustomElementHashKey key(aNamespaceID, typeAtom);
   if (!mRegistry->mCustomDefinitions.Get(&key, &data)) {
     // The type extension doesn't exist in the registry,
-    // thus we don't need to swizzle, but it is possibly
-    // an upgrade candidate.
+    // thus we don't need to enqueue callback or adjust
+    // the "is" attribute, but it is possibly an upgrade candidate.
     RegisterUnresolvedElement(aElement, typeAtom);
     return;
   }
 
   if (data->mLocalName != tagAtom) {
     // The element doesn't match the local name for the
     // definition, thus the element isn't a custom element
     // and we don't need to do anything more.
     return;
   }
 
-  if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
-    // Swizzling in the parser happens after the "is" attribute is added.
-    aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, aTypeExtension, true);
-  }
-
   // Enqueuing the created callback will set the CustomElementData on the
   // element, causing prototype swizzling to occur in Element::WrapObject.
   EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data);
 }
 
 already_AddRefed<Element>
 nsDocument::CreateElement(const nsAString& aTagName,
                           const nsAString& aTypeExtension,
                           ErrorResult& rv)
 {
   nsRefPtr<Element> elem = nsIDocument::CreateElement(aTagName, rv);
   if (rv.Failed()) {
     return nullptr;
   }
 
-  SwizzleCustomElement(elem, aTypeExtension,
-                       GetDefaultNamespaceID(), rv);
-  if (rv.Failed()) {
-    return nullptr;
+  if (!aTagName.Equals(aTypeExtension)) {
+    // Custom element type can not extend itself.
+    SetupCustomElement(elem, GetDefaultNamespaceID(), &aTypeExtension);
   }
 
   return elem.forget();
 }
 
 NS_IMETHODIMP
 nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
                             const nsAString& aQualifiedName,
@@ -5535,19 +5550,19 @@ nsDocument::CreateElementNS(const nsAStr
   if (!aNamespaceURI.EqualsLiteral("*")) {
     rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
                                                                nameSpaceId);
     if (rv.Failed()) {
       return nullptr;
     }
   }
 
-  SwizzleCustomElement(elem, aTypeExtension, nameSpaceId, rv);
-  if (rv.Failed()) {
-    return nullptr;
+  if (!aQualifiedName.Equals(aTypeExtension)) {
+    // A custom element type can not extend itself.
+    SetupCustomElement(elem, nameSpaceId, &aTypeExtension);
   }
 
   return elem.forget();
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
 {
@@ -5764,22 +5779,22 @@ nsDocument::CustomElementConstructor(JSC
   nsDependentAtomString localName(definition->mLocalName);
 
   nsCOMPtr<nsIContent> newElement;
   nsresult rv = document->CreateElem(localName, nullptr,
                                      definition->mNamespaceID,
                                      getter_AddRefs(newElement));
   NS_ENSURE_SUCCESS(rv, true);
 
-  ErrorResult errorResult;
   nsCOMPtr<Element> element = do_QueryInterface(newElement);
-  document->SwizzleCustomElement(element, elemName, definition->mNamespaceID,
-                                 errorResult);
-  if (errorResult.Failed()) {
-    return true;
+  if (definition->mLocalName != typeAtom) {
+    // This element is a custom element by extension, thus we need to
+    // do some special setup. For non-extended custom elements, this happens
+    // when the element is created.
+    document->SetupCustomElement(element, definition->mNamespaceID, &elemName);
   }
 
   rv = nsContentUtils::WrapNative(aCx, newElement, newElement, args.rval());
   NS_ENSURE_SUCCESS(rv, true);
 
   return true;
 }
 
@@ -6090,17 +6105,17 @@ nsDocument::RegisterElement(JSContext* a
 
   nsIGlobalObject* sgo = GetScopeObject();
   if (!sgo) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
   JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
-  nsCOMPtr<nsIAtom> nameAtom;;
+  nsCOMPtr<nsIAtom> nameAtom;
   int32_t namespaceID = kNameSpaceID_XHTML;
   JS::Rooted<JSObject*> protoObject(aCx);
   {
     JSAutoCompartment ac(aCx, global);
 
     JS::Handle<JSObject*> htmlProto(
       HTMLElementBinding::GetProtoObjectHandle(aCx, global));
     if (!htmlProto) {
@@ -6268,26 +6283,16 @@ nsDocument::RegisterElement(JSContext* a
       JS::RootedObject wrapper(aCx);
       if ((wrapper = cache->GetWrapper())) {
         if (!JS_SetPrototype(aCx, wrapper, protoObject)) {
           continue;
         }
       }
 
       EnqueueLifecycleCallback(nsIDocument::eCreated, elem, nullptr, definition);
-      //XXXsmaug It is unclear if we should use GetComposedDoc() here.
-      if (elem->GetUncomposedDoc()) {
-        // Normally callbacks can not be enqueued until the created
-        // callback has been invoked, however, the attached callback
-        // in element upgrade is an exception so pretend the created
-        // callback has been invoked.
-        elem->GetCustomElementData()->mCreatedCallbackInvoked = true;
-
-        EnqueueLifecycleCallback(nsIDocument::eAttached, elem, nullptr, definition);
-      }
     }
   }
 
   // Create constructor to return. Store the name of the custom element as the
   // name of the function.
   JSFunction* constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
                                            JSFUN_CONSTRUCTOR, JS::NullPtr(),
                                            NS_ConvertUTF16toUTF8(lcType).get());
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1552,21 +1552,22 @@ private:
   // custom elements speicification.
   static bool sProcessingBaseElementQueue;
 
   static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
 
 public:
   static void ProcessBaseElementQueue();
 
-  // Modify the prototype and "is" attribute of newly created custom elements.
-  virtual void SwizzleCustomElement(Element* aElement,
-                                    const nsAString& aTypeExtension,
-                                    uint32_t aNamespaceID,
-                                    mozilla::ErrorResult& rv);
+  // Enqueue created callback or register upgrade candidate for
+  // newly created custom elements, possibly extending an existing type.
+  // ex. <x-button>, <button is="x-button> (type extension)
+  virtual void SetupCustomElement(Element* aElement,
+                                  uint32_t aNamespaceID,
+                                  const nsAString* aTypeExtension);
 
   static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
 
   // The "registry" from the web components spec.
   nsRefPtr<mozilla::dom::Registry> mRegistry;
 
   nsRefPtr<mozilla::EventListenerManager> mListenerManager;
   nsRefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2232,20 +2232,19 @@ public:
    * element. e.g. <button is="x-button">.
    */
   virtual nsresult RegisterUnresolvedElement(Element* aElement,
                                              nsIAtom* aTypeName = nullptr) = 0;
   virtual void EnqueueLifecycleCallback(ElementCallbackType aType,
                                         Element* aCustomElement,
                                         mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
                                         mozilla::dom::CustomElementDefinition* aDefinition = nullptr) = 0;
-  virtual void SwizzleCustomElement(Element* aElement,
-                                    const nsAString& aTypeExtension,
-                                    uint32_t aNamespaceID,
-                                    mozilla::ErrorResult& rv) = 0;
+  virtual void SetupCustomElement(Element* aElement,
+                                  uint32_t aNamespaceID,
+                                  const nsAString* aTypeExtension = nullptr) = 0;
   virtual void
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
                     JS::MutableHandle<JSObject*> aRetval,
                     mozilla::ErrorResult& rv) = 0;
 
   /**
    * In some cases, new document instances must be associated with
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -358,16 +358,34 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
 
   Element *elem = aNode->IsElement() ? aNode->AsElement() : nullptr;
 
   nsCOMPtr<nsINode> clone;
   if (aClone) {
     rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
     NS_ENSURE_SUCCESS(rv, rv);
 
+    if (clone->IsElement()) {
+      // The cloned node may be a custom element that may require
+      // enqueing created callback and prototype swizzling.
+      Element* elem = clone->AsElement();
+      if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) {
+        elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID());
+      } else {
+        // Check if node may be custom element by type extension.
+        // ex. <button is="x-button">
+        nsAutoString extension;
+        if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) &&
+            !extension.IsEmpty()) {
+          elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID(),
+                                               &extension);
+        }
+      }
+    }
+
     if (aParent) {
       // If we're cloning we need to insert the cloned children into the cloned
       // parent.
       rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
                                   false);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) {
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2649,22 +2649,16 @@ nsresult HTMLMediaElement::FinishDecoder
   // Tell the decoder about its MediaResource now so things like principals are
   // available immediately.
   mDecoder->SetResource(aStream);
   mDecoder->SetAudioChannel(mAudioChannel);
   mDecoder->SetAudioCaptured(mAudioCaptured);
   mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   mDecoder->SetPreservesPitch(mPreservesPitch);
   mDecoder->SetPlaybackRate(mPlaybackRate);
-
-#ifdef MOZ_EME
-  if (mMediaKeys) {
-    mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
-  }
-#endif
   if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mDecoder->SetMinimizePrerollUntilPlaybackStarts();
   }
 
   // Update decoder principal before we start decoding, since it
   // can affect how we feed data to MediaStreams
   NotifyDecoderPrincipalChanged();
 
@@ -2676,16 +2670,22 @@ nsresult HTMLMediaElement::FinishDecoder
 
   nsresult rv = aDecoder->Load(aListener, aCloneDonor);
   if (NS_FAILED(rv)) {
     mDecoder = nullptr;
     LOG(PR_LOG_DEBUG, ("%p Failed to load for decoder %p", this, aDecoder));
     return rv;
   }
 
+#ifdef MOZ_EME
+  if (mMediaKeys) {
+    mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
+  }
+#endif
+
   // Decoder successfully created, the decoder now owns the MediaResource
   // which owns the channel.
   mChannel = nullptr;
 
   AddMediaElementToURITable();
 
   // We may want to suspend the new stream now.
   // This will also do an AddRemoveSelfReference.
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -261,23 +261,17 @@ NS_NewHTMLElement(Element** aResult, alr
       nsContentUtils::IsCustomElementName(name)) {
     nsIDocument* doc = nodeInfo->GetDocument();
 
     NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
     if (!*aResult) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    // Element may be unresolved at this point.
-    doc->RegisterUnresolvedElement(*aResult);
-
-    // Try to enqueue a created callback. The custom element data will be set
-    // and created callback will be enqueued if the custom element type
-    // has already been registered.
-    doc->EnqueueLifecycleCallback(nsIDocument::eCreated, *aResult);
+    doc->SetupCustomElement(*aResult, kNameSpaceID_XHTML);
 
     return NS_OK;
   }
 
   *aResult = CreateHTMLElement(tag,
                                nodeInfo.forget(), aFromParser).take();
   return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -276,40 +276,41 @@ void MediaDecoder::RecreateDecodedStream
 
 void MediaDecoder::DestroyDecodedStream()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (GetDecodedStream()) {
     GetStateMachine()->ResyncMediaStreamClock();
+  } else {
+    // Avoid the redundant blocking to output stream.
+    return;
   }
 
   // All streams are having their SourceMediaStream disconnected, so they
   // need to be explicitly blocked again.
   for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
     OutputStreamData& os = mOutputStreams[i];
     // During cycle collection, nsDOMMediaStream can be destroyed and send
     // its Destroy message before this decoder is destroyed. So we have to
     // be careful not to send any messages after the Destroy().
     if (os.mStream->IsDestroyed()) {
       // Probably the DOM MediaStream was GCed. Clean up.
-      if (os.mPort) {
-        os.mPort->Destroy();
-      }
+      MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
+      os.mPort->Destroy();
       mOutputStreams.RemoveElementAt(i);
       continue;
     }
     os.mStream->ChangeExplicitBlockerCount(1);
     // Explicitly remove all existing ports. This is not strictly necessary but it's
     // good form.
-    if (os.mPort) {
-      os.mPort->Destroy();
-      os.mPort = nullptr;
-    }
+    MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
+    os.mPort->Destroy();
+    os.mPort = nullptr;
   }
 
   mDecodedStream = nullptr;
 }
 
 void MediaDecoder::UpdateStreamBlockingForStateMachinePlaying()
 {
   GetReentrantMonitor().AssertCurrentThreadIn();
@@ -837,40 +838,38 @@ bool MediaDecoder::IsEnded() const
 }
 
 void MediaDecoder::PlaybackEnded()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown ||
       mPlayState == PLAY_STATE_SEEKING ||
-      (mPlayState == PLAY_STATE_LOADING)) {
+      mPlayState == PLAY_STATE_LOADING) {
     return;
   }
 
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
     for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
       OutputStreamData& os = mOutputStreams[i];
       if (os.mStream->IsDestroyed()) {
         // Probably the DOM MediaStream was GCed. Clean up.
-        if (os.mPort) {
-          os.mPort->Destroy();
-        }
+        MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
+        os.mPort->Destroy();
         mOutputStreams.RemoveElementAt(i);
         continue;
       }
       if (os.mFinishWhenEnded) {
         // Shouldn't really be needed since mDecodedStream should already have
         // finished, but doesn't hurt.
         os.mStream->Finish();
-        if (os.mPort) {
-          os.mPort->Destroy();
-        }
+        MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
+        os.mPort->Destroy();
         // Not really needed but it keeps the invariant that a stream not
         // connected to mDecodedStream is explicity blocked.
         os.mStream->ChangeExplicitBlockerCount(1);
         mOutputStreams.RemoveElementAt(i);
       }
     }
   }
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2953,17 +2953,18 @@ void MediaDecoderStateMachine::AdvanceFr
       mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
       mDecoder->IsExpectingMoreData()) {
     bool shouldBuffer;
     if (mReader->UseBufferingHeuristics()) {
       shouldBuffer = HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
                      (JustExitedQuickBuffering() || HasLowUndecodedData());
     } else {
       MOZ_ASSERT(mReader->IsWaitForDataSupported());
-      shouldBuffer = OutOfDecodedAudio() || OutOfDecodedVideo();
+      shouldBuffer = (OutOfDecodedAudio() && mAudioRequestStatus == RequestStatus::Waiting) ||
+                     (OutOfDecodedVideo() && mVideoRequestStatus == RequestStatus::Waiting);
     }
     if (shouldBuffer) {
       if (currentFrame) {
         VideoQueue().PushFront(currentFrame);
       }
       StartBuffering();
       // Don't go straight back to the state machine loop since that might
       // cause us to start decoding again and we could flip-flop between
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -202,29 +202,30 @@ TemporaryRef<SharedThreadPool> GetMediaD
                                Preferences::GetUint("media.num-decode-threads", 25));
 }
 
 bool
 ExtractH264CodecDetails(const nsAString& aCodec,
                         int16_t& aProfile,
                         int16_t& aLevel)
 {
-  // H.264 codecs parameters have a type defined as avc1.PPCCLL, where
+  // H.264 codecs parameters have a type defined as avcN.PPCCLL, where
+  // N = avc type. avc3 is avcc with SPS & PPS implicit (within stream)
   // PP = profile_idc, CC = constraint_set flags, LL = level_idc.
   // We ignore the constraint_set flags, as it's not clear from any
   // documentation what constraints the platform decoders support.
   // See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
   // for more details.
   if (aCodec.Length() != strlen("avc1.PPCCLL")) {
     return false;
   }
 
-  // Verify the codec starts with "avc1.".
+  // Verify the codec starts with "avc1." or "avc3.".
   const nsAString& sample = Substring(aCodec, 0, 5);
-  if (!sample.EqualsASCII("avc1.")) {
+  if (!sample.EqualsASCII("avc1.") && !sample.EqualsASCII("avc3.")) {
     return false;
   }
 
   // Extract the profile_idc, constrains, and level_idc.
   nsresult rv = NS_OK;
   aProfile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16);
   NS_ENSURE_SUCCESS(rv, false);
 
new file mode 100644
--- /dev/null
+++ b/dom/media/fmp4/AVCCDecoderModule.cpp
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AVCCDecoderModule.h"
+#include "ImageContainer.h"
+#include "MediaTaskQueue.h"
+#include "mp4_demuxer/DecoderData.h"
+#include "mp4_demuxer/AnnexB.h"
+
+namespace mozilla
+{
+
+class AVCCMediaDataDecoder : public MediaDataDecoder {
+public:
+
+  AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
+                       const mp4_demuxer::VideoDecoderConfig& aConfig,
+                       layers::LayersBackend aLayersBackend,
+                       layers::ImageContainer* aImageContainer,
+                       MediaTaskQueue* aVideoTaskQueue,
+                       MediaDataDecoderCallback* aCallback);
+
+  virtual ~AVCCMediaDataDecoder();
+
+  virtual nsresult Init() MOZ_OVERRIDE;
+  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+  virtual nsresult Flush() MOZ_OVERRIDE;
+  virtual nsresult Drain() MOZ_OVERRIDE;
+  virtual nsresult Shutdown() MOZ_OVERRIDE;
+  virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
+  virtual bool IsDormantNeeded() MOZ_OVERRIDE;
+  virtual void AllocateMediaResources() MOZ_OVERRIDE;
+  virtual void ReleaseMediaResources() MOZ_OVERRIDE;
+  virtual void ReleaseDecoder() MOZ_OVERRIDE;
+
+private:
+  // Will create the required MediaDataDecoder if we have a AVC SPS.
+  // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
+  // will set mError accordingly.
+  nsresult CreateDecoder();
+  nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
+
+  nsRefPtr<PlatformDecoderModule> mPDM;
+  mp4_demuxer::VideoDecoderConfig mCurrentConfig;
+  layers::LayersBackend mLayersBackend;
+  nsRefPtr<layers::ImageContainer> mImageContainer;
+  nsRefPtr<MediaTaskQueue> mVideoTaskQueue;
+  MediaDataDecoderCallback* mCallback;
+  nsRefPtr<MediaDataDecoder> mDecoder;
+  nsresult mLastError;
+};
+
+AVCCMediaDataDecoder::AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
+                                           const mp4_demuxer::VideoDecoderConfig& aConfig,
+                                           layers::LayersBackend aLayersBackend,
+                                           layers::ImageContainer* aImageContainer,
+                                           MediaTaskQueue* aVideoTaskQueue,
+                                           MediaDataDecoderCallback* aCallback)
+  : mPDM(aPDM)
+  , mCurrentConfig(aConfig)
+  , mLayersBackend(aLayersBackend)
+  , mImageContainer(aImageContainer)
+  , mVideoTaskQueue(aVideoTaskQueue)
+  , mCallback(aCallback)
+  , mDecoder(nullptr)
+  , mLastError(NS_OK)
+{
+  CreateDecoder();
+}
+
+AVCCMediaDataDecoder::~AVCCMediaDataDecoder()
+{
+}
+
+nsresult
+AVCCMediaDataDecoder::Init()
+{
+  if (mDecoder) {
+    return mDecoder->Init();
+  }
+  return mLastError;
+}
+
+nsresult
+AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
+{
+  mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample);
+  if (!mDecoder) {
+    // It is not possible to create an AVCC H264 decoder without SPS.
+    // As such, creation will fail if the extra_data just extracted doesn't
+    // contain a SPS.
+    nsresult rv = CreateDecoderAndInit(aSample);
+    if (rv == NS_ERROR_NOT_INITIALIZED) {
+      // We are missing the required SPS to create the decoder.
+      // Ignore for the time being, the MP4Sample will be dropped.
+      return NS_OK;
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  aSample->extra_data = mCurrentConfig.extra_data;
+
+  return mDecoder->Input(aSample);
+}
+
+nsresult
+AVCCMediaDataDecoder::Flush()
+{
+  if (mDecoder) {
+    return mDecoder->Flush();
+  }
+  return mLastError;
+}
+
+nsresult
+AVCCMediaDataDecoder::Drain()
+{
+  if (mDecoder) {
+    return mDecoder->Drain();
+  }
+  return mLastError;
+}
+
+nsresult
+AVCCMediaDataDecoder::Shutdown()
+{
+  if (mDecoder) {
+    return mDecoder->Shutdown();
+  }
+  return NS_OK;
+}
+
+bool
+AVCCMediaDataDecoder::IsWaitingMediaResources()
+{
+  if (mDecoder) {
+    return mDecoder->IsWaitingMediaResources();
+  }
+  return MediaDataDecoder::IsWaitingMediaResources();
+}
+
+bool
+AVCCMediaDataDecoder::IsDormantNeeded()
+{
+  if (mDecoder) {
+    return mDecoder->IsDormantNeeded();
+  }
+  return MediaDataDecoder::IsDormantNeeded();
+}
+
+void
+AVCCMediaDataDecoder::AllocateMediaResources()
+{
+  if (mDecoder) {
+    mDecoder->AllocateMediaResources();
+  }
+}
+
+void
+AVCCMediaDataDecoder::ReleaseMediaResources()
+{
+  if (mDecoder) {
+    mDecoder->ReleaseMediaResources();
+  }
+}
+
+void
+AVCCMediaDataDecoder::ReleaseDecoder()
+{
+  if (mDecoder) {
+    mDecoder->ReleaseDecoder();
+  }
+}
+
+nsresult
+AVCCMediaDataDecoder::CreateDecoder()
+{
+  if (!mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) {
+    // nothing found yet, will try again later
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
+                                      mLayersBackend,
+                                      mImageContainer,
+                                      mVideoTaskQueue,
+                                      mCallback);
+  if (!mDecoder) {
+    mLastError = NS_ERROR_FAILURE;
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+nsresult
+AVCCMediaDataDecoder::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
+{
+  nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
+    mp4_demuxer::AnnexB::ExtractExtraData(aSample);
+  if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  mCurrentConfig.extra_data = extra_data;
+
+  nsresult rv = CreateDecoder();
+  NS_ENSURE_SUCCESS(rv, rv);
+  return Init();
+}
+
+// AVCCDecoderModule
+
+AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM)
+: mPDM(aPDM)
+{
+  MOZ_ASSERT(aPDM);
+}
+
+AVCCDecoderModule::~AVCCDecoderModule()
+{
+}
+
+nsresult
+AVCCDecoderModule::Startup()
+{
+  return mPDM->Startup();
+}
+
+nsresult
+AVCCDecoderModule::Shutdown()
+{
+  return mPDM->Shutdown();
+}
+
+already_AddRefed<MediaDataDecoder>
+AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
+                                      layers::LayersBackend aLayersBackend,
+                                      layers::ImageContainer* aImageContainer,
+                                      MediaTaskQueue* aVideoTaskQueue,
+                                      MediaDataDecoderCallback* aCallback)
+{
+  nsRefPtr<MediaDataDecoder> decoder;
+
+  if (strcmp(aConfig.mime_type, "video/avc") ||
+      !mPDM->DecoderNeedsAVCC(aConfig)) {
+    // There is no need for an AVCC wrapper for non-AVC content.
+    decoder = mPDM->CreateVideoDecoder(aConfig,
+                                       aLayersBackend,
+                                       aImageContainer,
+                                       aVideoTaskQueue,
+                                       aCallback);
+  } else {
+    decoder = new AVCCMediaDataDecoder(mPDM,
+                                       aConfig,
+                                       aLayersBackend,
+                                       aImageContainer,
+                                       aVideoTaskQueue,
+                                       aCallback);
+  }
+  return decoder.forget();
+}
+
+already_AddRefed<MediaDataDecoder>
+AVCCDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
+                                      MediaTaskQueue* aAudioTaskQueue,
+                                      MediaDataDecoderCallback* aCallback)
+{
+  return mPDM->CreateAudioDecoder(aConfig,
+                                  aAudioTaskQueue,
+                                  aCallback);
+}
+
+bool
+AVCCDecoderModule::SupportsAudioMimeType(const char* aMimeType)
+{
+  return mPDM->SupportsAudioMimeType(aMimeType);
+}
+
+bool
+AVCCDecoderModule::SupportsVideoMimeType(const char* aMimeType)
+{
+  return mPDM->SupportsVideoMimeType(aMimeType);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/fmp4/AVCCDecoderModule.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_AVCCDecoderModule_h
+#define mozilla_AVCCDecoderModule_h
+
+#include "PlatformDecoderModule.h"
+
+namespace mozilla {
+
+class AVCCMediaDataDecoder;
+
+// AVCCDecoderModule is a PlatformDecoderModule wrapper used to ensure that
+// only AVCC format is fed to the underlying PlatformDecoderModule.
+// The AVCCDecoderModule allows playback of content where the SPS NAL may not be
+// provided in the init segment (e.g. AVC3 or Annex B)
+// AVCCDecoderModule will monitor the input data, and will delay creation of the
+// MediaDataDecoder until a SPS and PPS NALs have been extracted.
+//
+// AVCC-only decoder modules are AppleVideoDecoder and EMEH264Decoder.
+
+class AVCCDecoderModule : public PlatformDecoderModule {
+public:
+  explicit AVCCDecoderModule(PlatformDecoderModule* aPDM);
+  virtual ~AVCCDecoderModule();
+
+  virtual nsresult Startup() MOZ_OVERRIDE;
+  virtual nsresult Shutdown() MOZ_OVERRIDE;
+
+  virtual already_AddRefed<MediaDataDecoder>
+  CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
+                     layers::LayersBackend aLayersBackend,
+                     layers::ImageContainer* aImageContainer,
+                     MediaTaskQueue* aVideoTaskQueue,
+                     MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<MediaDataDecoder>
+  CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
+                     MediaTaskQueue* aAudioTaskQueue,
+                     MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
+
+  virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
+  virtual bool SupportsVideoMimeType(const char* aMimeType) MOZ_OVERRIDE;
+
+private:
+  nsRefPtr<PlatformDecoderModule> mPDM;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_AVCCDecoderModule_h
--- a/dom/media/fmp4/BlankDecoderModule.cpp
+++ b/dom/media/fmp4/BlankDecoderModule.cpp
@@ -245,14 +245,15 @@ public:
   virtual bool
   SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE
   {
     return true;
   }
 
 };
 
-PlatformDecoderModule* CreateBlankDecoderModule()
+already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule()
 {
-  return new BlankDecoderModule();
+  nsRefPtr<PlatformDecoderModule> pdm = new BlankDecoderModule();
+  return pdm.forget();
 }
 
 } // namespace mozilla
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -667,19 +667,25 @@ MP4Reader::SizeOfQueue(TrackType aTrack)
   return decoder.mOutput.Length() + (decoder.mNumSamplesInput - decoder.mNumSamplesOutput);
 }
 
 nsresult
 MP4Reader::ResetDecode()
 {
   MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
   Flush(kVideo);
-  mDemuxer->SeekVideo(0);
+  {
+    MonitorAutoLock mon(mIndexMonitor);
+    mDemuxer->SeekVideo(0);
+  }
   Flush(kAudio);
-  mDemuxer->SeekAudio(0);
+  {
+    MonitorAutoLock mon(mIndexMonitor);
+    mDemuxer->SeekAudio(0);
+  }
   return MediaDecoderReader::ResetDecode();
 }
 
 void
 MP4Reader::Output(TrackType aTrack, MediaData* aSample)
 {
 #ifdef LOG_SAMPLE_DECODE
   VLOG("Decoded %s sample time=%lld dur=%lld",
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -118,17 +118,17 @@ private:
   void NotifyResourcesStatusChanged();
   void RequestCodecResource();
   bool IsWaitingOnCodecResource();
   virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
 
   size_t SizeOfQueue(TrackType aTrack);
 
   nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
-  nsAutoPtr<PlatformDecoderModule> mPlatform;
+  nsRefPtr<PlatformDecoderModule> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
   public:
     DecoderCallback(MP4Reader* aReader,
                     mp4_demuxer::TrackType aType)
       : mReader(aReader)
       , mType(aType)
     {
--- a/dom/media/fmp4/PlatformDecoderModule.cpp
+++ b/dom/media/fmp4/PlatformDecoderModule.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PlatformDecoderModule.h"
+#include "AVCCDecoderModule.h"
+
 #ifdef XP_WIN
 #include "WMFDecoderModule.h"
 #endif
 #ifdef MOZ_FFMPEG
 #include "FFmpegRuntimeLinker.h"
 #endif
 #ifdef MOZ_APPLEMEDIA
 #include "AppleDecoderModule.h"
@@ -26,17 +28,17 @@
 #include "EMEDecoderModule.h"
 #include "mozilla/CDMProxy.h"
 #endif
 #include "SharedThreadPool.h"
 #include "MediaTaskQueue.h"
 
 namespace mozilla {
 
-extern PlatformDecoderModule* CreateBlankDecoderModule();
+extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
 
 bool PlatformDecoderModule::sUseBlankDecoder = false;
 bool PlatformDecoderModule::sFFmpegDecoderEnabled = false;
 bool PlatformDecoderModule::sGonkDecoderEnabled = false;
 bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false;
 bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false;
 
 /* static */
@@ -71,90 +73,103 @@ PlatformDecoderModule::Init()
 #endif
 #ifdef MOZ_APPLEMEDIA
   AppleDecoderModule::Init();
 #endif
 }
 
 #ifdef MOZ_EME
 /* static */
-PlatformDecoderModule*
+already_AddRefed<PlatformDecoderModule>
 PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
                                         bool aHasAudio,
                                         bool aHasVideo,
                                         MediaTaskQueue* aTaskQueue)
 {
   bool cdmDecodesAudio;
   bool cdmDecodesVideo;
   {
     CDMCaps::AutoLock caps(aProxy->Capabilites());
     cdmDecodesAudio = caps.CanDecryptAndDecodeAudio();
     cdmDecodesVideo = caps.CanDecryptAndDecodeVideo();
   }
 
-  nsAutoPtr<PlatformDecoderModule> pdm;
+  nsRefPtr<PlatformDecoderModule> pdm;
   if ((!cdmDecodesAudio && aHasAudio) || (!cdmDecodesVideo && aHasVideo)) {
     // The CDM itself can't decode. We need to wrap a PDM to decode the
     // decrypted output of the CDM.
     pdm = Create();
     if (!pdm) {
       return nullptr;
     }
   }
 
-  return new EMEDecoderModule(aProxy,
-                              pdm.forget(),
-                              cdmDecodesAudio,
-                              cdmDecodesVideo);
+  nsRefPtr<PlatformDecoderModule> emepdm(
+    new AVCCDecoderModule(new EMEDecoderModule(aProxy,
+                                               pdm,
+                                               cdmDecodesAudio,
+                                               cdmDecodesVideo)));
+  return emepdm.forget();
 }
 #endif
 
 /* static */
-PlatformDecoderModule*
+already_AddRefed<PlatformDecoderModule>
 PlatformDecoderModule::Create()
 {
   // Note: This runs on the decode thread.
   MOZ_ASSERT(!NS_IsMainThread());
 
+  nsRefPtr<PlatformDecoderModule> m(CreatePDM());
+
+  if (m && NS_SUCCEEDED(m->Startup())) {
+    return m.forget();
+  }
+  return nullptr;
+}
+
+/* static */
+already_AddRefed<PlatformDecoderModule>
+PlatformDecoderModule::CreatePDM()
+{
 #ifdef MOZ_WIDGET_ANDROID
   if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){
-    return new AndroidDecoderModule();
+    nsRefPtr<PlatformDecoderModule> m(new AndroidDecoderModule());
+    return m.forget();
   }
 #endif
   if (sUseBlankDecoder) {
     return CreateBlankDecoderModule();
   }
 #ifdef XP_WIN
-  nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
-  if (NS_SUCCEEDED(m->Startup())) {
-    return m.forget();
-  }
+  nsRefPtr<PlatformDecoderModule> m(new WMFDecoderModule());
+  return m.forget();
 #endif
 #ifdef MOZ_FFMPEG
   if (sFFmpegDecoderEnabled) {
-    nsAutoPtr<PlatformDecoderModule> m(FFmpegRuntimeLinker::CreateDecoderModule());
+    nsRefPtr<PlatformDecoderModule> m(FFmpegRuntimeLinker::CreateDecoderModule());
     if (m) {
       return m.forget();
     }
   }
 #endif
 #ifdef MOZ_APPLEMEDIA
-  nsAutoPtr<AppleDecoderModule> m(new AppleDecoderModule());
-  if (NS_SUCCEEDED(m->Startup())) {
-    return m.forget();
-  }
+  nsRefPtr<PlatformDecoderModule> m(new AVCCDecoderModule(new AppleDecoderModule()));
+  return m.forget();
 #endif
 #ifdef MOZ_GONK_MEDIACODEC
   if (sGonkDecoderEnabled) {
-    return new GonkDecoderModule();
+    nsRefPtr<PlatformDecoderModule> m(new GonkDecoderModule());
+    return m.forget();
   }
 #endif
 #ifdef MOZ_WIDGET_ANDROID
   if(sAndroidMCDecoderEnabled){
-    return new AndroidDecoderModule();
+    nsRefPtr<PlatformDecoderModule> m(new AndroidDecoderModule());
+    return m.forget();
   }
 #endif
   return nullptr;
 }
 
 bool
 PlatformDecoderModule::SupportsAudioMimeType(const char* aMimeType)
 {
@@ -162,9 +177,15 @@ PlatformDecoderModule::SupportsAudioMime
 }
 
 bool
 PlatformDecoderModule::SupportsVideoMimeType(const char* aMimeType)
 {
   return !strcmp(aMimeType, "video/mp4") || !strcmp(aMimeType, "video/avc");
 }
 
+bool
+PlatformDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
+{
+  return false;
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -49,38 +49,47 @@ typedef int64_t Microseconds;
 // means that we won't have fragmented MP4 supported in Media Source
 // Extensions.
 //
 // A cross-platform decoder module that discards input and produces "blank"
 // output samples exists for testing, and is created when the pref
 // "media.fragmented-mp4.use-blank-decoder" is true.
 class PlatformDecoderModule {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule)
+
   // Call on the main thread to initialize the static state
   // needed by Create().
   static void Init();
 
   // Factory method that creates the appropriate PlatformDecoderModule for
   // the platform we're running on. Caller is responsible for deleting this
   // instance. It's expected that there will be multiple
   // PlatformDecoderModules alive at the same time. There is one
   // PlatformDecoderModule created per MP4Reader.
   // This is called on the decode task queue.
-  static PlatformDecoderModule* Create();
+  static already_AddRefed<PlatformDecoderModule> Create();
+  // As Create() but do not initialize the created PlatformDecoderModule.
+  static already_AddRefed<PlatformDecoderModule> CreatePDM();
+
+  // Perform any per-instance initialization.
+  // This is called on the decode task queue.
+  virtual nsresult Startup() { return NS_OK; };
 
 #ifdef MOZ_EME
   // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
   // decrypt-and-decode EME encrypted content. If the CDM only decrypts and
   // does not decode, we create a PDM and use that to create MediaDataDecoders
   // that we use on on aTaskQueue to decode the decrypted stream.
   // This is called on the decode task queue.
-  static PlatformDecoderModule* CreateCDMWrapper(CDMProxy* aProxy,
-                                                 bool aHasAudio,
-                                                 bool aHasVideo,
-                                                 MediaTaskQueue* aTaskQueue);
+  static already_AddRefed<PlatformDecoderModule>
+  CreateCDMWrapper(CDMProxy* aProxy,
+                   bool aHasAudio,
+                   bool aHasVideo,
+                   MediaTaskQueue* aTaskQueue);
 #endif
 
   // Called to shutdown the decoder module and cleanup state. The PDM
   // is deleted immediately after Shutdown() is called. Shutdown() is
   // called after Shutdown() has been called on all MediaDataDecoders
   // created from this PlatformDecoderModule.
   // This is called on the decode task queue.
   virtual nsresult Shutdown() = 0;
@@ -119,20 +128,22 @@ public:
                      MediaDataDecoderCallback* aCallback) = 0;
 
   // An audio decoder module must support AAC by default.
   // If more audio codec is to be supported, SupportsAudioMimeType will have
   // to be extended
   virtual bool SupportsAudioMimeType(const char* aMimeType);
   virtual bool SupportsVideoMimeType(const char* aMimeType);
 
-  virtual ~PlatformDecoderModule() {}
+  // Indicates if the video decoder requires AVCC format.
+  virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig);
 
 protected:
   PlatformDecoderModule() {}
+  virtual ~PlatformDecoderModule() {}
   // Caches pref media.fragmented-mp4.use-blank-decoder
   static bool sUseBlankDecoder;
   static bool sFFmpegDecoderEnabled;
   static bool sGonkDecoderEnabled;
   static bool sAndroidMCDecoderPreferred;
   static bool sAndroidMCDecoderEnabled;
 };
 
--- a/dom/media/fmp4/SharedDecoderManager.cpp
+++ b/dom/media/fmp4/SharedDecoderManager.cpp
@@ -67,17 +67,17 @@ SharedDecoderManager::~SharedDecoderMana
 
 already_AddRefed<MediaDataDecoder>
 SharedDecoderManager::CreateVideoDecoder(
   const mp4_demuxer::VideoDecoderConfig& aConfig,
   layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer,
   MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
 {
   if (!mDecoder) {
-    nsAutoPtr<PlatformDecoderModule> platform(PlatformDecoderModule::Create());
+    nsRefPtr<PlatformDecoderModule> platform(PlatformDecoderModule::Create());
     mDecoder = platform->CreateVideoDecoder(
       aConfig, aLayersBackend, aImageContainer, aVideoTaskQueue, mCallback);
     if (!mDecoder) {
       return nullptr;
     }
     nsresult rv = mDecoder->Init();
     NS_ENSURE_SUCCESS(rv, nullptr);
   }
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -61,17 +61,17 @@ public:
     return InitDecoder(mSurfaceTexture->JavaSurface());
   }
 
   void Cleanup() MOZ_OVERRIDE {
     mGLContext = nullptr;
   }
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
-    mp4_demuxer::AnnexB::ConvertSample(aSample);
+    mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
     return MediaCodecDataDecoder::Input(aSample);
   }
 
   EGLImage CopySurface() {
     if (!EnsureGLContext()) {
       return nullptr;
     }
 
@@ -257,18 +257,18 @@ AndroidDecoderModule::CreateAudioDecoder
   if(format == nullptr)
     return nullptr;
 
   JNIEnv* env = GetJNIForThread();
 
   if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) {
     uint8_t* csd0 = new uint8_t[2];
 
-    csd0[0] = aConfig.audio_specific_config[0];
-    csd0[1] = aConfig.audio_specific_config[1];
+    csd0[0] = (*aConfig.audio_specific_config)[0];
+    csd0[1] = (*aConfig.audio_specific_config)[1];
 
     jobject buffer = env->NewDirectByteBuffer(csd0, 2);
     format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer);
 
     env->DeleteLocalRef(buffer);
   }
 
   nsRefPtr<MediaDataDecoder> decoder =
--- a/dom/media/fmp4/apple/AppleATDecoder.cpp
+++ b/dom/media/fmp4/apple/AppleATDecoder.cpp
@@ -288,27 +288,27 @@ AppleATDecoder::DecodeSample(mp4_demuxer
                                             channels,
                                             rate);
   mCallback->Output(audio);
   return NS_OK;
 }
 
 nsresult
 AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
-                                         const mozilla::Vector<uint8_t>& aExtraData)
+                                         const nsTArray<uint8_t>& aExtraData)
 {
   // Request the properties from CoreAudio using the codec magic cookie
   AudioFormatInfo formatInfo;
   PodZero(&formatInfo.mASBD);
   formatInfo.mASBD.mFormatID = mFormatID;
   if (mFormatID == kAudioFormatMPEG4AAC) {
     formatInfo.mASBD.mFormatFlags = mConfig.extended_profile;
   }
-  formatInfo.mMagicCookieSize = aExtraData.length();
-  formatInfo.mMagicCookie = aExtraData.begin();
+  formatInfo.mMagicCookieSize = aExtraData.Length();
+  formatInfo.mMagicCookie = aExtraData.Elements();
 
   UInt32 formatListSize;
   // Attempt to retrieve the default format using
   // kAudioFormatProperty_FormatInfo method.
   // This method only retrieves the FramesPerPacket information required
   // by the decoder, which depends on the codec type and profile.
   aDesc.mFormatID = mFormatID;
   aDesc.mChannelsPerFrame = mConfig.channel_count;
@@ -369,31 +369,31 @@ nsresult
 AppleATDecoder::SetupDecoder(mp4_demuxer::MP4Sample* aSample)
 {
   if (mFormatID == kAudioFormatMPEG4AAC &&
       mConfig.extended_profile == 2) {
     // Check for implicit SBR signalling if stream is AAC-LC
     // This will provide us with an updated magic cookie for use with
     // GetInputAudioDescription.
     if (NS_SUCCEEDED(GetImplicitAACMagicCookie(aSample)) &&
-        !mMagicCookie.length()) {
+        !mMagicCookie.Length()) {
       // nothing found yet, will try again later
       return NS_ERROR_NOT_INITIALIZED;
     }
     // An error occurred, fallback to using default stream description
   }
 
   LOG("Initializing Apple AudioToolbox decoder");
 
   AudioStreamBasicDescription inputFormat;
   PodZero(&inputFormat);
   nsresult rv =
     GetInputAudioDescription(inputFormat,
-                             mMagicCookie.length() ?
-                                 mMagicCookie : mConfig.extra_data);
+                             mMagicCookie.Length() ?
+                                 mMagicCookie : *mConfig.extra_data);
   if (NS_FAILED(rv)) {
     return rv;
   }
   // Fill in the output format manually.
   PodZero(&mOutputFormat);
   mOutputFormat.mFormatID = kAudioFormatLinearPCM;
   mOutputFormat.mSampleRate = inputFormat.mSampleRate;
   mOutputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
@@ -444,17 +444,17 @@ static void
     rv = AudioFileStreamGetProperty(aStream, aProperty,
                                     &size, data);
     if (rv) {
       LOG("Couldn't get property '%s' (%s)",
           FourCC2Str(aProperty), FourCC2Str(rv));
       decoder->mFileStreamError = true;
       return;
     }
-    decoder->mMagicCookie.append(data.get(), size);
+    decoder->mMagicCookie.AppendElements(data.get(), size);
   }
 }
 
 static void
 _SampleCallback(void* aSBR,
                 UInt32 aNumBytes,
                 UInt32 aNumPackets,
                 const void* aData,
@@ -490,17 +490,17 @@ AppleATDecoder::GetImplicitAACMagicCooki
   OSStatus status = AudioFileStreamParseBytes(mStream,
                                               adtssample.size,
                                               adtssample.data,
                                               0 /* discontinuity */);
   if (status) {
     NS_WARNING("Couldn't parse sample");
   }
 
-  if (status || mFileStreamError || mMagicCookie.length()) {
+  if (status || mFileStreamError || mMagicCookie.Length()) {
     // We have decoded a magic cookie or an error occurred as such
     // we won't need the stream any longer.
     AudioFileStreamClose(mStream);
     mStream = nullptr;
   }
 
   return (mFileStreamError || status) ? NS_ERROR_FAILURE : NS_OK;
 }
--- a/dom/media/fmp4/apple/AppleATDecoder.h
+++ b/dom/media/fmp4/apple/AppleATDecoder.h
@@ -4,61 +4,60 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_AppleATDecoder_h
 #define mozilla_AppleATDecoder_h
 
 #include <AudioToolbox/AudioToolbox.h>
 #include "PlatformDecoderModule.h"
-#include "mozilla/RefPtr.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/Vector.h"
 #include "nsIThread.h"
 
 namespace mozilla {
 
 class MediaTaskQueue;
 class MediaDataDecoderCallback;
 
 class AppleATDecoder : public MediaDataDecoder {
 public:
   AppleATDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                  MediaTaskQueue* aVideoTaskQueue,
                  MediaDataDecoderCallback* aCallback);
-  ~AppleATDecoder();
+  virtual ~AppleATDecoder();
 
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   // Callbacks also need access to the config.
   const mp4_demuxer::AudioDecoderConfig& mConfig;
 
   // Use to extract magic cookie for HE-AAC detection.
-  mozilla::Vector<uint8_t> mMagicCookie;
+  nsTArray<uint8_t> mMagicCookie;
   // Will be set to true should an error occurred while attempting to retrieve
   // the magic cookie property.
   bool mFileStreamError;
 
 private:
-  RefPtr<MediaTaskQueue> mTaskQueue;
+  nsRefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
   AudioConverterRef mConverter;
   AudioStreamBasicDescription mOutputFormat;
   UInt32 mFormatID;
   AudioFileStreamID mStream;
   nsTArray<nsAutoPtr<mp4_demuxer::MP4Sample>> mQueuedSamples;
 
   void SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample);
   nsresult DecodeSample(mp4_demuxer::MP4Sample* aSample);
   nsresult GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
-                                    const mozilla::Vector<uint8_t>& aExtraData);
+                                    const nsTArray<uint8_t>& aExtraData);
   // Setup AudioConverter once all information required has been gathered.
   // Will return NS_ERROR_NOT_INITIALIZED if more data is required.
   nsresult SetupDecoder(mp4_demuxer::MP4Sample* aSample);
   nsresult GetImplicitAACMagicCookie(const mp4_demuxer::MP4Sample* aSample);
 };
 
 } // namespace mozilla
 
--- a/dom/media/fmp4/apple/AppleDecoderModule.cpp
+++ b/dom/media/fmp4/apple/AppleDecoderModule.cpp
@@ -193,9 +193,15 @@ AppleDecoderModule::CreateAudioDecoder(c
 }
 
 bool
 AppleDecoderModule::SupportsAudioMimeType(const char* aMimeType)
 {
   return !strcmp(aMimeType, "audio/mp4a-latm") || !strcmp(aMimeType, "audio/mpeg");
 }
 
+bool
+AppleDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
+{
+  return true;
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/apple/AppleDecoderModule.h
+++ b/dom/media/fmp4/apple/AppleDecoderModule.h
@@ -11,19 +11,17 @@
 
 namespace mozilla {
 
 class AppleDecoderModule : public PlatformDecoderModule {
 public:
   AppleDecoderModule();
   virtual ~AppleDecoderModule();
 
-  // Perform any per-instance initialization.
-  // Main thread only.
-  nsresult Startup();
+  virtual nsresult Startup() MOZ_OVERRIDE;
 
   // Called when the decoders have shutdown. Main thread only.
   // Does this really need to be main thread only????
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   // Decode thread.
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
@@ -34,16 +32,18 @@ public:
 
   // Decode thread.
   virtual already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                      MediaTaskQueue* aAudioTaskQueue,
                      MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
   virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
+  virtual bool
+  DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) MOZ_OVERRIDE;
 
   static void Init();
   static nsresult CanDecode();
 
 private:
   friend class InitTask;
   friend class LinkTask;
   friend class UnlinkTask;
--- a/dom/media/fmp4/apple/AppleVDADecoder.cpp
+++ b/dom/media/fmp4/apple/AppleVDADecoder.cpp
@@ -399,18 +399,18 @@ AppleVDADecoder::InitializeSession()
   }
 
   return NS_OK;
 }
 
 CFDictionaryRef
 AppleVDADecoder::CreateDecoderSpecification()
 {
-  const uint8_t* extradata = mConfig.extra_data.begin();
-  int extrasize = mConfig.extra_data.length();
+  const uint8_t* extradata = mConfig.extra_data->Elements();
+  int extrasize = mConfig.extra_data->Length();
 
   OSType format = 'avc1';
   AutoCFRelease<CFNumberRef> avc_width  =
     CFNumberCreate(kCFAllocatorDefault,
                    kCFNumberSInt32Type,
                    &mConfig.image_width);
   AutoCFRelease<CFNumberRef> avc_height =
     CFNumberCreate(kCFAllocatorDefault,
--- a/dom/media/fmp4/apple/AppleVDADecoder.h
+++ b/dom/media/fmp4/apple/AppleVDADecoder.h
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_AppleVDADecoder_h
 #define mozilla_AppleVDADecoder_h
 
 #include "PlatformDecoderModule.h"
-#include "mozilla/RefPtr.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "MP4Reader.h"
 #include "MP4Decoder.h"
 #include "nsIThread.h"
 #include "ReorderQueue.h"
 
 #include "VideoDecodeAcceleration/VDADecoder.h"
 
@@ -65,36 +64,36 @@ public:
     MediaTaskQueue* aVideoTaskQueue,
     MediaDataDecoderCallback* aCallback,
     layers::ImageContainer* aImageContainer);
 
   AppleVDADecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                   MediaTaskQueue* aVideoTaskQueue,
                   MediaDataDecoderCallback* aCallback,
                   layers::ImageContainer* aImageContainer);
-  ~AppleVDADecoder();
+  virtual ~AppleVDADecoder();
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   nsresult OutputFrame(CVPixelBufferRef aImage,
                        nsAutoPtr<AppleFrameRef> aFrameRef);
 
  protected:
   AppleFrameRef* CreateAppleFrameRef(const mp4_demuxer::MP4Sample* aSample);
   void DrainReorderedFrames();
   void ClearReorderedFrames();
   CFDictionaryRef CreateOutputConfiguration();
 
   const mp4_demuxer::VideoDecoderConfig& mConfig;
-  RefPtr<MediaTaskQueue> mTaskQueue;
+  nsRefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
-  layers::ImageContainer* mImageContainer;
+  nsRefPtr<layers::ImageContainer> mImageContainer;
   ReorderQueue mReorderQueue;
 
 private:
   VDADecoder mDecoder;
   bool mIs106;
 
   // Method to pass a frame to VideoToolbox for decoding.
   nsresult SubmitFrame(mp4_demuxer::MP4Sample* aSample);
--- a/dom/media/fmp4/apple/AppleVTDecoder.cpp
+++ b/dom/media/fmp4/apple/AppleVTDecoder.cpp
@@ -255,25 +255,25 @@ AppleVTDecoder::SubmitFrame(mp4_demuxer:
 
 nsresult
 AppleVTDecoder::InitializeSession()
 {
   OSStatus rv;
 
 #ifdef LOG_MEDIA_SHA1
   SHA1Sum avc_hash;
-  avc_hash.update(mConfig.extra_data.begin(), mConfig.extra_data.length());
+  avc_hash.update(mConfig.extra_data->Elements(), mConfig.extra_data->Length());
   uint8_t digest_buf[SHA1Sum::kHashSize];
   avc_hash.finish(digest_buf);
   nsAutoCString avc_digest;
   for (size_t i = 0; i < sizeof(digest_buf); i++) {
     avc_digest.AppendPrintf("%02x", digest_buf[i]);
   }
   LOG("AVCDecoderConfig %ld bytes sha1 %s",
-      mConfig.extra_data.length(), avc_digest.get());
+      mConfig.extra_data->Length(), avc_digest.get());
 #endif // LOG_MEDIA_SHA1
 
   AutoCFRelease<CFDictionaryRef> extensions = CreateDecoderExtensions();
 
   rv = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
                                       kCMVideoCodecType_H264,
                                       mConfig.image_width,
                                       mConfig.image_height,
@@ -307,18 +307,18 @@ AppleVTDecoder::InitializeSession()
   return NS_OK;
 }
 
 CFDictionaryRef
 AppleVTDecoder::CreateDecoderExtensions()
 {
   AutoCFRelease<CFDataRef> avc_data =
     CFDataCreate(kCFAllocatorDefault,
-                 mConfig.extra_data.begin(),
-                 mConfig.extra_data.length());
+                 mConfig.extra_data->Elements(),
+                 mConfig.extra_data->Length());
 
   const void* atomsKey[] = { CFSTR("avcC") };
   const void* atomsValue[] = { avc_data };
   static_assert(ArrayLength(atomsKey) == ArrayLength(atomsValue),
                 "Non matching keys/values array size");
 
   AutoCFRelease<CFDictionaryRef> atoms =
     CFDictionaryCreate(kCFAllocatorDefault,
--- a/dom/media/fmp4/apple/AppleVTDecoder.h
+++ b/dom/media/fmp4/apple/AppleVTDecoder.h
@@ -14,17 +14,17 @@
 namespace mozilla {
 
 class AppleVTDecoder : public AppleVDADecoder {
 public:
   AppleVTDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                  MediaTaskQueue* aVideoTaskQueue,
                  MediaDataDecoderCallback* aCallback,
                  layers::ImageContainer* aImageContainer);
-  ~AppleVTDecoder();
+  virtual ~AppleVTDecoder();
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
 private:
   CMVideoFormatDescriptionRef mFormat;
--- a/dom/media/fmp4/eme/EMEAudioDecoder.cpp
+++ b/dom/media/fmp4/eme/EMEAudioDecoder.cpp
@@ -273,19 +273,18 @@ EMEAudioDecoder::GmpInit()
   NS_ENSURE_SUCCESS(rv, rv);
   MOZ_ASSERT(mGMP);
 
   mAudioRate = mConfig.samples_per_second;
   mAudioBytesPerSample = mConfig.bits_per_sample / 8;
   mAudioChannels = mConfig.channel_count;
 
   nsTArray<uint8_t> extraData;
-  extraData.AppendElements(&mConfig.audio_specific_config[0],
-                           mConfig.audio_specific_config.length());
-
+  extraData.AppendElements(mConfig.audio_specific_config->Elements(),
+                           mConfig.audio_specific_config->Length());
   mGMP->InitDecode(kGMPAudioCodecAAC,
                    mAudioChannels,
                    mConfig.bits_per_sample,
                    mAudioRate,
                    extraData,
                    this);
 
   return NS_OK;
--- a/dom/media/fmp4/eme/EMEDecoderModule.cpp
+++ b/dom/media/fmp4/eme/EMEDecoderModule.cpp
@@ -253,9 +253,15 @@ EMEDecoderModule::CreateAudioDecoder(con
   }
 
   nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                          aCallback,
                                                          mProxy));
   return emeDecoder.forget();
 }
 
+bool
+EMEDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
+{
+  return mCDMDecodesVideo && aConfig.crypto.valid;
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/eme/EMEDecoderModule.h
+++ b/dom/media/fmp4/eme/EMEDecoderModule.h
@@ -40,20 +40,23 @@ public:
                     MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
   // Decode thread.
   virtual already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                      MediaTaskQueue* aAudioTaskQueue,
                      MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
+  virtual bool
+  DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) MOZ_OVERRIDE;
+
 private:
   nsRefPtr<CDMProxy> mProxy;
   // Will be null if CDM has decoding capability.
-  nsAutoPtr<PlatformDecoderModule> mPDM;
+  nsRefPtr<PlatformDecoderModule> mPDM;
   // We run the PDM on its own task queue.
   nsRefPtr<MediaTaskQueue> mTaskQueue;
   bool mCDMDecodesAudio;
   bool mCDMDecodesVideo;
 
 };
 
 } // namespace mozilla
--- a/dom/media/fmp4/eme/EMEH264Decoder.cpp
+++ b/dom/media/fmp4/eme/EMEH264Decoder.cpp
@@ -272,18 +272,18 @@ EMEH264Decoder::GmpInit()
   codec.mGMPApiVersion = kGMPVersion33;
 
   codec.mCodecType = kGMPVideoCodecH264;
   codec.mWidth = mConfig.display_width;
   codec.mHeight = mConfig.display_height;
 
   nsTArray<uint8_t> codecSpecific;
   codecSpecific.AppendElement(0); // mPacketizationMode.
-  codecSpecific.AppendElements(mConfig.extra_data.begin(),
-                               mConfig.extra_data.length());
+  codecSpecific.AppendElements(mConfig.extra_data->Elements(),
+                               mConfig.extra_data->Length());
 
   rv = mGMP->InitDecode(codec,
                         codecSpecific,
                         this,
                         PR_GetNumberOfProcessors());
   NS_ENSURE_SUCCESS(rv, rv);
 
   mVideoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
--- a/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
@@ -19,18 +19,17 @@ namespace mozilla
 
 FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
-  mExtraData.append(aConfig.audio_specific_config.begin(),
-                    aConfig.audio_specific_config.length());
+  mExtraData = aConfig.audio_specific_config;
 }
 
 nsresult
 FFmpegAudioDecoder<LIBAV_VER>::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
@@ -3,33 +3,33 @@
 /* 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 <string.h>
 #include <unistd.h>
 
 #include "MediaTaskQueue.h"
-#include "mp4_demuxer/mp4_demuxer.h"
 #include "FFmpegLibs.h"
 #include "FFmpegLog.h"
 #include "FFmpegDataDecoder.h"
 #include "prsystem.h"
 
 namespace mozilla
 {
 
 bool FFmpegDataDecoder<LIBAV_VER>::sFFmpegInitDone = false;
 StaticMutex FFmpegDataDecoder<LIBAV_VER>::sMonitor;
 
 FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(MediaTaskQueue* aTaskQueue,
                                                 AVCodecID aCodecID)
   : mTaskQueue(aTaskQueue)
   , mCodecContext(nullptr)
   , mFrame(NULL)
+  , mExtraData(nullptr)
   , mCodecID(aCodecID)
 {
   MOZ_COUNT_CTOR(FFmpegDataDecoder);
 }
 
 FFmpegDataDecoder<LIBAV_VER>::~FFmpegDataDecoder()
 {
   MOZ_COUNT_DTOR(FFmpegDataDecoder);
@@ -89,21 +89,25 @@ FFmpegDataDecoder<LIBAV_VER>::Init()
 
   // FFmpeg will call back to this to negotiate a video pixel format.
   mCodecContext->get_format = ChoosePixelFormat;
 
   mCodecContext->thread_count = PR_GetNumberOfProcessors();
   mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
   mCodecContext->thread_safe_callbacks = false;
 
-  mCodecContext->extradata_size = mExtraData.length();
-  for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
-    mExtraData.append(0);
+  if (mExtraData) {
+    mCodecContext->extradata_size = mExtraData->Length();
+    for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
+      mExtraData->AppendElement(0);
+    }
+    mCodecContext->extradata = mExtraData->Elements();
+  } else {
+    mCodecContext->extradata_size = 0;
   }
-  mCodecContext->extradata = mExtraData.begin();
 
   if (codec->capabilities & CODEC_CAP_DR1) {
     mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
   }
 
   if (avcodec_open2(mCodecContext, codec, nullptr) < 0) {
     NS_WARNING("Couldn't initialise ffmpeg decoder");
     return NS_ERROR_FAILURE;
--- a/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.h
@@ -4,18 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __FFmpegDataDecoder_h__
 #define __FFmpegDataDecoder_h__
 
 #include "PlatformDecoderModule.h"
 #include "FFmpegLibs.h"
-#include "mozilla/Vector.h"
 #include "mozilla/StaticMutex.h"
+#include "mp4_demuxer/mp4_demuxer.h"
 
 namespace mozilla
 {
 
 template <int V>
 class FFmpegDataDecoder : public MediaDataDecoder
 {
 };
@@ -36,17 +36,17 @@ public:
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
 protected:
   AVFrame*        PrepareFrame();
 
   MediaTaskQueue* mTaskQueue;
   AVCodecContext* mCodecContext;
   AVFrame*        mFrame;
-  Vector<uint8_t> mExtraData;
+  nsRefPtr<mp4_demuxer::ByteBuffer> mExtraData;
 
 private:
   static bool sFFmpegInitDone;
   static StaticMutex sMonitor;
 
   AVCodecID mCodecID;
 };
 
--- a/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h
@@ -13,17 +13,22 @@
 
 namespace mozilla
 {
 
 template <int V>
 class FFmpegDecoderModule : public PlatformDecoderModule
 {
 public:
-  static PlatformDecoderModule* Create() { return new FFmpegDecoderModule(); }
+  static already_AddRefed<PlatformDecoderModule>
+  Create()
+  {
+    nsRefPtr<PlatformDecoderModule> pdm = new FFmpegDecoderModule();
+    return pdm.forget();
+  }
 
   FFmpegDecoderModule() {}
   virtual ~FFmpegDecoderModule() {}
 
   virtual nsresult Shutdown() MOZ_OVERRIDE { return NS_OK; }
 
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
@@ -52,13 +57,14 @@ public:
   {
     return FFmpegAudioDecoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
   }
 
   virtual bool SupportsVideoMimeType(const char* aMimeType) MOZ_OVERRIDE
   {
     return FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
   }
+
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegDecoderModule_h__
--- a/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaTaskQueue.h"
 #include "nsThreadUtils.h"
 #include "nsAutoPtr.h"
 #include "ImageContainer.h"
 
 #include "mp4_demuxer/mp4_demuxer.h"
+#include "mp4_demuxer/AnnexB.h"
 
 #include "FFmpegH264Decoder.h"
 
 #define GECKO_FRAME_TYPE 0x00093CC0
 
 typedef mozilla::layers::Image Image;
 typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
 
@@ -27,17 +28,16 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::VideoDecoderConfig& aConfig,
   ImageContainer* aImageContainer)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
   , mImageContainer(aImageContainer)
 {
   MOZ_COUNT_CTOR(FFmpegH264Decoder);
-  mExtraData.append(aConfig.extra_data.begin(), aConfig.extra_data.length());
 }
 
 nsresult
 FFmpegH264Decoder<LIBAV_VER>::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -48,16 +48,17 @@ FFmpegH264Decoder<LIBAV_VER>::Init()
 }
 
 FFmpegH264Decoder<LIBAV_VER>::DecodeResult
 FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(mp4_demuxer::MP4Sample* aSample)
 {
   AVPacket packet;
   av_init_packet(&packet);
 
+  mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
   aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
   packet.data = aSample->data;
   packet.size = aSample->size;
   packet.dts = aSample->decode_timestamp;
   packet.pts = aSample->composition_timestamp;
   packet.flags = aSample->is_sync_point ? AV_PKT_FLAG_KEY : 0;
   packet.pos = aSample->byte_offset;
 
--- a/dom/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp
@@ -16,24 +16,24 @@ namespace mozilla
 {
 
 FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus =
   LinkStatus_INIT;
 
 struct AvFormatLib
 {
   const char* Name;
-  PlatformDecoderModule* (*Factory)();
+  already_AddRefed<PlatformDecoderModule> (*Factory)();
   uint32_t Version;
 };
 
 template <int V> class FFmpegDecoderModule
 {
 public:
-  static PlatformDecoderModule* Create();
+  static already_AddRefed<PlatformDecoderModule> Create();
 };
 
 static const AvFormatLib sLibs[] = {
   { "libavformat.so.56", FFmpegDecoderModule<55>::Create, 55 },
   { "libavformat.so.55", FFmpegDecoderModule<55>::Create, 55 },
   { "libavformat.so.54", FFmpegDecoderModule<54>::Create, 54 },
   { "libavformat.so.53", FFmpegDecoderModule<53>::Create, 53 },
   { "libavformat.56.dylib", FFmpegDecoderModule<55>::Create, 55 },
@@ -96,24 +96,24 @@ FFmpegRuntimeLinker::Bind(const char* aL
     }                                                                          \
   }
 #include "FFmpegFunctionList.h"
 #undef AV_FUNC
 #undef LIBAVCODEC_ALLVERSION
   return true;
 }
 
-/* static */ PlatformDecoderModule*
+/* static */ already_AddRefed<PlatformDecoderModule>
 FFmpegRuntimeLinker::CreateDecoderModule()
 {
   if (!Link()) {
     return nullptr;
   }
-  PlatformDecoderModule* module = sLib->Factory();
-  return module;
+  nsRefPtr<PlatformDecoderModule> module = sLib->Factory();
+  return module.forget();
 }
 
 /* static */ void
 FFmpegRuntimeLinker::Unlink()
 {
   if (sLinkedLib) {
     dlclose(sLinkedLib);
     sLinkedLib = nullptr;
--- a/dom/media/fmp4/ffmpeg/FFmpegRuntimeLinker.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegRuntimeLinker.h
@@ -2,30 +2,30 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __FFmpegRuntimeLinker_h__
 #define __FFmpegRuntimeLinker_h__
 
+#include "PlatformDecoderModule.h"
 #include <stdint.h>
 
 namespace mozilla
 {
 
-class PlatformDecoderModule;
 struct AvFormatLib;
 
 class FFmpegRuntimeLinker
 {
 public:
   static bool Link();
   static void Unlink();
-  static PlatformDecoderModule* CreateDecoderModule();
+  static already_AddRefed<PlatformDecoderModule> CreateDecoderModule();
 
 private:
   static void* sLinkedLib;
   static const AvFormatLib* sLib;
 
   static bool Bind(const char* aLibName, uint32_t Version);
 
   static enum LinkStatus {
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -41,18 +41,18 @@ GonkAudioDecoderManager::GonkAudioDecode
   : mAudioChannels(aConfig.channel_count)
   , mAudioRate(aConfig.samples_per_second)
   , mAudioProfile(aConfig.aac_profile)
   , mUseAdts(true)
   , mAudioBuffer(nullptr)
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
-  mUserData.AppendElements(&aConfig.audio_specific_config[0],
-                           aConfig.audio_specific_config.length());
+  mUserData.AppendElements(aConfig.audio_specific_config->Elements(),
+                           aConfig.audio_specific_config->Length());
   // Pass through mp3 without applying an ADTS header.
   if (strcmp(aConfig.mime_type, "audio/mp4a-latm") != 0) {
       mUseAdts = false;
   }
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
 {
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -440,17 +440,17 @@ GonkVideoDecoderManager::Input(mp4_demux
 {
   if (mDecoder == nullptr) {
     GVDM_LOG("Decoder is not inited");
     return NS_ERROR_UNEXPECTED;
   }
   status_t rv;
   if (aSample != nullptr) {
     // We must prepare samples in AVC Annex B.
-    mp4_demuxer::AnnexB::ConvertSample(aSample);
+    mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
     // Forward sample data to the decoder.
 
     QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
 
     const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
     uint32_t length = aSample->size;
     rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
   }
--- a/dom/media/fmp4/moz.build
+++ b/dom/media/fmp4/moz.build
@@ -1,23 +1,25 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS += [
+    'AVCCDecoderModule.h',
     'MP4Decoder.h',
     'MP4Reader.h',
     'MP4Stream.h',
     'PlatformDecoderModule.h',
     'SharedDecoderManager.h',
 ]
 
 UNIFIED_SOURCES += [
+    'AVCCDecoderModule.cpp',
     'BlankDecoderModule.cpp',
     'MP4Decoder.cpp',
     'MP4Stream.cpp',
     'PlatformDecoderModule.cpp',
     'SharedDecoderManager.cpp',
 ]
 
 SOURCES += [
--- a/dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -78,18 +78,18 @@ WMFAudioMFTManager::WMFAudioMFTManager(
 {
   MOZ_COUNT_CTOR(WMFAudioMFTManager);
 
   if (!strcmp(aConfig.mime_type, "audio/mpeg")) {
     mStreamType = MP3;
   } else if (!strcmp(aConfig.mime_type, "audio/mp4a-latm")) {
     mStreamType = AAC;
     AACAudioSpecificConfigToUserData(aConfig.aac_profile,
-                                     &aConfig.audio_specific_config[0],
-                                     aConfig.audio_specific_config.length(),
+                                     aConfig.audio_specific_config->Elements(),
+                                     aConfig.audio_specific_config->Length(),
                                      mUserData);
   } else {
     mStreamType = Unknown;
   }
 }
 
 WMFAudioMFTManager::~WMFAudioMFTManager()
 {
--- a/dom/media/fmp4/wmf/WMFDecoderModule.h
+++ b/dom/media/fmp4/wmf/WMFDecoderModule.h
@@ -12,17 +12,17 @@
 namespace mozilla {
 
 class WMFDecoderModule : public PlatformDecoderModule {
 public:
   WMFDecoderModule();
   virtual ~WMFDecoderModule();
 
   // Initializes the module, loads required dynamic libraries, etc.
-  nsresult Startup();
+  virtual nsresult Startup() MOZ_OVERRIDE;
 
   // Called when the decoders have shutdown.
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -210,17 +210,17 @@ WMFVideoMFTManager::Init()
   return decoder.forget();
 }
 
 HRESULT
 WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
 {
   if (mStreamType != VP8 && mStreamType != VP9) {
     // We must prepare samples in AVC Annex B.
-    mp4_demuxer::AnnexB::ConvertSample(aSample);
+    mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
   }
   // Forward sample data to the decoder.
   const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
   uint32_t length = aSample->size;
   return mDecoder->Input(data, length, aSample->composition_timestamp);
 }
 
 HRESULT
--- a/dom/media/gmp-plugin/gmp-test-storage.cpp
+++ b/dom/media/gmp-plugin/gmp-test-storage.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gmp-test-storage.h"
 #include <vector>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/NullPtr.h"
 
 class WriteRecordClient : public GMPRecordClient {
 public:
   GMPErr Init(GMPRecord* aRecord,
               GMPTask* aOnSuccess,
               GMPTask* aOnFailure,
               const uint8_t* aData,
               uint32_t aDataSize) {
@@ -20,17 +21,17 @@ public:
     mOnSuccess = aOnSuccess;
     mOnFailure = aOnFailure;
     mData.insert(mData.end(), aData, aData + aDataSize);
     return mRecord->Open();
   }
 
   virtual void OpenComplete(GMPErr aStatus) MOZ_OVERRIDE {
     if (GMP_SUCCEEDED(aStatus)) {
-      mRecord->Write(&mData.front(), mData.size());
+      mRecord->Write(mData.size() ? &mData.front() : nullptr, mData.size());
     } else {
       GMPRunOnMainThread(mOnFailure);
       mOnSuccess->Destroy();
     }
   }
 
   virtual void ReadComplete(GMPErr aStatus,
                             const uint8_t* aData,
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -67,53 +67,16 @@ private:
   GMPGetAPIFunc mGetAPIFunc;
   SandboxStarter* mSandboxStarter;
 };
 
 GMPLoader* CreateGMPLoader(SandboxStarter* aStarter) {
   return static_cast<GMPLoader*>(new GMPLoaderImpl(aStarter));
 }
 
-#if defined(XP_WIN) && defined(HASH_NODE_ID_WITH_DEVICE_ID)
-MOZ_NEVER_INLINE
-static bool
-GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom)
-{
-  // "Top" of the free space on the stack is directly after the memory
-  // holding our return address.
-  uint8_t* top = (uint8_t*)_AddressOfReturnAddress();
-
-  // Look down the stack until we find the guard page...
-  MEMORY_BASIC_INFORMATION memInfo = {0};
-  uint8_t* bottom = top;
-  while (1) {
-    if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
-      return false;
-    }
-    if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) {
-      bottom = (uint8_t*)memInfo.BaseAddress + memInfo.RegionSize;
-#ifdef DEBUG
-      if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
-        return false;
-      }
-      assert(!(memInfo.Protect & PAGE_GUARD)); // Should have found boundary.
-#endif
-      break;
-    } else if (memInfo.State != MEM_COMMIT ||
-               (memInfo.AllocationProtect & PAGE_READWRITE) != PAGE_READWRITE) {
-      return false;
-    }
-    bottom = (uint8_t*)memInfo.BaseAddress - 1;
-  }
-  *aOutTop = top;
-  *aOutBottom = bottom;
-  return true;
-}
-#endif
-
 bool
 GMPLoaderImpl::Load(const char* aLibPath,
                     uint32_t aLibPathLen,
                     char* aOriginSalt,
                     uint32_t aOriginSaltLen,
                     const GMPPlatformAPI* aPlatformAPI)
 {
   std::string nodeId;
@@ -141,27 +104,19 @@ GMPLoaderImpl::Load(const char* aLibPath
     memset(aOriginSalt, 0, aOriginSaltLen);
     volumeId = 0;
     memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size());
     deviceId = L"";
 
     if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) {
       return false;
     }
-    // We've successfully bound the origin salt to node id.
-    // rlz_lib::GetRawMachineId and/or the system functions it
-    // called could have left user identifiable data on the stack,
-    // so carefully zero the stack down to the guard page.
-    uint8_t* top;
-    uint8_t* bottom;
-    if (!GetStackAfterCurrentFrame(&top, &bottom)) {
-      return false;
-    }
-    assert(top >= bottom);
-    SecureZeroMemory(bottom, (top - bottom));
+    // TODO: (Bug 1114867) Clear any memory on the stack that may have been
+    // used by functions we've called that may have left behind data that
+    // can be used to uniquely identify the user.
   } else
 #endif
   {
     nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen);
   }
 
   // Start the sandbox now that we've generated the device bound node id.
   // This must happen after the node id is bound to the device id, as
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -143,37 +143,40 @@ GMPParent::LoadProcess()
     if (!mProcess->Launch(30 * 1000)) {
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
 
     bool opened = Open(mProcess->GetChannel(), mProcess->GetChildProcessHandle());
     if (!opened) {
+      LOGD(("%s::%s: Failed to create new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
-    LOGD(("%s::%s: Created new process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
+    LOGD(("%s::%s: Created new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
 
     bool ok = SendSetNodeId(mNodeId);
     if (!ok) {
+      LOGD(("%s::%s: Failed to send node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
-    LOGD(("%s::%s: Failed to send node id %p", __CLASS__, __FUNCTION__, (void *)mProcess));
+    LOGD(("%s::%s: Sent node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
 
     ok = SendStartPlugin();
     if (!ok) {
+      LOGD(("%s::%s: Failed to send start to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
-    LOGD(("%s::%s: Failed to send start %p", __CLASS__, __FUNCTION__, (void *)mProcess));
+    LOGD(("%s::%s: Sent StartPlugin to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
   }
 
   mState = GMPStateLoaded;
 
   return NS_OK;
 }
 
 void
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -4,16 +4,17 @@ support-files =
   mediasource.js
   seek.webm seek.webm^headers^
   seek_lowres.webm seek_lowres.webm^headers^
 
 [test_MediaSource.html]
 [test_MediaSource_disabled.html]
 [test_BufferedSeek.html]
 [test_BufferingWait.html]
+skip-if = true # bug 1093133
 [test_EndOfStream.html]
 skip-if = (toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187
 [test_FrameSelection.html]
 [test_HaveMetadataUnbufferedSeek.html]
 [test_LoadedMetadataFired.html]
 [test_SeekableAfterEndOfStream.html]
 [test_SeekableAfterEndOfStreamSplit.html]
 [test_SeekableBeforeEndOfStream.html]
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -166,20 +166,16 @@ var gPlayTests = [
     type:"video/ogg", duration:0.266 },
 
   // Test playback of a webm file
   { name:"seek.webm", type:"video/webm", duration:3.966 },
 
   // Test playback of a WebM file with non-zero start time.
   { name:"split.webm", type:"video/webm", duration:1.967 },
 
-  // Test playback of a WebM file with vp9 video
-  //{ name:"vp9.webm", type:"video/webm", duration:4 },
-  { name:"vp9cake.webm", type:"video/webm", duration:7.966 },
-
   // Test playback of a raw file
   { name:"seek.yuv", type:"video/x-raw-yuv", duration:1.833 },
 
   // A really short, low sample rate, single channel file. This tests whether
   // we can handle playing files when only push very little audio data to the
   // hardware.
   { name:"spacestorm-1000Hz-100ms.ogg", type:"audio/ogg", duration:0.099 },
 
@@ -217,17 +213,21 @@ var gPlayTests = [
   { name:"huge-id3.mp3", type:"audio/mpeg", duration:1.00 },
   // A truncated VBR MP3 with just enough frames to keep most decoders happy.
   // The Xing header reports the length of the file to be around 10 seconds, but
   // there is really only one second worth of data. We want MP3FrameParser to
   // trust the header, so this should be reported as 10 seconds.
   { name:"vbr-head.mp3", type:"audio/mpeg", duration:10.00 },
 
   // Invalid file
-  { name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
+  { name:"bogus.duh", type:"bogus/duh", duration:Number.NaN },
+
+  // Test playback of a WebM file with vp9 video
+  //{ name:"vp9.webm", type:"video/webm", duration:4 },
+  { name:"vp9cake.webm", type:"video/webm", duration:7.966 }
 ];
 
 // A file for each type we can support.
 var gSnifferTests = [
   { name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444 },
   { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942 },
   { name:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
   { name:"gizmo.mp4", type:"video/mp4", duration:5.56, size:383631 },
--- a/dom/media/test/test_playback.html
+++ b/dom/media/test/test_playback.html
@@ -111,16 +111,30 @@ function startTest(test, token) {
   v.addEventListener("timeupdate", timeUpdate, false);
 
   // We should get "ended" and "suspend" events for every resource
   v.addEventListener("ended", checkEnded, false);
   v.addEventListener("suspend", checkSuspended, false);
 
   document.body.appendChild(v);
   v.play();
+
+  if (test.name == "vp9cake.webm") {
+    // Log events for debugging.
+    var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+                  "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+                  "waiting", "pause"];
+    function logEvent(e) {
+      var v = e.target;
+      info(e.target.token + ": got " + e.type);
+    }
+    events.forEach(function(e) {
+      v.addEventListener(e, logEvent, false);
+    });
+  }
 }
 
 manager.runTests(gPlayTests, startTest);
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webm/IntelWebMVideoDecoder.cpp
+++ b/dom/media/webm/IntelWebMVideoDecoder.cpp
@@ -51,17 +51,17 @@ public:
     byte_offset = aByteOffset;
     is_sync_point = aSyncPoint;
 
     data =  new uint8_t[aSize];
     size = aSize;
     memmove(data, aData, size);
   }
 
-  ~VP8Sample()
+  virtual ~VP8Sample()
   {
     delete data;
   }
 };
 
 IntelWebMVideoDecoder::IntelWebMVideoDecoder(WebMReader* aReader)
   : WebMVideoDecoder()
   , mReader(aReader)
--- a/dom/media/webm/IntelWebMVideoDecoder.h
+++ b/dom/media/webm/IntelWebMVideoDecoder.h
@@ -54,17 +54,17 @@ private:
 
   bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
 
   bool IsSupportedVideoMimeType(const char* aMimeType);
 
   VP8Sample* PopSample();
 
   nsRefPtr<WebMReader> mReader;
-  nsAutoPtr<PlatformDecoderModule> mPlatform;
+  nsRefPtr<PlatformDecoderModule> mPlatform;
   nsRefPtr<MediaDataDecoder> mMediaDataDecoder;
 
   // TaskQueue on which decoder can choose to decode.
   // Only non-null up until the decoder is created.
   nsRefPtr<MediaTaskQueue> mTaskQueue;
 
   // Monitor that protects all non-threadsafe state; the primitives
   // that follow.
--- a/dom/network/NetUtils.cpp
+++ b/dom/network/NetUtils.cpp
@@ -173,19 +173,21 @@ int32_t NetUtils::do_dhcp_do_request(con
     // JB 4.3
     // http://androidxref.com/4.3_r2.1/xref/system/core/libnetutils/dhcp_utils.c#181
     DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char**, char*, uint32_t*, char*, char*)
     USE_DLFUNC(dhcp_do_request)
     char *dns[3] = {dns1, dns2, nullptr};
     char domains[PROPERTY_VALUE_MAX];
     ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns,
                           server, lease, vendorinfo, domains);
-  } else if (sdkVersion == 19) {
-    // JB 4.4
+  } else if (sdkVersion >= 19) {
+    // KitKat 4.4.X
     // http://androidxref.com/4.4_r1/xref/system/core/libnetutils/dhcp_utils.c#18
+    // Lollipop 5.0
+    //http://androidxref.com/5.0.0_r2/xref/system/core/libnetutils/dhcp_utils.c#186
     DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*,  uint32_t*, char**, char*, uint32_t*, char*, char*, char*)
     USE_DLFUNC(dhcp_do_request)
     char *dns[3] = {dns1, dns2, nullptr};
     char domains[PROPERTY_VALUE_MAX];
     char mtu[PROPERTY_VALUE_MAX];
     ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorinfo, domains, mtu);
   } else {
     NS_WARNING("Unable to perform do_dhcp_request: unsupported sdk version!");
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -1,15 +1,19 @@
 [DEFAULT]
 support-files =
   inert_style.css
 
 [test_bug900724.html]
 [test_bug1017896.html]
 [test_content_element.html]
+[test_custom_element_adopt_callbacks.html]
+[test_custom_element_callback_innerhtml.html]
+[test_custom_element_clone_callbacks.html]
+[test_custom_element_clone_callbacks_extended.html]
 [test_nested_content_element.html]
 [test_dest_insertion_points.html]
 [test_dest_insertion_points_shadow.html]
 [test_fallback_dest_insertion_points.html]
 [test_detached_style.html]
 [test_dynamic_content_element_matching.html]
 [test_document_register.html]
 [test_document_register_base_queue.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_adopt_callbacks.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1081039
+-->
+<head>
+  <title>Test callbacks for adopted custom elements.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<template id="template"><x-foo></x-foo></template>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a>
+<script>
+
+var p = Object.create(HTMLElement.prototype);
+p.createdCallback = function() {
+  ok(false, "Created callback should not be called for adopted node.");
+};
+
+document.registerElement("x-foo", { prototype: p });
+
+var template = document.getElementById("template");
+var adoptedFoo = document.adoptNode(template.content.firstChild);
+is(adoptedFoo.nodeName, "X-FOO");
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1102502
+-->
+<head>
+  <title>Test for attached callback for element created in the document by the parser</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1102502">Bug 1102502</a>
+<div id="container"></div>
+
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+var attachedCallbackCount = 0;
+
+var p = Object.create(HTMLElement.prototype);
+
+p.createdCallback = function() {
+  ok(true, "createdCallback called.");
+};
+
+p.attachedCallback = function() {
+  ok(true, "attachedCallback should be called when the parser creates an element in the document.");
+  attachedCallbackCount++;
+  // attachedCallback should be called twice, once for the element created for innerHTML and
+  // once for the element created in this document.
+  if (attachedCallbackCount == 2) {
+    SimpleTest.finish();
+  }
+}
+
+document.registerElement("x-foo", { prototype: p });
+
+var container = document.getElementById("container");
+container.innerHTML = '<x-foo></x-foo>';
+
+</script>
+
+<x-foo></x-foo>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1081039
+-->
+<head>
+  <title>Test callbacks for cloned custom elements.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+// Test to make sure created callback is called on clones that are upgraded and clones
+// created after registering the custom element.
+
+var callbackCalledOnUpgrade = false;
+var callbackCalledOnClone = false;
+
+var foo = document.createElement("x-foo");
+var fooClone = foo.cloneNode(true);
+
+var p = Object.create(HTMLElement.prototype);
+p.createdCallback = function() {
+  is(this.__proto__, p, "Correct prototype should be set on custom elements.");
+
+  if (this == fooClone) {
+    // Callback called for the element created before registering the custom element.
+    // Should be called on element upgrade.
+    is(callbackCalledOnUpgrade, false, "Upgrade should only be called once per clone.");
+    callbackCalledOnUpgrade = true;
+  } else if (this != foo) {
+    // Callback called for the element created after registering the custom element.
+    is(callbackCalledOnClone, false, "Upgrade should only be called once per clone.");
+    callbackCalledOnClone = true;
+  }
+
+  if (callbackCalledOnUpgrade && callbackCalledOnClone) {
+    SimpleTest.finish();
+  }
+};
+
+document.registerElement("x-foo", { prototype: p });
+
+var anotherFooClone = foo.cloneNode(true);
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks_extended.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1081039
+-->
+<head>
+  <title>Test callbacks for cloned extended custom elements.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+// Test to make sure created callback is called on clones that are upgraded and clones
+// created after registering the custom element.
+
+var callbackCalledOnUpgrade = false;
+var callbackCalledOnClone = false;
+
+var foo = document.createElement("button", "x-foo");
+is(foo.getAttribute("is"), "x-foo");
+
+var fooClone = foo.cloneNode(true);
+
+var p = Object.create(HTMLButtonElement.prototype);
+p.createdCallback = function() {
+  is(this.__proto__, p, "Correct prototype should be set on custom elements.");
+
+  if (this == fooClone) {
+    // Callback called for the element created before registering the custom element.
+    // Should be called on element upgrade.
+    is(callbackCalledOnUpgrade, false, "Upgrade should only be called once per clone.");
+    callbackCalledOnUpgrade = true;
+  } else if (this != foo) {
+    // Callback called for the element created after registering the custom element.
+    is(callbackCalledOnClone, false, "Upgrade should only be called once per clone.");
+    callbackCalledOnClone = true;
+  }
+
+  if (callbackCalledOnUpgrade && callbackCalledOnClone) {
+    SimpleTest.finish();
+  }
+};
+
+document.registerElement("x-foo", { prototype: p, extends: "button" });
+
+var anotherFooClone = foo.cloneNode(true);
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
--- a/dom/workers/test/test_websocket.html
+++ b/dom/workers/test/test_websocket.html
@@ -9,16 +9,18 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <pre id="feedback"></pre>
 <script class="testbody" type="text/javascript">
 
+SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
+function() {
   var worker = new Worker("websocket_worker.js");
 
   worker.onmessage = function(event) {
     is(event.target, worker, "event.target should be a worker!");
 
     if (event.data.type == 'finish') {
       info("All done!");
       SimpleTest.finish();
@@ -33,14 +35,16 @@
   worker.onerror = function(event) {
     is(event.target, worker);
     info("error!");
     ok(false, "Worker had an error: " + event.data);
     SimpleTest.finish();
   };
 
   worker.postMessage('foobar');
-  SimpleTest.waitForExplicitFinish();
+});
+
+SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/workers/test/test_websocket_basic.html
+++ b/dom/workers/test/test_websocket_basic.html
@@ -10,16 +10,18 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test"></pre>
 <script class="testbody" type="text/javascript">
 
+SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
+function() {
   var worker = new Worker("websocket_basic_worker.js");
 
   worker.onmessage = function(event) {
     is(event.target, worker);
 
     if (event.data.type == 'finish') {
       runTest();
     } else if (event.data.type == 'status') {
@@ -44,14 +46,16 @@
       return;
     }
 
     var test = tests.shift();
     test();
   }
 
   runTest();
-  SimpleTest.waitForExplicitFinish();
+});
+
+SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/workers/test/test_websocket_loadgroup.html
+++ b/dom/workers/test/test_websocket_loadgroup.html
@@ -10,16 +10,18 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test"></pre>
 <script class="testbody" type="text/javascript">
 
+SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
+function() {
   var worker = new Worker("websocket_loadgroup_worker.js");
 
   var stopped = false;
   worker.onmessage = function(e) {
     if (e.data == 'opened') {
       stopped = true;
       window.stop();
     } else if (e.data == 'closed') {
@@ -48,14 +50,16 @@
       return;
     }
 
     var test = tests.shift();
     test();
   }
 
   runTest();
-  SimpleTest.waitForExplicitFinish();
+});
+
+SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/workers/test/test_websocket_pref.html
+++ b/dom/workers/test/test_websocket_pref.html
@@ -14,16 +14,18 @@
 <script id="js_script" type="text/js-worker">
 onmessage = function() {
   postMessage("WebSocket" in this ? "OK" : "KO");
 }
 </script>
 
 <script class="testbody" type="text/javascript">
 
+SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
+function() {
   var blob = new Blob([document.getElementById("js_script").textContent],
                       {type: "text/javascript"});
   var url = URL.createObjectURL(blob);
 
   var tests = [
     function() {
       SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
       function() {
@@ -58,16 +60,18 @@ onmessage = function() {
       SimpleTest.finish();
       return;
     }
 
     var t = tests.shift();
     t();
   }
 
-  SimpleTest.waitForExplicitFinish();
   runTest();
+});
+
+SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -147,17 +147,17 @@ var interfaceNamesInGlobalScope =
     "XMLHttpRequest",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XMLHttpRequestUpload",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "URL",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "URLSearchParams",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "WebSocket",
+   { name: "WebSocket", pref: "dom.workers.websocket.enabled" },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Worker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WorkerGlobalScope",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WorkerLocation",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WorkerNavigator",
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -106,17 +106,17 @@ ClientCanvasLayer::Initialize(const Data
           factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, nullConsGL, caps);
 #endif
         }
         break;
       }
       case mozilla::layers::LayersBackend::LAYERS_D3D10:
       case mozilla::layers::LayersBackend::LAYERS_D3D11: {
 #ifdef XP_WIN
-        if (mGLContext->IsANGLE() && DoesD3D11DeviceWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device())) {
+        if (mGLContext->IsANGLE() && DoesD3D11TextureSharingWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device())) {
           factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps);
         }
 #endif
         break;
       }
       default:
         break;
     }
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -590,17 +590,16 @@ CopyFrontToBack(TextureClient* aFront,
 
   gfx::IntPoint rectToCopyTopLeft = aRectToCopy.TopLeft();
   aFront->CopyToTextureClient(aBack, &aRectToCopy, &rectToCopyTopLeft);
   return true;
 }
 
 void
 TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
-                                        bool aCanRerasterizeValidRegion,
                                         nsIntRegion& aAddPaintedRegion)
 {
   if (mBackBuffer && mFrontBuffer) {
     gfx::IntSize tileSize = mFrontBuffer->GetSize();
     const nsIntRect tileRect = nsIntRect(0, 0, tileSize.width, tileSize.height);
 
     if (aDirtyRegion.Contains(tileRect)) {
       // The dirty region means that we no longer need the front buffer, so
@@ -609,19 +608,17 @@ TileClient::ValidateBackBufferFromFront(
     } else {
       // Region that needs copying.
       nsIntRegion regionToCopy = mInvalidBack;
 
       regionToCopy.Sub(regionToCopy, aDirtyRegion);
 
       aAddPaintedRegion = regionToCopy;
 
-      if (regionToCopy.IsEmpty() ||
-          (aCanRerasterizeValidRegion &&
-           regionToCopy.Area() < tileSize.width * tileSize.height * MINIMUM_TILE_COPY_AREA)) {
+      if (regionToCopy.IsEmpty()) {
         // Just redraw it all.
         return;
       }
 
       // Copy the bounding rect of regionToCopy. As tiles are quite small, it
       // is unlikely that we'd save much by copying each individual rect of the
       // region, but we can reevaluate this if it becomes an issue.
       const nsIntRect rectToCopy = regionToCopy.GetBounds();
@@ -708,17 +705,16 @@ TileClient::DiscardBackBuffer()
 }
 
 TextureClient*
 TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion,
                           gfxContentType aContent,
                           SurfaceMode aMode,
                           bool *aCreatedTextureClient,
                           nsIntRegion& aAddPaintedRegion,
-                          bool aCanRerasterizeValidRegion,
                           RefPtr<TextureClient>* aBackBufferOnWhite)
 {
   // Try to re-use the front-buffer if possible
   if (mFrontBuffer &&
       mFrontBuffer->HasInternalBuffer() &&
       mFrontLock->GetReadCount() == 1 &&
       !(aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mFrontBufferOnWhite)) {
     // If we had a backbuffer we no longer care about it since we'll
@@ -773,17 +769,17 @@ TileClient::GetBackBuffer(const nsIntReg
     }
 
     MOZ_ASSERT(mBackLock->IsValid());
 
     *aCreatedTextureClient = true;
     mInvalidBack = nsIntRect(0, 0, mBackBuffer->GetSize().width, mBackBuffer->GetSize().height);
   }
 
-  ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion, aAddPaintedRegion);
+  ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion);
 
   *aBackBufferOnWhite = mBackBufferOnWhite;
   return mBackBuffer;
 }
 
 TileDescriptor
 TileClient::GetTileDescriptor()
 {
@@ -1111,17 +1107,16 @@ ClientTiledLayerBuffer::ValidateTile(Til
   SurfaceMode mode;
   gfxContentType content = GetContentType(&mode);
   nsIntRegion extraPainted;
   RefPtr<TextureClient> backBufferOnWhite;
   RefPtr<TextureClient> backBuffer =
     aTile.GetBackBuffer(offsetScaledDirtyRegion,
                         content, mode,
                         &createdTextureClient, extraPainted,
-                        usingTiledDrawTarget,
                         &backBufferOnWhite);
 
   extraPainted.MoveBy(aTileOrigin);
   extraPainted.And(extraPainted, mNewValidRegion);
   mPaintedRegion.Or(mPaintedRegion, extraPainted);
 
   if (!backBuffer) {
     NS_WARNING("Failed to allocate a tile TextureClient");
@@ -1145,18 +1140,16 @@ ClientTiledLayerBuffer::ValidateTile(Til
       NS_WARNING("Failed to lock tile TextureClient for updating.");
       aTile.DiscardBackBuffer();
       aTile.DiscardFrontBuffer();
       return TileClient();
     }
   }
 
   if (usingTiledDrawTarget) {
-    aTile.Flip();
-
     if (createdTextureClient) {
       if (!mCompositableClient->AddTextureClient(backBuffer)) {
         NS_WARNING("Failed to add tile TextureClient.");
         aTile.DiscardFrontBuffer();
         aTile.DiscardBackBuffer();
         return aTile;
       }
       if (backBufferOnWhite && !mCompositableClient->AddTextureClient(backBufferOnWhite)) {
@@ -1175,50 +1168,50 @@ ClientTiledLayerBuffer::ValidateTile(Til
       dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
       moz2DTile.mDrawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
     } else {
       moz2DTile.mDrawTarget = dt;
     }
     moz2DTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x * mResolution, aTileOrigin.y * mResolution);
     if (!dt || (backBufferOnWhite && !dtOnWhite)) {
       aTile.DiscardFrontBuffer();
+      aTile.DiscardBackBuffer();
       return aTile;
     }
 
     mMoz2DTiles.push_back(moz2DTile);
     mTilingOrigin.x = std::min(mTilingOrigin.x, moz2DTile.mTileOrigin.x);
     mTilingOrigin.y = std::min(mTilingOrigin.y, moz2DTile.mTileOrigin.y);
 
     nsIntRegionRectIterator it(aDirtyRegion);
     for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
       gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x,
                          dirtyRect->y - aTileOrigin.y,
                          dirtyRect->width,
                          dirtyRect->height);
       drawRect.Scale(mResolution);
 
-      gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
-                            NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
-                            drawRect.width,
-                            drawRect.height);
-      gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
-      // Mark the newly updated area as invalid in the back buffer
-      aTile.mInvalidBack.Or(aTile.mInvalidBack, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
+      // Mark the newly updated area as invalid in the front buffer
+      aTile.mInvalidFront.Or(aTile.mInvalidFront,
+        nsIntRect(NS_roundf(drawRect.x), NS_roundf(drawRect.y),
+                  drawRect.width, drawRect.height));
 
       if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
         dt->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
         dtOnWhite->FillRect(drawRect, ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
       } else if (content == gfxContentType::COLOR_ALPHA) {
         dt->ClearRect(drawRect);
       }
     }
 
     // The new buffer is now validated, remove the dirty region from it.
-    aTile.mInvalidFront.Sub(nsIntRect(0, 0, GetTileSize().width, GetTileSize().height),
-                            offsetScaledDirtyRegion);
+    aTile.mInvalidBack.Sub(nsIntRect(0, 0, GetTileSize().width, GetTileSize().height),
+                           offsetScaledDirtyRegion);
+
+    aTile.Flip();
 
     return aTile;
   }
 
   // Single paint buffer case:
 
   MOZ_ASSERT(!backBufferOnWhite, "Component alpha only supported with TiledDrawTarget");
 
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -234,17 +234,16 @@ struct TileClient
   * knows to upload it.
   *
   * If nullptr is returned, aTextureClientOnWhite is undefined.
   */
   TextureClient* GetBackBuffer(const nsIntRegion& aDirtyRegion,
                                gfxContentType aContent, SurfaceMode aMode,
                                bool *aCreatedTextureClient,
                                nsIntRegion& aAddPaintedRegion,
-                               bool aCanRerasterizeValidRegion,
                                RefPtr<TextureClient>* aTextureClientOnWhite);
 
   void DiscardFrontBuffer();
 
   void DiscardBackBuffer();
 
   /* We wrap the back buffer in a class that disallows assignment
    * so that we can track when ever it changes so that we can update
@@ -274,17 +273,16 @@ struct TileClient
   nsIntRegion mInvalidFront;
   nsIntRegion mInvalidBack;
   nsExpirationState mExpirationState;
 
 private:
   // Copies dirty pixels from the front buffer into the back buffer,
   // and records the copied region in aAddPaintedRegion.
   void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
-                                   bool aCanRerasterizeValidRegion,
                                    nsIntRegion& aAddPaintedRegion);
 };
 
 /**
  * This struct stores all the data necessary to perform a paint so that it
  * doesn't need to be recalculated on every repeated transaction.
  */
 struct BasicTiledLayerPaintData {
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -773,17 +773,17 @@ gfxTextRun::MeasureText(uint32_t aStart,
 }
 
 #define MEASUREMENT_BUFFER_SIZE 100
 
 uint32_t
 gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
                                 bool aLineBreakBefore, gfxFloat aWidth,
                                 PropertyProvider *aProvider,
-                                bool aSuppressInitialBreak,
+                                SuppressBreak aSuppressBreak,
                                 gfxFloat *aTrimWhitespace,
                                 Metrics *aMetrics,
                                 gfxFont::BoundingBoxType aBoundingBoxType,
                                 gfxContext *aRefContext,
                                 bool *aUsedHyphenation,
                                 uint32_t *aLastBreak,
                                 bool aCanWordWrap,
                                 gfxBreakPriority *aBreakPriority)
@@ -842,17 +842,18 @@ gfxTextRun::BreakAndMeasureText(uint32_t
                                                 hyphenBuffer);
             }
         }
 
         // There can't be a word-wrap break opportunity at the beginning of the
         // line: if the width is too small for even one character to fit, it 
         // could be the first and last break opportunity on the line, and that
         // would trigger an infinite loop.
-        if (!aSuppressInitialBreak || i > aStart) {
+        if (aSuppressBreak != eSuppressAllBreaks &&
+            (aSuppressBreak != eSuppressInitialBreak || i > aStart)) {
             bool atNaturalBreak = mCharacterGlyphs[i].CanBreakBefore() == 1;
             bool atHyphenationBreak =
                 !atNaturalBreak && haveHyphenation && hyphenBuffer[i - bufferStart];
             bool atBreak = atNaturalBreak || atHyphenationBreak;
             bool wordWrapping =
                 aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() &&
                 *aBreakPriority <= gfxBreakPriority::eWordWrapBreak;
 
@@ -1761,17 +1762,17 @@ gfxFontGroup::GetFontAt(int32_t i, uint3
             fe = ufe->GetPlatformFontEntry();
             if (!fe) {
                 return nullptr;
             }
             unicodeRangeMap = ufe->GetUnicodeRangeMap();
         }
         font = fe->FindOrMakeFont(&mStyle, mFonts[i].NeedsBold(),
                                   unicodeRangeMap);
-        if (font && !font->Valid()) {
+        if (!font || !font->Valid()) {
             ff.SetInvalid();
             return nullptr;
         }
         mFonts[i].SetFont(font);
     }
     return font.get();
 }
 
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -302,16 +302,24 @@ public:
      * @param aAdvanceWidthDelta if non-null, returns the change in advance
      * width of the given range.
      */
     virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength,
                                  bool aLineBreakBefore, bool aLineBreakAfter,
                                  gfxFloat *aAdvanceWidthDelta,
                                  gfxContext *aRefContext);
 
+    enum SuppressBreak {
+      eNoSuppressBreak,
+      // Measure the range of text as if there is no break before it.
+      eSuppressInitialBreak,
+      // Measure the range of text as if it contains no break
+      eSuppressAllBreaks
+    };
+
     /**
      * Finds the longest substring that will fit into the given width.
      * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
      * Guarantees the following:
      * -- 0 <= result <= aMaxLength
      * -- result is the maximal value of N such that either
      *       N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
      *   OR  N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
@@ -326,20 +334,17 @@ public:
      * The call has the effect of
      * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
      * and the returned metrics and the invariants above reflect this.
      *
      * @param aMaxLength this can be UINT32_MAX, in which case the length used
      * is up to the end of the string
      * @param aLineBreakBefore set to true if and only if there is an actual
      * line break at the start of this string.
-     * @param aSuppressInitialBreak if true, then we assume there is no possible
-     * linebreak before aStart. If false, then we will check the internal
-     * line break opportunity state before deciding whether to return 0 as the
-     * character to break before.
+     * @param aSuppressBreak what break should be suppressed.
      * @param aTrimWhitespace if non-null, then we allow a trailing run of
      * spaces to be trimmed; the width of the space(s) will not be included in
      * the measured string width for comparison with the limit aWidth, and
      * trimmed spaces will not be included in returned metrics. The width
      * of the trimmed spaces will be returned in aTrimWhitespace.
      * Trimmed spaces are still counted in the "characters fit" result.
      * @param aMetrics if non-null, we fill this in for the returned substring.
      * If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
@@ -363,17 +368,17 @@ public:
      * not set a break with a lower priority. @see gfxBreakPriority.
      * 
      * Note that negative advance widths are possible especially if negative
      * spacing is provided.
      */
     uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
                                  bool aLineBreakBefore, gfxFloat aWidth,
                                  PropertyProvider *aProvider,
-                                 bool aSuppressInitialBreak,
+                                 SuppressBreak aSuppressBreak,
                                  gfxFloat *aTrimWhitespace,
                                  Metrics *aMetrics,
                                  gfxFont::BoundingBoxType aBoundingBoxType,
                                  gfxContext *aRefContextForTightBoundingBox,
                                  bool *aUsedHyphenation,
                                  uint32_t *aLastBreak,
                                  bool aCanWordWrap,
                                  gfxBreakPriority *aBreakPriority);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -428,17 +428,17 @@ gfxWindowsPlatform::UpdateRenderMode()
     if (d2dDisabled || mUsingGDIFonts) {
         tryD2D = false;
     }
 
     ID3D11Device *device = GetD3D11Device();
     if (isVistaOrHigher && !safeMode && tryD2D &&
         device &&
         device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 &&
-        DoesD3D11DeviceWork(device)) {
+        DoesD3D11TextureSharingWork(device)) {
 
         VerifyD2DDevice(d2dForceEnabled);
         if (mD2DDevice && GetD3D11Device()) {
             mRenderMode = RENDER_DIRECT2D;
             mUseDirectWrite = true;
         }
     } else {
         mD2DDevice = nullptr;
@@ -1548,20 +1548,16 @@ gfxWindowsPlatform::GetDXGIAdapter()
   }
 
   // We leak this module everywhere, we might as well do so here as well.
   dxgiModule.disown();
 
   return mAdapter;
 }
 
-#define TEXTURE_SIZE 32
-
-// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
-// with E_OUTOFMEMORY.
 bool DoesD3D11DeviceWork(ID3D11Device *device)
 {
   static bool checked;
   static bool result;
 
   if (checked)
       return result;
   checked = true;
@@ -1585,16 +1581,39 @@ bool DoesD3D11DeviceWork(ID3D11Device *d
     }
     if (displayLinkModuleVersion <= V(8,6,1,36484)) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
 #endif
       return false;
     }
   }
+  result = true;
+  return true;
+}
+
+#define TEXTURE_SIZE 32
+
+// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
+// with E_OUTOFMEMORY.
+bool DoesD3D11TextureSharingWork(ID3D11Device *device)
+{
+  static bool checked;
+  static bool result;
+
+  if (checked)
+      return result;
+  checked = true;
+
+  if (gfxPrefs::Direct2DForceEnabled() ||
+      gfxPrefs::LayersAccelerationForceEnabled())
+  {
+    result = true;
+    return true;
+  }
 
   RefPtr<ID3D11Texture2D> texture;
   D3D11_TEXTURE2D_DESC desc;
   desc.Width = TEXTURE_SIZE;
   desc.Height = TEXTURE_SIZE;
   desc.MipLevels = 1;
   desc.ArraySize = 1;
   desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
@@ -1780,17 +1799,17 @@ gfxWindowsPlatform::InitD3D11Devices()
       if (gfxPrefs::LayersD3D11DisableWARP()) {
         return;
       }
 
       useWARP = true;
       adapter = nullptr;
     }
 
-    if (FAILED(hr)) {
+    if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
       if (gfxPrefs::LayersD3D11DisableWARP()) {
         return;
       }
 
       useWARP = true;
       adapter = nullptr;
     }
   }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -290,11 +290,12 @@ private:
     mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
 
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 };
 
+bool DoesD3D11TextureSharingWork(ID3D11Device *device);
 bool DoesD3D11DeviceWork(ID3D11Device *device);
 
 #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -1026,17 +1026,17 @@ imgLoader::imgLoader()
 {
   sMemReporter->AddRef();
   sMemReporter->RegisterLoader(this);
 }
 
 already_AddRefed<imgLoader>
 imgLoader::GetInstance()
 {
-  static StaticRefPtr<imgLoader> singleton;
+  static nsRefPtr<imgLoader> singleton;
   if (!singleton) {
     singleton = imgLoader::Create();
     if (!singleton)
         return nullptr;
     ClearOnShutdown(&singleton);
   }
   nsRefPtr<imgLoader> loader = singleton.get();
   return loader.forget();
--- a/ipc/chromium/src/chrome/common/ipc_message_utils.h
+++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h
@@ -548,276 +548,11 @@ struct ParamTraitsMozilla<nsresult> {
     l->append(StringPrintf(L"%u", static_cast<uint32_t>(p)));
   }
 };
 
 // Finally, ParamTraits itself.
 
 template <class P> struct ParamTraits : ParamTraitsMozilla<P> {};
 
-//-----------------------------------------------------------------------------
-// Generic message subclasses
-
-// Used for asynchronous messages.
-template <class ParamType>
-class MessageWithTuple : public Message {
- public:
-  typedef ParamType Param;
-
-  MessageWithTuple(int32_t routing_id, uint16_t type, const Param& p)
-      : Message(routing_id, type, PRIORITY_NORMAL) {
-    WriteParam(this, p);
-  }
-
-  static bool Read(const Message* msg, Param* p) {
-    void* iter = NULL;
-    bool rv = ReadParam(msg, &iter, p);
-    DCHECK(rv) << "Error deserializing message " << msg->type();
-    return rv;
-  }
-
-  // Generic dispatcher.  Should cover most cases.
-  template<class T, class Method>
-  static bool Dispatch(const Message* msg, T* obj, Method func) {
-    Param p;
-    if (Read(msg, &p)) {
-      DispatchToMethod(obj, func, p);
-      return true;
-    }
-    return false;
-  }
-
-  // The following dispatchers exist for the case where the callback function
-  // needs the message as well.  They assume that "Param" is a type of Tuple
-  // (except the one arg case, as there is no Tuple1).
-  template<class T, typename TA>
-  static bool Dispatch(const Message* msg, T* obj,
-                       void (T::*func)(const Message&, TA)) {
-    Param p;
-    if (Read(msg, &p)) {
-      (obj->*func)(*msg, p);
-      return true;
-    }
-    return false;
-  }
-
-  template<class T, typename TA, typename TB>
-  static bool Dispatch(const Message* msg, T* obj,
-                       void (T::*func)(const Message&, TA, TB)) {
-    Param p;
-    if (Read(msg, &p)) {
-      (obj->*func)(*msg, p.a, p.b);
-      return true;
-    }
-    return false;
-  }
-
-  template<class T, typename TA, typename TB, typename TC>
-  static bool Dispatch(const Message* msg, T* obj,
-                       void (T::*func)(const Message&, TA, TB, TC)) {
-    Param p;
-    if (Read(msg, &p)) {
-      (obj->*func)(*msg, p.a, p.b, p.c);
-      return true;
-    }
-    return false;
-  }
-
-  template<class T, typename TA, typename TB, typename TC, typename TD>
-  static bool Dispatch(const Message* msg, T* obj,
-                       void (T::*func)(const Message&, TA, TB, TC, TD)) {
-    Param p;
-    if (Read(msg, &p)) {
-      (obj->*func)(*msg, p.a, p.b, p.c, p.d);
-      return true;
-    }
-    return false;
-  }
-
-  template<class T, typename TA, typename TB, typename TC, typename TD,
-           typename TE>
-  static bool Dispatch(const Message* msg, T* obj,
-                       void (T::*func)(const Message&, TA, TB, TC, TD, TE)) {
-    Param p;
-    if (Read(msg, &p)) {
-      (obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e);
-      return true;
-    }
-    return false;
-  }
-
-  static void Log(const Message* msg, std::wstring* l) {
-    Param p;
-    if (Read(msg, &p))
-      LogParam(p, l);
-  }
-
-  // Functions used to do manual unpacking.  Only used by the automation code,
-  // these should go away once that code uses SyncChannel.
-  template<typename TA, typename TB>
-  static bool Read(const IPC::Message* msg, TA* a, TB* b) {
-    ParamType params;
-    if (!Read(msg, &params))
-      return false;
-    *a = params.a;
-    *b = params.b;
-    return true;
-  }
-
-  template<typename TA, typename TB, typename TC>
-  static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) {
-    ParamType params;
-    if (!Read(msg, &params))
-      return false;
-    *a = params.a;
-    *b = params.b;
-    *c = params.c;
-    return true;
-  }
-
-  template<typename TA, typename TB, typename TC, typename TD>
-  static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) {
-    ParamType params;
-    if (!Read(msg, &params))
-      return false;
-    *a = params.a;
-    *b = params.b;
-    *c = params.c;
-    *d = params.d;
-    return true;
-  }
-
-  template<typename TA, typename TB, typename TC, typename TD, typename TE>
-  static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d, TE* e) {
-    ParamType params;
-    if (!Read(msg, &params))
-      return false;
-    *a = params.a;
-    *b = params.b;
-    *c = params.c;
-    *d = params.d;
-    *e = params.e;
-    return true;
-  }
-};
-
-// This class assumes that its template argument is a RefTuple (a Tuple with
-// reference elements).
-template <class RefTuple>
-class ParamDeserializer : public MessageReplyDeserializer {
- public:
-  explicit ParamDeserializer(const RefTuple& out) : out_(out) { }
-
-  bool SerializeOutputParameters(const IPC::Message& msg, void* iter) {
-    return ReadParam(&msg, &iter, &out_);
-  }
-
-  RefTuple out_;
-};
-
-// Used for synchronous messages.
-template <class SendParamType, class ReplyParamType>
-class MessageWithReply : public SyncMessage {
- public:
-  typedef SendParamType SendParam;
-  typedef ReplyParamType ReplyParam;
-
-  MessageWithReply(int32_t routing_id, uint16_t type,
-                   const SendParam& send, const ReplyParam& reply)
-      : SyncMessage(routing_id, type, PRIORITY_NORMAL,
-                    new ParamDeserializer<ReplyParam>(reply)) {
-    WriteParam(this, send);
-  }
-
-  static void Log(const Message* msg, std::wstring* l) {
-    if (msg->is_sync()) {
-      SendParam p;
-      void* iter = SyncMessage::GetDataIterator(msg);
-      if (ReadParam(msg, &iter, &p))
-        LogParam(p, l);
-
-    } else {
-      // This is an outgoing reply.  Now that we have the output parameters, we
-      // can finally log the message.
-      typename ReplyParam::ValueTuple p;
-      void* iter = SyncMessage::GetDataIterator(msg);
-      if (ReadParam(msg, &iter, &p))
-        LogParam(p, l);
-    }
-  }
-
-  template<class T, class Method>
-  static bool Dispatch(const Message* msg, T* obj, Method func) {
-    SendParam send_params;
-    void* iter = GetDataIterator(msg);
-    Message* reply = GenerateReply(msg);
-    bool error;
-    if (ReadParam(msg, &iter, &send_params)) {
-      typename ReplyParam::ValueTuple reply_params;
-      DispatchToMethod(obj, func, send_params, &reply_params);
-      WriteParam(reply, reply_params);
-      error = false;
-    } else {
-      NOTREACHED() << "Error deserializing message " << msg->type();
-      reply->set_reply_error();
-      error = true;
-    }
-
-    obj->Send(reply);
-    return !error;
-  }
-
-  template<class T, class Method>
-  static bool DispatchDelayReply(const Message* msg, T* obj, Method func) {
-    SendParam send_params;
-    void* iter = GetDataIterator(msg);
-    Message* reply = GenerateReply(msg);
-    bool error;
-    if (ReadParam(msg, &iter, &send_params)) {
-      Tuple1<Message&> t = MakeRefTuple(*reply);
-
-      DispatchToMethod(obj, func, send_params, &t);
-      error = false;
-    } else {
-      NOTREACHED() << "Error deserializing message " << msg->type();
-      reply->set_reply_error();
-      obj->Send(reply);
-      error = true;
-    }
-    return !error;
-  }
-
-  template<typename TA>
-  static void WriteReplyParams(Message* reply, TA a) {
-    ReplyParam p(a);
-    WriteParam(reply, p);
-  }
-
-  template<typename TA, typename TB>
-  static void WriteReplyParams(Message* reply, TA a, TB b) {
-    ReplyParam p(a, b);
-    WriteParam(reply, p);
-  }
-
-  template<typename TA, typename TB, typename TC>
-  static void WriteReplyParams(Message* reply, TA a, TB b, TC c) {
-    ReplyParam p(a, b, c);
-    WriteParam(reply, p);
-  }
-
-  template<typename TA, typename TB, typename TC, typename TD>
-  static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) {
-    ReplyParam p(a, b, c, d);
-    WriteParam(reply, p);
-  }
-
-  template<typename TA, typename TB, typename TC, typename TD, typename TE>
-  static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) {
-    ReplyParam p(a, b, c, d, e);
-    WriteParam(reply, p);
-  }
-};
-
-//-----------------------------------------------------------------------------
-
 }  // namespace IPC
 
 #endif  // CHROME_COMMON_IPC_MESSAGE_UTILS_H_
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -687,22 +687,16 @@ struct GCMethods<JSFunction *>
     static void postBarrier(JSFunction **vp) {
         JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp));
     }
     static void relocate(JSFunction **vp) {
         JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell **>(vp));
     }
 };
 
-#ifdef JS_DEBUG
-/* This helper allows us to assert that Rooted<T> is scoped within a request. */
-extern JS_PUBLIC_API(bool)
-IsInRequest(JSContext *cx);
-#endif
-
 } /* namespace js */
 
 namespace JS {
 
 /*
  * Local variable of type T whose value is always rooted. This is typically
  * used for local variables, or for non-rooted values being passed to a
  * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
@@ -725,30 +719,24 @@ class MOZ_STACK_CLASS Rooted : public js
     }
 
   public:
     explicit Rooted(JSContext *cx
                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(js::GCMethods<T>::initial())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-#ifdef JS_DEBUG
-        MOZ_ASSERT(js::IsInRequest(cx));
-#endif
         init(js::ContextFriendFields::get(cx));
     }
 
     Rooted(JSContext *cx, T initial
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-#ifdef JS_DEBUG
-        MOZ_ASSERT(js::IsInRequest(cx));
-#endif
         init(js::ContextFriendFields::get(cx));
     }
 
     explicit Rooted(js::ContextFriendFields *cx
                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(js::GCMethods<T>::initial())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1,12 +1,51 @@
 /* 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/. */
 
+// ES6 draft rev29 (2014/12/06) 22.2.3.8 %TypedArray%.prototype.fill(value [, start [, end ]])
+function TypedArrayFill(value, start = 0, end = undefined) {
+    // This function is not generic.
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, value, start, end,
+                            "TypedArrayFill");
+    }
+
+    // Steps 1-2.
+    var O = this;
+
+    // Steps 3-5.
+    var len = TypedArrayLength(O);
+
+    // Steps 6-7.
+    var relativeStart = ToInteger(start);
+
+    // Step 8.
+    var k = relativeStart < 0
+            ? std_Math_max(len + relativeStart, 0)
+            : std_Math_min(relativeStart, len);
+
+    // Steps 9-10.
+    var relativeEnd = end === undefined ? len : ToInteger(end);
+
+    // Step 11.
+    var final = relativeEnd < 0
+                ? std_Math_max(len + relativeEnd, 0)
+                : std_Math_min(relativeEnd, len);
+
+    // Step 12.
+    for (; k < final; k++) {
+        O[k] = value;
+    }
+
+    // Step 13.
+    return O;
+}
+
 // ES6 draft rev28 (2014/10/14) 22.2.3.10 %TypedArray%.prototype.find(predicate[, thisArg]).
 function TypedArrayFind(predicate, thisArg = undefined) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, predicate, thisArg,
                             "TypedArrayFind");
     }
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1801,18 +1801,27 @@ ia64*-hpux*)
             LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT"
             if test -z "$DEVELOPER_OPTIONS"; then
                 LDFLAGS="$LDFLAGS -RELEASE"
             fi
         fi
         dnl For profile-guided optimization
         PROFILE_GEN_CFLAGS="-GL"
         PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
-        PROFILE_USE_CFLAGS="-GL"
-        PROFILE_USE_LDFLAGS="-LTCG:PGOPTIMIZE"
+        dnl XXX: PGO builds can fail with warnings treated as errors,
+        dnl specifically "no profile data available" appears to be
+        dnl treated as an error sometimes. This might be a consequence
+        dnl of using WARNINGS_AS_ERRORS in some modules, combined
+        dnl with the linker doing most of the work in the whole-program
+        dnl optimization/PGO case. I think it's probably a compiler bug,
+        dnl but we work around it here.
+        PROFILE_USE_CFLAGS="-GL -wd4624 -wd4952"
+        dnl XXX: should be -LTCG:PGOPTIMIZE, but that fails on libxul.
+        dnl Probably also a compiler bug, but what can you do?
+        PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE"
         LDFLAGS="$LDFLAGS -DYNAMICBASE"
     fi
     AC_DEFINE(HAVE_SNPRINTF)
     AC_DEFINE(HAVE__MSIZE)
     AC_DEFINE(_WINDOWS)
     AC_DEFINE(WIN32)
     AC_DEFINE(XP_WIN)
     AC_DEFINE(XP_WIN32)
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -266,16 +266,19 @@ MarkPagesUnused(void *p, size_t size)
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     LPVOID p2 = MapMemoryAt(p, size, MEM_RESET);
     return p2 == p;
 }
 
 bool
 MarkPagesInUse(void *p, size_t size)
 {
+    if (!DecommitEnabled())
+        return true;
+
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     PROCESS_MEMORY_COUNTERS pmc;
@@ -339,16 +342,19 @@ MarkPagesUnused(void *p, size_t size)
 {
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     return true;
 }
 
 bool
 MarkPagesInUse(void *p, size_t size)
 {
+    if (!DecommitEnabled())
+        return true;
+
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     return 0;
@@ -656,16 +662,19 @@ MarkPagesUnused(void *p, size_t size)
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     int result = madvise(p, size, MADV_DONTNEED);
     return result != -1;
 }
 
 bool
 MarkPagesInUse(void *p, size_t size)
 {
+    if (!DecommitEnabled())
+        return true;
+
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     struct rusage usage;
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -866,78 +866,69 @@ Statistics::stopTimingMutator(double &mu
     return true;
 }
 
 void
 Statistics::beginPhase(Phase phase)
 {
     Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
 
-    // Re-entry is allowed during callbacks. Do not account nested GC time
-    // against the callbacks.
+    // Re-entry is allowed during callbacks, so pause callback phases while
+    // other phases are in progress, auto-resuming after they end. As a result,
+    // nested GC time will not be accounted against the callback phases.
     //
     // Reuse this mechanism for managing PHASE_MUTATOR.
     if (parent == PHASE_GC_BEGIN || parent == PHASE_GC_END || parent == PHASE_MUTATOR) {
         suspendedPhases[suspendedPhaseNestingDepth++] = parent;
         MOZ_ASSERT(suspendedPhaseNestingDepth <= mozilla::ArrayLength(suspendedPhases));
-        endPhase(parent);
+        recordPhaseEnd(parent);
         parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
     }
 
     // Guard against any other re-entry.
-#ifdef DEBUG
-    if (phaseStartTimes[phase]) {
-        fprintf(stderr, "phase %d already has start time of %ld; recursive entry detected!\n",
-                phase, phaseStartTimes[phase]);
-        for (int i = 0; i < phaseNestingDepth; i++)
-            fprintf(stderr, "  stack[%d]: %d\n", i, phaseNesting[i]);
-        MOZ_CRASH("My horse for a stack trace!\n");
-    }
     MOZ_ASSERT(!phaseStartTimes[phase]);
-#endif
 
-#ifdef DEBUG
     MOZ_ASSERT(phases[phase].index == phase);
     MOZ_ASSERT(phaseNestingDepth < MAX_NESTING);
     MOZ_ASSERT_IF(gcDepth == 1 && phase != PHASE_MINOR_GC, phases[phase].parent == parent);
-#endif
 
     phaseNesting[phaseNestingDepth] = phase;
     phaseNestingDepth++;
 
     phaseStartTimes[phase] = PRMJ_Now();
 }
 
 void
-Statistics::endPhase(Phase phase)
+Statistics::recordPhaseEnd(Phase phase)
 {
     int64_t now = PRMJ_Now();
 
     if (phase == PHASE_MUTATOR)
         timedGCStart = now;
 
     phaseNestingDepth--;
 
     int64_t t = now - phaseStartTimes[phase];
     if (!slices.empty())
         slices.back().phaseTimes[phase] += t;
     phaseTimes[phase] += t;
     phaseStartTimes[phase] = 0;
+}
+
+void
+Statistics::endPhase(Phase phase)
+{
+    recordPhaseEnd(phase);
 
     // When emptying the stack, we may need to resume a callback phase
-    // (PHASE_GC_BEGIN/END) or if not, return to timing the mutator
-    // (PHASE_MUTATOR).
-    //
-    // However, if the phase we're ending is PHASE_MUTATOR, that means
-    // beginPhase is calling endPhase(PHASE_MUTATOR) because some other phase
-    // is starting. So don't resume any earlier phase.
-    if (phaseNestingDepth == 0 && suspendedPhaseNestingDepth > 0 && phase != PHASE_MUTATOR) {
+    // (PHASE_GC_BEGIN/END) or return to timing the mutator (PHASE_MUTATOR).
+    if (phaseNestingDepth == 0 && suspendedPhaseNestingDepth > 0) {
         Phase resumePhase = suspendedPhases[--suspendedPhaseNestingDepth];
         if (resumePhase == PHASE_MUTATOR)
-            timedGCTime += now - timedGCStart;
+            timedGCTime += PRMJ_Now() - timedGCStart;
         beginPhase(resumePhase);
     }
 }
 
 void
 Statistics::endParallelPhase(Phase phase, const GCParallelTask *task)
 {
     phaseNestingDepth--;
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -224,16 +224,18 @@ struct Statistics
     /* Sweep times for SCCs of compartments. */
     Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
 
     JS::GCSliceCallback sliceCallback;
 
     void beginGC(JSGCInvocationKind kind);
     void endGC();
 
+    void recordPhaseEnd(Phase phase);
+
     void gcDuration(int64_t *total, int64_t *maxPause);
     void sccDurations(int64_t *total, int64_t *maxPause);
     void printStats();
     bool formatData(StatisticsSerializer &ss, uint64_t timestamp);
 
     UniqueChars formatDescription();
     UniqueChars formatSliceDescription(unsigned i, const SliceData &slice);
     UniqueChars formatTotals();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/recover-lambdas-bug1113940.js
@@ -0,0 +1,32 @@
+
+gczeal(14);
+
+// The object metadata callback can iterate over the stack. Thus during the
+// allocation of the lambda we might inspect the stack which is still incomplete
+// because the lambda is not yet reconstructed.
+setObjectMetadataCallback(function() {});
+function f() {
+    (function() {
+        '' ^ Object
+    })();
+}
+x = 0;
+for (var j = 0; j < 99; ++j) {
+    x += f();
+}
+
+try {
+  x = true;
+  setObjectMetadataCallback(function([x, y, z], ... Debugger) {});
+  for (var i = 0; i < 10; ++i) {
+    var f = function() {
+      function g() {
+	x++;
+      }
+      g();
+    }
+    f();
+  }
+} catch (e) {
+  assertEq(e instanceof TypeError, true);
+}
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -9525,29 +9525,16 @@ CodeGenerator::loadJSScriptForBlock(MBas
     // The current JSScript means the script for the current
     // basic block. This may be an inlined script.
 
     JSScript *script = block->info().script();
     masm.movePtr(ImmGCPtr(script), reg);
 }
 
 void
-CodeGenerator::visitHaveSameClass(LHaveSameClass *ins)
-{
-    Register lhs = ToRegister(ins->lhs());
-    Register rhs = ToRegister(ins->rhs());
-    Register temp = ToRegister(ins->getTemp(0));
-    Register output = ToRegister(ins->output());
-
-    masm.loadObjClass(lhs, temp);
-    masm.loadObjClass(rhs, output);
-    masm.cmpPtrSet(Assembler::Equal, temp, output, output);
-}
-
-void
 CodeGenerator::visitHasClass(LHasClass *ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register output = ToRegister(ins->output());
 
     masm.loadObjClass(lhs, output);
     masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
 }
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -307,17 +307,16 @@ class CodeGenerator : public CodeGenerat
     void visitGetDOMMember(LGetDOMMember *lir);
     void visitSetDOMProperty(LSetDOMProperty *lir);
     void visitCallDOMNative(LCallDOMNative *lir);
     void visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir);
     void visitIsCallable(LIsCallable *lir);
     void visitOutOfLineIsCallable(OutOfLineIsCallable *ool);
     void visitIsObject(LIsObject *lir);
     void visitIsObjectAndBranch(LIsObjectAndBranch *lir);
-    void visitHaveSameClass(LHaveSameClass *lir);
     void visitHasClass(LHasClass *lir);
     void visitAsmJSParameter(LAsmJSParameter *lir);
     void visitAsmJSReturn(LAsmJSReturn *ret);
     void visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
     void visitLexicalCheck(LLexicalCheck *ins);
     void visitThrowUninitializedLexical(LThrowUninitializedLexical *ins);
     void visitDebugger(LDebugger *ins);
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -781,17 +781,16 @@ class IonBuilder
     InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
     bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
                                                      ScalarTypeDescr::Type *arrayType);
     InliningStatus inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *target);
 
     // Utility intrinsics.
     InliningStatus inlineIsCallable(CallInfo &callInfo);
     InliningStatus inlineIsObject(CallInfo &callInfo);
-    InliningStatus inlineHaveSameClass(CallInfo &callInfo);
     InliningStatus inlineToObject(CallInfo &callInfo);
     InliningStatus inlineToInteger(CallInfo &callInfo);
     InliningStatus inlineToString(CallInfo &callInfo);
     InliningStatus inlineDump(CallInfo &callInfo);
     InliningStatus inlineHasClass(CallInfo &callInfo, const Class *clasp,
                                   const Class *clasp2 = nullptr,
                                   const Class *clasp3 = nullptr,
                                   const Class *clasp4 = nullptr);
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "jit/JitFrames-inl.h"
 
 #include "jsfun.h"
+#include "jsinfer.h"
 #include "jsobj.h"
 #include "jsscript.h"
 
 #include "gc/ForkJoinNursery.h"
 #include "gc/Marking.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineIC.h"
@@ -28,16 +29,17 @@
 #include "jit/Snapshots.h"
 #include "jit/VMFunctions.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Debugger.h"
 #include "vm/ForkJoin.h"
 #include "vm/Interpreter.h"
 #include "vm/TraceLogging.h"
 
+#include "jsinferinlines.h"
 #include "jsscriptinlines.h"
 #include "gc/Nursery-inl.h"
 #include "jit/JitFrameIterator-inl.h"
 #include "vm/Debugger-inl.h"
 #include "vm/Probes-inl.h"
 
 namespace js {
 namespace jit {
@@ -2115,16 +2117,20 @@ SnapshotIterator::computeInstructionResu
             return false;
 
         // No need to iterate over the only resume point.
         if (!numResults) {
             MOZ_ASSERT(results->isInitialized());
             return true;
         }
 
+        // Use AutoEnterAnalysis to avoid invoking the object metadata callback,
+        // which could try to walk the stack while bailing out.
+        types::AutoEnterAnalysis enter(cx);
+
         // Fill with the results of recover instructions.
         SnapshotIterator s(*this);
         s.instructionResults_ = results;
         while (s.moreInstructions()) {
             // Skip resume point and only interpret recover instructions.
             if (s.instruction()->isResumePoint()) {
                 s.skipInstruction();
                 continue;
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -6517,38 +6517,16 @@ class LIsObjectAndBranch : public LContr
     MBasicBlock *ifTrue() const {
         return getSuccessor(0);
     }
     MBasicBlock *ifFalse() const {
         return getSuccessor(1);
     }
 };
 
-class LHaveSameClass : public LInstructionHelper<1, 2, 1>
-{
-  public:
-    LIR_HEADER(HaveSameClass);
-    LHaveSameClass(const LAllocation &left, const LAllocation &right,
-                   const LDefinition &temp) {
-        setOperand(0, left);
-        setOperand(1, right);
-        setTemp(0, temp);
-    }
-
-    const LAllocation *lhs() {
-        return getOperand(0);
-    }
-    const LAllocation *rhs() {
-        return getOperand(1);
-    }
-    MHaveSameClass *mir() const {
-        return mir_->toHaveSameClass();
-    }
-};
-
 class LHasClass : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(HasClass);
     explicit LHasClass(const LAllocation &lhs) {
         setOperand(0, lhs);
     }
 
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -316,17 +316,16 @@
     _(ProfilerStackOp)              \
     _(GetDOMProperty)               \
     _(GetDOMMember)                 \
     _(SetDOMProperty)               \
     _(CallDOMNative)                \
     _(IsCallable)                   \
     _(IsObject)                     \
     _(IsObjectAndBranch)            \
-    _(HaveSameClass)                \
     _(HasClass)                     \
     _(AsmJSLoadHeap)                \
     _(AsmJSStoreHeap)               \
     _(AsmJSLoadGlobalVar)           \
     _(AsmJSStoreGlobalVar)          \
     _(AsmJSLoadFFIFunc)             \
     _(AsmJSParameter)               \
     _(AsmJSReturn)                  \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3670,28 +3670,16 @@ LIRGenerator::visitIsObject(MIsObject *i
     MDefinition *opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType_Value);
     LIsObject *lir = new(alloc()) LIsObject();
     useBoxAtStart(lir, LIsObject::Input, opd);
     define(lir, ins);
 }
 
 void
-LIRGenerator::visitHaveSameClass(MHaveSameClass *ins)
-{
-    MDefinition *lhs = ins->lhs();
-    MDefinition *rhs = ins->rhs();
-
-    MOZ_ASSERT(lhs->type() == MIRType_Object);
-    MOZ_ASSERT(rhs->type() == MIRType_Object);
-
-    define(new(alloc()) LHaveSameClass(useRegister(lhs), useRegister(rhs), temp()), ins);
-}
-
-void
 LIRGenerator::visitHasClass(MHasClass *ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType_Object);
     MOZ_ASSERT(ins->type() == MIRType_Boolean);
     define(new(alloc()) LHasClass(useRegister(ins->object())), ins);
 }
 
 void
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -256,17 +256,16 @@ class LIRGenerator : public LIRGenerator
     void visitThrow(MThrow *ins);
     void visitIn(MIn *ins);
     void visitInArray(MInArray *ins);
     void visitInstanceOf(MInstanceOf *ins);
     void visitCallInstanceOf(MCallInstanceOf *ins);
     void visitProfilerStackOp(MProfilerStackOp *ins);
     void visitIsCallable(MIsCallable *ins);
     void visitIsObject(MIsObject *ins);
-    void visitHaveSameClass(MHaveSameClass *ins);
     void visitHasClass(MHasClass *ins);
     void visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins);
     void visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins);
     void visitAsmJSLoadFFIFunc(MAsmJSLoadFFIFunc *ins);
     void visitAsmJSParameter(MAsmJSParameter *ins);
     void visitAsmJSReturn(MAsmJSReturn *ins);
     void visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
     void visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -180,18 +180,16 @@ IonBuilder::inlineNativeCall(CallInfo &c
         native == intrinsic_InParallelSection)
         return inlineForceSequentialOrInParallelSection(callInfo);
     if (native == intrinsic_ForkJoinGetSlice)
         return inlineForkJoinGetSlice(callInfo);
 
     // Utility intrinsics.
     if (native == intrinsic_IsCallable)
         return inlineIsCallable(callInfo);
-    if (native == intrinsic_HaveSameClass)
-        return inlineHaveSameClass(callInfo);
     if (native == intrinsic_ToObject)
         return inlineToObject(callInfo);
     if (native == intrinsic_IsObject)
         return inlineIsObject(callInfo);
     if (native == intrinsic_ToInteger)
         return inlineToInteger(callInfo);
     if (native == intrinsic_ToString)
         return inlineToString(callInfo);
@@ -2074,46 +2072,16 @@ IonBuilder::inlineUnsafeGetReservedSlot(
     // We don't track reserved slot types, so always emit a barrier.
     if (!pushTypeBarrier(load, getInlineReturnTypeSet(), BarrierKind::TypeSet))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineHaveSameClass(CallInfo &callInfo)
-{
-    if (callInfo.argc() != 2 || callInfo.constructing())
-        return InliningStatus_NotInlined;
-    if (callInfo.getArg(0)->type() != MIRType_Object)
-        return InliningStatus_NotInlined;
-    if (callInfo.getArg(1)->type() != MIRType_Object)
-        return InliningStatus_NotInlined;
-
-    types::TemporaryTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
-    types::TemporaryTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
-    const Class *arg1Clasp = arg1Types ? arg1Types->getKnownClass() : nullptr;
-    const Class *arg2Clasp = arg2Types ? arg2Types->getKnownClass() : nullptr;
-    if (arg1Clasp && arg2Clasp) {
-        MConstant *constant = MConstant::New(alloc(), BooleanValue(arg1Clasp == arg2Clasp));
-        current->add(constant);
-        current->push(constant);
-        return InliningStatus_Inlined;
-    }
-
-    callInfo.setImplicitlyUsedUnchecked();
-
-    MHaveSameClass *sameClass = MHaveSameClass::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
-    current->add(sameClass);
-    current->push(sameClass);
-
-    return InliningStatus_Inlined;
-}
-
-IonBuilder::InliningStatus
 IonBuilder::inlineIsCallable(CallInfo &callInfo)
 {
     if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_Boolean)
         return InliningStatus_NotInlined;
     if (callInfo.getArg(0)->type() != MIRType_Object)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11877,39 +11877,16 @@ class MIsObject
   public:
     INSTRUCTION_HEADER(IsObject);
     static MIsObject *New(TempAllocator &alloc, MDefinition *obj) {
         return new(alloc) MIsObject(obj);
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    AliasSet getAliasSet() const {
-        return AliasSet::None();
-    }
-};
-
-class MHaveSameClass
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
-{
-    MHaveSameClass(MDefinition *left, MDefinition *right)
-      : MBinaryInstruction(left, right)
-    {
-        setResultType(MIRType_Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(HaveSameClass);
-
-    static MHaveSameClass *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
-        return new(alloc) MHaveSameClass(left, right);
-    }
-
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -227,17 +227,16 @@ namespace jit {
     _(InterruptCheck)                                                       \
     _(AsmJSInterruptCheck)                                                  \
     _(ProfilerStackOp)                                                      \
     _(GetDOMProperty)                                                       \
     _(GetDOMMember)                                                         \
     _(SetDOMProperty)                                                       \
     _(IsCallable)                                                           \
     _(IsObject)                                                             \
-    _(HaveSameClass)                                                        \
     _(HasClass)                                                             \
     _(AsmJSNeg)                                                             \
     _(AsmJSUnsignedToDouble)                                                \
     _(AsmJSUnsignedToFloat32)                                               \
     _(AsmJSLoadHeap)                                                        \
     _(AsmJSStoreHeap)                                                       \
     _(AsmJSLoadGlobalVar)                                                   \
     _(AsmJSStoreGlobalVar)                                                  \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -327,17 +327,16 @@ class ParallelSafetyVisitor : public MDe
     UNSAFE_OP(InArray)
     SAFE_OP(GuardThreadExclusive)
     SAFE_OP(InterruptCheckPar)
     SAFE_OP(CheckOverRecursedPar)
     SAFE_OP(FunctionDispatch)
     SAFE_OP(TypeObjectDispatch)
     SAFE_OP(IsCallable)
     SAFE_OP(IsObject)
-    SAFE_OP(HaveSameClass)
     SAFE_OP(HasClass)
     UNSAFE_OP(EffectiveAddress)
     UNSAFE_OP(AsmJSUnsignedToDouble)
     UNSAFE_OP(AsmJSUnsignedToFloat32)
     UNSAFE_OP(AsmJSNeg)
     UNSAFE_OP(AsmJSLoadHeap)
     UNSAFE_OP(AsmJSStoreHeap)
     UNSAFE_OP(AsmJSLoadGlobalVar)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -724,23 +724,16 @@ JS_BeginRequest(JSContext *cx)
 JS_PUBLIC_API(void)
 JS_EndRequest(JSContext *cx)
 {
     MOZ_ASSERT(cx->outstandingRequests != 0);
     cx->outstandingRequests--;
     StopRequest(cx);
 }
 
-JS_PUBLIC_API(bool)
-JS_IsInRequest(JSRuntime *rt)
-{
-    MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
-    return rt->requestDepth != 0;
-}
-
 JS_PUBLIC_API(void)
 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback, void *data)
 {
     rt->cxCallback = cxCallback;
     rt->cxCallbackData = data;
 }
 
 JS_PUBLIC_API(JSContext *)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1371,19 +1371,16 @@ JS_PUBLIC_API(void)
 JS_SetRuntimePrivate(JSRuntime *rt, void *data);
 
 extern JS_PUBLIC_API(void)
 JS_BeginRequest(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_EndRequest(JSContext *cx);
 
-extern JS_PUBLIC_API(bool)
-JS_IsInRequest(JSRuntime *rt);
-
 namespace js {
 
 void
 AssertHeapIsIdle(JSRuntime *rt);
 
 void
 AssertHeapIsIdle(JSContext *cx);
 
@@ -1409,42 +1406,16 @@ class JSAutoRequest
 
 #if 0
   private:
     static void *operator new(size_t) CPP_THROW_NEW { return 0; }
     static void operator delete(void *, size_t) { }
 #endif
 };
 
-class JSAutoCheckRequest
-{
-  public:
-    explicit JSAutoCheckRequest(JSContext *cx
-                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-#ifdef JS_DEBUG
-        mContext = cx;
-        MOZ_ASSERT(JS_IsInRequest(JS_GetRuntime(cx)));
-#endif
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    ~JSAutoCheckRequest() {
-#ifdef JS_DEBUG
-        MOZ_ASSERT(JS_IsInRequest(JS_GetRuntime(mContext)));
-#endif
-    }
-
-  private:
-#ifdef JS_DEBUG
-    JSContext *mContext;
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 extern JS_PUBLIC_API(void)
 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback, void *data);
 
 extern JS_PUBLIC_API(JSContext *)
 JS_NewContext(JSRuntime *rt, size_t stackChunkSize);
 
 extern JS_PUBLIC_API(void)
 JS_DestroyContext(JSContext *cx);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -958,17 +958,16 @@ bool intrinsic_ThrowError(JSContext *cx,
 bool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_IsConstructing(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_SubstringKernel(JSContext *cx, unsigned argc, Value *vp);
 
 bool intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_DefineDataProperty(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_UnsafeSetReservedSlot(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_UnsafeGetReservedSlot(JSContext *cx, unsigned argc, Value *vp);
-bool intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp);
 
 bool intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_NewParallelArray(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_ForkJoinGetSlice(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp);
 
 bool intrinsic_ObjectIsTypedObject(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1428,22 +1428,16 @@ js::ReportErrorWithId(JSContext *cx, con
         return;
     JSAutoByteString bytes(cx, idstr);
     if (!bytes)
         return;
     JS_ReportError(cx, msg, bytes.ptr());
 }
 
 #ifdef DEBUG
-JS_PUBLIC_API(bool)
-js::IsInRequest(JSContext *cx)
-{
-    return !!cx->runtime()->requestDepth;
-}
-
 bool
 js::HasObjectMovedOp(JSObject *obj) {
     return !!GetObjectClass(obj)->ext.objectMovedOp;
 }
 #endif
 
 JS_FRIEND_API(void)
 JS_StoreObjectPostBarrierCallback(JSContext* cx,
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2526,19 +2526,17 @@ TypeCompartment::print(JSContext *cx, bo
 
     Zone *zone = compartment()->zone();
     AutoEnterAnalysis enter(nullptr, zone);
 
     if (!force && !InferSpewActive(ISpewResult))
         return;
 
     for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
-        // Note: use cx->runtime() instead of cx to work around IsInRequest(cx)
-        // assertion failures when we're called from DestroyContext.
-        RootedScript script(cx->runtime(), i.get<JSScript>());
+        RootedScript script(cx, i.get<JSScript>());
         if (script->types())
             script->types()->printTypes(cx, script);
     }
 
     for (gc::ZoneCellIter i(zone, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
         TypeObject *object = i.get<TypeObject>();
         object->print();
     }
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -844,17 +844,18 @@ Unbox(JSContext *cx, HandleObject obj, M
 
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
 NewObjectMetadata(ExclusiveContext *cxArg, JSObject **pmetadata)
 {
     // The metadata callback is invoked before each created object, except when
-    // analysis/compilation is active, to avoid recursion.
+    // analysis/compilation is active, to avoid recursion. It is also skipped
+    // when we allocate objects during a bailout, to prevent stack iterations.
     MOZ_ASSERT(!*pmetadata);
     if (JSContext *cx = cxArg->maybeJSContext()) {
         if (MOZ_UNLIKELY((size_t)cx->compartment()->hasObjectMetadataCallback()) &&
             !cx->zone()->types.activeAnalysis)
         {
             // Use AutoEnterAnalysis to prohibit both any GC activity under the
             // callback, and any reentering of JS via Invoke() etc.
             types::AutoEnterAnalysis enter(cx);
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -1,29 +1,33 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "jspropertytree.h"
 
+#include "mozilla/DebugOnly.h"
+
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jstypes.h"
 
 #include "vm/Shape.h"
 
 #include "jsgcinlines.h"
 
 #include "vm/Shape-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
+using mozilla::DebugOnly;
+
 inline HashNumber
 ShapeHasher::hash(const Lookup &l)
 {
     return l.hash();
 }
 
 inline bool
 ShapeHasher::match(const Key k, const Lookup &l)
@@ -205,17 +209,17 @@ PropertyTree::lookupChild(ThreadSafeCont
     } else if (kidp->isHash()) {
         if (KidsHash::Ptr p = kidp->toHash()->readonlyThreadsafeLookup(child))
             shape = *p;
     } else {
         return nullptr;
     }
 
     if (shape) {
-        JS::Zone *zone = shape->arenaHeader()->zone;
+        DebugOnly<JS::Zone *> zone = shape->arenaHeader()->zone;
         MOZ_ASSERT(!zone->needsIncrementalBarrier());
         MOZ_ASSERT(!(zone->isGCSweeping() && !shape->isMarked() &&
                      !shape->arenaHeader()->allocatedDuringIncremental));
     }
 
     return shape;
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedArray/fill.js
@@ -0,0 +1,77 @@
+const constructors = [
+    Int8Array,
+    Uint8Array,
+    Uint8ClampedArray,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+];
+
+for (var constructor of constructors) {
+    assertDeepEq(constructor.prototype.fill.length, 1);
+
+    assertDeepEq(new constructor([]).fill(1), new constructor([]));
+    assertDeepEq(new constructor([1,1,1]).fill(2), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 1), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 1, 2), new constructor([1,2,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, -2), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, -2, -1), new constructor([1,2,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, undefined), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, undefined, undefined), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 1, undefined), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, undefined, 1), new constructor([2,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 2, 1), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, -1, 1), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, -2, 1), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 1, -2), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0.1), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0.9), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 1.1), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0.1, 0.9), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0.1, 1.9), new constructor([2,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0.1, 1.9), new constructor([2,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, -0), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0, -0), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, NaN), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0, NaN), new constructor([1,1,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, false), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, true), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, "0"), new constructor([2,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, "1"), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, "-2"), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, "-2", "-1"), new constructor([1,2,1]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, {valueOf: ()=>1}), new constructor([1,2,2]));
+    assertDeepEq(new constructor([1,1,1]).fill(2, 0, {valueOf: ()=>1}), new constructor([2,1,1]));
+
+    // Called from other globals.
+    if (typeof newGlobal === "function") {
+        var fill = newGlobal()[constructor.name].prototype.fill;
+        assertDeepEq(fill.call(new constructor([3, 2, 1]), 2), new constructor([2, 2, 2]));
+    }
+
+    // Throws if `this` isn't a TypedArray.
+    var nonTypedArrays = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+                         /* new Proxy(new constructor(), {}) // This probably should throw */
+                         ];
+    nonTypedArrays.forEach(nonTypedArray => {
+        assertThrowsInstanceOf(function() {
+            constructor.prototype.fill.call(nonTypedArray, 1);
+        }, TypeError);
+    });
+
+    // Test that the length getter is never called.
+    Object.defineProperty(new constructor([1, 2, 3]), "length", {
+        get() {
+            throw new Error("length accessor called");
+        }
+    }).fill(1);
+}
+
+assertDeepEq(new Float32Array([0, 0]).fill(NaN), new Float32Array([NaN, NaN]));
+assertDeepEq(new Float64Array([0, 0]).fill(NaN), new Float64Array([NaN, NaN]));
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1860,30 +1860,25 @@ Debugger::updateExecutionObservabilityOf
 static inline void
 MarkBaselineScriptActiveIfObservable(JSScript *script, const Debugger::ExecutionObservableSet &obs)
 {
     if (obs.shouldRecompileOrInvalidate(script))
         script->baselineScript()->setActive();
 }
 
 static bool
-AppendAndInvalidateScriptIfObservable(JSContext *cx, Zone *zone, JSScript *script,
-                                      const Debugger::ExecutionObservableSet &obs,
-                                      Vector<JSScript *> &scripts)
-{
-    if (obs.shouldRecompileOrInvalidate(script)) {
-        // Enter the script's compartment as addPendingRecompile attempts to
-        // cancel off-thread compilations, whose books are kept on the
-        // script's compartment.
-        MOZ_ASSERT(script->compartment()->zone() == zone);
-        AutoCompartment ac(cx, script->compartment());
-        zone->types.addPendingRecompile(cx, script);
-        return scripts.append(script);
-    }
-    return true;
+AppendAndInvalidateScript(JSContext *cx, Zone *zone, JSScript *script, Vector<JSScript *> &scripts)
+{
+    // Enter the script's compartment as addPendingRecompile attempts to
+    // cancel off-thread compilations, whose books are kept on the
+    // script's compartment.
+    MOZ_ASSERT(script->compartment()->zone() == zone);
+    AutoCompartment ac(cx, script->compartment());
+    zone->types.addPendingRecompile(cx, script);
+    return scripts.append(script);
 }
 
 static bool
 UpdateExecutionObservabilityOfScriptsInZone(JSContext *cx, Zone *zone,
                                             const Debugger::ExecutionObservableSet &obs,
                                             Debugger::IsObserving observing)
 {
     using namespace js::jit;
@@ -1919,23 +1914,29 @@ UpdateExecutionObservabilityOfScriptsInZ
 
     Vector<JSScript *> scripts(cx);
 
     // Iterate through observable scripts, invalidating their Ion scripts and
     // appending them to a vector for discarding their baseline scripts later.
     {
         types::AutoEnterAnalysis enter(fop, zone);
         if (JSScript *script = obs.singleScriptForZoneInvalidation()) {
-            if (!AppendAndInvalidateScriptIfObservable(cx, zone, script, obs, scripts))
-                return false;
+            if (obs.shouldRecompileOrInvalidate(script)) {
+                if (!AppendAndInvalidateScript(cx, zone, script, scripts))
+                    return false;
+            }
         } else {
             for (gc::ZoneCellIter iter(zone, gc::FINALIZE_SCRIPT); !iter.done(); iter.next()) {
                 JSScript *script = iter.get<JSScript>();
-                if (!AppendAndInvalidateScriptIfObservable(cx, zone, script, obs, scripts))
-                    return false;
+                if (obs.shouldRecompileOrInvalidate(script) &&
+                    !gc::IsScriptAboutToBeFinalized(&script))
+                {
+                    if (!AppendAndInvalidateScript(cx, zone, script, scripts))
+                        return false;
+                }
             }
         }
     }
 
     // Iterate through the scripts again and finish discarding
     // BaselineScripts. This must be done as a separate phase as we can only
     // discard the BaselineScript on scripts that have no IonScript.
     for (size_t i = 0; i < scripts.length(); i++) {
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -486,21 +486,18 @@ RegExpShared::compile(JSContext *cx, Han
 
     return compile(cx, fakeySource, input, mode, force);
 }
 
 bool
 RegExpShared::compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
                       CompilationMode mode, ForceByteCodeEnum force)
 {
-    if (!ignoreCase() && !StringHasRegExpMetaChars(pattern)) {
+    if (!ignoreCase() && !StringHasRegExpMetaChars(pattern))
         canStringMatch = true;
-        parenCount = 0;
-        return true;
-    }
 
     CompileOptions options(cx);
     TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
 
     LifoAllocScope scope(&cx->tempLifoAlloc());
 
     /* Parse the pattern. */
     irregexp::RegExpCompileData data;
@@ -532,17 +529,17 @@ RegExpShared::compile(JSContext *cx, Han
 
     return true;
 }
 
 bool
 RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input,
                                  CompilationMode mode, ForceByteCodeEnum force)
 {
-    if (isCompiled(mode, input->hasLatin1Chars(), force) || canStringMatch)
+    if (isCompiled(mode, input->hasLatin1Chars(), force))
         return true;
     return compile(cx, input, mode, force);
 }
 
 RegExpRunStatus
 RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
                       MatchPairs *matches)
 {
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -180,17 +180,17 @@ class RegExpShared
     // Register a table with this RegExpShared, and take ownership.
     bool addTable(uint8_t *table) {
         return tables.append(table);
     }
 
     /* Accessors */
 
     size_t getParenCount() const {
-        MOZ_ASSERT(isCompiled() || canStringMatch);
+        MOZ_ASSERT(isCompiled());
         return parenCount;
     }
 
     /* Accounts for the "0" (whole match) pair. */
     size_t pairCount() const            { return getParenCount() + 1; }
 
     JSAtom *getSource() const           { return source; }
     RegExpFlag getFlags() const         { return flags; }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -575,28 +575,16 @@ js::intrinsic_UnsafeGetReservedSlot(JSCo
     MOZ_ASSERT(args[0].isObject());
     MOZ_ASSERT(args[1].isInt32());
 
     args.rval().set(args[0].toObject().as<NativeObject>().getReservedSlot(args[1].toPrivateUint32()));
     return true;
 }
 
 bool
-js::intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].isObject());
-    MOZ_ASSERT(args[1].isObject());
-
-    args.rval().setBoolean(args[0].toObject().getClass() == args[1].toObject().getClass());
-    return true;
-}
-
-bool
 js::intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
 
     JSObject *obj = &args[0].toObject();
     bool isPacked = obj->is<ArrayObject>() && !obj->hasLazyType() &&
@@ -1082,17 +1070,16 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
     JS_FN("SubstringKernel",         intrinsic_SubstringKernel,         3,0),
 
     JS_FN("UnsafePutElements",       intrinsic_UnsafePutElements,       3,0),
     JS_FN("_DefineDataProperty",     intrinsic_DefineDataProperty,      4,0),
     JS_FN("UnsafeSetReservedSlot",   intrinsic_UnsafeSetReservedSlot,   3,0),
     JS_FN("UnsafeGetReservedSlot",   intrinsic_UnsafeGetReservedSlot,   2,0),
-    JS_FN("HaveSameClass",           intrinsic_HaveSameClass,           2,0),
     JS_FN("IsPackedArray",           intrinsic_IsPackedArray,           1,0),
 
     JS_FN("GetIteratorPrototype",    intrinsic_GetIteratorPrototype,    0,0),
 
     JS_FN("NewArrayIterator",        intrinsic_NewArrayIterator,        0,0),
     JS_FN("IsArrayIterator",         intrinsic_IsArrayIterator,         1,0),
     JS_FN("CallArrayIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>,      2,0),
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -776,16 +776,17 @@ TypedArrayObject::subarray(JSContext *cx
 }
 
 /* static */ const JSFunctionSpec
 TypedArrayObject::protoFunctions[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0),                          \
     JS_FN("subarray", TypedArrayObject::subarray, 2, 0),
     JS_FN("set", TypedArrayObject::set, 2, 0),
     JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0),
+    JS_SELF_HOSTED_FN("fill", "TypedArrayFill", 3, 0),
     JS_SELF_HOSTED_FN("find", "TypedArrayFind", 2, 0),
     JS_SELF_HOSTED_FN("findIndex", "TypedArrayFindIndex", 2, 0),
     JS_SELF_HOSTED_FN("indexOf", "TypedArrayIndexOf", 2, 0),
     JS_SELF_HOSTED_FN("lastIndexOf", "TypedArrayLastIndexOf", 2, 0),
     JS_SELF_HOSTED_FN("reverse", "TypedArrayReverse", 0, 0),
     JS_FS_END
 };
 
--- a/layout/generic/nsBRFrame.cpp
+++ b/layout/generic/nsBRFrame.cpp
@@ -90,19 +90,19 @@ BRFrame::Reflow(nsPresContext* aPresCont
   LogicalSize finalSize(wm);
   finalSize.BSize(wm) = 0; // BR frames with block size 0 are ignored in quirks
                            // mode by nsLineLayout::VerticalAlignFrames .
                            // However, it's not always 0.  See below.
   finalSize.ISize(wm) = 0;
   aMetrics.SetBlockStartAscent(0);
 
   // Only when the BR is operating in a line-layout situation will it
-  // behave like a BR.
+  // behave like a BR. BR is suppressed when it is inside ruby frames.
   nsLineLayout* ll = aReflowState.mLineLayout;
-  if (ll) {
+  if (ll && !StyleContext()->IsDirectlyInsideRuby()) {
     // Note that the compatibility mode check excludes AlmostStandards
     // mode, since this is the inline box model.  See bug 161691.
     if ( ll->LineIsEmpty() ||
          aPresContext->CompatibilityMode() == eCompatibility_FullStandards ) {
       // The line is logically empty; any whitespace is trimmed away.
       //
       // If this frame is going to terminate the line we know
       // that nothing else will go on the line. Therefore, in this
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -426,17 +426,18 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame
   psd->mParent = mCurrentSpan;
   psd->mReflowState = aSpanReflowState;
   psd->mIStart = aIStart;
   psd->mICoord = aIStart;
   psd->mIEnd = aIEnd;
   psd->mBaseline = aBaseline;
 
   nsIFrame* frame = aSpanReflowState->frame;
-  psd->mNoWrap = !frame->StyleText()->WhiteSpaceCanWrap(frame);
+  psd->mNoWrap = !frame->StyleText()->WhiteSpaceCanWrap(frame) ||
+                 frame->StyleContext()->IsDirectlyInsideRuby();
   psd->mWritingMode = aSpanReflowState->GetWritingMode();
 
   // Switch to new span
   mCurrentSpan = psd;
   mSpanDepth++;
 }
 
 nscoord
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -6,16 +6,17 @@
 
 /* rendering object for CSS "display: ruby-base-container" */
 
 #include "nsRubyBaseContainerFrame.h"
 #include "nsContentUtils.h"
 #include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
+#include "nsStyleStructInlines.h"
 #include "WritingModes.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
@@ -251,33 +252,32 @@ ShouldBreakBefore(const nsHTMLReflowStat
 /* virtual */ void
 nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
                                  nsHTMLReflowMetrics& aDesiredSize,
                                  const nsHTMLReflowState& aReflowState,
                                  nsReflowStatus& aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsRubyBaseContainerFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+  aStatus = NS_FRAME_COMPLETE;
 
   if (!aReflowState.mLineLayout) {
     NS_ASSERTION(
       aReflowState.mLineLayout,
       "No line layout provided to RubyBaseContainerFrame reflow method.");
-    aStatus = NS_FRAME_COMPLETE;
     return;
   }
 
   MoveOverflowToChildList();
   // Ask text containers to drain overflows
   const uint32_t rtcCount = mTextContainers.Length();
   for (uint32_t i = 0; i < rtcCount; i++) {
     mTextContainers[i]->MoveOverflowToChildList();
   }
 
-  aStatus = NS_FRAME_COMPLETE;
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
   LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
                         aReflowState.AvailableHeight());
 
   const uint32_t spanCount = mSpanContainers.Length();
   const uint32_t totalCount = rtcCount + spanCount;
   // We have a reflow state and a line layout for each RTC.
   // They are conceptually the state of the RTCs, but we don't actually
@@ -337,42 +337,68 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
 
   WritingMode frameWM = aReflowState.GetWritingMode();
   LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding();
   nscoord startEdge = borderPadding.IStart(frameWM);
   nscoord endEdge = aReflowState.AvailableISize() - borderPadding.IEnd(frameWM);
   aReflowState.mLineLayout->BeginSpan(this, &aReflowState,
                                       startEdge, endEdge, &mBaseline);
 
-  // Reflow pairs excluding any span
-  nscoord pairsISize = ReflowPairs(aPresContext, aReflowState,
-                                   rtcReflowStates, aStatus);
-  nscoord isize = pairsISize;
+  nsIFrame* parent = GetParent();
+  bool inNestedRuby = parent->StyleContext()->IsDirectlyInsideRuby();
+  // Allow line break between ruby bases when white-space allows,
+  // we are not inside a nested ruby, and there is no span.
+  bool allowLineBreak = !inNestedRuby && StyleText()->WhiteSpaceCanWrap(this);
+  bool allowInitialLineBreak = allowLineBreak;
+  if (!GetPrevInFlow()) {
+    allowInitialLineBreak = !inNestedRuby &&
+      parent->StyleText()->WhiteSpaceCanWrap(parent);
+  }
+  if (allowInitialLineBreak && aReflowState.mLineLayout->LineIsBreakable() &&
+      aReflowState.mLineLayout->NotifyOptionalBreakPosition(
+        this, 0, startEdge <= aReflowState.AvailableISize(),
+        gfxBreakPriority::eNormalBreak)) {
+    aStatus = NS_INLINE_LINE_BREAK_BEFORE();
+  }
+
+  nscoord isize = 0;
+  if (aStatus == NS_FRAME_COMPLETE) {
+    // Reflow pairs excluding any span
+    bool allowInternalLineBreak = allowLineBreak && mSpanContainers.IsEmpty();
+    isize = ReflowPairs(aPresContext, allowInternalLineBreak,
+                        aReflowState, rtcReflowStates, aStatus);
+  }
 
   // If there exists any span, the pairs must either be completely
   // reflowed, or be not reflowed at all.
   MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) ||
              NS_FRAME_IS_COMPLETE(aStatus) || mSpanContainers.IsEmpty());
   if (!NS_INLINE_IS_BREAK_BEFORE(aStatus) &&
       NS_FRAME_IS_COMPLETE(aStatus) && !mSpanContainers.IsEmpty()) {
     // Reflow spans
     nscoord spanISize = ReflowSpans(aPresContext, aReflowState,
-                                    spanReflowStates, aStatus);
-    // ReflowSpans never reports break or incomplete, but we still need
-    // to check if it exceed the line.
-    MOZ_ASSERT(aStatus == NS_FRAME_COMPLETE);
+                                    spanReflowStates);
     if (isize < spanISize) {
       nscoord delta = spanISize - isize;
-      if (ShouldBreakBefore(aReflowState, delta)) {
+      if (allowLineBreak && ShouldBreakBefore(aReflowState, delta)) {
         aStatus = NS_INLINE_LINE_BREAK_BEFORE();
       } else {
         aReflowState.mLineLayout->AdvanceICoord(delta);
         isize = spanISize;
       }
     }
+    // When there are spans, ReflowPairs and ReflowOnePair won't
+    // record any optional break position. We have to record one
+    // at the end of this segment.
+    if (!NS_INLINE_IS_BREAK(aStatus) && allowLineBreak &&
+        aReflowState.mLineLayout->NotifyOptionalBreakPosition(
+          this, INT32_MAX, startEdge + isize <= aReflowState.AvailableISize(),
+          gfxBreakPriority::eNormalBreak)) {
+      aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
+    }
   }
 
   DebugOnly<nscoord> lineSpanSize = aReflowState.mLineLayout->EndSpan(this);
   // When there are no frames inside the ruby base container, EndSpan
   // will return 0. However, in this case, the actual width of the
   // container could be non-zero because of non-empty ruby annotations.
   MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) ||
              isize == lineSpanSize || mFrames.IsEmpty());
@@ -400,44 +426,37 @@ struct MOZ_STACK_CLASS nsRubyBaseContain
   ContinuationTraversingState mBase;
   nsAutoTArray<ContinuationTraversingState, RTC_ARRAY_SIZE> mTexts;
 
   explicit PullFrameState(nsRubyBaseContainerFrame* aFrame);
 };
 
 nscoord
 nsRubyBaseContainerFrame::ReflowPairs(nsPresContext* aPresContext,
+                                      bool aAllowLineBreak,
                                       const nsHTMLReflowState& aReflowState,
                                       nsTArray<nsHTMLReflowState*>& aReflowStates,
                                       nsReflowStatus& aStatus)
 {
   nsLineLayout* lineLayout = aReflowState.mLineLayout;
-  if (!lineLayout->LineIsEmpty()) {
-    // Record break position only if the line is not empty.
-    if (lineLayout->NotifyOptionalBreakPosition(
-          this, 0, true, gfxBreakPriority::eNormalBreak)) {
-      aStatus = NS_INLINE_LINE_BREAK_BEFORE();
-      return 0;
-    }
-  }
-
   const uint32_t rtcCount = mTextContainers.Length();
   nscoord istart = lineLayout->GetCurrentICoord();
   nscoord icoord = istart;
   nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
   aStatus = NS_FRAME_COMPLETE;
 
   mPairCount = 0;
   nsIFrame* baseFrame = nullptr;
   nsAutoTArray<nsIFrame*, RTC_ARRAY_SIZE> textFrames;
   textFrames.SetCapacity(rtcCount);
   PairEnumerator e(this, mTextContainers);
   for (; !e.AtEnd(); e.Next()) {
     e.GetFrames(baseFrame, textFrames);
-    icoord += ReflowOnePair(aPresContext, aReflowState, aReflowStates,
+    icoord += ReflowOnePair(aPresContext, aAllowLineBreak,
+                            aReflowState, aReflowStates,
                             baseFrame, textFrames, reflowStatus);
     if (NS_INLINE_IS_BREAK(reflowStatus)) {
       break;
     }
     // We are not handling overflow here.
     MOZ_ASSERT(reflowStatus == NS_FRAME_COMPLETE);
   }
 
@@ -449,37 +468,30 @@ nsRubyBaseContainerFrame::ReflowPairs(ns
 
     // Try pull some frames from next continuations. This call replaces
     // |baseFrame| and |textFrames| with the frame pulled in each level.
     PullOnePair(lineLayout, pullFrameState, baseFrame, textFrames, isComplete);
     if (isComplete) {
       // No more frames can be pulled.
       break;
     }
-    icoord += ReflowOnePair(aPresContext, aReflowState, aReflowStates,
+    icoord += ReflowOnePair(aPresContext, aAllowLineBreak,
+                            aReflowState, aReflowStates,
                             baseFrame, textFrames, reflowStatus);
   }
 
   if (!e.AtEnd() && NS_INLINE_IS_BREAK_AFTER(reflowStatus)) {
     // The current pair has been successfully placed.
     // Skip to the next pair and mark break before.
     e.Next();
     e.GetFrames(baseFrame, textFrames);
     reflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
   }
   if (!e.AtEnd() || (GetNextInFlow() && !isComplete)) {
     NS_FRAME_SET_INCOMPLETE(aStatus);
-  } else {
-    // Completely reflow the whole segment, record a break position.
-    // We record an extra break position here because ReflowOnePair
-    // won't record any break position if there exist spans.
-    if (lineLayout->NotifyOptionalBreakPosition(
-          this, INT32_MAX, true, gfxBreakPriority::eNormalBreak)) {
-      reflowStatus = NS_INLINE_LINE_BREAK_AFTER(reflowStatus);
-    }
   }
 
   if (NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
     if (!mPairCount || !mSpanContainers.IsEmpty()) {
       // If no pair has been placed yet, or we have any span,
       // the whole container should be in the next line.
       aStatus = NS_INLINE_LINE_BREAK_BEFORE();
       return 0;
@@ -506,16 +518,17 @@ nsRubyBaseContainerFrame::ReflowPairs(ns
     aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
   }
 
   return icoord - istart;
 }
 
 nscoord
 nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext,
+                                        bool aAllowLineBreak,
                                         const nsHTMLReflowState& aReflowState,
                                         nsTArray<nsHTMLReflowState*>& aReflowStates,
                                         nsIFrame* aBaseFrame,
                                         const nsTArray<nsIFrame*>& aTextFrames,
                                         nsReflowStatus& aStatus)
 {
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
   const uint32_t rtcCount = mTextContainers.Length();
@@ -554,72 +567,61 @@ nsRubyBaseContainerFrame::ReflowOnePair(
       }
 
       nsReflowStatus reflowStatus;
       nsHTMLReflowMetrics metrics(*aReflowStates[i]);
 
       bool pushedFrame;
       aReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus,
                                                  &metrics, pushedFrame);
-      if (NS_INLINE_IS_BREAK(reflowStatus)) {
-        // If any breaking occurs when reflowing a ruby text frame,
-        // we should abandon reflowing this pair.
-        aStatus = NS_INLINE_LINE_BREAK_BEFORE();
-        return 0;
-      }
-      MOZ_ASSERT(!pushedFrame, "Shouldn't push frame if there is no break");
+      MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
+                 "Any line break inside ruby box should has been suppressed");
       pairISize = std::max(pairISize, metrics.ISize(lineWM));
     }
   }
-  if (ShouldBreakBefore(aReflowState, pairISize)) {
+  if (aAllowLineBreak && ShouldBreakBefore(aReflowState, pairISize)) {
     // Since ruby text container uses an independent line layout, it
     // may successfully place a frame because the line is empty while
     // the line of base container is not.
     aStatus = NS_INLINE_LINE_BREAK_BEFORE();
     return 0;
   }
 
   // Reflow the base frame
   if (aBaseFrame) {
     MOZ_ASSERT(aBaseFrame->GetType() == nsGkAtoms::rubyBaseFrame);
     nsReflowStatus reflowStatus;
     nsHTMLReflowMetrics metrics(aReflowState);
 
     bool pushedFrame;
     aReflowState.mLineLayout->ReflowFrame(aBaseFrame, reflowStatus,
                                           &metrics, pushedFrame);
-    if (NS_INLINE_IS_BREAK(reflowStatus)) {
-      // We cannot place the ruby base frame. Abandon this pair.
-      aStatus = NS_INLINE_LINE_BREAK_BEFORE();
-      return 0;
-    }
-    MOZ_ASSERT(!pushedFrame, "Shouldn't push frame if there is no break");
+    MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
+               "Any line break inside ruby box should has been suppressed");
     pairISize = std::max(pairISize, metrics.ISize(lineWM));
   }
 
   // Align all the line layout to the new coordinate.
   nscoord icoord = istart + pairISize;
   aReflowState.mLineLayout->AdvanceICoord(
     icoord - aReflowState.mLineLayout->GetCurrentICoord());
   for (uint32_t i = 0; i < rtcCount; i++) {
     nsLineLayout* lineLayout = aReflowStates[i]->mLineLayout;
     lineLayout->AdvanceICoord(icoord - lineLayout->GetCurrentICoord());
     if (aBaseFrame && aTextFrames[i]) {
       lineLayout->AttachLastFrameToBaseLineLayout();
     }
   }
 
   mPairCount++;
-  // We only break between bases if there is no span.
-  if (mSpanContainers.IsEmpty()) {
-    if (aReflowState.mLineLayout->NotifyOptionalBreakPosition(
-          this, mPairCount, icoord <= aReflowState.AvailableISize(),
-          gfxBreakPriority::eNormalBreak)) {
-      aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
-    }
+  if (aAllowLineBreak &&
+      aReflowState.mLineLayout->NotifyOptionalBreakPosition(
+        this, mPairCount, icoord <= aReflowState.AvailableISize(),
+        gfxBreakPriority::eNormalBreak)) {
+    aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
   }
 
   return pairISize;
 }
 
 nsRubyBaseContainerFrame::PullFrameState::PullFrameState(
     nsRubyBaseContainerFrame* aFrame)
   : mBase(aFrame)
@@ -656,31 +658,29 @@ nsRubyBaseContainerFrame::PullOnePair(ns
     // We pulled frames from the next line, hence mark it dirty.
     aLineLayout->SetDirtyNextLine();
   }
 }
 
 nscoord
 nsRubyBaseContainerFrame::ReflowSpans(nsPresContext* aPresContext,
                                       const nsHTMLReflowState& aReflowState,
-                                      nsTArray<nsHTMLReflowState*>& aReflowStates,
-                                      nsReflowStatus& aStatus)
+                                      nsTArray<nsHTMLReflowState*>& aReflowStates)
 {
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
   const uint32_t spanCount = mSpanContainers.Length();
   nscoord spanISize = 0;
 
   for (uint32_t i = 0; i < spanCount; i++) {
     nsRubyTextContainerFrame* container = mSpanContainers[i];
     nsIFrame* rtFrame = container->GetFirstPrincipalChild();
     nsReflowStatus reflowStatus;
     nsHTMLReflowMetrics metrics(*aReflowStates[i]);
     bool pushedFrame;
     aReflowStates[i]->mLineLayout->ReflowFrame(rtFrame, reflowStatus,
                                                &metrics, pushedFrame);
-    // It should never cause break, since it is always
-    // at the beginning in its line layout.
-    MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame);
+    MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
+               "Any line break inside ruby box should has been suppressed");
     spanISize = std::max(spanISize, metrics.ISize(lineWM));
   }
 
   return spanISize;
 }
--- a/layout/generic/nsRubyBaseContainerFrame.h
+++ b/layout/generic/nsRubyBaseContainerFrame.h
@@ -74,31 +74,32 @@ protected:
   friend nsContainerFrame*
     NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   explicit nsRubyBaseContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
 
   nscoord CalculateMaxSpanISize(nsRenderingContext* aRenderingContext);
 
   nscoord ReflowPairs(nsPresContext* aPresContext,
+                      bool aAllowLineBreak,
                       const nsHTMLReflowState& aReflowState,
                       nsTArray<nsHTMLReflowState*>& aReflowStates,
                       nsReflowStatus& aStatus);
 
   nscoord ReflowOnePair(nsPresContext* aPresContext,
+                        bool aAllowLineBreak,
                         const nsHTMLReflowState& aReflowState,
                         nsTArray<nsHTMLReflowState*>& aReflowStates,
                         nsIFrame* aBaseFrame,
                         const nsTArray<nsIFrame*>& aTextFrames,
                         nsReflowStatus& aStatus);
 
   nscoord ReflowSpans(nsPresContext* aPresContext,
                       const nsHTMLReflowState& aReflowState,
-                      nsTArray<nsHTMLReflowState*>& aReflowStates,
-                      nsReflowStatus& aStatus);
+                      nsTArray<nsHTMLReflowState*>& aReflowStates);
 
   struct PullFrameState;
 
   // Pull ruby base and corresponding ruby text frames from
   // continuations after them.
   void PullOnePair(nsLineLayout* aLineLayout,
                    PullFrameState& aPullFrameState,
                    nsIFrame*& aBaseFrame,
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -8228,21 +8228,27 @@ nsTextFrame::ReflowText(nsLineLayout& aL
   bool usedHyphenation;
   gfxFloat trimmedWidth = 0;
   gfxFloat availWidth = aAvailableWidth;
   bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
                                    (GetStateBits() & TEXT_IS_IN_TOKEN_MATHML);
   int32_t unusedOffset;  
   gfxBreakPriority breakPriority;
   aLineLayout.GetLastOptionalBreakPosition(&unusedOffset, &breakPriority);
+  gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak;
+  if (StyleContext()->IsDirectlyInsideRuby()) {
+    suppressBreak = gfxTextRun::eSuppressAllBreaks;
+  } else if (!aLineLayout.LineIsBreakable()) {
+    suppressBreak = gfxTextRun::eSuppressInitialBreak;
+  }
   uint32_t transformedCharsFit =
     mTextRun->BreakAndMeasureText(transformedOffset, transformedLength,
                                   (GetStateBits() & TEXT_START_OF_LINE) != 0,
                                   availWidth,
-                                  &provider, !aLineLayout.LineIsBreakable(),
+                                  &provider, suppressBreak,
                                   canTrimTrailingWhitespace ? &trimmedWidth : nullptr,
                                   &textMetrics, boundingBoxType, ctx,
                                   &usedHyphenation, &transformedLastBreak,
                                   textStyle->WordCanWrap(this), &breakPriority);
   if (!length && !textMetrics.mAscent && !textMetrics.mDescent) {
     // If we're measuring a zero-length piece of text, update
     // the height manually.
     nsFontMetrics* fm = provider.GetFontMetrics();
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -12,18 +12,18 @@
 != different-fraction-of-range-unthemed-1.html different-fraction-of-range-unthemed-1-notref.html
 == same-fraction-of-range-unthemed-1.html same-fraction-of-range-unthemed-1-ref.html
 
 # dynamic value changes:
 == value-prop-unthemed.html 75pct-unthemed-common-ref.html
 == value-prop.html 75pct-common-ref.html
 == valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
 == valueAsNumber-prop.html 75pct-common-ref.html
-== stepDown-unthemed.html 75pct-unthemed-common-ref.html
-== stepDown.html 75pct-common-ref.html
+fuzzy-if(B2G,1,1) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
+fuzzy-if(B2G,1,1) == stepDown.html 75pct-common-ref.html
 == stepUp-unthemed.html 75pct-unthemed-common-ref.html
 == stepUp.html 75pct-common-ref.html
 fuzzy-if(B2G,1,1) == max-prop.html 100pct-common-ref.html
 == reset-value.html reset-value-ref.html
 
 # 'direction' property:
 == direction-unthemed-1.html direction-unthemed-1-ref.html
 
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -6034,34 +6034,32 @@ CSSParserImpl::ParseDeclarationBlock(uin
     if (!ExpectSymbol('{', true)) {
       REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart);
       OUTPUT_ERROR();
       return nullptr;
     }
   }
   css::Declaration* declaration = new css::Declaration();
   mData.AssertInitialState();
-  if (declaration) {
-    for (;;) {
-      bool changed;
-      if (!ParseDeclaration(declaration, aFlags, true, &changed, aContext)) {
-        if (!SkipDeclaration(checkForBraces)) {
+  for (;;) {
+    bool changed;
+    if (!ParseDeclaration(declaration, aFlags, true, &changed, aContext)) {
+      if (!SkipDeclaration(checkForBraces)) {
+        break;
+      }
+      if (checkForBraces) {
+        if (ExpectSymbol('}', true)) {
           break;
         }
-        if (checkForBraces) {
-          if (ExpectSymbol('}', true)) {
-            break;
-          }
-        }
-        // Since the skipped declaration didn't end the block we parse
-        // the next declaration.
-      }
-    }
-    declaration->CompressFrom(&mData);
-  }
+      }
+      // Since the skipped declaration didn't end the block we parse
+      // the next declaration.
+    }
+  }
+  declaration->CompressFrom(&mData);
   return declaration;
 }
 
 bool
 CSSParserImpl::ParseColor(nsCSSValue& aValue)
 {
   if (!GetToken(true)) {
     REPORT_UNEXPECTED_EOF(PEColorEOF);
--- a/media/libstagefright/binding/AnnexB.cpp
+++ b/media/libstagefright/binding/AnnexB.cpp
@@ -1,97 +1,339 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/Endian.h"
 #include "mp4_demuxer/AnnexB.h"
 #include "mp4_demuxer/ByteReader.h"
+#include "mp4_demuxer/ByteWriter.h"
 #include "mp4_demuxer/DecoderData.h"
 
 using namespace mozilla;
 
 namespace mp4_demuxer
 {
 
 static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 };
 
 void
-AnnexB::ConvertSample(MP4Sample* aSample)
+AnnexB::ConvertSampleToAnnexB(MP4Sample* aSample)
 {
   MOZ_ASSERT(aSample);
-  if (!aSample->size) {
+
+  if (!IsAVCC(aSample)) {
     return;
   }
   MOZ_ASSERT(aSample->data);
-  MOZ_ASSERT(aSample->size >= ArrayLength(kAnnexBDelimiter));
-  MOZ_ASSERT(aSample->prefix_data);
+
+  ConvertSampleTo4BytesAVCC(aSample);
 
   uint8_t* d = aSample->data;
   while (d + 4 < aSample->data + aSample->size) {
-    uint32_t nalLen = (uint32_t(d[0]) << 24) +
-                      (uint32_t(d[1]) << 16) +
-                      (uint32_t(d[2]) << 8) +
-                       uint32_t(d[3]);
+    uint32_t nalLen = mozilla::BigEndian::readUint32(d);
     // Overwrite the NAL length with the Annex B separator.
     memcpy(d, kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter));
     d += 4 + nalLen;
   }
 
-  // Prepend the Annex B header with SPS and PPS tables to keyframes.
+  // Prepend the Annex B NAL with SPS and PPS tables to keyframes.
   if (aSample->is_sync_point) {
-    aSample->Prepend(&(*aSample->prefix_data)[0],
-                     aSample->prefix_data->Length());
+    nsRefPtr<ByteBuffer> annexB =
+      ConvertExtraDataToAnnexB(aSample->extra_data);
+    aSample->Prepend(annexB->Elements(), annexB->Length());
   }
 }
 
-already_AddRefed<nsRcTArray<uint8_t>>
-AnnexB::ConvertExtraDataToAnnexB(mozilla::Vector<uint8_t>& aExtraData)
+already_AddRefed<ByteBuffer>
+AnnexB::ConvertExtraDataToAnnexB(const ByteBuffer* aExtraData)
 {
   // AVCC 6 byte header looks like:
   //     +------+------+------+------+------+------+------+------+
   // [0] |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   1  |
   //     +------+------+------+------+------+------+------+------+
   // [1] | profile                                               |
   //     +------+------+------+------+------+------+------+------+
   // [2] | compatiblity                                          |
   //     +------+------+------+------+------+------+------+------+
   // [3] | level                                                 |
   //     +------+------+------+------+------+------+------+------+
   // [4] | unused                                  | nalLenSiz-1 |
   //     +------+------+------+------+------+------+------+------+
   // [5] | unused             | numSps                           |
   //     +------+------+------+------+------+------+------+------+
 
-  nsRefPtr<nsRcTArray<uint8_t>> annexB = new nsRcTArray<uint8_t>();
+  nsRefPtr<ByteBuffer> annexB = new ByteBuffer;
 
-  ByteReader reader(aExtraData);
+  ByteReader reader(*aExtraData);
   const uint8_t* ptr = reader.Read(5);
   if (ptr && ptr[0] == 1) {
     // Append SPS then PPS
     ConvertSPSOrPPS(reader, reader.ReadU8() & 31, annexB);
     ConvertSPSOrPPS(reader, reader.ReadU8(), annexB);
 
     // MP4Box adds extra bytes that we ignore. I don't know what they do.
   }
   reader.DiscardRemaining();
 
   return annexB.forget();
 }
 
 void
 AnnexB::ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
-                        nsTArray<uint8_t>* aAnnexB)
+                        ByteBuffer* aAnnexB)
 {
   for (int i = 0; i < aCount; i++) {
     uint16_t length = aReader.ReadU16();
 
     const uint8_t* ptr = aReader.Read(length);
     if (!ptr) {
       MOZ_ASSERT(false);
       return;
     }
     aAnnexB->AppendElements(kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter));
     aAnnexB->AppendElements(ptr, length);
   }
 }
 
+static bool
+FindStartCodeInternal(ByteReader& aBr) {
+  size_t offset = aBr.Offset();
+
+  for (uint32_t i = 0; i < aBr.Align() && aBr.Remaining() >= 3; i++) {
+    if (aBr.PeekU24() == 0x000001) {
+      return true;
+    }
+    aBr.Read(1);
+  }
+
+  while (aBr.Remaining() >= 6) {
+    uint32_t x32 = aBr.PeekU32();
+    if ((x32 - 0x01010101) & (~x32) & 0x80808080) {
+      if ((x32 >> 8) == 0x000001) {
+        return true;
+      }
+      if (x32 == 0x000001) {
+        aBr.Read(1);
+        return true;
+      }
+      if ((x32 & 0xff) == 0) {
+        const uint8_t* p = aBr.Peek(1);
+        if ((x32 & 0xff00) == 0 && p[4] == 1) {
+          aBr.Read(2);
+          return true;
+        }
+        if (p[4] == 0 && p[5] == 1) {
+          aBr.Read(3);
+          return true;
+        }
+      }
+    }
+    aBr.Read(4);
+  }
+
+  while (aBr.Remaining() >= 3) {
+    if (aBr.PeekU24() == 0x000001) {
+      return true;
+    }
+    aBr.Read(1);
+  }
+
+  // No start code were found; Go back to the beginning.
+  aBr.Seek(offset);
+  return false;
+}
+
+static bool
+FindStartCode(ByteReader& aBr, size_t& aStartSize)
+{
+  if (!FindStartCodeInternal(aBr)) {
+    aStartSize = 0;
+    return false;
+  }
+
+  aStartSize = 3;
+  if (aBr.Offset()) {
+    // Check if it's 4-bytes start code
+    aBr.Rewind(1);
+    if (aBr.ReadU8() == 0) {
+      aStartSize = 4;
+    }
+  }
+  aBr.Read(3);
+  return true;
+}
+
+static void
+ParseNALUnits(ByteWriter& aBw, ByteReader& aBr)
+{
+  size_t startSize;
+
+  bool rv = FindStartCode(aBr, startSize);
+  if (rv) {
+    size_t startOffset = aBr.Offset();
+    while (FindStartCode(aBr, startSize)) {
+      size_t offset = aBr.Offset();
+      size_t sizeNAL = offset - startOffset - startSize;
+      aBr.Seek(startOffset);
+      aBw.WriteU32(sizeNAL);
+      aBw.Write(aBr.Read(sizeNAL), sizeNAL);
+      aBr.Read(startSize);
+      startOffset = offset;
+    }
+  }
+  size_t sizeNAL = aBr.Remaining();
+  if (sizeNAL) {
+    aBw.WriteU32(sizeNAL);
+    aBw.Write(aBr.Read(sizeNAL), sizeNAL);
+  }
+}
+
+void
+AnnexB::ConvertSampleToAVCC(MP4Sample* aSample)
+{
+  if (IsAVCC(aSample)) {
+    ConvertSampleTo4BytesAVCC(aSample);
+    return;
+  }
+
+  uint32_t header = mozilla::BigEndian::readUint32(aSample->data);
+  if (header != 0x00000001 && (header >> 8) != 0x000001) {
+    // Not AnnexB, can't convert.
+    return;
+  }
+
+  mozilla::Vector<uint8_t> nalu;
+  ByteWriter writer(nalu);
+  ByteReader reader(aSample->data, aSample->size);
+
+  ParseNALUnits(writer, reader);
+  aSample->Replace(nalu.begin(), nalu.length());
+}
+
+already_AddRefed<ByteBuffer>
+AnnexB::ExtractExtraData(const MP4Sample* aSample)
+{
+  nsRefPtr<ByteBuffer> extradata = new ByteBuffer;
+  if (!IsAVCC(aSample)) {
+    return extradata.forget();
+  }
+  // SPS content
+  mozilla::Vector<uint8_t> sps;
+  ByteWriter spsw(sps);
+  int numSps = 0;
+  // PPS content
+  mozilla::Vector<uint8_t> pps;
+  ByteWriter ppsw(pps);
+  int numPps = 0;
+
+  int nalLenSize = ((*aSample->extra_data)[4] & 3) + 1;
+  ByteReader reader(aSample->data, aSample->size);
+
+  // Find SPS and PPS NALUs in AVCC data
+  uint8_t* d = aSample->data;
+  while (reader.Remaining() > nalLenSize) {
+    uint32_t nalLen;
+    switch (nalLenSize) {
+      case 1: nalLen = reader.ReadU8();  break;
+      case 2: nalLen = reader.ReadU16(); break;
+      case 3: nalLen = reader.ReadU24(); break;
+      case 4: nalLen = reader.ReadU32(); break;
+    }
+    uint8_t nalType = reader.PeekU8();
+    const uint8_t* p = reader.Read(nalLen);
+    if (!p) {
+      return extradata.forget();
+    }
+
+    if (nalType == 0x67) { /* SPS */
+      numSps++;
+      spsw.WriteU16(nalLen);
+      spsw.Write(p, nalLen);
+    } else if (nalType == 0x68) { /* PPS */
+      numPps++;
+      ppsw.WriteU16(nalLen);
+      ppsw.Write(p, nalLen);
+    }
+  }
+
+  if (numSps && sps.length() > 5) {
+    extradata->AppendElement(1);        // version
+    extradata->AppendElement(sps[3]);   // profile
+    extradata->AppendElement(sps[4]);   // profile compat
+    extradata->AppendElement(sps[5]);   // level
+    extradata->AppendElement(0xfc | 3); // nal size - 1
+    extradata->AppendElement(0xe0 | numSps);
+    extradata->AppendElements(sps.begin(), sps.length());
+    extradata->AppendElement(numPps);
+    if (numPps) {
+      extradata->AppendElements(pps.begin(), pps.length());
+    }
+  }
+
+  return extradata.forget();
+}
+
+bool
+AnnexB::HasSPS(const MP4Sample* aSample)
+{
+  return HasSPS(aSample->extra_data);
+}
+
+bool
+AnnexB::HasSPS(const ByteBuffer* aExtraData)
+{
+  if (!aExtraData) {
+    return false;
+  }
+
+  ByteReader reader(*aExtraData);
+  const uint8_t* ptr = reader.Read(5);
+  if (!ptr || !reader.CanRead8()) {
+    return false;
+  }
+  uint8_t numSps = reader.ReadU8() & 0x1f;
+  reader.DiscardRemaining();
+
+  return numSps > 0;
+}
+
+void
+AnnexB::ConvertSampleTo4BytesAVCC(MP4Sample* aSample)
+{
+  MOZ_ASSERT(IsAVCC(aSample));
+
+  int nalLenSize = ((*aSample->extra_data)[4] & 3) + 1;
+
+  if (nalLenSize == 4) {
+    return;
+  }
+  mozilla::Vector<uint8_t> dest;
+  ByteWriter writer(dest);
+  ByteReader reader(aSample->data, aSample->size);
+  while (reader.Remaining() > nalLenSize) {
+    uint32_t nalLen;
+    switch (nalLenSize) {
+      case 1: nalLen = reader.ReadU8();  break;
+      case 2: nalLen = reader.ReadU16(); break;
+      case 3: nalLen = reader.ReadU24(); break;
+      case 4: nalLen = reader.ReadU32(); break;
+    }
+    const uint8_t* p = reader.Read(nalLen);
+    if (!p) {
+      return;
+    }
+    writer.WriteU32(nalLen);
+    writer.Write(p, nalLen);
+  }
+  aSample->Replace(dest.begin(), dest.length());
+}
+
+bool
+AnnexB::IsAVCC(const MP4Sample* aSample)
+{
+  return aSample->size >= 3 && aSample->extra_data &&
+    aSample->extra_data->Length() >= 7 && (*aSample->extra_data)[0] == 1;
+}
+
+
 } // namespace mp4_demuxer
--- a/media/libstagefright/binding/DecoderData.cpp
+++ b/media/libstagefright/binding/DecoderData.cpp
@@ -70,16 +70,22 @@ FindData(sp<MetaData>& aMetaData, uint32
   if (!aMetaData->findData(aKey, &type, &data, &size) || size % sizeof(T)) {
     return false;
   }
 
   aDest->AppendElements(reinterpret_cast<const T*>(data), size / sizeof(T));
   return true;
 }
 
+static bool
+FindData(sp<MetaData>& aMetaData, uint32_t aKey, ByteBuffer* aDest)
+{
+  return FindData(aMetaData, aKey, static_cast<nsTArray<uint8_t>*>(aDest));
+}
+
 bool
 CryptoFile::DoUpdate(sp<MetaData>& aMetaData)
 {
   const void* data;
   size_t size;
   uint32_t type;
 
   // There's no point in checking that the type matches anything because it
@@ -141,24 +147,24 @@ AudioDecoderConfig::Update(sp<MetaData>&
 {
   TrackConfig::Update(aMetaData, aMimeType);
   channel_count = FindInt32(aMetaData, kKeyChannelCount);
   bits_per_sample = FindInt32(aMetaData, kKeySampleSize);
   samples_per_second = FindInt32(aMetaData, kKeySampleRate);
   frequency_index = Adts::GetFrequencyIndex(samples_per_second);
   aac_profile = FindInt32(aMetaData, kKeyAACProfile);
 
-  if (FindData(aMetaData, kKeyESDS, &extra_data)) {
-    ESDS esds(&extra_data[0], extra_data.length());
+  if (FindData(aMetaData, kKeyESDS, extra_data)) {
+    ESDS esds(extra_data->Elements(), extra_data->Length());
 
     const void* data;
     size_t size;
     if (esds.getCodecSpecificInfo(&data, &size) == OK) {
       const uint8_t* cdata = reinterpret_cast<const uint8_t*>(data);
-      audio_specific_config.append(cdata, size);
+      audio_specific_config->AppendElements(cdata, size);
       if (size > 1) {
         ABitReader br(cdata, size);
         extended_profile = br.getBits(5);
 
         if (extended_profile == 31) {  // AAC-ELD => additional 6 bits
           extended_profile = 32 + br.getBits(6);
         }
       }
@@ -177,22 +183,17 @@ void
 VideoDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
 {
   TrackConfig::Update(aMetaData, aMimeType);
   display_width = FindInt32(aMetaData, kKeyDisplayWidth);
   display_height = FindInt32(aMetaData, kKeyDisplayHeight);
   image_width = FindInt32(aMetaData, kKeyWidth);
   image_height = FindInt32(aMetaData, kKeyHeight);
 
-  if (FindData(aMetaData, kKeyAVCC, &extra_data) && extra_data.length() >= 7) {
-    // Set size of the NAL length to 4. The demuxer formats its output with
-    // this NAL length size.
-    extra_data[4] |= 3;
-    annex_b = AnnexB::ConvertExtraDataToAnnexB(extra_data);
-  }
+  FindData(aMetaData, kKeyAVCC, extra_data);
 }
 
 bool
 VideoDecoderConfig::IsValid()
 {
   return display_width > 0 && display_height > 0;
 }
 
@@ -200,29 +201,30 @@ MP4Sample::MP4Sample()
   : mMediaBuffer(nullptr)
   , decode_timestamp(0)
   , composition_timestamp(0)
   , duration(0)
   , byte_offset(0)
   , is_sync_point(0)
   , data(nullptr)
   , size(0)
+  , extra_data(nullptr)
 {
 }
 
 MP4Sample::MP4Sample(const MP4Sample& copy)
   : mMediaBuffer(nullptr)
   , decode_timestamp(copy.decode_timestamp)
   , composition_timestamp(copy.composition_timestamp)
   , duration(copy.duration)
   , byte_offset(copy.byte_offset)
   , is_sync_point(copy.is_sync_point)
   , size(copy.size)
   , crypto(copy.crypto)
-  , prefix_data(copy.prefix_data)
+  , extra_data(copy.extra_data)
 {
   extra_buffer = data = new uint8_t[size];
   memcpy(data, copy.data, size);
 }
 
 MP4Sample::~MP4Sample()
 {
   if (mMediaBuffer) {
@@ -286,9 +288,30 @@ MP4Sample::Prepend(const uint8_t* aData,
   if (newData != data) {
     extra_buffer = data = newData;
     if (mMediaBuffer) {
       mMediaBuffer->release();
       mMediaBuffer = nullptr;
     }
   }
 }
+
+void
+MP4Sample::Replace(const uint8_t* aData, size_t aSize)
+{
+  // If the existing MediaBuffer has enough space then we just recycle it. If
+  // not then we copy to a new buffer.
+  uint8_t* newData = mMediaBuffer && aSize <= mMediaBuffer->size()
+                       ? data
+                       : new uint8_t[aSize];
+
+  memcpy(newData, aData, aSize);
+  size = aSize;
+
+  if (newData != data) {
+    extra_buffer = data = newData;
+    if (mMediaBuffer) {
+      mMediaBuffer->release();
+      mMediaBuffer = nullptr;
+    }
+  }
 }
+}
--- a/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
@@ -12,25 +12,34 @@ template <class T> struct already_AddRef
 namespace mp4_demuxer
 {
 class ByteReader;
 class MP4Sample;
 
 class AnnexB
 {
 public:
-  // Convert a sample from NAL unit syntax to Annex B.
-  // Assumes size of NAL length field is 4 bytes.
-  static void ConvertSample(MP4Sample* aSample);
+  // All conversions assume size of NAL length field is 4 bytes.
+  // Convert a sample from AVCC format to Annex B.
+  static void ConvertSampleToAnnexB(MP4Sample* aSample);
+  // Convert a sample from Annex B to AVCC.
+  // an AVCC extradata must not be set.
+  static void ConvertSampleToAVCC(MP4Sample* aSample);
+  static void ConvertSampleTo4BytesAVCC(MP4Sample* aSample);
 
-  // Parse an AVCC box and construct the Annex B sample header.
-  static already_AddRefed<nsRcTArray<uint8_t>> ConvertExtraDataToAnnexB(
-    mozilla::Vector<uint8_t>& aExtraData);
+  // Parse an AVCC extradata and construct the Annex B sample header.
+  static already_AddRefed<ByteBuffer> ConvertExtraDataToAnnexB(
+    const ByteBuffer* aExtraData);
+  static already_AddRefed<ByteBuffer> ExtractExtraData(
+    const MP4Sample* aSample);
+  static bool HasSPS(const MP4Sample* aSample);
+  static bool HasSPS(const ByteBuffer* aExtraData);
+  static bool IsAVCC(const MP4Sample* aSample);
 
 private:
   // AVCC box parser helper.
   static void ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
-                              nsTArray<uint8_t>* aAnnexB);
+                              ByteBuffer* aAnnexB);
 };
 
 } // namespace mp4_demuxer
 
 #endif // MP4_DEMUXER_ANNEX_B_H_
--- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
@@ -11,41 +11,51 @@
 
 namespace mp4_demuxer {
 
 class ByteReader
 {
 public:
   ByteReader() : mPtr(nullptr), mRemaining(0) {}
   explicit ByteReader(const mozilla::Vector<uint8_t>& aData)
-    : mPtr(&aData[0]), mRemaining(aData.length())
+    : mPtr(&aData[0]), mRemaining(aData.length()), mLength(aData.length())
   {
   }
   ByteReader(const uint8_t* aData, size_t aSize)
-    : mPtr(aData), mRemaining(aSize)
+    : mPtr(aData), mRemaining(aSize), mLength(aSize)
   {
   }
   template<size_t S>
   ByteReader(const nsAutoTArray<uint8_t, S>& aData)
-    : mPtr(&aData[0]), mRemaining(aData.Length())
+    : mPtr(&aData[0]), mRemaining(aData.Length()), mLength(aData.Length())
+  {
+  }
+  explicit ByteReader(const nsTArray<uint8_t>& aData)
+    : mPtr(&aData[0]), mRemaining(aData.Length()), mLength(aData.Length())
   {
   }
 
   void SetData(const nsTArray<uint8_t>& aData)
   {
     MOZ_ASSERT(!mPtr && !mRemaining);
     mPtr = &aData[0];
     mRemaining = aData.Length();
+    mLength = mRemaining;
   }
 
   ~ByteReader()
   {
     MOZ_ASSERT(!mRemaining);
   }
 
+  size_t Offset()
+  {
+    return mLength - mRemaining;
+  }
+
   // Make it explicit if we're not using the extra bytes.
   void DiscardRemaining() {
     mRemaining = 0;
   }
 
   size_t Remaining() const { return mRemaining; }
 
   bool CanRead8() { return mRemaining >= 1; }
@@ -67,27 +77,42 @@ public:
     auto ptr = Read(2);
     if (!ptr) {
       MOZ_ASSERT(false);
       return 0;
     }
     return mozilla::BigEndian::readUint16(ptr);
   }
 
+  uint32_t ReadU24()
+  {
+    auto ptr = Read(3);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+  }
+
+  uint32_t Read24()
+  {
+    return (uint32_t)ReadU24();
+  }
+
   uint32_t ReadU32()
   {
     auto ptr = Read(4);
     if (!ptr) {
       MOZ_ASSERT(false);
       return 0;
     }
     return mozilla::BigEndian::readUint32(ptr);
   }
 
-  int64_t Read32()
+  int32_t Read32()
   {
     auto ptr = Read(4);
     if (!ptr) {
       MOZ_ASSERT(false);
       return 0;
     }
     return mozilla::BigEndian::readInt32(ptr);
   }
@@ -121,16 +146,136 @@ public:
     mRemaining -= aCount;
 
     const uint8_t* result = mPtr;
     mPtr += aCount;
 
     return result;
   }
 
+  const uint8_t* Rewind(size_t aCount)
+  {
+    MOZ_ASSERT(aCount <= Offset());
+    size_t rewind = Offset();
+    if (aCount < rewind) {
+      rewind = aCount;
+    }
+    mRemaining += rewind;
+    mPtr -= rewind;
+    return mPtr;
+  }
+
+  uint8_t PeekU8()
+  {
+    auto ptr = Peek(1);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return *ptr;
+  }
+
+  uint16_t PeekU16()
+  {
+    auto ptr = Peek(2);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return mozilla::BigEndian::readUint16(ptr);
+  }
+
+  uint32_t PeekU24()
+  {
+    auto ptr = Peek(3);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+  }
+
+  uint32_t Peek24()
+  {
+    return (uint32_t)PeekU24();
+  }
+
+  uint32_t PeekU32()
+  {
+    auto ptr = Peek(4);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return mozilla::BigEndian::readUint32(ptr);
+  }
+
+  int32_t Peek32()
+  {
+    auto ptr = Peek(4);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return mozilla::BigEndian::readInt32(ptr);
+  }
+
+  uint64_t PeekU64()
+  {
+    auto ptr = Peek(8);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return mozilla::BigEndian::readUint64(ptr);
+  }
+
+  int64_t Peek64()
+  {
+    auto ptr = Peek(8);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return mozilla::BigEndian::readInt64(ptr);
+  }
+
+  const uint8_t* Peek(size_t aCount)
+  {
+    if (aCount > mRemaining) {
+      MOZ_ASSERT(false);
+      return nullptr;
+    }
+    return mPtr;
+  }
+
+  const uint8_t* Seek(size_t aOffset)
+  {
+    if (aOffset >= mLength) {
+      MOZ_ASSERT(false);
+      return nullptr;
+    }
+
+    mPtr = mPtr - Offset() + aOffset;
+    mRemaining = mLength - aOffset;
+    return mPtr;
+  }
+
+  const uint8_t* Reset()
+  {
+    mPtr -= Offset();
+    mRemaining = mLength;
+    return mPtr;
+  }
+
+  uint32_t Align()
+  {
+    return 4 - ((intptr_t)mPtr & 3);
+  }
+
   template <typename T> bool CanReadType() { return mRemaining >= sizeof(T); }
 
   template <typename T> T ReadType()
   {
     auto ptr = Read(sizeof(T));
     if (!ptr) {
       MOZ_ASSERT(false);
       return 0;
@@ -149,12 +294,13 @@ public:
     aDest.Clear();
     aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength);
     return true;
   }
 
 private:
   const uint8_t* mPtr;
   size_t mRemaining;
+  size_t mLength;
 };
 }
 
 #endif
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/include/mp4_demuxer/ByteWriter.h
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BYTE_WRITER_H_
+#define BYTE_WRITER_H_
+
+#include "mozilla/Endian.h"
+#include "mozilla/Vector.h"
+#include "nsTArray.h"
+
+namespace mp4_demuxer {
+
+class ByteWriter
+{
+public:
+  explicit ByteWriter(mozilla::Vector<uint8_t>& aData)
+    : mPtr(aData)
+  {
+  }
+  ~ByteWriter()
+  {
+  }
+
+  void WriteU8(uint8_t aByte)
+  {
+    mPtr.append(aByte);
+  }
+
+  void WriteU16(uint16_t aShort)
+  {
+    uint8_t c[2];
+    mozilla::BigEndian::writeUint16(&c[0], aShort);
+    mPtr.append(&c[0], 2);
+  }
+
+  void WriteU32(uint32_t aLong)
+  {
+    uint8_t c[4];
+    mozilla::BigEndian::writeUint32(&c[0], aLong);
+    mPtr.append(&c[0], 4);
+  }
+
+  void Write32(int32_t aLong)
+  {
+    uint8_t c[4];
+    mozilla::BigEndian::writeInt32(&c[0], aLong);
+    mPtr.append(&c[0], 4);
+  }
+
+  void WriteU64(uint64_t aLongLong)
+  {
+    uint8_t c[8];
+    mozilla::BigEndian::writeUint64(&c[0], aLongLong);
+    mPtr.append(&c[0], 8);
+  }
+
+  void Write64(int64_t aLongLong)
+  {
+    uint8_t c[8];
+    mozilla::BigEndian::writeInt64(&c[0], aLongLong);
+    mPtr.append(&c[0], 8);
+  }
+
+  void Write(const uint8_t* aSrc, size_t aCount)
+  {
+    mPtr.append(aSrc, aCount);
+  }
+
+private:
+  mozilla::Vector<uint8_t>& mPtr;
+};
+}
+
+#endif
--- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
@@ -4,16 +4,17 @@
 
 #ifndef DECODER_DATA_H_
 #define DECODER_DATA_H_
 
 #include "mozilla/Types.h"
 #include "mozilla/Vector.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "nsRefPtr.h"
 
 namespace stagefright
 {
 template <typename T> class sp;
 class MetaData;
 class MediaBuffer;
 }
 
@@ -25,16 +26,18 @@ class MP4Demuxer;
 template <typename T>
 class nsRcTArray : public nsTArray<T> {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsRcTArray);
 
 private:
   ~nsRcTArray() {}
 };
 
+typedef nsRcTArray<uint8_t> ByteBuffer;
+
 struct PsshInfo
 {
   PsshInfo() {}
   PsshInfo(const PsshInfo& aOther) : uuid(aOther.uuid), data(aOther.data) {}
   nsTArray<uint8_t> uuid;
   nsTArray<uint8_t> data;
 };
 
@@ -94,79 +97,88 @@ class AudioDecoderConfig : public TrackC
 public:
   AudioDecoderConfig()
     : channel_count(0)
     , bits_per_sample(0)
     , samples_per_second(0)
     , frequency_index(0)
     , aac_profile(0)
     , extended_profile(0)
+    , extra_data(new ByteBuffer)
+    , audio_specific_config(new ByteBuffer)
   {
   }
 
   uint32_t channel_count;
   uint32_t bits_per_sample;
   uint32_t samples_per_second;
   int8_t frequency_index;
   int8_t aac_profile;
   int8_t extended_profile;
-  mozilla::Vector<uint8_t> extra_data;
-  mozilla::Vector<uint8_t> audio_specific_config;
+  nsRefPtr<ByteBuffer> extra_data;
+  nsRefPtr<ByteBuffer> audio_specific_config;
 
   void Update(stagefright::sp<stagefright::MetaData>& aMetaData,
               const char* aMimeType);
   bool IsValid();
 
 private:
   friend class MP4Demuxer;
 };
 
 class VideoDecoderConfig : public TrackConfig
 {
 public:
-  VideoDecoderConfig() : display_width(0), display_height(0) {}
+  VideoDecoderConfig()
+    : display_width(0)
+    , display_height(0)
+    , image_width(0)
+    , image_height(0)
+    , extra_data(new ByteBuffer)
+  {
+  }
 
   int32_t display_width;
   int32_t display_height;
 
   int32_t image_width;
   int32_t image_height;
 
-  mozilla::Vector<uint8_t> extra_data;   // Unparsed AVCDecoderConfig payload.
-  nsRefPtr<nsRcTArray<uint8_t>> annex_b; // Parsed version for sample prepend.
+  nsRefPtr<ByteBuffer> extra_data;   // Unparsed AVCDecoderConfig payload.
 
   void Update(stagefright::sp<stagefright::MetaData>& aMetaData,
               const char* aMimeType);
   bool IsValid();
 };
 
 typedef int64_t Microseconds;
 
 class MP4Sample
 {
 public:
   MP4Sample();
   MP4Sample(const MP4Sample& copy);
-  ~MP4Sample();
+  virtual ~MP4Sample();
   void Update(int64_t& aMediaTime);
   void Pad(size_t aPaddingBytes);
 
   stagefright::MediaBuffer* mMediaBuffer;
 
   Microseconds decode_timestamp;
   Microseconds composition_timestamp;
   Microseconds duration;
   int64_t byte_offset;
   bool is_sync_point;
 
   uint8_t* data;
   size_t size;
 
   CryptoSample crypto;
-  nsRefPtr<nsRcTArray<uint8_t>> prefix_data;
+  nsRefPtr<ByteBuffer> extra_data;
 
   void Prepend(const uint8_t* aData, size_t aSize);
+  void Replace(const uint8_t* aData, size_t aSize);
 
   nsAutoArrayPtr<uint8_t> extra_buffer;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -211,17 +211,17 @@ MP4Demuxer::DemuxAudioSample()
 }
 
 MP4Sample*
 MP4Demuxer::DemuxVideoSample()
 {
   if (mPrivate->mVideoIterator) {
     nsAutoPtr<MP4Sample> sample(mPrivate->mVideoIterator->GetNext());
     if (sample) {
-      sample->prefix_data = mVideoConfig.annex_b;
+      sample->extra_data = mVideoConfig.extra_data;
       if (sample->crypto.valid) {
         sample->crypto.mode = mVideoConfig.crypto.mode;
         sample->crypto.key.AppendElements(mVideoConfig.crypto.key);
       }
     }
     return sample.forget();
   }
 
@@ -230,17 +230,17 @@ MP4Demuxer::DemuxVideoSample()
     mPrivate->mVideo->read(&sample->mMediaBuffer, &mPrivate->mVideoOptions);
   mPrivate->mVideoOptions.clearSeekTo();
 
   if (status < 0) {
     return nullptr;
   }
 
   sample->Update(mVideoConfig.media_time);
-  sample->prefix_data = mVideoConfig.annex_b;
+  sample->extra_data = mVideoConfig.extra_data;
 
   return sample.forget();
 }
 
 void
 MP4Demuxer::UpdateIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges)
 {
   for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -48,16 +48,17 @@ if CONFIG['OS_TARGET'] != 'Android':
     ]
 
 EXPORTS.mp4_demuxer += [
     'binding/include/mp4_demuxer/Adts.h',
     'binding/include/mp4_demuxer/AnnexB.h',
     'binding/include/mp4_demuxer/AtomType.h',
     'binding/include/mp4_demuxer/BufferStream.h',
     'binding/include/mp4_demuxer/ByteReader.h',
+    'binding/include/mp4_demuxer/ByteWriter.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/Interval.h',
     'binding/include/mp4_demuxer/MoofParser.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
 ]
 
 SOURCES += [
     'frameworks/av/media/libstagefright/foundation/hexdump.cpp',
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -490,49 +490,79 @@
  *   attribute need not be provided in such cases.
  * MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is
  *   expected to live on the stack or in static storage, so it is a compile-time
  *   error to use it, or an array of such objects, as the type of a new
  *   expression (unless placement new is being used). If a member of another
  *   class uses this class, or if another class inherits from this class, then
  *   it is considered to be a non-heap class as well, although this attribute
  *   need not be provided in such cases.
+ * MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are
+ *   intended to prevent introducing static initializers.  This attribute
+ *   currently makes it a compile-time error to instantiate these classes
+ *   anywhere other than at the global scope, or as a static member of a class.
+ * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial
+ *   constructor and a trivial destructor.  Setting this attribute on a class
+ *   makes it a compile-time error for that class to get a non-trivial
+ *   constructor or destructor for any reason.
  * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return
  *   value is allocated on the heap, and will as a result check such allocations
  *   during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking.
  * MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors
  *   are disallowed by default unless they are marked as MOZ_IMPLICIT. This
  *   attribute must be used for constructors which intend to provide implicit
  *   conversions.
  * MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile
  *   time error to pass arithmetic expressions on variables to the function.
+ * MOZ_STRONG_REF: Applies to declarations of pointer types.  This attribute
+ *   tells the compiler that the raw pointer is a strong reference, and that
+ *   property is somehow enforced by the code.  This can make the compiler
+ *   ignore these pointers when validating the usage of pointers otherwise.
+ * MOZ_WEAK_REF: Applies to declarations of pointer types.  This attribute
+ *   tells the compiler that the raw pointer is a weak reference, and that
+ *   property is somehow enforced by the code.  This can make the compiler
+ *   ignore these pointers when validating the usage of pointers otherwise.
  */
 #ifdef MOZ_CLANG_PLUGIN
 #  define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
 #  define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
 #  define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
+#  define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
+#  ifdef DEBUG
+     /* in debug builds, these classes do have non-trivial constructors. */
+#    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class")))
+#  else
+#    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
+            MOZ_TRIVIAL_CTOR_DTOR
+#  endif
 #  define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
+#  define MOZ_STRONG_REF __attribute__((annotate("moz_strong_ref")))
+#  define MOZ_WEAK_REF __attribute__((annotate("moz_weak_ref")))
 /*
  * It turns out that clang doesn't like void func() __attribute__ {} without a
  * warning, so use pragmas to disable the warning. This code won't work on GCC
  * anyways, so the warning is safe to ignore.
  */
 #  define MOZ_HEAP_ALLOCATOR \
     _Pragma("clang diagnostic push") \
     _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
     __attribute__((annotate("moz_heap_allocator"))) \
     _Pragma("clang diagnostic pop")
 #else
 #  define MOZ_MUST_OVERRIDE /* nothing */
 #  define MOZ_STACK_CLASS /* nothing */
 #  define MOZ_NONHEAP_CLASS /* nothing */
+#  define MOZ_TRIVIAL_CTOR_DTOR /* nothing */
+#  define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */
 #  define MOZ_IMPLICIT /* nothing */
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
 #  define MOZ_HEAP_ALLOCATOR /* nothing */
+#  define MOZ_STRONG_REF /* nothing */
+#  define MOZ_WEAK_REF /* nothing */
 #endif /* MOZ_CLANG_PLUGIN */
 
 /*
  * MOZ_THIS_IN_INITIALIZER_LIST is used to avoid a warning when we know that
  * it's safe to use 'this' in an initializer list.
  */
 #ifdef _MSC_VER
 #  define MOZ_THIS_IN_INITIALIZER_LIST() \
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -129,18 +129,22 @@ pref("dom.indexedDB.logging.profiler-mar
 // Whether or not Web Workers are enabled.
 pref("dom.workers.enabled", true);
 // The number of workers per domain allowed to run concurrently.
 pref("dom.workers.maxPerDomain", 20);
 
 // Whether or not Shared Web Workers are enabled.
 pref("dom.workers.sharedWorkers.enabled", true);
 
-// WebSocket in workers are enabled.
+// WebSocket in workers are disabled by default.
+#ifdef RELEASE_BUILD
+pref("dom.workers.websocket.enabled", false);
+#else
 pref("dom.workers.websocket.enabled", true);
+#endif
 
 // Service workers
 pref("dom.serviceWorkers.enabled", false);
 
 // Whether nonzero values can be returned from performance.timing.*
 pref("dom.enable_performance", true);
 
 // Whether resource timing will be gathered and returned by performance.GetEntries*
@@ -3947,16 +3951,20 @@ pref("layers.enable-tiles", true);
 pref("layers.tiled-drawtarget.enabled", true);
 #endif
 
 // ANDROID covers android and b2g
 #ifdef ANDROID
 pref("layers.offmainthreadcomposition.enabled", true);
 #endif
 
+#ifdef MOZ_WIDGET_GONK
+pref("layers.tiled-drawtarget.enabled", true);
+#endif
+
 // same effect as layers.offmainthreadcomposition.enabled, but specifically for
 // use with tests.
 pref("layers.offmainthreadcomposition.testing.enabled", false);
 
 // whether to allow use of the basic compositor
 pref("layers.offmainthreadcomposition.force-basic", false);
 
 // Whether to animate simple opacity and transforms on the compositor
--- a/netwerk/test/httpserver/httpd.js
+++ b/netwerk/test/httpserver/httpd.js
@@ -2736,16 +2736,18 @@ ServerHandler.prototype =
       var fis = new FileInputStream(file, PR_RDONLY, PERMS_READONLY,
                                     Ci.nsIFileInputStream.CLOSE_ON_EOF);
 
       try
       {
         var sis = new ScriptableInputStream(fis);
         var s = Cu.Sandbox(gGlobalObject);
         s.importFunction(dump, "dump");
+        s.importFunction(atob, "atob");
+        s.importFunction(btoa, "btoa");
 
         // Define a basic key-value state-preservation API across requests, with
         // keys initially corresponding to the empty string.
         var self = this;
         var path = metadata.path;
         s.importFunction(function getState(k)
         {
           return self._getState(path, k);
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -434,24 +434,21 @@ nsHtml5TreeOperation::CreateElement(int3
     } else {
       nsString& value = *(aAttributes->getValueNoBoundsCheck(i));
       newContent->SetAttr(nsuri,
                           localName,
                           prefix,
                           value,
                           false);
 
-      // Custom element prototype swizzling may be needed if there is an
-      // "is" attribute.
+      // Custom element setup may be needed if there is an "is" attribute.
       if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
-        ErrorResult errorResult;
-        newContent->OwnerDoc()->SwizzleCustomElement(newContent,
-                                                     value,
-                                                     newContent->GetNameSpaceID(),
-                                                     errorResult);
+        newContent->OwnerDoc()->SetupCustomElement(newContent,
+                                                   newContent->GetNameSpaceID(),
+                                                   &value);
       }
     }
   }
   return newContent;
 }
 
 void
 nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -367,16 +367,20 @@ NSSCertDBTrustDomain::CheckRevocation(En
   }
 
   // If we have a stapled OCSP response then the verification of that response
   // determines the result unless the OCSP response is expired. We make an
   // exception for expired responses because some servers, nginx in particular,
   // are known to serve expired responses due to bugs.
   // We keep track of the result of verifying the stapled response but don't
   // immediately return failure if the response has expired.
+  //
+  // We only set the OCSP stapling status if we're validating the end-entity
+  // certificate. Non-end-entity certificates would always be
+  // OCSP_STAPLING_NONE unless/until we implement multi-stapling.
   Result stapledOCSPResponseResult = Success;
   if (stapledOCSPResponse) {
     PR_ASSERT(endEntityOrCA == EndEntityOrCA::MustBeEndEntity);
     bool expired;
     stapledOCSPResponseResult =
       VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
                                              maxOCSPLifetimeInDays,
                                              *stapledOCSPResponse,
@@ -396,17 +400,17 @@ NSSCertDBTrustDomain::CheckRevocation(En
              ("NSSCertDBTrustDomain: expired stapled OCSP response"));
     } else {
       // stapled OCSP response present but invalid for some reason
       mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_INVALID;
       PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
              ("NSSCertDBTrustDomain: stapled OCSP response: failure"));
       return stapledOCSPResponseResult;
     }
-  } else {
+  } else if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
     // no stapled OCSP response
     mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_NONE;
     PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
            ("NSSCertDBTrustDomain: no stapled OCSP response"));
   }
 
   Result cachedResponseResult = Success;
   Time cachedResponseValidThrough(Time::uninitialized);
--- a/security/pkix/include/pkix/bind.h
+++ b/security/pkix/include/pkix/bind.h
@@ -145,17 +145,17 @@ private:
   void operator=(const BindToMemberFunction4&) /*= delete*/;
 };
 
 template <typename R, typename P1, typename B1, typename B2, typename B3,
           typename B4, typename B5>
 class Bind5
 {
 public:
-  typedef R (&F)(P1&, B1, B2, B3, B4, B5);
+  typedef R (*F)(P1&, B1, B2, B3, B4, B5);
   Bind5(F f, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5)
     : f(f), b1(b1), b2(b2), b3(b3), b4(b4), b5(b5) { }
   R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4, b5); }
 private:
   const F f;
   B1 b1;
   B2 b2;
   B3 b3;
@@ -204,17 +204,17 @@ bind(R (C1::*f)(P1&, P2&, P3, P4&), C1* 
      Placeholder3, Placeholder4&)
 {
   return internal::BindToMemberFunction4<R, C1, P1, P2, P3, P4>(f, that);
 }
 
 template <typename R, typename P1, typename B1, typename B2, typename B3,
           typename B4, typename B5>
 inline internal::Bind5<R, P1, B1, B2, B3, B4, B5&>
-bind(R (&f)(P1&, B1, B2, B3, B4, B5&), Placeholder1&, B1 b1, B2 b2, B3 b3,
+bind(R (*f)(P1&, B1, B2, B3, B4, B5&), Placeholder1&, B1 b1, B2 b2, B3 b3,
      B4 b4, B5& b5)
 {
   return internal::Bind5<R, P1, B1, B2, B3, B4, B5&>(f, b1, b2, b3, b4, b5);
 }
 
 #endif
 
 } } // namespace mozilla::pkix
--- a/testing/marionette/client/marionette/__init__.py
+++ b/testing/marionette/client/marionette/__init__.py
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from gestures import smooth_scroll, pinch
 from by import By
 from marionette import Marionette, HTMLElement, Actions, MultiActions
 from marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest
 from errors import (
     ElementNotVisibleException,
+    ElementNotAccessibleException,
     ErrorCodes,
     FrameSendFailureError,
     FrameSendNotInitializedError,
     InvalidCookieDomainException,
     InvalidElementStateException,
     InvalidResponseException,
     InvalidSelectorException,
     JavascriptException,
--- a/testing/marionette/client/marionette/errors.py
+++ b/testing/marionette/client/marionette/errors.py
@@ -8,16 +8,17 @@ class ErrorCodes(object):
     SUCCESS = 0
     NO_SUCH_ELEMENT = 7
     NO_SUCH_FRAME = 8
     UNKNOWN_COMMAND = 9
     STALE_ELEMENT_REFERENCE = 10
     ELEMENT_NOT_VISIBLE = 11
     INVALID_ELEMENT_STATE = 12
     UNKNOWN_ERROR = 13
+    ELEMENT_NOT_ACCESSIBLE = 56
     ELEMENT_IS_NOT_SELECTABLE = 15
     JAVASCRIPT_ERROR = 17
     XPATH_LOOKUP_ERROR = 19
     TIMEOUT = 21
     NO_SUCH_WINDOW = 23
     INVALID_COOKIE_DOMAIN = 24
     UNABLE_TO_SET_COOKIE = 25
     UNEXPECTED_ALERT_OPEN = 26
@@ -108,16 +109,19 @@ class ScriptTimeoutException(MarionetteE
 
 class ElementNotVisibleException(MarionetteException):
     def __init__(self, message="Element is not currently visible and may not be manipulated",
                  status=ErrorCodes.ELEMENT_NOT_VISIBLE,
                  stacktrace=None, cause=None):
         super(ElementNotVisibleException, self).__init__(
             message, status=status, cause=cause, stacktrace=stacktrace)
 
+class ElementNotAccessibleException(MarionetteException):
+    pass
+
 class NoSuchFrameException(MarionetteException):
     pass
 
 class InvalidElementStateException(MarionetteException):
     pass
 
 class NoAlertPresentException(MarionetteException):
     pass
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -672,16 +672,18 @@ class Marionette(object):
         if status == errors.ErrorCodes.NO_SUCH_ELEMENT:
             raise errors.NoSuchElementException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.NO_SUCH_FRAME:
             raise errors.NoSuchFrameException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.STALE_ELEMENT_REFERENCE:
             raise errors.StaleElementException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.ELEMENT_NOT_VISIBLE:
             raise errors.ElementNotVisibleException(message=message, status=status, stacktrace=stacktrace)
+        elif status == errors.ErrorCodes.ELEMENT_NOT_ACCESSIBLE:
+            raise errors.ElementNotAccessibleException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.INVALID_ELEMENT_STATE:
             raise errors.InvalidElementStateException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.UNKNOWN_ERROR:
             raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.ELEMENT_IS_NOT_SELECTABLE:
             raise errors.ElementNotSelectableException(message=message, status=status, stacktrace=stacktrace)
         elif status == errors.ErrorCodes.JAVASCRIPT_ERROR:
             raise errors.JavascriptException(message=message, status=status, stacktrace=stacktrace)
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/tests/unit/test_accessibility.py
@@ -0,0 +1,141 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_test import MarionetteTestCase
+from errors import ElementNotAccessibleException
+from errors import ElementNotVisibleException
+
+
+class TestAccessibility(MarionetteTestCase):
+
+    # Elements that are accessible with and without the accessibliity API
+    valid_elementIDs = [
+        # Button1 is an accessible button with a valid accessible name
+        # computed from subtree
+        "button1",
+        # Button2 is an accessible button with a valid accessible name
+        # computed from aria-label
+        "button2"
+    ]
+
+    # Elements that are not accessible with the accessibility API
+    invalid_elementIDs = [
+        # Button3 does not have an accessible object
+        "button3",
+        # Button4 does not support any accessible actions
+        "button4",
+        # Button5 does not have a correct accessibility role and may not be
+        # manipulated via the accessibility API
+        "button5",
+        # Button6 is missing an accesible name
+        "button6",
+        # Button7 is not currently visible via the accessibility API and may
+        # not be manipulated by it
+        "button7",
+        # Button8 is not currently visible via the accessibility API and may
+        # not be manipulated by it (in hidden subtree)
+        "button8"
+    ]
+
+    # Elements that are either accessible to accessibility API or not accessible
+    # at all
+    falsy_elements = [
+        # Element is only visible to the accessibility API and may be
+        # manipulated by it
+        "button9",
+        # Element is not currently visible
+        "button10"
+    ]
+
+    displayed_elementIDs = [
+        "button1", "button2", "button3", "button4", "button5", "button6",
+        "button9", "no_accessible_but_displayed"
+    ]
+
+    displayed_but_a11y_hidden_elementIDs = ["button7", "button8"]
+
+    disabled_elementIDs = ["button11", "no_accessible_but_disabled"]
+
+    def run_element_test(self, ids, testFn):
+        for id in ids:
+            element = self.marionette.find_element("id", id)
+            testFn(element)
+
+    def setup_accessibility(self, raisesAccessibilityExceptions=True, navigate=True):
+        self.marionette.delete_session()
+        self.marionette.start_session(
+            {"raisesAccessibilityExceptions": raisesAccessibilityExceptions})
+        # Navigate to test_accessibility.html
+        if navigate:
+            test_accessibility = self.marionette.absolute_url("test_accessibility.html")
+            self.marionette.navigate(test_accessibility)
+
+    def test_valid_single_tap(self):
+        self.setup_accessibility()
+        # No exception should be raised
+        self.run_element_test(self.valid_elementIDs, lambda button: button.tap())
+
+    def test_single_tap_raises_element_not_accessible(self):
+        self.setup_accessibility()
+        self.run_element_test(self.invalid_elementIDs,
+                              lambda button: self.assertRaises(ElementNotAccessibleException,
+                                                               button.tap))
+        self.run_element_test(self.falsy_elements,
+                              lambda button: self.assertRaises(ElementNotAccessibleException,
+                                                               button.tap))
+
+    def test_single_tap_raises_no_exceptions(self):
+        self.setup_accessibility(False, True)
+        # No exception should be raised
+        self.run_element_test(self.invalid_elementIDs, lambda button: button.tap())
+        # Elements are invisible
+        self.run_element_test(self.falsy_elements,
+                              lambda button: self.assertRaises(ElementNotVisibleException,
+                                                               button.tap))
+
+    def test_valid_click(self):
+        self.setup_accessibility()
+        # No exception should be raised
+        self.run_element_test(self.valid_elementIDs, lambda button: button.click())
+
+    def test_click_raises_element_not_accessible(self):
+        self.setup_accessibility()
+        self.run_element_test(self.invalid_elementIDs,
+                              lambda button: self.assertRaises(ElementNotAccessibleException,
+                                                               button.click))
+        self.run_element_test(self.falsy_elements,
+                              lambda button: self.assertRaises(ElementNotAccessibleException,
+                                                               button.click))
+
+    def test_click_raises_no_exceptions(self):
+        self.setup_accessibility(False, True)
+        # No exception should be raised
+        self.run_element_test(self.invalid_elementIDs, lambda button: button.click())
+        # Elements are invisible
+        self.run_element_test(self.falsy_elements,
+                              lambda button: self.assertRaises(ElementNotVisibleException,
+                                                               button.click))
+
+    def test_element_visible_but_not_visible_to_accessbility(self):
+        self.setup_accessibility()
+        # Elements are displayed but hidden from accessibility API
+        self.run_element_test(self.displayed_but_a11y_hidden_elementIDs,
+                              lambda element: self.assertRaises(ElementNotAccessibleException,
+                                                                element.is_displayed))
+
+    def test_element_is_visible_to_accessibility(self):
+        self.setup_accessibility()
+        # No exception should be raised
+        self.run_element_test(self.displayed_elementIDs, lambda element: element.is_displayed())
+
+    def test_is_element_is_not_enabled_to_accessbility(self):
+        self.setup_accessibility()
+        # Button is enabled but disabled via the accessibility API
+        self.assertRaises(ElementNotAccessibleException,
+                          self.marionette.find_element("id", "button12").is_enabled)
+
+    def test_element_is_enabled_to_accessibility(self):
+        self.setup_accessibility()
+        # No exception should be raised
+        self.run_element_test(self.disabled_elementIDs, lambda element: element.is_enabled())
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -11,16 +11,18 @@ b2g = true
 ; true if the test should be skipped
 skip = false
 
 [test_marionette.py]
 [test_data_driven.py]
 [test_session.py]
 [test_capabilities.py]
 
+[test_accessibility.py]
+
 [test_expectedfail.py]
 expected = fail
 [test_import_script.py]
 b2g = false
 [test_import_script_reuse_window.py]
 b2g = false
 [test_click.py]
 [test_click_chrome.py]
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/www/test_accessibility.html
@@ -0,0 +1,42 @@
+<!-- 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/. -->
+
+<!DOCTYPE html>
+
+<html>
+<meta charset="UTF-8">
+<head>
+<title>Marionette Test</title>
+</head>
+<body>
+  <button id="button1">button1</button>
+  <button id="button2" aria-label="button2"></button>
+  <span id="button3">I am a bad button with no accessible</span>
+  <h1 id="button4">I am a bad button that is actually a header</h1>
+  <h1 id="button5">
+    I am a bad button that is actually an actionable header with a listener
+  </h1>
+  <button id="button6"></button>
+  <button id="button7" aria-hidden="true">button7</button>
+  <div aria-hidden="true">
+    <button id="button8">button8</button>
+  </div>
+  <button id="button9" style="position:absolute;left:-100px;top:-455px;">
+    button9
+  </button>
+  <button id="button10" style="visibility:hidden;">
+    button10
+  </button>
+  <span id="no_accessible_but_displayed">I have no accessible object</span>
+  <button id="button11" disabled>button11</button>
+  <button id="button12" aria-disabled="true">button12</button>
+  <span id="no_accessible_but_disabled" disabled>I have no accessible object</span>
+  <script>
+      document.getElementById('button5').addEventListener('click', function() {
+        // A pseudo button that has a listener but is missing button semantics.
+        return true;
+      });
+  </script>
+</body>
+</html>
--- a/testing/marionette/marionette-elements.js
+++ b/testing/marionette/marionette-elements.js
@@ -7,16 +7,17 @@
  * The ElementManager manages DOM references and interactions with elements.
  * According to the WebDriver spec (http://code.google.com/p/selenium/wiki/JsonWireProtocol), the
  * server sends the client an element reference, and maintains the map of reference to element.
  * The client uses this reference when querying/interacting with the element, and the
  * server uses maps this reference to the actual element when it executes the command.
  */
 
 this.EXPORTED_SYMBOLS = [
+  "Accessibility",
   "ElementManager",
   "CLASS_NAME",
   "SELECTOR",
   "ID",
   "NAME",
   "LINK_TEXT",
   "PARTIAL_LINK_TEXT",
   "TAG",
@@ -42,16 +43,159 @@ this.ANON= "anon";
 this.ANON_ATTRIBUTE = "anon attribute";
 
 function ElementException(msg, num, stack) {
   this.message = msg;
   this.code = num;
   this.stack = stack;
 }
 
+this.Accessibility = function Accessibility() {
+  // A flag indicating whether the accessibility issue should be logged or cause
+  // an exception. Default: log to stdout.
+  this.strict = false;
+  // An interface for in-process accessibility clients
+  // Note: we access it lazily to not enable accessibility when it is not needed
+  Object.defineProperty(this, 'accessibleRetrieval', {
+    configurable: true,
+    get: function() {
+      delete this.accessibleRetrieval;
+      this.accessibleRetrieval = Components.classes[
+        '@mozilla.org/accessibleRetrieval;1'].getService(
+          Components.interfaces.nsIAccessibleRetrieval);
+      return this.accessibleRetrieval;
+    }
+  });
+};
+
+Accessibility.prototype = {
+  /**
+   * Accessible object roles that support some action
+   * @type Object
+   */
+  actionableRoles: new Set([
+    'pushbutton',
+    'checkbutton',
+    'combobox',
+    'key',
+    'link',
+    'menuitem',
+    'check menu item',
+    'radio menu item',
+    'option',
+    'radiobutton',
+    'slider',
+    'spinbutton',
+    'pagetab',
+    'entry',
+    'outlineitem'
+  ]),
+
+  /**
+   * Get an accessible object for a DOM element
+   * @param nsIDOMElement element
+   * @param Boolean mustHaveAccessible a flag indicating that the element must
+   * have an accessible object
+   * @return nsIAccessible object for the element
+   */
+  getAccessibleObject(element, mustHaveAccessible = false) {
+    let acc = this.accessibleRetrieval.getAccessibleFor(element);
+    if (!acc && mustHaveAccessible) {
+      this.handleErrorMessage('Element does not have an accessible object');
+    }
+    return acc;
+  },
+
+  /**
+   * Check if the accessible has a role that supports some action
+   * @param nsIAccessible object
+   * @return Boolean an indicator of role being actionable
+   */
+  isActionableRole(accessible) {
+    return this.actionableRoles.has(
+      this.accessibleRetrieval.getStringRole(accessible.role));
+  },
+
+  /**
+   * Determine if an accessible has at least one action that it supports
+   * @param nsIAccessible object
+   * @return Boolean an indicator of supporting at least one accessible action
+   */
+  hasActionCount(accessible) {
+    return accessible.actionCount > 0;
+  },
+
+  /**
+   * Determine if an accessible has a valid name
+   * @param nsIAccessible object
+   * @return Boolean an indicator that the element has a non empty valid name
+   */
+  hasValidName(accessible) {
+    return accessible.name && accessible.name.trim();
+  },
+
+  /**
+   * Check if an accessible has a set hidden attribute
+   * @param nsIAccessible object
+   * @return Boolean an indicator that the element has a hidden accessible
+   * attribute set to true
+   */
+  hasHiddenAttribute(accessible) {
+    let hidden;
+    try {
+      hidden = accessible.attributes.getStringProperty('hidden');
+    } finally {
+      // If the property is missing, exception will be thrown.
+      return hidden && hidden === 'true';
+    }
+  },
+
+  /**
+   * Verify if an accessible has a given state
+   * @param nsIAccessible object
+   * @param String stateName name of the state to match
+   * @return Boolean accessible has a state
+   */
+  matchState(accessible, stateName) {
+    let stateToMatch = Components.interfaces.nsIAccessibleStates[stateName];
+    let state = {};
+    accessible.getState(state, {});
+    return !!(state.value & stateToMatch);
+  },
+
+  /**
+   * Check if an accessible is hidden from the user of the accessibility API
+   * @param nsIAccessible object
+   * @return Boolean an indicator that the element is hidden from the user
+   */
+  isHidden(accessible) {
+    while (accessible) {
+      if (this.hasHiddenAttribute(accessible)) {
+        return true;
+      }
+      accessible = accessible.parent;
+    }
+    return false;
+  },
+
+  /**
+   * Send an error message or log the error message in the log
+   * @param String message
+   */
+  handleErrorMessage(message) {
+    if (!message) {
+      return;
+    }
+    if (this.strict) {
+      throw new ElementException(message, 56, null);
+    }
+    dump(Date.now() + " Marionette: " + message);
+  }
+};
+
 this.ElementManager = function ElementManager(notSupported) {
   this.seenItems = {};
   this.timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
   this.elementStrategies = [CLASS_NAME, SELECTOR, ID, NAME, LINK_TEXT, PARTIAL_LINK_TEXT, TAG, XPATH, ANON, ANON_ATTRIBUTE];
   for (let i = 0; i < notSupported.length; i++) {
     this.elementStrategies.splice(this.elementStrategies.indexOf(notSupported[i]), 1);
   }
 }
--- a/testing/marionette/marionette-listener.js
+++ b/testing/marionette/marionette-listener.js
@@ -34,16 +34,17 @@ let isB2G = false;
 
 let marionetteTestName;
 let winUtil = content.QueryInterface(Ci.nsIInterfaceRequestor)
                      .getInterface(Ci.nsIDOMWindowUtils);
 let listenerId = null; //unique ID of this listener
 let curFrame = content;
 let previousFrame = null;
 let elementManager = new ElementManager([]);
+let accessibility = new Accessibility();
 let importedScripts = null;
 let inputSource = null;
 
 // The sandbox we execute test scripts in. Gets lazily created in
 // createExecuteContentSandbox().
 let sandbox;
 
 // the unload handler
@@ -205,16 +206,17 @@ function waitForReady() {
 }
 
 /**
  * Called when we start a new session. It registers the
  * current environment, and resets all values
  */
 function newSession(msg) {
   isB2G = msg.json.B2G;
+  accessibility.strict = msg.json.raisesAccessibilityExceptions;
   resetValues();
   if (isB2G) {
     readyStateTimer.initWithCallback(waitForReady, 100, Ci.nsITimer.TYPE_ONE_SHOT);
     // We have to set correct mouse event source to MOZ_SOURCE_TOUCH
     // to offer a way for event listeners to differentiate
     // events being the result of a physical mouse action.
     // This is especially important for the touch event shim,
     // in order to prevent creating touch event for these fake mouse events.
@@ -940,34 +942,96 @@ function generateEvents(type, x, y, touc
 
 /**
  * Function that perform a single tap
  */
 function singleTap(msg) {
   let command_id = msg.json.command_id;
   try {
     let el = elementManager.getKnownElement(msg.json.id, curFrame);
+    let acc = accessibility.getAccessibleObject(el, true);
     // after this block, the element will be scrolled into view
-    if (!checkVisible(el, msg.json.corx, msg.json.cory)) {
-       sendError("Element is not currently visible and may not be manipulated", 11, null, command_id);
-       return;
+    let visible = checkVisible(el, msg.json.corx, msg.json.cory);
+    checkVisibleAccessibility(acc, visible);
+    if (!visible) {
+      sendError("Element is not currently visible and may not be manipulated", 11, null, command_id);
+      return;
     }
+    checkActionableAccessibility(acc);
     if (!curFrame.document.createTouch) {
       mouseEventsOnly = true;
     }
     c = coordinates(el, msg.json.corx, msg.json.cory);
     generateEvents('tap', c.x, c.y, null, el);
     sendOk(msg.json.command_id);
   }
   catch (e) {
     sendError(e.message, e.code, e.stack, msg.json.command_id);
   }
 }
 
 /**
+ * Check if the element's unavailable accessibility state matches the enabled
+ * state
+ * @param nsIAccessible object
+ * @param Boolean enabled element's enabled state
+ */
+function checkEnabledStateAccessibility(accesible, enabled) {
+  if (!accesible) {
+    return;
+  }
+  if (enabled && accessibility.matchState(accesible, 'STATE_UNAVAILABLE')) {
+    accessibility.handleErrorMessage('Element is enabled but disabled via ' +
+      'the accessibility API');
+  }
+}
+
+/**
+ * Check if the element's visible state corresponds to its accessibility API
+ * visibility
+ * @param nsIAccessible object
+ * @param Boolean visible element's visibility state
+ */
+function checkVisibleAccessibility(accesible, visible) {
+  if (!accesible) {
+    return;
+  }
+  let hiddenAccessibility = accessibility.isHidden(accesible);
+  let message;
+  if (visible && hiddenAccessibility) {
+    message = 'Element is not currently visible via the accessibility API ' +
+      'and may not be manipulated by it';
+  } else if (!visible && !hiddenAccessibility) {
+    message = 'Element is currently only visible via the accessibility API ' +
+      'and can be manipulated by it';
+  }
+  accessibility.handleErrorMessage(message);
+}
+
+/**
+ * Check if it is possible to activate an element with the accessibility API
+ * @param nsIAccessible object
+ */
+function checkActionableAccessibility(accesible) {
+  if (!accesible) {
+    return;
+  }
+  let message;
+  if (!accessibility.hasActionCount(accesible)) {
+    message = 'Element does not support any accessible actions';
+  } else if (!accessibility.isActionableRole(accesible)) {
+    message = 'Element does not have a correct accessibility role ' +
+      'and may not be manipulated via the accessibility API';
+  } else if (!accessibility.hasValidName(accesible)) {
+    message = 'Element is missing an accesible name';
+  }
+  accessibility.handleErrorMessage(message);
+}
+
+/**
  * Given an element and a pair of coordinates, returns an array of the form
  * [ clientX, clientY, pageX, pageY, screenX, screenY ]
  */
 function getCoordinateInfo(el, corx, cory) {
   let win = el.ownerDocument.defaultView;
   return [ corx, // clientX
            cory, // clientY
            corx + win.pageXOffset, // pageX
@@ -1426,17 +1490,21 @@ function getActiveElement(msg) {
 /**
  * Send click event to element
  */
 function clickElement(msg) {
   let command_id = msg.json.command_id;
   let el;
   try {
     el = elementManager.getKnownElement(msg.json.id, curFrame);
-    if (checkVisible(el)) {
+    let acc = accessibility.getAccessibleObject(el, true);
+    let visible = checkVisible(el);
+    checkVisibleAccessibility(acc, visible);
+    if (visible) {
+      checkActionableAccessibility(acc);
       if (utils.isElementEnabled(el)) {
         utils.synthesizeMouseAtCenter(el, {}, el.ownerDocument.defaultView)
       }
       else {
         sendError("Element is not Enabled", 12, null, command_id)
       }
     }
     else {
@@ -1494,17 +1562,19 @@ function getElementTagName(msg) {
 
 /**
  * Check if element is displayed
  */
 function isElementDisplayed(msg) {
   let command_id = msg.json.command_id;
   try {
     let el = elementManager.getKnownElement(msg.json.id, curFrame);
-    sendResponse({value: utils.isElementDisplayed(el)}, command_id);
+    let displayed = utils.isElementDisplayed(el);
+    checkVisibleAccessibility(accessibility.getAccessibleObject(el), displayed);
+    sendResponse({value: displayed}, command_id);
   }
   catch (e) {
     sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
  * Return the property of the computed style of an element
@@ -1590,17 +1660,20 @@ function getElementRect(msg){
 
 /**
  * Check if element is enabled
  */
 function isElementEnabled(msg) {
   let command_id = msg.json.command_id;
   try {
     let el = elementManager.getKnownElement(msg.json.id, curFrame);
-    sendResponse({value: utils.isElementEnabled(el)}, command_id);
+    let enabled = utils.isElementEnabled(el);
+    checkEnabledStateAccessibility(accessibility.getAccessibleObject(el),
+      enabled);
+    sendResponse({value: enabled}, command_id);
   }
   catch (e) {
     sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
  * Check if element is selected
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -169,16 +169,17 @@ function MarionetteServerConnection(aPre
     "browserName": appName,
     "browserVersion": Services.appinfo.version,
     "platformName": Services.appinfo.OS.toUpperCase(),
     "platformVersion": Services.appinfo.platformVersion,
 
     // Supported features
     "handlesAlerts": false,
     "nativeEvents": false,
+    "raisesAccessibilityExceptions": false,
     "rotatable": appName == "B2G",
     "secureSsl": false,
     "takesElementScreenshot": true,
     "takesScreenshot": true,
 
     // Selenium 2 compat
     "platform": Services.appinfo.OS.toUpperCase(),
 
@@ -2911,18 +2912,20 @@ MarionetteServerConnection.prototype = {
         // set to true if we updated mainContentId
         mainContent = ((mainContent == true) && (this.curBrowser.mainContentId != null));
         if (mainContent) {
           this.mainContentFrameId = this.curBrowser.curFrameId;
         }
         this.curBrowser.elementManager.seenItems[reg.id] = Cu.getWeakReference(listenerWindow);
         if (nullPrevious && (this.curBrowser.curFrameId != null)) {
           if (!this.sendAsync("newSession",
-                              { B2G: (appName == "B2G") },
-                              this.newSessionCommandId)) {
+              { B2G: (appName == "B2G"),
+                raisesAccessibilityExceptions:
+                  this.sessionCapabilities.raisesAccessibilityExceptions },
+              this.newSessionCommandId)) {
             return;
           }
           if (this.curBrowser.newSession) {
             this.getSessionCapabilities();
             this.newSessionCommandId = null;
           }
         }
         if (this.curBrowser.frameRegsPending) {
--- a/testing/mochitest/server.js
+++ b/testing/mochitest/server.js
@@ -69,17 +69,17 @@ function makeTagFunc(tagName)
     // write the close tag
     response += "</" + tagName + ">\n";
     return response;
   }
 }
 
 function makeTags() {
   // map our global HTML generation functions
-  for each (var tag in tags) {
+  for (let tag of tags) {
       this[tag] = makeTagFunc(tag.toLowerCase());
   }
 }
 
 var _quitting = false;
 
 /** Quit when all activity has completed. */
 function serverStopped()
@@ -387,34 +387,38 @@ function list(requestPath, directory, re
   var count = 0;
   var path = requestPath;
   if (path.charAt(path.length - 1) != "/") {
     path += "/";
   }
 
   var dir = directory.QueryInterface(Ci.nsIFile);
   var links = {};
-  
+
   // The SimpleTest directory is hidden
-  var files = [file for (file in dirIter(dir))
-               if (file.exists() && file.path.indexOf("SimpleTest") == -1)];
-  
+  let files = [];
+  for (let file of dirIter(dir)) {
+    if (file.exists() && file.path.indexOf("SimpleTest") == -1) {
+      files.push(file);
+    }
+  }
+
   // Sort files by name, so that tests can be run in a pre-defined order inside
   // a given directory (see bug 384823)
   function leafNameComparator(first, second) {
     if (first.leafName < second.leafName)
       return -1;
     if (first.leafName > second.leafName)
       return 1;
     return 0;
   }
   files.sort(leafNameComparator);
-  
+
   count = files.length;
-  for each (var file in files) {
+  for (let file of files) {
     var key = path + file.leafName;
     var childCount = 0;
     if (file.isDirectory()) {
       key += "/";
     }
     if (recurse && file.isDirectory()) {
       [links[key], childCount] = list(key, file, recurse);
       count += childCount;
@@ -543,17 +547,18 @@ function arrayOfTestFiles(linkArray, fil
 }
 /**
  * Produce a flat array of test file paths to be executed in the harness.
  */
 function jsonArrayOfTestFiles(links)
 {
   var testFiles = [];
   arrayOfTestFiles(links, testFiles);
-  testFiles = ['"' + file['url'] + '"' for each(file in testFiles)];
+  testFiles = testFiles.map(function(file) { return '"' + file['url'] + '"'; });
+
   return "[" + testFiles.join(",\n") + "]";
 }
 
 /**
  * Produce a normal directory listing.
  */
 function regularListing(metadata, response)
 {
--- 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,14 +1,8 @@
 [attached-callback-move-element-test.html]
   type: testharness
-  [Test attached callback if moving custom element inside document without browsing context]
-    expected: FAIL
-
   [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 without browsing context]
-    expected: FAIL
-
   [Test attached callback if moving custom element from document with browsing context to document with browsing context]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-test.html.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[attached-callback-test.html]
-  type: testharness
-  [Test attached callback if custom element is created via innerHTML property before registration. Document has no browsing context]
-    expected: FAIL
-
-  [Test attached callback if custom element is unregistered]
-    expected: FAIL
-
-  [Test attached callback. Registered element is created via innerHTML property. Document has browsing context]
-    expected: FAIL
-
--- a/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/created-callback-invocation-order-test.html.ini
+++ b/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/created-callback-invocation-order-test.html.ini
@@ -1,17 +1,8 @@
 [created-callback-invocation-order-test.html]
   type: testharness
-  [Test attached callback is enqueued after created callback]
-    expected: FAIL
-
-  [Test attributeChanged callback is not enqueued before created callback started. Document has browsing context]
-    expected: FAIL
-
   [Test attached callback is enqueued after created callback, but before created callback had started]
     expected: FAIL
 
   [Test attached callback is enqueued after created callback had started]
     expected: FAIL
 
-  [Test detached callback is enqueued after created callback had started]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/detached-callback-move-element-test.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[detached-callback-move-element-test.html]
-  type: testharness
-  [Test detached callback is not called if moving custom element inside document without browsing context]
-    expected: FAIL
-
-  [Test detached callback is not called if moving custom element from document without browsing context to document with browsing context]
-    expected: FAIL
-
--- a/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/detached-callback-no-browsing-context-test.html.ini
+++ b/testing/web-platform/meta/custom-elements/custom-element-lifecycle/types-of-callbacks/detached-callback-no-browsing-context-test.html.ini
@@ -1,20 +1,5 @@
 [detached-callback-no-browsing-context-test.html]
   type: testharness
-  [Test detached callback if custom element is created via innerHTML property. Document has no browsing context]
-    expected: FAIL
-
-  [Test detached callback if custom element is via innerHTML property before registration of a custom element. Document has no browsing context]
-    expected: FAIL
-
-  [Test detached callback if removing custom element via innerHTML property. Document has no browsing context]
-    expected: FAIL
-
-  [Test detached callback if removing perent of custom element. Document has no browsing context]
-    expected: FAIL
-
-  [Test detached callback if removing perent of custom element via innerHTML property. Document has no browsing context]
-    expected: FAIL
-
   [Test detached callback is not called, if document\'s window is navigated to another document and custom element is removed]
     expected: FAIL
 
--- a/testing/web-platform/meta/custom-elements/instantiating-custom-elements/extensions-to-document-interface/create-element-is-attribute.html.ini
+++ b/testing/web-platform/meta/custom-elements/instantiating-custom-elements/extensions-to-document-interface/create-element-is-attribute.html.ini
@@ -1,14 +1,8 @@
 [create-element-is-attribute.html]
   type: testharness
   [Test Document.createElement() sets the element\'s IS attribute value to type, if type is not the same as localName]
     expected: FAIL
 
-  [Test Document.createElement() sets the element\'s IS attribute value to type, if type is not the same as localName and an element definition with matching localName, namespace, and type is not registered]
-    expected: FAIL
-
   [Test Document.createElementNS() sets the element\'s IS attribute value to type, if type is not the same as localName]
     expected: FAIL
 
-  [Test Document.createElementNS() sets the element\'s IS attribute value to type, if type is not the same as localNameand and an element definition with matching localName, namespace, and type is not registered ]
-    expected: FAIL
-
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6745,17 +6745,20 @@ nsWindow::GetPreferredCompositorBackends
       aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
     }
 
     ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
 
     if (!prefs.mPreferD3D9) {
       aHints.AppendElement(LayersBackend::LAYERS_D3D11);
     }
-    aHints.AppendElement(LayersBackend::LAYERS_D3D9);
+    if (prefs.mPreferD3D9 || !mozilla::IsVistaOrLater()) {
+      // We don't want D3D9 except on Windows XP
+      aHints.AppendElement(LayersBackend::LAYERS_D3D9);
+    }
   }
   aHints.AppendElement(LayersBackend::LAYERS_BASIC);
 }
 
 void
 nsWindow::WindowUsesOMTC()
 {
   ULONG_PTR style = ::GetClassLongPtr(mWnd, GCL_STYLE);
--- a/xpcom/base/StaticPtr.h
+++ b/xpcom/base/StaticPtr.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_StaticPtr_h
 #define mozilla_StaticPtr_h
 
 #include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/NullPtr.h"
 
 namespace mozilla {
 
 /**
  * StaticAutoPtr and StaticRefPtr are like nsAutoPtr and nsRefPtr, except they
  * are suitable for use as global variables.
  *
@@ -20,27 +21,26 @@ namespace mozilla {
  * compiler to emit  a static initializer (in release builds, anyway).
  *
  * In order to accomplish this, Static{Auto,Ref}Ptr must have a trivial
  * constructor and destructor.  As a consequence, it cannot initialize its raw
  * pointer to 0 on construction, and it cannot delete/release its raw pointer
  * upon destruction.
  *
  * Since the compiler guarantees that all global variables are initialized to
- * 0, these trivial constructors are safe, so long as you use
- * Static{Auto,Ref}Ptr as a global variable.  If you use Static{Auto,Ref}Ptr as
- * a stack variable or as a class instance variable, you will get what you
- * deserve.
+ * 0, these trivial constructors are safe.  Since we rely on this, the clang
+ * plugin, run as part of our "static analysis" builds, makes it a compile-time
+ * error to use Static{Auto,Ref}Ptr as anything except a global variable.
  *
  * Static{Auto,Ref}Ptr have a limited interface as compared to ns{Auto,Ref}Ptr;
  * this is intentional, since their range of acceptable uses is smaller.
  */
 
 template<class T>
-class StaticAutoPtr
+class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticAutoPtr
 {
 public:
   // In debug builds, check that mRawPtr is initialized for us as we expect
   // by the compiler.  In non-debug builds, don't declare a constructor
   // so that the compiler can see that the constructor is trivial.
 #ifdef DEBUG
   StaticAutoPtr()
   {
@@ -82,17 +82,17 @@ private:
     mRawPtr = aNewPtr;
     delete oldPtr;
   }
 
   T* mRawPtr;
 };
 
 template<class T>
-class StaticRefPtr
+class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticRefPtr
 {
 public:
   // In debug builds, check that mRawPtr is initialized for us as we expect
   // by the compiler.  In non-debug builds, don't declare a constructor
   // so that the compiler can see that the constructor is trivial.
 #ifdef DEBUG
   StaticRefPtr()
   {
--- a/xpcom/reflect/xptcall/md/unix/moz.build
+++ b/xpcom/reflect/xptcall/md/unix/moz.build
@@ -14,24 +14,24 @@ if CONFIG['OS_ARCH'] == 'Darwin':
             'xptcinvoke_asm_ppc_rhapsody.s',
         ]
         GENERATED_SOURCES += [
             'xptcstubs_asm_ppc_darwin.s',
         ]
     if '86' in CONFIG['OS_TEST'] and CONFIG['OS_TEST'] != 'x86_64':
         DEFINES['MOZ_NEED_LEADING_UNDERSCORE'] = True
 
-if CONFIG['OS_ARCH'] in ('NetBSD', 'GNU'):
+if CONFIG['OS_ARCH'] == 'GNU':
     if CONFIG['CPU_ARCH'] == 'x86':
         SOURCES += [
             'xptcinvoke_gcc_x86_unix.cpp',
             'xptcstubs_gcc_x86_unix.cpp'
         ]
 
-if CONFIG['OS_ARCH'] in ('Linux', 'FreeBSD', 'OpenBSD') or \
+if CONFIG['OS_ARCH'] in ('Linux', 'FreeBSD', 'NetBSD', 'OpenBSD') or \
    CONFIG['OS_ARCH'].startswith('GNU_'):
     if CONFIG['OS_TEST'] == 'x86_64':
         SOURCES += [
             'xptcinvoke_x86_64_unix.cpp',
             'xptcstubs_x86_64_linux.cpp',
         ]
     elif CONFIG['OS_TEST'].find('86') != -1:
         SOURCES += [