Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 18 Apr 2014 22:11:32 -0400
changeset 197815 725b5f3decfe1ccd79decbb758634a6e0ddedd59
parent 197814 f1ad078b79e534ca43a580b694261851c9bb3a75 (current diff)
parent 197811 582b2d81ebe148856358b97f5395dd714c2efa5c (diff)
child 197816 ee7632b3d59f6a0433fe93ef3b22a691b7b1e8bd
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.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.
js/public/Tracer.h
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -778,20 +778,16 @@ var CustomEventManager = {
           JSON.stringify({ callerID: detail.chromeEventID,
                            keyword: detail.keyword,
                            manifestURL: detail.manifestURL,
                            selectedApps: detail.peers }));
         break;
       case 'inputmethod-update-layouts':
         KeyboardHelper.handleEvent(detail);
         break;
-      case 'nfc-hardware-state-change':
-        Services.obs.notifyObservers(null, 'nfc-hardware-state-change',
-          JSON.stringify({ nfcHardwareState: detail.nfcHardwareState }));
-        break;
     }
   }
 }
 
 var AlertsHelper = {
   _listeners: {},
   _count: 0,
 
--- a/b2g/chrome/content/touchcontrols.css
+++ b/b2g/chrome/content/touchcontrols.css
@@ -24,16 +24,17 @@
 
 .controlsSpacer {
   display: none;
   -moz-box-flex: 0;
 }
 
 .fullscreenButton,
 .playButton,
+.castingButton,
 .muteButton {
   -moz-appearance: none;
   min-height: 42px;
   min-width: 42px;
   border: none !important;
 }
 
 .fullscreenButton {
@@ -57,16 +58,20 @@
 .controlBar.audio-only .playButton {
   transform: translateX(28px);
 }
 
 .playButton[paused="true"] {
   background: url("chrome://b2g/content/images/play-hdpi.png") no-repeat center;
 }
 
+.castingButton {
+  display: none;
+}
+
 .muteButton {
   background: url("chrome://b2g/content/images/mute-hdpi.png") no-repeat center;
 }
 
 .muteButton[muted="true"] {
   background: url("chrome://b2g/content/images/unmute-hdpi.png") no-repeat center;
 }
 
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- 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="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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"/>
@@ -126,11 +126,11 @@
   <!-- Emulator specific things -->
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="09485b73629856b21b2ed6073e327ab0e69a1189"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8afce6d5d48b71b6e7cb917179fb6147fb747521"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="72e3a520e3c700839f07ba0113fd527b923c3330"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="6a7ada569fd37c09ed4bbee6eb78cea5b467b229"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
 </manifest>
--- 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="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <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="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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": "26f2c60c0ba0e64114467663c33c82360c13f4cf", 
+    "revision": "38d1561fe26c12f371c44a47c498722ce06518c2", 
     "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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <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/inari/sources.xml
+++ b/b2g/config/inari/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="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/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="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <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"/>
@@ -122,17 +122,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="6a7ada569fd37c09ed4bbee6eb78cea5b467b229"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/metro/theme/touchcontrols.css
+++ b/browser/metro/theme/touchcontrols.css
@@ -24,16 +24,17 @@
 
 .controlsSpacer {
   display: none;
   -moz-box-flex: 0;
 }
 
 .fullscreenButton,
 .playButton,
+.castingButton,
 .muteButton {
   -moz-appearance: none;
   min-height: 42px;
   min-width: 42px;
   border: none !important;
 }
 
 .fullscreenButton {
@@ -57,16 +58,20 @@
 .controlBar.audio-only .playButton {
   transform: translateX(28px);
 }
 
 .playButton[paused="true"] {
   background: url("chrome://browser/skin/images/play-hdpi.png") no-repeat center;
 }
 
+.castingButton {
+  display: none;
+}
+
 .muteButton {
   background: url("chrome://browser/skin/images/mute-hdpi.png") no-repeat center;
 }
 
 .muteButton[muted="true"] {
   background: url("chrome://browser/skin/images/unmute-hdpi.png") no-repeat center;
 }
 
--- a/content/base/src/nsCCUncollectableMarker.h
+++ b/content/base/src/nsCCUncollectableMarker.h
@@ -1,20 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsCCUncollectableMarker_h_
 #define nsCCUncollectableMarker_h_
 
-#include "nsIObserver.h"
+#include "js/TracingAPI.h"
 #include "mozilla/Attributes.h"
-
-struct JSTracer;
+#include "nsIObserver.h"
 
 class nsCCUncollectableMarker MOZ_FINAL : public nsIObserver
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   /**
    * Inits a global nsCCUncollectableMarker. Should only be called once.
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -48,16 +48,17 @@
 #include "nsCrossSiteListenerProxy.h"
 #include "nsSandboxFlags.h"
 #include "nsContentTypeParser.h"
 #include "nsINetworkSeer.h"
 #include "mozilla/dom/EncodingUtils.h"
 
 #include "mozilla/CORSMode.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/unused.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -809,21 +810,20 @@ NotifyOffThreadScriptLoadCompletedRunnab
   }
 
   return rv;
 }
 
 static void
 OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData)
 {
-  NotifyOffThreadScriptLoadCompletedRunnable* aRunnable =
-    static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData);
+  nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> aRunnable =
+    dont_AddRef(static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData));
   aRunnable->SetToken(aToken);
   NS_DispatchToMainThread(aRunnable);
-  NS_RELEASE(aRunnable);
 }
 
 nsresult
 nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
 {
   if (!aRequest->mElement->GetScriptAsync() || aRequest->mIsInline) {
     return NS_ERROR_FAILURE;
   }
@@ -843,31 +843,29 @@ nsScriptLoader::AttemptAsyncScriptParse(
 
   JS::CompileOptions options(cx);
   FillCompileOptionsForRequest(aRequest, global, &options);
 
   if (!JS::CanCompileOffThread(cx, options, aRequest->mScriptText.Length())) {
     return NS_ERROR_FAILURE;
   }
 
-  NotifyOffThreadScriptLoadCompletedRunnable* runnable =
+  nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> runnable =
     new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this);
 
-  // This reference will be consumed by OffThreadScriptLoaderCallback.
-  NS_ADDREF(runnable);
-
   if (!JS::CompileOffThread(cx, options,
                             aRequest->mScriptText.get(), aRequest->mScriptText.Length(),
                             OffThreadScriptLoaderCallback,
                             static_cast<void*>(runnable))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mDocument->BlockOnload();
 
+  unused << runnable.forget();
   return NS_OK;
 }
 
 nsresult
 nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken)
 {
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Processing requests when running scripts is unsafe.");
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -7,17 +7,17 @@
 
   The base XUL element class and associates.
 
 */
 
 #ifndef nsXULElement_h__
 #define nsXULElement_h__
 
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 #include "mozilla/Attributes.h"
 #include "nsIDOMEvent.h"
 #include "nsIServiceManager.h"
 #include "nsIAtom.h"
 #include "nsINodeInfo.h"
 #include "nsIControllers.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMXULElement.h"
--- a/content/xul/document/src/XULDocument.h
+++ b/content/xul/document/src/XULDocument.h
@@ -20,16 +20,17 @@
 #include "nsIURI.h"
 #include "nsIXULDocument.h"
 #include "nsScriptLoader.h"
 #include "nsIStreamListener.h"
 #include "nsICSSLoaderObserver.h"
 
 #include "mozilla/Attributes.h"
 
+#include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 
 class nsIRDFResource;
 class nsIRDFService;
 class nsPIWindowRoot;
 #if 0 // XXXbe save me, scc (need NSCAP_FORWARD_DECL(nsXULPrototypeScript))
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
@@ -37,17 +38,16 @@ class nsIXULPrototypeScript;
 #else
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsXULElement.h"
 #endif
 #include "nsURIHashKey.h"
 #include "nsInterfaceHashtable.h"
 
-struct JSTracer;
 struct PRLogModuleInfo;
 
 class nsRefMapEntry : public nsStringHashKey
 {
 public:
   nsRefMapEntry(const nsAString& aKey) :
     nsStringHashKey(&aKey)
   {
--- a/content/xul/document/src/nsXULPrototypeCache.cpp
+++ b/content/xul/document/src/nsXULPrototypeCache.cpp
@@ -17,17 +17,17 @@
 #include "nsIObjectOutputStream.h"
 #include "nsIObserverService.h"
 #include "nsIStringStream.h"
 #include "nsIStorageStream.h"
 
 #include "nsNetUtil.h"
 #include "nsAppDirectoryServiceDefs.h"
 
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 using namespace mozilla::scache;
--- a/content/xul/document/src/nsXULPrototypeDocument.h
+++ b/content/xul/document/src/nsXULPrototypeDocument.h
@@ -1,32 +1,32 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 nsXULPrototypeDocument_h__
 #define nsXULPrototypeDocument_h__
 
+#include "js/TracingAPI.h"
 #include "mozilla/Attributes.h"
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsISerializable.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIAtom;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeInfoManager;
 class nsXULPrototypeElement;
 class nsXULPrototypePI;
 class nsXULPDGlobalObject;
-struct JSTracer;
 
 namespace mozilla {
 namespace dom {
 class XULDocument;
 } // namespace dom
 } // namespace mozilla
 
 /**
--- a/dom/apps/src/InterAppCommService.js
+++ b/dom/apps/src/InterAppCommService.js
@@ -71,31 +71,28 @@ function InterAppCommService() {
   //
   // For example:
   //
   // {
   //   "foo": {
   //     "app://subApp1.gaiamobile.org/manifest.webapp": {
   //       pageURL: "app://subApp1.gaiamobile.org/handler.html",
   //       description: "blah blah",
-  //       appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED,
   //       rules: { ... }
   //     },
   //     "app://subApp2.gaiamobile.org/manifest.webapp": {
   //       pageURL: "app://subApp2.gaiamobile.org/handler.html",
   //       description: "blah blah",
-  //       appStatus: Ci.nsIPrincipal.APP_STATUS_PRIVILEGED,
   //       rules: { ... }
   //     }
   //   },
   //   "bar": {
   //     "app://subApp3.gaiamobile.org/manifest.webapp": {
   //       pageURL: "app://subApp3.gaiamobile.org/handler.html",
   //       description: "blah blah",
-  //       appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED,
   //       rules: { ... }
   //     }
   //   }
   // }
   //
   // TODO Bug 908999 - Update registered connections when app gets uninstalled.
   this._registeredConnections = {};
 
@@ -209,38 +206,37 @@ function InterAppCommService() {
   //     }
   //   }
   // }
   this._messagePortPairs = {};
 }
 
 InterAppCommService.prototype = {
   registerConnection: function(aKeyword, aHandlerPageURI, aManifestURI,
-                               aDescription, aAppStatus, aRules) {
+                               aDescription, aRules) {
     let manifestURL = aManifestURI.spec;
     let pageURL = aHandlerPageURI.spec;
 
     if (DEBUG) {
       debug("registerConnection: aKeyword: " + aKeyword +
             " manifestURL: " + manifestURL + " pageURL: " + pageURL +
-            " aDescription: " + aDescription + " aAppStatus: " + aAppStatus +
+            " aDescription: " + aDescription +
             " aRules.minimumAccessLevel: " + aRules.minimumAccessLevel +
             " aRules.manifestURLs: " + aRules.manifestURLs +
             " aRules.installOrigins: " + aRules.installOrigins);
     }
 
     let subAppManifestURLs = this._registeredConnections[aKeyword];
     if (!subAppManifestURLs) {
       subAppManifestURLs = this._registeredConnections[aKeyword] = {};
     }
 
     subAppManifestURLs[manifestURL] = {
       pageURL: pageURL,
       description: aDescription,
-      appStatus: aAppStatus,
       rules: aRules,
       manifestURL: manifestURL
     };
   },
 
   _matchMinimumAccessLevel: function(aRules, aAppStatus) {
     if (!aRules || !aRules.minimumAccessLevel) {
       if (DEBUG) {
@@ -295,77 +291,76 @@ InterAppCommService.prototype = {
     if (DEBUG) {
       debug("rules.manifestURLs is not matched!" +
             " manifestURLs: " + manifestURLs +
             " aManifestURL : " + aManifestURL);
     }
     return false;
   },
 
-  _matchInstallOrigins: function(aRules, aManifestURL) {
+  _matchInstallOrigins: function(aRules, aInstallOrigin) {
     if (!aRules || !Array.isArray(aRules.installOrigins)) {
       if (DEBUG) {
         debug("rules.installOrigins is not available. No need to match.");
       }
       return true;
     }
 
-    let installOrigin =
-      appsService.getAppByManifestURL(aManifestURL).installOrigin;
-
     let installOrigins = aRules.installOrigins;
-    if (installOrigins.indexOf(installOrigin) != -1) {
+    if (installOrigins.indexOf(aInstallOrigin) != -1) {
       return true;
     }
 
     if (DEBUG) {
       debug("rules.installOrigins is not matched!" +
-            " aManifestURL: " + aManifestURL +
             " installOrigins: " + installOrigins +
-            " installOrigin : " + installOrigin);
+            " installOrigin : " + aInstallOrigin);
     }
     return false;
   },
 
-  _matchRules: function(aPubAppManifestURL, aPubAppStatus, aPubRules,
-                        aSubAppManifestURL, aSubAppStatus, aSubRules) {
+  _matchRules: function(aPubAppManifestURL, aPubRules,
+                        aSubAppManifestURL, aSubRules) {
+    let pubApp = appsService.getAppByManifestURL(aPubAppManifestURL);
+    let subApp = appsService.getAppByManifestURL(aSubAppManifestURL);
+
     // TODO Bug 907068 In the initiative step, we only expose this API to
     // certified apps to meet the time line. Eventually, we need to make
     // it available for the non-certified apps as well. For now, only the
     // certified apps can match the rules.
-    if (aPubAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED ||
-        aSubAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
+    if (pubApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED ||
+        subApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
       if (DEBUG) {
         debug("Only certified apps are allowed to do connections.");
       }
       return false;
     }
 
     if (!aPubRules && !aSubRules) {
       if (DEBUG) {
         debug("No rules for publisher and subscriber. No need to match.");
       }
       return true;
     }
 
     // Check minimumAccessLevel.
-    if (!this._matchMinimumAccessLevel(aPubRules, aSubAppStatus) ||
-        !this._matchMinimumAccessLevel(aSubRules, aPubAppStatus)) {
+    if (!this._matchMinimumAccessLevel(aPubRules, subApp.appStatus) ||
+        !this._matchMinimumAccessLevel(aSubRules, pubApp.appStatus)) {
       return false;
     }
 
     // Check manifestURLs.
     if (!this._matchManifestURLs(aPubRules, aSubAppManifestURL) ||
         !this._matchManifestURLs(aSubRules, aPubAppManifestURL)) {
       return false;
     }
 
     // Check installOrigins.
-    if (!this._matchInstallOrigins(aPubRules, aSubAppManifestURL) ||
-        !this._matchInstallOrigins(aSubRules, aPubAppManifestURL)) {
+    if (!this._matchInstallOrigins(aPubRules, subApp.installOrigin) ||
+        !this._matchInstallOrigins(aSubRules, pubApp.installOrigin)) {
       return false;
     }
 
     // Check developers.
     // TODO Do we really want to check this? This one seems naive.
 
     if (DEBUG) debug("All rules are matched.");
     return true;
@@ -447,17 +442,16 @@ InterAppCommService.prototype = {
   },
 
   _connect: function(aMessage, aTarget) {
     let keyword = aMessage.keyword;
     let pubRules = aMessage.rules;
     let pubAppManifestURL = aMessage.manifestURL;
     let outerWindowID = aMessage.outerWindowID;
     let requestID = aMessage.requestID;
-    let pubAppStatus = aMessage.appStatus;
 
     let subAppManifestURLs = this._registeredConnections[keyword];
     if (!subAppManifestURLs) {
       if (DEBUG) {
         debug("No apps are subscribed for this connection. Returning.");
       }
       this._dispatchMessagePorts(keyword, pubAppManifestURL, [],
                                  aTarget, outerWindowID, requestID);
@@ -481,22 +475,21 @@ InterAppCommService.prototype = {
         if (DEBUG) {
           debug("Don't need to select again. Skipping: " + subAppManifestURL);
         }
         continue;
       }
 
       // Only rule-matched publishers/subscribers are allowed to connect.
       let subscribedInfo = subAppManifestURLs[subAppManifestURL];
-      let subAppStatus = subscribedInfo.appStatus;
       let subRules = subscribedInfo.rules;
 
       let matched =
-        this._matchRules(pubAppManifestURL, pubAppStatus, pubRules,
-                         subAppManifestURL, subAppStatus, subRules);
+        this._matchRules(pubAppManifestURL, pubRules,
+                         subAppManifestURL, subRules);
       if (!matched) {
         if (DEBUG) {
           debug("Rules are not matched. Skipping: " + subAppManifestURL);
         }
         continue;
       }
 
       appsToSelect.push({
new file mode 100644
--- /dev/null
+++ b/dom/apps/src/ScriptPreloader.jsm
@@ -0,0 +1,76 @@
+/* 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/. */
+
+"use strict";
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+this.EXPORTED_SYMBOLS = ["ScriptPreloader"];
+
+function debug(aMsg) {
+  //dump("--*-- ScriptPreloader: " + aMsg + "\n");
+}
+
+this.ScriptPreloader = {
+#ifdef MOZ_B2G
+  _enabled: true,
+#else
+  _enabled: false,
+#endif
+
+  preload: function(aApp, aManifest) {
+    debug("Preloading " + aApp.origin);
+    let deferred = Promise.defer();
+
+    if (!this._enabled) {
+      deferred.resolve();
+      return deferred.promise;
+    }
+
+    if (aManifest.precompile &&
+        Array.isArray(aManifest.precompile) &&
+        aManifest.precompile.length > 0) {
+      let origin = Services.io.newURI(aApp.origin, null, null);
+      let toLoad = aManifest.precompile.length;
+      let principal =
+        Services.scriptSecurityManager
+                .getAppCodebasePrincipal(origin, aApp.localId, false);
+
+      aManifest.precompile.forEach((aPath) => {
+        let uri = Services.io.newURI(aPath, null, origin);
+        debug("Script to compile: " + uri.spec);
+        try {
+          Services.scriptloader.precompileScript(uri, principal,
+            (aSubject, aTopic, aData) => {
+              let uri = aSubject.QueryInterface(Ci.nsIURI);
+              debug("Done compiling " + uri.spec);
+
+              toLoad--;
+              if (toLoad == 0) {
+                deferred.resolve();
+              }
+            });
+        } catch (e) {
+          // Resolve the promise if precompileScript throws.
+          deferred.resolve();
+        }
+      });
+    } else {
+      // The precompile field is not an array, let the developer know.
+      // We don't want to have to enable debug for that to show up.
+      if (aManifest.precompile) {
+        Cu.reportError("ASM.JS compilation failed: the 'precompile' manifest " +
+                       "property should be an array of script uris.\n");
+      }
+      deferred.resolve();
+    }
+
+    return deferred.promise;
+  }
+}
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -481,17 +481,16 @@ WebappsApplication.prototype = {
 
   connect: function(aKeyword, aRules) {
     return this.createPromise(function (aResolve, aReject) {
       cpmm.sendAsyncMessage("Webapps:Connect",
                             { keyword: aKeyword,
                               rules: aRules,
                               manifestURL: this.manifestURL,
                               outerWindowID: this._id,
-                              appStatus: this._appStatus,
                               requestID: this.getPromiseResolverId({
                                 resolve: aResolve,
                                 reject: aReject
                               })});
     }.bind(this));
   },
 
   getConnections: function() {
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -56,16 +56,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/SystemMessagePermissionsChecker.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
   "resource://gre/modules/WebappOSUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ScriptPreloader",
+                                  "resource://gre/modules/ScriptPreloader.jsm");
+
 #ifdef MOZ_WIDGET_GONK
 XPCOMUtils.defineLazyGetter(this, "libcutils", function() {
   Cu.import("resource://gre/modules/systemlibs.js");
   return libcutils;
 });
 #endif
 
 function debug(aMsg) {
@@ -729,17 +732,16 @@ this.DOMApplicationRegistry = {
         msgmgr.registerPage("connection", handlerPageURI, manifestURI);
       }
 
       interAppCommService.
         registerConnection(keyword,
                            handlerPageURI,
                            manifestURI,
                            connection.description,
-                           AppsUtils.getAppManifestStatus(manifest),
                            connection.rules);
     }
   },
 
   _registerSystemMessages: function(aManifest, aApp) {
     this._registerSystemMessagesForEntryPoint(aManifest, aApp, null);
 
     if (!aManifest.entry_points) {
@@ -1484,17 +1486,19 @@ this.DOMApplicationRegistry = {
           for (let prop in app.staged) {
             app[prop] = app.staged[prop];
           }
           delete app.staged;
         }
 
         delete app.retryingDownload;
 
-        this._saveApps().then(() => {
+        // Update the asm.js scripts we need to compile.
+        ScriptPreloader.preload(app, aData)
+          .then(() => this._saveApps()).then(() => {
           // Update the handlers and permissions for this app.
           this.updateAppHandlers(aOldManifest, aData, app);
 
           AppsUtils.loadJSONAsync(staged.path).then((aUpdateManifest) => {
             let appObject = AppsUtils.cloneAppObject(app);
             appObject.updateManifest = aUpdateManifest;
             this.notifyUpdateHandlers(appObject, aData, appFile.path);
           });
@@ -2590,23 +2594,29 @@ onInstallSuccessAck: function onInstallS
       this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
                            aNewApp.manifestURL, aManifest, aNewApp.appStatus);
 
       this.broadcastMessage("Webapps:UpdateState", {
         app: app,
         manifest: aManifest,
         manifestURL: aNewApp.manifestURL
       });
-      this.broadcastMessage("Webapps:FireEvent", {
-        eventType: ["downloadsuccess", "downloadapplied"],
-        manifestURL: aNewApp.manifestURL
-      });
-      if (aInstallSuccessCallback) {
-        aInstallSuccessCallback(aManifest, zipFile.path);
-      }
+
+      // Check if we have asm.js code to preload for this application.
+      ScriptPreloader.preload(aNewApp, aManifest)
+                     .then(() => {
+          this.broadcastMessage("Webapps:FireEvent", {
+            eventType: ["downloadsuccess", "downloadapplied"],
+            manifestURL: aNewApp.manifestURL
+          });
+          if (aInstallSuccessCallback) {
+            aInstallSuccessCallback(aManifest, zipFile.path);
+          }
+        }
+      );
     });
   },
 
   _nextLocalId: function() {
     let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1;
 
     while (this.getManifestURLByLocalId(id)) {
       id++;
--- a/dom/apps/src/moz.build
+++ b/dom/apps/src/moz.build
@@ -31,16 +31,17 @@ EXTRA_JS_MODULES += [
     'PermissionsInstaller.jsm',
     'PermissionsTable.jsm',
     'StoreTrustAnchor.jsm',
 ]
 
 EXTRA_PP_JS_MODULES += [
     'AppsUtils.jsm',
     'OperatorApps.jsm',
+    'ScriptPreloader.jsm',
     'Webapps.jsm',
 ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'gklayout'
 
 LOCAL_INCLUDES += [
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -170,52 +170,32 @@ Crypto::ImportUserCertificates(const nsA
                                bool aDoForcedBackup,
                                nsAString& aReturn,
                                ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 }
 
 void
-Crypto::PopChallengeResponse(const nsAString& aChallenge,
-                             nsAString& aReturn,
-                             ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
-void
-Crypto::Random(int32_t aNumBytes, nsAString& aReturn, ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
-void
 Crypto::SignText(JSContext* aContext,
                  const nsAString& aStringToSign,
                  const nsAString& aCaOption,
                  const Sequence<nsCString>& aArgs,
                  nsAString& aReturn)
 
 {
   aReturn.AssignLiteral("error:internalError");
 }
 
 void
 Crypto::Logout(ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 }
 
-void
-Crypto::DisableRightClick(ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
 #endif
 
 /* static */ uint8_t*
 Crypto::GetRandomValues(uint32_t aLength)
 {
   nsCOMPtr<nsIRandomGenerator> randomGenerator;
   nsresult rv;
   randomGenerator = do_GetService("@mozilla.org/security/random-generator;1");
--- a/dom/base/Crypto.h
+++ b/dom/base/Crypto.h
@@ -61,31 +61,24 @@ public:
                       ErrorResult& aRv);
 
   virtual void ImportUserCertificates(const nsAString& aNickname,
                                       const nsAString& aCmmfResponse,
                                       bool aDoForcedBackup,
                                       nsAString& aReturn,
                                       ErrorResult& aRv);
 
-  virtual void PopChallengeResponse(const nsAString& aChallenge,
-                                    nsAString& aReturn,
-                                    ErrorResult& aRv);
-
-  virtual void Random(int32_t aNumBytes, nsAString& aReturn, ErrorResult& aRv);
-
   virtual void SignText(JSContext* aContext,
                         const nsAString& aStringToSign,
                         const nsAString& aCaOption,
                         const Sequence<nsCString>& aArgs,
                         nsAString& aReturn);
 
   virtual void Logout(ErrorResult& aRv);
 
-  virtual void DisableRightClick(ErrorResult& aRv);
 #endif
 
   // WebIDL
 
   nsPIDOMWindow*
   GetParentObject() const
   {
     return mWindow;
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -6,17 +6,17 @@
 #ifndef nsWrapperCache_h___
 #define nsWrapperCache_h___
 
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Assertions.h"
 #include "js/Id.h"          // must come before js/RootingAPI.h
 #include "js/Value.h"       // must come before js/RootingAPI.h
 #include "js/RootingAPI.h"
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 
 class XPCWrappedNativeScope;
 
 #define NS_WRAPPERCACHE_IID \
 { 0x6f3179a1, 0x36f7, 0x4a5c, \
   { 0x8c, 0xf1, 0xad, 0xc8, 0x7c, 0xde, 0x3e, 0x87 } }
 
 /**
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsWrapperCacheInline_h___
 #define nsWrapperCacheInline_h___
 
 #include "nsWrapperCache.h"
 #include "js/GCAPI.h"
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 
 inline JSObject*
 nsWrapperCache::GetWrapper() const
 {
     JSObject* obj = GetWrapperPreserveColor();
     if (obj) {
       JS::ExposeObjectToActiveJS(obj);
     }
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_TypedArray_h
 #define mozilla_dom_TypedArray_h
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/RootingAPI.h"
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
 /*
--- a/dom/interfaces/apps/nsIInterAppCommService.idl
+++ b/dom/interfaces/apps/nsIInterAppCommService.idl
@@ -11,30 +11,27 @@ interface nsIURI;
  *
  * This interface contains helpers for Inter-App Communication API [1] related
  * purposes. A singleton service of this interface will be instantiated during
  * the system boot-up, which plays the role of the central service receiving
  * messages from and interacting with the content processes.
  *
  * [1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
  */
-[scriptable, uuid(7fdd8b68-0b0a-11e3-9b4c-afbc236da250)]
+[scriptable, uuid(b3d711a4-c6a4-11e3-8fd3-738e7fbcb6d6)]
 interface nsIInterAppCommService : nsISupports
 {
   /*
    * Registration of a page that wants to be connected to other apps through
    * the Inter-App Communication API.
    *
    * @param keyword        The connection's keyword.
    * @param handlerPageURI The URI of the handler's page.
    * @param manifestURI    The webapp's manifest URI.
    * @param description    The connection's description.
-   * @param appStatus      The app status can be Ci.nsIPrincipal.APP_STATUS_[
-   *                       NOT_INSTALLED, INSTALLED, PRIVILEGED, CERTIFIED].
    * @param rules          The connection's rules.
    */
   void registerConnection(in DOMString      keyword,
                           in nsIURI         handlerPageURI,
                           in nsIURI         manifestURI,
                           in DOMString      description,
-                          in unsigned short appStatus,
                           in jsval          rules);
 };
--- a/dom/system/gonk/Nfc.js
+++ b/dom/system/gonk/Nfc.js
@@ -411,17 +411,16 @@ XPCOMUtils.defineLazyGetter(this, "gMess
 
 function Nfc() {
   debug("Starting Worker");
   this.worker = new ChromeWorker("resource://gre/modules/nfc_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
 
   Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
-  Services.obs.addObserver(this, NFC.TOPIC_HARDWARE_STATE, false);
 
   gMessageManager.init(this);
   let lock = gSettingsService.createLock();
   lock.get(NFC.SETTING_NFC_ENABLED, this);
   // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
   this.sessionTokenMap = {};
   this.targetsByRequestId = {};
 
@@ -652,36 +651,19 @@ Nfc.prototype = {
     switch (topic) {
       case NFC.TOPIC_MOZSETTINGS_CHANGED:
         let setting = JSON.parse(data);
         if (setting) {
           let setting = JSON.parse(data);
           this.handle(setting.key, setting.value);
         }
         break;
-      case NFC.TOPIC_HARDWARE_STATE:
-        let state = JSON.parse(data);
-        if (state) {
-          let level = this.hardwareStateToPowerlevel(state.nfcHardwareState);
-          this.setConfig({ powerLevel: level });
-        }
-        break;
     }
   },
 
   setConfig: function setConfig(prop) {
     this.sendToWorker("config", prop);
-  },
-
-  hardwareStateToPowerlevel: function hardwareStateToPowerlevel(state) {
-    switch (state) {
-      case 0:   return NFC.NFC_POWER_LEVEL_DISABLED;
-      case 1:   return NFC.NFC_POWER_LEVEL_ENABLED;
-      case 2:   return NFC.NFC_POWER_LEVEL_ENABLED;
-      case 3:   return NFC.NFC_POWER_LEVEL_LOW;
-      default:  return NFC.NFC_POWER_LEVEL_UNKNOWN;
-    }
   }
 };
 
 if (NFC_ENABLED) {
   this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Nfc]);
 }
--- a/dom/system/gonk/nfc_consts.js
+++ b/dom/system/gonk/nfc_consts.js
@@ -40,34 +40,38 @@ this.NFC_RESPONSE_CONFIG = 1001;
 this.NFC_RESPONSE_READ_NDEF_DETAILS = 1002;
 this.NFC_RESPONSE_READ_NDEF = 1003;
 
 this.NFC_NOTIFICATION_INITIALIZED = 2000;
 this.NFC_NOTIFICATION_TECH_DISCOVERED = 2001;
 this.NFC_NOTIFICATION_TECH_LOST = 2002;
 
 this.NFC_TECHS = {
-  0:'NDEF',
-  1:'NDEF_WRITEABLE',
-  2:'NDEF_FORMATABLE',
-  3:'P2P'
+  0:"NDEF",
+  1:"NDEF_WRITEABLE",
+  2:"NDEF_FORMATABLE",
+  3:"P2P",
+  4:"NFC_A",
+  5:"NFC_B",
+  6:"NFC_F",
+  7:"NFC_V",
+  8:"NFC_ISO_DEP"
 };
 
 // TODO: Bug 933595. Fill-in all error codes for Gonk/nfcd protocol
 this.GECKO_NFC_ERROR_SUCCESS             = 0;
 this.GECKO_NFC_ERROR_GENERIC_FAILURE     = 1;
 
 // NFC powerlevels must match config PDUs.
 this.NFC_POWER_LEVEL_UNKNOWN        = -1;
 this.NFC_POWER_LEVEL_DISABLED       = 0;
 this.NFC_POWER_LEVEL_LOW            = 1;
 this.NFC_POWER_LEVEL_ENABLED        = 2;
 
 this.TOPIC_MOZSETTINGS_CHANGED      = "mozsettings-changed";
 this.TOPIC_XPCOM_SHUTDOWN           = "xpcom-shutdown";
-this.TOPIC_HARDWARE_STATE           = "nfc-hardware-state-change";
 this.SETTING_NFC_ENABLED            = "nfc.enabled";
 
 this.NFC_PEER_EVENT_READY = 0x01;
 this.NFC_PEER_EVENT_LOST  = 0x02;
 
 // Allow this file to be imported via Components.utils.import().
 this.EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/tests/mochitest/crypto/test_legacy.html
+++ b/dom/tests/mochitest/crypto/test_legacy.html
@@ -12,22 +12,17 @@
 ok("crypto" in window, "crypto in window");
 ok("version" in window.crypto, "version in window.crypto");
 ok("enableSmartCardEvents" in window.crypto,
    "enableSmartCardEvents in window.crypto");
 ok("generateCRMFRequest" in window.crypto,
    "generateCRMFRequest in window.crypto");
 ok("importUserCertificates" in window.crypto,
    "importUserCertificates in window.crypto");
-ok("popChallengeResponse" in window.crypto,
-   "popChallengeResponse in window.crypto");
-ok("random" in window.crypto, "random in window.crypto");
 ok("signText" in window.crypto, "signText in window.crypto");
-ok("disableRightClick" in window.crypto,
-   "disableRightClick in window.crypto");
 
 function jsCallback () {
 }
 
 try {
   window.crypto.generateCRMFRequest(null, null, null, null, jsCallback.toString());
   ok(false, "window.crypto.generateCRMFRequest failed, should throw error");
 } catch (e) {
--- a/dom/tests/mochitest/crypto/test_no_legacy.html
+++ b/dom/tests/mochitest/crypto/test_no_legacy.html
@@ -12,17 +12,12 @@
 ok("crypto" in window, "crypto in window");
 ok(!("version" in window.crypto), "version not in window.crypto");
 ok(!("enableSmartCardEvents" in window.crypto),
    "enableSmartCardEvents not in window.crypto");
 ok(!("generateCRMFRequest" in window.crypto),
    "generateCRMFRequest not in window.crypto");
 ok(!("importUserCertificates" in window.crypto),
    "importUserCertificates not in window.crypto");
-ok(!("popChallengeResponse" in window.crypto),
-   "popChallengeResponse not in window.crypto");
-ok(!("random" in window.crypto), "random not in window.crypto");
 ok(!("signText" in window.crypto), "signText not in window.crypto");
-ok(!("disableRightClick" in window.crypto),
-   "disableRightClick not in window.crypto");
 
 </script>
 </body></html>
--- a/dom/webidl/Crypto.webidl
+++ b/dom/webidl/Crypto.webidl
@@ -34,28 +34,19 @@ interface CryptoLegacy {
                                   ByteString? jsCallback,
                                   any... args);
 
   [Throws]
   DOMString importUserCertificates(DOMString nickname,
                                    DOMString cmmfResponse,
                                    boolean doForcedBackup);
 
-  [Throws]
-  DOMString popChallengeResponse(DOMString challenge);
-
-  [Throws]
-  DOMString random(long numBytes);
-
   DOMString signText(DOMString stringToSign,
                      DOMString caOption,
                      ByteString... args);
 
   [Throws]
   void logout();
-
-  [Throws]
-  void disableRightClick();
 };
 
 Crypto implements CryptoLegacy;
 #endif // !MOZ_DISABLE_CRYPTOLEGACY
 
--- a/ipc/app/macbuild/Contents/Info.plist.in
+++ b/ipc/app/macbuild/Contents/Info.plist.in
@@ -24,12 +24,10 @@
 		<string>10.5.0</string>
 		<key>x86_64</key>
 		<string>10.6.0</string>
 	</dict>
 	<key>LSUIElement</key>
 	<string>1</string>
 	<key>NSSupportsAutomaticGraphicsSwitching</key>
 	<true/>
-	<key>NSPrincipalClass</key>
-	<string>NSApplication</string>
 </dict>
 </plist>
rename from js/public/Tracer.h
rename to js/public/TracingAPI.h
--- a/js/public/Tracer.h
+++ b/js/public/TracingAPI.h
@@ -1,22 +1,22 @@
 /* -*- 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/. */
 
-#ifndef js_Tracer_h
-#define js_Tracer_h
+#ifndef js_TracingAPI_h
+#define js_TracingAPI_h
 
 #include "mozilla/NullPtr.h"
- 
+
 #include "jspubtd.h"
 
-struct JSTracer;
+class JS_PUBLIC_API(JSTracer);
 
 namespace JS {
 template <typename T> class Heap;
 template <typename T> class TenuredHeap;
 }
 
 // Tracer callback, called for each traceable thing directly referenced by a
 // particular object or runtime structure. It is the callback responsibility
@@ -41,85 +41,112 @@ typedef void
 (* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize);
 
 enum WeakMapTraceKind {
     DoNotTraceWeakMaps = 0,
     TraceWeakMapValues = 1,
     TraceWeakMapKeysValues = 2
 };
 
-struct JSTracer {
-    JSRuntime           *runtime;
+class JS_PUBLIC_API(JSTracer)
+{
+  public:
+    JSTracer(JSRuntime *rt, JSTraceCallback traceCallback,
+             WeakMapTraceKind weakTraceKind = TraceWeakMapValues);
+
+    // Set debugging information about a reference to a traceable thing to prepare
+    // for the following call to JS_CallTracer.
+    //
+    // When printer is null, arg must be const char * or char * C string naming
+    // the reference and index must be either (size_t)-1 indicating that the name
+    // alone describes the reference or it must be an index into some array vector
+    // that stores the reference.
+    //
+    // When printer callback is not null, the arg and index arguments are
+    // available to the callback as debugPrintArg_ and debugPrintIndex_ fields
+    // of JSTracer.
+    //
+    // The storage for name or callback's arguments needs to live only until
+    // the following call to JS_CallTracer returns.
+    void setTracingDetails(JSTraceNamePrinter printer, const void *arg, size_t index) {
+        debugPrinter_ = printer;
+        debugPrintArg_ = arg;
+        debugPrintIndex_ = index;
+    }
+
+    void setTracingIndex(const char *name, size_t index) {
+        setTracingDetails(nullptr, (void *)name, index);
+    }
+
+    void setTracingName(const char *name) {
+        setTracingDetails(nullptr, (void *)name, size_t(-1));
+    }
+
+    // Remove the currently set tracing details.
+    void clearTracingDetails() {
+        debugPrinter_ = nullptr;
+        debugPrintArg_ = nullptr;
+    }
+
+    // Return true if tracing details are currently set.
+    bool hasTracingDetails() const;
+
+    // Get the string set with the most recent call to setTracingName or return
+    // fallback if a name printer function has been installed.
+    const char *tracingName(const char *fallback) const;
+
+    // Build a description of this edge in the heap graph. This call may invoke
+    // the debug printer, which may inspect arbitrary areas of the heap.
+    const char *getTracingEdgeName(char *buffer, size_t bufferSize);
+
+    // Access the currently active tracing details.
+    JSTraceNamePrinter debugPrinter() const;
+    const void *debugPrintArg() const;
+    size_t debugPrintIndex() const;
+
+    // Return the runtime set on the tracer.
+    JSRuntime *runtime() const { return runtime_; }
+
+    // Return the weak map tracing behavior set on this tracer.
+    WeakMapTraceKind eagerlyTraceWeakMaps() const { return eagerlyTraceWeakMaps_; }
+
+    // Update the trace callback.
+    void setTraceCallback(JSTraceCallback traceCallback);
+
+#ifdef JS_GC_ZEAL
+    // Sets the "real" location for a marked reference, when passing the address
+    // directly is not feasable. This address is used for matching against the
+    // store buffer when verifying the correctness of the entrees there.
+    //
+    // This is currently complicated by our need to nest calls for Values
+    // stored as keys in hash tables.
+    void setTracingLocation(void *location);
+    void unsetTracingLocation();
+    void **tracingLocation(void **thingp);
+#else
+    void setTracingLocation(void *location) {}
+    void unsetTracingLocation() {}
+    void **tracingLocation(void **thingp) { return nullptr; }
+#endif
+
+    // We expose |callback| directly so that IS_GC_MARKING_TRACER can compare
+    // it to GCMarker::GrayCallback.
     JSTraceCallback     callback;
-    JSTraceNamePrinter  debugPrinter;
-    const void          *debugPrintArg;
-    size_t              debugPrintIndex;
-    WeakMapTraceKind    eagerlyTraceWeakMaps;
+
+  private:
+    JSRuntime           *runtime_;
+    JSTraceNamePrinter  debugPrinter_;
+    const void          *debugPrintArg_;
+    size_t              debugPrintIndex_;
+    WeakMapTraceKind    eagerlyTraceWeakMaps_;
 #ifdef JS_GC_ZEAL
-    void                *realLocation;
+    void                *realLocation_;
 #endif
 };
 
-// Set debugging information about a reference to a traceable thing to prepare
-// for the following call to JS_CallTracer.
-//
-// When printer is null, arg must be const char * or char * C string naming
-// the reference and index must be either (size_t)-1 indicating that the name
-// alone describes the reference or it must be an index into some array vector
-// that stores the reference.
-//
-// When printer callback is not null, the arg and index arguments are
-// available to the callback as debugPrintArg and debugPrintIndex fields
-// of JSTracer.
-//
-// The storage for name or callback's arguments needs to live only until
-// the following call to JS_CallTracer returns.
-//
-# define JS_SET_TRACING_DETAILS(trc, printer, arg, index)                     \
-    JS_BEGIN_MACRO                                                            \
-        (trc)->debugPrinter = (printer);                                      \
-        (trc)->debugPrintArg = (arg);                                         \
-        (trc)->debugPrintIndex = (index);                                     \
-    JS_END_MACRO
-
-// Sets the real location for a marked reference, when passing the address
-// directly is not feasable.
-//
-// FIXME: This is currently overcomplicated by our need to nest calls for Values
-// stored as keys in hash tables, but will get simplified once we can rekey
-// in-place.
-//
-#ifdef JS_GC_ZEAL
-# define JS_SET_TRACING_LOCATION(trc, location)                               \
-    JS_BEGIN_MACRO                                                            \
-        if (!(trc)->realLocation || !(location))                              \
-            (trc)->realLocation = (location);                                 \
-    JS_END_MACRO
-# define JS_UNSET_TRACING_LOCATION(trc)                                       \
-    JS_BEGIN_MACRO                                                            \
-        (trc)->realLocation = nullptr;                                        \
-    JS_END_MACRO
-#else
-# define JS_SET_TRACING_LOCATION(trc, location)                               \
-    JS_BEGIN_MACRO                                                            \
-    JS_END_MACRO
-# define JS_UNSET_TRACING_LOCATION(trc)                                       \
-    JS_BEGIN_MACRO                                                            \
-    JS_END_MACRO
-#endif
-
-// Convenience macro to describe the argument of JS_CallTracer using C string
-// and index.
-# define JS_SET_TRACING_INDEX(trc, name, index)                               \
-    JS_SET_TRACING_DETAILS(trc, nullptr, name, index)
-
-// Convenience macro to describe the argument of JS_CallTracer using C string.
-# define JS_SET_TRACING_NAME(trc, name)                                       \
-    JS_SET_TRACING_DETAILS(trc, nullptr, name, (size_t)-1)
-
 // The JS_Call*Tracer family of functions traces the given GC thing reference.
 // This performs the tracing action configured on the given JSTracer:
 // typically calling the JSTracer::callback or marking the thing as live.
 //
 // The argument to JS_Call*Tracer is an in-out param: when the function
 // returns, the garbage collector might have moved the GC thing. In this case,
 // the reference passed to JS_Call*Tracer will be updated to the object's new
 // location. Callers of this method are responsible for updating any state
@@ -160,37 +187,30 @@ JS_CallHeapScriptTracer(JSTracer *trc, J
 extern JS_PUBLIC_API(void)
 JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap<JSFunction *> *funp, const char *name);
 
 template <typename HashSetEnum>
 inline void
 JS_CallHashSetObjectTracer(JSTracer *trc, HashSetEnum &e, JSObject *const &key, const char *name)
 {
     JSObject *updated = key;
-    JS_SET_TRACING_LOCATION(trc, reinterpret_cast<void *>(&const_cast<JSObject *&>(key)));
+    trc->setTracingLocation(reinterpret_cast<void *>(&const_cast<JSObject *&>(key)));
     JS_CallObjectTracer(trc, &updated, name);
     if (updated != key)
         e.rekeyFront(key, updated);
 }
 
 // Trace an object that is known to always be tenured.  No post barriers are
 // required in this case.
 extern JS_PUBLIC_API(void)
 JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name);
 
-// API for JSTraceCallback implementations.
-extern JS_PUBLIC_API(void)
-JS_TracerInit(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback);
-
 extern JS_PUBLIC_API(void)
 JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
 
 extern JS_PUBLIC_API(void)
 JS_TraceRuntime(JSTracer *trc);
 
 extern JS_PUBLIC_API(void)
 JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
                      void *thing, JSGCTraceKind kind, bool includeDetails);
 
-extern JS_PUBLIC_API(const char *)
-JS_GetTraceEdgeName(JSTracer *trc, char *buffer, int bufferSize);
-
-#endif /* js_Tracer_h */
+#endif /* js_TracingAPI_h */
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -824,17 +824,17 @@ HashableValue::operator==(const Hashable
 #endif
     return b;
 }
 
 HashableValue
 HashableValue::mark(JSTracer *trc) const
 {
     HashableValue hv(*this);
-    JS_SET_TRACING_LOCATION(trc, (void *)this);
+    trc->setTracingLocation((void *)this);
     gc::MarkValue(trc, &hv.value, "key");
     return hv;
 }
 
 
 /*** MapIterator *********************************************************************************/
 
 namespace {
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -660,28 +660,28 @@ js::regexp_exec_no_statics(JSContext *cx
 /* ES5 15.10.6.3. */
 static bool
 regexp_test_impl(JSContext *cx, CallArgs args)
 {
     MatchPair match;
     MatchConduit conduit(&match);
     RegExpRunStatus status = ExecuteRegExp(cx, args, conduit);
     args.rval().setBoolean(status == RegExpRunStatus_Success);
-    return (status != RegExpRunStatus_Error);
+    return status != RegExpRunStatus_Error;
 }
 
 /* Separate interface for use by IonMonkey. */
 bool
 js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result)
 {
     MatchPair match;
     MatchConduit conduit(&match);
     RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit, UpdateRegExpStatics);
     *result = (status == RegExpRunStatus_Success);
-    return (status != RegExpRunStatus_Error);
+    return status != RegExpRunStatus_Error;
 }
 
 bool
 js::regexp_test(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod(cx, IsRegExp, regexp_test_impl, args);
 }
@@ -696,10 +696,10 @@ js::regexp_test_no_statics(JSContext *cx
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
 
     MatchPair match;
     MatchConduit conduit(&match);
     RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, DontUpdateRegExpStatics);
     args.rval().setBoolean(status == RegExpRunStatus_Success);
-    return (status != RegExpRunStatus_Error);
+    return status != RegExpRunStatus_Error;
 }
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -679,30 +679,34 @@ NondeterministicGetWeakMapKeys(JSContext
 struct JSCountHeapNode {
     void                *thing;
     JSGCTraceKind       kind;
     JSCountHeapNode     *next;
 };
 
 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet;
 
-typedef struct JSCountHeapTracer {
+class CountHeapTracer
+{
+  public:
+    CountHeapTracer(JSRuntime *rt, JSTraceCallback callback) : base(rt, callback) {}
+
     JSTracer            base;
     VisitedSet          visited;
     JSCountHeapNode     *traceList;
     JSCountHeapNode     *recycleList;
     bool                ok;
-} JSCountHeapTracer;
+};
 
 static void
 CountHeapNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
     JS_ASSERT(trc->callback == CountHeapNotify);
 
-    JSCountHeapTracer *countTracer = (JSCountHeapTracer *)trc;
+    CountHeapTracer *countTracer = (CountHeapTracer *)trc;
     void *thing = *thingp;
 
     if (!countTracer->ok)
         return;
 
     VisitedSet::AddPtr p = countTracer->visited.lookupForAdd(thing);
     if (p)
         return;
@@ -788,18 +792,17 @@ CountHeap(JSContext *cx, unsigned argc, 
                     if (!!bytes)
                         JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
                     return false;
                 }
             }
         }
     }
 
-    JSCountHeapTracer countTracer;
-    JS_TracerInit(&countTracer.base, JS_GetRuntime(cx), CountHeapNotify);
+    CountHeapTracer countTracer(JS_GetRuntime(cx), CountHeapNotify);
     if (!countTracer.visited.init()) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
     countTracer.ok = true;
     countTracer.traceList = nullptr;
     countTracer.recycleList = nullptr;
 
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -810,17 +810,17 @@ class MOZ_STACK_CLASS TokenStream
 #ifdef DEBUG
         // Poison the TokenBuf so it cannot be accessed again.
         void poison() {
             ptr = nullptr;
         }
 #endif
 
         static bool isRawEOLChar(int32_t c) {
-            return (c == '\n' || c == '\r' || c == LINE_SEPARATOR || c == PARA_SEPARATOR);
+            return c == '\n' || c == '\r' || c == LINE_SEPARATOR || c == PARA_SEPARATOR;
         }
 
         // Finds the next EOL, but stops once 'max' jschars have been scanned
         // (*including* the starting jschar).
         const jschar *findEOLMax(const jschar *p, size_t max);
 
       private:
         const jschar *base_;            // base of buffer
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -17,18 +17,18 @@
 using namespace js;
 using namespace js::gc;
 
 void
 js::TraceRuntime(JSTracer *trc)
 {
     JS_ASSERT(!IS_GC_MARKING_TRACER(trc));
 
-    MinorGC(trc->runtime, JS::gcreason::EVICT_NURSERY);
-    AutoPrepareForTracing prep(trc->runtime, WithAtoms);
+    MinorGC(trc->runtime(), JS::gcreason::EVICT_NURSERY);
+    AutoPrepareForTracing prep(trc->runtime(), WithAtoms);
     MarkRuntime(trc);
 }
 
 static void
 IterateCompartmentsArenasCells(JSRuntime *rt, Zone *zone, void *data,
                                JSIterateCompartmentCallback compartmentCallback,
                                IterateArenaCallback arenaCallback,
                                IterateCellCallback cellCallback)
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -148,31 +148,31 @@ template<typename T>
 static inline void
 CheckMarkedThing(JSTracer *trc, T *thing)
 {
 #ifdef DEBUG
     JS_ASSERT(trc);
     JS_ASSERT(thing);
 
     /* This function uses data that's not available in the nursery. */
-    if (IsInsideNursery(trc->runtime, thing))
+    if (IsInsideNursery(trc->runtime(), thing))
         return;
 
     /*
      * Permanent atoms are not associated with this runtime, but will be ignored
      * during marking.
      */
     if (ThingIsPermanentAtom(thing))
         return;
 
     JS_ASSERT(thing->zone());
-    JS_ASSERT(thing->zone()->runtimeFromMainThread() == trc->runtime);
-    JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
+    JS_ASSERT(thing->zone()->runtimeFromMainThread() == trc->runtime());
+    JS_ASSERT(trc->hasTracingDetails());
 
-    DebugOnly<JSRuntime *> rt = trc->runtime;
+    DebugOnly<JSRuntime *> rt = trc->runtime();
 
     JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gcManipulatingDeadZones,
                  !thing->zone()->scheduledForDestruction);
 
     JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
     JS_ASSERT_IF(thing->zone()->requireGCTracer(),
                  IS_GC_MARKING_TRACER(trc));
@@ -212,17 +212,17 @@ MarkInternal(JSTracer *trc, T **thingp)
 
     if (!trc->callback) {
         /*
          * We may mark a Nursery thing outside the context of the
          * MinorCollectionTracer because of a pre-barrier. The pre-barrier is
          * not needed in this case because we perform a minor collection before
          * each incremental slice.
          */
-        if (IsInsideNursery(trc->runtime, thing))
+        if (IsInsideNursery(trc->runtime(), thing))
             return;
 
         /*
          * Don't mark permanent atoms, as they may be associated with another
          * runtime. Note that PushMarkStack() also checks this, but the tests
          * and maybeAlive write below should only be done on the main thread.
          */
         if (ThingIsPermanentAtom(thing))
@@ -234,103 +234,101 @@ MarkInternal(JSTracer *trc, T **thingp)
          */
         if (!thing->zone()->isGCMarking())
             return;
 
         PushMarkStack(AsGCMarker(trc), thing);
         thing->zone()->maybeAlive = true;
     } else {
         trc->callback(trc, (void **)thingp, MapTypeToTraceKind<T>::kind);
-        JS_UNSET_TRACING_LOCATION(trc);
+        trc->unsetTracingLocation();
     }
 
-    trc->debugPrinter = nullptr;
-    trc->debugPrintArg = nullptr;
+    trc->clearTracingDetails();
 }
 
 #define JS_ROOT_MARKING_ASSERT(trc)                                     \
     JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc),                             \
-                 trc->runtime->gcIncrementalState == NO_INCREMENTAL ||  \
-                 trc->runtime->gcIncrementalState == MARK_ROOTS);
+                 trc->runtime()->gcIncrementalState == NO_INCREMENTAL ||  \
+                 trc->runtime()->gcIncrementalState == MARK_ROOTS);
 
 namespace js {
 namespace gc {
 
 template <typename T>
 void
 MarkUnbarriered(JSTracer *trc, T **thingp, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkInternal(trc, thingp);
 }
 
 template <typename T>
 static void
 Mark(JSTracer *trc, BarrieredPtr<T> *thing, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkInternal(trc, thing->unsafeGet());
 }
 
 void
 MarkPermanentAtom(JSTracer *trc, JSAtom *atom, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
 
     JS_ASSERT(atom->isPermanent());
 
     CheckMarkedThing(trc, atom);
 
     if (!trc->callback) {
         // Atoms do not refer to other GC things so don't need to go on the mark stack.
         // Additionally, PushMarkStack will ignore permanent atoms.
         atom->markIfUnmarked();
     } else {
         void *thing = atom;
         trc->callback(trc, &thing, JSTRACE_STRING);
         JS_ASSERT(thing == atom);
-        JS_UNSET_TRACING_LOCATION(trc);
+        trc->unsetTracingLocation();
     }
 
-    trc->debugPrinter = nullptr;
-    trc->debugPrintArg = nullptr;
+    trc->clearTracingDetails();
 }
 
 } /* namespace gc */
 } /* namespace js */
 
 template <typename T>
 static void
 MarkRoot(JSTracer *trc, T **thingp, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkInternal(trc, thingp);
 }
 
 template <typename T>
 static void
 MarkRange(JSTracer *trc, size_t len, HeapPtr<T> *vec, const char *name)
 {
     for (size_t i = 0; i < len; ++i) {
         if (vec[i].get()) {
-            JS_SET_TRACING_INDEX(trc, name, i);
+            trc->setTracingIndex(name, i);
             MarkInternal(trc, vec[i].unsafeGet());
         }
     }
 }
 
 template <typename T>
 static void
 MarkRootRange(JSTracer *trc, size_t len, T **vec, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
     for (size_t i = 0; i < len; ++i) {
         if (vec[i]) {
-            JS_SET_TRACING_INDEX(trc, name, i);
+            trc->setTracingIndex(name, i);
             MarkInternal(trc, &vec[i]);
         }
     }
 }
 
 namespace js {
 namespace gc {
 
@@ -532,17 +530,17 @@ gc::MarkKind(JSTracer *trc, void **thing
         MarkInternal(trc, reinterpret_cast<jit::JitCode **>(thingp));
         break;
     }
 }
 
 static void
 MarkGCThingInternal(JSTracer *trc, void **thingp, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     JS_ASSERT(thingp);
     if (!*thingp)
         return;
     MarkKind(trc, thingp, GetGCThingTraceKind(*thingp));
 }
 
 void
 gc::MarkGCThingRoot(JSTracer *trc, void **thingp, const char *name)
@@ -559,137 +557,137 @@ gc::MarkGCThingUnbarriered(JSTracer *trc
 
 /*** ID Marking ***/
 
 static inline void
 MarkIdInternal(JSTracer *trc, jsid *id)
 {
     if (JSID_IS_STRING(*id)) {
         JSString *str = JSID_TO_STRING(*id);
-        JS_SET_TRACING_LOCATION(trc, (void *)id);
+        trc->setTracingLocation((void *)id);
         MarkInternal(trc, &str);
         *id = NON_INTEGER_ATOM_TO_JSID(reinterpret_cast<JSAtom *>(str));
     } else if (MOZ_UNLIKELY(JSID_IS_OBJECT(*id))) {
         JSObject *obj = JSID_TO_OBJECT(*id);
-        JS_SET_TRACING_LOCATION(trc, (void *)id);
+        trc->setTracingLocation((void *)id);
         MarkInternal(trc, &obj);
         *id = OBJECT_TO_JSID(obj);
     } else {
         /* Unset realLocation manually if we do not call MarkInternal. */
-        JS_UNSET_TRACING_LOCATION(trc);
+        trc->unsetTracingLocation();
     }
 }
 
 void
 gc::MarkId(JSTracer *trc, BarrieredId *id, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkIdInternal(trc, id->unsafeGet());
 }
 
 void
 gc::MarkIdRoot(JSTracer *trc, jsid *id, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkIdInternal(trc, id);
 }
 
 void
 gc::MarkIdUnbarriered(JSTracer *trc, jsid *id, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkIdInternal(trc, id);
 }
 
 void
 gc::MarkIdRange(JSTracer *trc, size_t len, HeapId *vec, const char *name)
 {
     for (size_t i = 0; i < len; ++i) {
-        JS_SET_TRACING_INDEX(trc, name, i);
+        trc->setTracingIndex(name, i);
         MarkIdInternal(trc, vec[i].unsafeGet());
     }
 }
 
 void
 gc::MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
     for (size_t i = 0; i < len; ++i) {
-        JS_SET_TRACING_INDEX(trc, name, i);
+        trc->setTracingIndex(name, i);
         MarkIdInternal(trc, &vec[i]);
     }
 }
 
 /*** Value Marking ***/
 
 static inline void
 MarkValueInternal(JSTracer *trc, Value *v)
 {
     if (v->isMarkable()) {
         JS_ASSERT(v->toGCThing());
         void *thing = v->toGCThing();
-        JS_SET_TRACING_LOCATION(trc, (void *)v);
+        trc->setTracingLocation((void *)v);
         MarkKind(trc, &thing, v->gcKind());
         if (v->isString())
             v->setString((JSString *)thing);
         else
             v->setObjectOrNull((JSObject *)thing);
     } else {
         /* Unset realLocation manually if we do not call MarkInternal. */
-        JS_UNSET_TRACING_LOCATION(trc);
+        trc->unsetTracingLocation();
     }
 }
 
 void
 gc::MarkValue(JSTracer *trc, BarrieredValue *v, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkValueInternal(trc, v->unsafeGet());
 }
 
 void
 gc::MarkValueRoot(JSTracer *trc, Value *v, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkValueInternal(trc, v);
 }
 
 void
 gc::MarkTypeRoot(JSTracer *trc, types::Type *v, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     if (v->isSingleObject()) {
         JSObject *obj = v->singleObject();
         MarkInternal(trc, &obj);
         *v = types::Type::ObjectType(obj);
     } else if (v->isTypeObject()) {
         types::TypeObject *typeObj = v->typeObject();
         MarkInternal(trc, &typeObj);
         *v = types::Type::ObjectType(typeObj);
     }
 }
 
 void
 gc::MarkValueRange(JSTracer *trc, size_t len, BarrieredValue *vec, const char *name)
 {
     for (size_t i = 0; i < len; ++i) {
-        JS_SET_TRACING_INDEX(trc, name, i);
+        trc->setTracingIndex(name, i);
         MarkValueInternal(trc, vec[i].unsafeGet());
     }
 }
 
 void
 gc::MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
     for (size_t i = 0; i < len; ++i) {
-        JS_SET_TRACING_INDEX(trc, name, i);
+        trc->setTracingIndex(name, i);
         MarkValueInternal(trc, &vec[i]);
     }
 }
 
 bool
 gc::IsValueMarked(Value *v)
 {
     JS_ASSERT(v->isMarkable());
@@ -729,65 +727,65 @@ bool
 gc::IsSlotMarked(HeapSlot *s)
 {
     return IsMarked(s);
 }
 
 void
 gc::MarkSlot(JSTracer *trc, HeapSlot *s, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkValueInternal(trc, s->unsafeGet());
 }
 
 void
 gc::MarkArraySlots(JSTracer *trc, size_t len, HeapSlot *vec, const char *name)
 {
     for (size_t i = 0; i < len; ++i) {
-        JS_SET_TRACING_INDEX(trc, name, i);
+        trc->setTracingIndex(name, i);
         MarkValueInternal(trc, vec[i].unsafeGet());
     }
 }
 
 void
 gc::MarkObjectSlots(JSTracer *trc, JSObject *obj, uint32_t start, uint32_t nslots)
 {
     JS_ASSERT(obj->isNative());
     for (uint32_t i = start; i < (start + nslots); ++i) {
-        JS_SET_TRACING_DETAILS(trc, js_GetObjectSlotName, obj, i);
+        trc->setTracingDetails(js_GetObjectSlotName, obj, i);
         MarkValueInternal(trc, obj->nativeGetSlotRef(i).unsafeGet());
     }
 }
 
 static bool
 ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell)
 {
     if (!IS_GC_MARKING_TRACER(trc))
         return true;
 
     uint32_t color = AsGCMarker(trc)->getMarkColor();
     JS_ASSERT(color == BLACK || color == GRAY);
 
-    if (IsInsideNursery(trc->runtime, cell)) {
+    if (IsInsideNursery(trc->runtime(), cell)) {
         JS_ASSERT(color == BLACK);
         return false;
     }
 
     JS::Zone *zone = cell->tenuredZone();
     if (color == BLACK) {
         /*
          * Having black->gray edges violates our promise to the cycle
          * collector. This can happen if we're collecting a compartment and it
          * has an edge to an uncollected compartment: it's possible that the
          * source and destination of the cross-compartment edge should be gray,
          * but the source was marked black by the conservative scanner.
          */
         if (cell->isMarked(GRAY)) {
             JS_ASSERT(!zone->isCollecting());
-            trc->runtime->gcFoundBlackGrayEdges = true;
+            trc->runtime()->gcFoundBlackGrayEdges = true;
         }
         return zone->isGCMarking();
     } else {
         if (zone->isGCMarkingBlack()) {
             /*
              * The destination compartment is being not being marked gray now,
              * but it will be later, so record the cell so it can be marked gray
              * at the appropriate time.
@@ -822,24 +820,24 @@ gc::MarkCrossCompartmentSlot(JSTracer *t
         MarkSlot(trc, dst, name);
 }
 
 /*** Special Marking ***/
 
 void
 gc::MarkObject(JSTracer *trc, HeapPtr<GlobalObject, JSScript *> *thingp, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkInternal(trc, thingp->unsafeGet());
 }
 
 void
 gc::MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
 {
-    JS_SET_TRACING_NAME(trc, name);
+    trc->setTracingName(name);
     MarkValueInternal(trc, v);
 }
 
 bool
 gc::IsCellMarked(Cell **thingp)
 {
     return IsMarked<Cell>(thingp);
 }
@@ -857,122 +855,122 @@ gc::IsCellAboutToBeFinalized(Cell **thin
 
 #define JS_COMPARTMENT_ASSERT_STR(rt, thing)                            \
     JS_ASSERT((thing)->zone()->isGCMarking() ||                         \
               (rt)->isAtomsZone((thing)->zone()));
 
 static void
 PushMarkStack(GCMarker *gcmarker, ObjectImpl *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 /*
  * PushMarkStack for BaseShape unpacks its children directly onto the mark
  * stack. For a pre-barrier between incremental slices, this may result in
  * objects in the nursery getting pushed onto the mark stack. It is safe to
  * ignore these objects because they will be marked by the matching
  * post-barrier during the minor GC at the start of each incremental slice.
  */
 static void
 MaybePushMarkStackBetweenSlices(GCMarker *gcmarker, JSObject *thing)
 {
-    JSRuntime *rt = gcmarker->runtime;
+    JSRuntime *rt = gcmarker->runtime();
     JS_COMPARTMENT_ASSERT(rt, thing);
     JS_ASSERT_IF(rt->isHeapBusy(), !IsInsideNursery(rt, thing));
 
     if (!IsInsideNursery(rt, thing) && thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushType(thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, JSScript *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     /*
      * We mark scripts directly rather than pushing on the stack as they can
      * refer to other scripts only indirectly (like via nested functions) and
      * we cannot get to deep recursion.
      */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         MarkChildren(gcmarker, thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, LazyScript *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     /*
      * We mark lazy scripts directly rather than pushing on the stack as they
      * only refer to normal scripts and to strings, and cannot recurse.
      */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         MarkChildren(gcmarker, thing);
 }
 
 static void
 ScanShape(GCMarker *gcmarker, Shape *shape);
 
 static void
 PushMarkStack(GCMarker *gcmarker, Shape *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     /* We mark shapes directly rather than pushing on the stack. */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         ScanShape(gcmarker, thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, jit::JitCode *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushJitCode(thing);
 }
 
 static inline void
 ScanBaseShape(GCMarker *gcmarker, BaseShape *base);
 
 static void
 PushMarkStack(GCMarker *gcmarker, BaseShape *thing)
 {
-    JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
-    JS_ASSERT(!IsInsideNursery(gcmarker->runtime, thing));
+    JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
+    JS_ASSERT(!IsInsideNursery(gcmarker->runtime(), thing));
 
     /* We mark base shapes directly rather than pushing on the stack. */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         ScanBaseShape(gcmarker, thing);
 }
 
 static void
 ScanShape(GCMarker *gcmarker, Shape *shape)
@@ -1023,30 +1021,30 @@ ScanBaseShape(GCMarker *gcmarker, BaseSh
         JS_ASSERT(base->compartment() == unowned->compartment());
         unowned->markIfUnmarked(gcmarker->getMarkColor());
     }
 }
 
 static inline void
 ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
 {
-    JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
+    JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
     JS_ASSERT(str->isMarked());
 
     /*
      * Add extra asserts to confirm the static type to detect incorrect string
      * mutations.
      */
     JS_ASSERT(str->JSString::isLinear());
     while (str->hasBase()) {
         str = str->base();
         JS_ASSERT(str->JSString::isLinear());
         if (str->isPermanentAtom())
             break;
-        JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
+        JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
         if (!str->markIfUnmarked())
             break;
     }
 }
 
 /*
  * The function tries to scan the whole rope tree using the marking stack as
  * temporary storage. If that becomes full, the unscanned ropes are added to
@@ -1059,17 +1057,17 @@ ScanLinearString(GCMarker *gcmarker, JSL
 static void
 ScanRope(GCMarker *gcmarker, JSRope *rope)
 {
     ptrdiff_t savedPos = gcmarker->stack.position();
     JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
     for (;;) {
         JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
         JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope());
-        JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope);
+        JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), rope);
         JS_ASSERT(rope->isMarked());
         JSRope *next = nullptr;
 
         JSString *right = rope->rightChild();
         if (!right->isPermanentAtom() && right->markIfUnmarked()) {
             if (right->isLinear())
                 ScanLinearString(gcmarker, &right->asLinear());
             else
@@ -1113,17 +1111,17 @@ ScanString(GCMarker *gcmarker, JSString 
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSString *str)
 {
     // Permanent atoms might not be associated with this runtime.
     if (str->isPermanentAtom())
         return;
 
-    JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
+    JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
 
     /*
      * As string can only refer to other strings we fully scan its GC graph
      * using the explicit stack when navigating the rope tree to avoid
      * dealing with strings on the stack in drainMarkStack.
      */
     if (str->markIfUnmarked())
         ScanString(gcmarker, str);
@@ -1485,51 +1483,51 @@ GCMarker::processMarkStackTop(SliceBudge
         JS_ASSERT((addr3 - addr2) % sizeof(Value) == 0);
         vp = reinterpret_cast<HeapSlot *>(addr2);
         end = reinterpret_cast<HeapSlot *>(addr3);
         goto scan_value_array;
     }
 
     if (tag == ObjectTag) {
         obj = reinterpret_cast<JSObject *>(addr);
-        JS_COMPARTMENT_ASSERT(runtime, obj);
+        JS_COMPARTMENT_ASSERT(runtime(), obj);
         goto scan_obj;
     }
 
     processMarkStackOther(tag, addr);
     return;
 
   scan_value_array:
     JS_ASSERT(vp <= end);
     while (vp != end) {
         const Value &v = *vp++;
         if (v.isString()) {
             JSString *str = v.toString();
             if (!str->isPermanentAtom()) {
-                JS_COMPARTMENT_ASSERT_STR(runtime, str);
-                JS_ASSERT(runtime->isAtomsZone(str->zone()) || str->zone() == obj->zone());
+                JS_COMPARTMENT_ASSERT_STR(runtime(), str);
+                JS_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == obj->zone());
                 if (str->markIfUnmarked())
                     ScanString(this, str);
             }
         } else if (v.isObject()) {
             JSObject *obj2 = &v.toObject();
-            JS_COMPARTMENT_ASSERT(runtime, obj2);
+            JS_COMPARTMENT_ASSERT(runtime(), obj2);
             JS_ASSERT(obj->compartment() == obj2->compartment());
             if (obj2->markIfUnmarked(getMarkColor())) {
                 pushValueArray(obj, vp, end);
                 obj = obj2;
                 goto scan_obj;
             }
         }
     }
     return;
 
   scan_obj:
     {
-        JS_COMPARTMENT_ASSERT(runtime, obj);
+        JS_COMPARTMENT_ASSERT(runtime(), obj);
 
         budget.step();
         if (budget.isOverBudget()) {
             pushObject(obj);
             return;
         }
 
         types::TypeObject *type = obj->typeFromGC();
@@ -1539,18 +1537,18 @@ GCMarker::processMarkStackTop(SliceBudge
         PushMarkStack(this, shape);
 
         /* Call the trace hook if necessary. */
         const Class *clasp = type->clasp();
         if (clasp->trace) {
             // Global objects all have the same trace hook. That hook is safe without barriers
             // if the gloal has no custom trace hook of it's own, or has been moved to a different
             // compartment, and so can't have one.
-            JS_ASSERT_IF(runtime->gcMode() == JSGC_MODE_INCREMENTAL &&
-                         runtime->gcIncrementalEnabled &&
+            JS_ASSERT_IF(runtime()->gcMode() == JSGC_MODE_INCREMENTAL &&
+                         runtime()->gcIncrementalEnabled &&
                          !(clasp->trace == JS_GlobalObjectTraceHook &&
                            (!obj->compartment()->options().getTrace() ||
                             !obj->isOwnGlobal())),
                          clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
             clasp->trace(this, obj);
         }
 
         if (!shape->isNative())
@@ -1581,17 +1579,17 @@ GCMarker::processMarkStackTop(SliceBudge
         goto scan_value_array;
     }
 }
 
 bool
 GCMarker::drainMarkStack(SliceBudget &budget)
 {
 #ifdef DEBUG
-    JSRuntime *rt = runtime;
+    JSRuntime *rt = runtime();
 
     struct AutoCheckCompartment {
         JSRuntime *runtime;
         AutoCheckCompartment(JSRuntime *rt) : runtime(rt) {
             JS_ASSERT(!rt->gcStrictCompartmentChecking);
             runtime->gcStrictCompartmentChecking = true;
         }
         ~AutoCheckCompartment() { runtime->gcStrictCompartmentChecking = false; }
@@ -1676,28 +1674,28 @@ UnmarkGrayChildren(JSTracer *trc, void *
 
 struct UnmarkGrayTracer : public JSTracer
 {
     /*
      * We set eagerlyTraceWeakMaps to false because the cycle collector will fix
      * up any color mismatches involving weakmaps when it runs.
      */
     UnmarkGrayTracer(JSRuntime *rt)
-      : tracingShape(false), previousShape(nullptr), unmarkedAny(false)
-    {
-        JS_TracerInit(this, rt, UnmarkGrayChildren);
-        eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
-    }
+      : JSTracer(rt, UnmarkGrayChildren, DoNotTraceWeakMaps),
+        tracingShape(false),
+        previousShape(nullptr),
+        unmarkedAny(false)
+    {}
 
     UnmarkGrayTracer(JSTracer *trc, bool tracingShape)
-      : tracingShape(tracingShape), previousShape(nullptr), unmarkedAny(false)
-    {
-        JS_TracerInit(this, trc->runtime, UnmarkGrayChildren);
-        eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
-    }
+      : JSTracer(trc->runtime(), UnmarkGrayChildren, DoNotTraceWeakMaps),
+        tracingShape(tracingShape),
+        previousShape(nullptr),
+        unmarkedAny(false)
+    {}
 
     /* True iff we are tracing the immediate children of a shape. */
     bool tracingShape;
 
     /* If tracingShape, shape child or nullptr. Otherwise, nullptr. */
     void *previousShape;
 
     /* Whether we unmarked anything. */
@@ -1734,27 +1732,27 @@ struct UnmarkGrayTracer : public JSTrace
  *   of the containers, we must add unmark-graying read barriers to these
  *   containers.
  */
 static void
 UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
     void *thing = *thingp;
     int stackDummy;
-    if (!JS_CHECK_STACK_SIZE(trc->runtime->mainThread.nativeStackLimit[StackForSystemCode], &stackDummy)) {
+    if (!JS_CHECK_STACK_SIZE(trc->runtime()->mainThread.nativeStackLimit[StackForSystemCode], &stackDummy)) {
         /*
          * If we run out of stack, we take a more drastic measure: require that
          * we GC again before the next CC.
          */
-        trc->runtime->gcGrayBitsValid = false;
+        trc->runtime()->gcGrayBitsValid = false;
         return;
     }
 
     UnmarkGrayTracer *tracer = static_cast<UnmarkGrayTracer *>(trc);
-    if (!IsInsideNursery(trc->runtime, thing)) {
+    if (!IsInsideNursery(trc->runtime(), thing)) {
         if (!JS::GCThingIsMarkedGray(thing))
             return;
 
         UnmarkGrayGCThing(thing);
         tracer->unmarkedAny = true;
     }
 
     /*
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -294,27 +294,25 @@ class MinorCollectionTracer : public JST
     /* Insert the given relocation entry into the list of things to visit. */
     MOZ_ALWAYS_INLINE void insertIntoFixupList(RelocationOverlay *entry) {
         *tail = entry;
         tail = &entry->next_;
         *tail = nullptr;
     }
 
     MinorCollectionTracer(JSRuntime *rt, Nursery *nursery)
-      : JSTracer(),
+      : JSTracer(rt, Nursery::MinorGCCallback, TraceWeakMapKeysValues),
         nursery(nursery),
         session(rt, MinorCollecting),
         tenuredSize(0),
         head(nullptr),
         tail(&head),
         savedRuntimeNeedBarrier(rt->needsBarrier()),
         disableStrictProxyChecking(rt)
     {
-        JS_TracerInit(this, rt, Nursery::MinorGCCallback);
-        eagerlyTraceWeakMaps = TraceWeakMapKeysValues;
         rt->gcNumber++;
 
         /*
          * We disable the runtime needsBarrier() check so that pre-barriers do
          * not fire on objects that have been relocated. The pre-barrier's
          * call to obj->zone() will try to look through shape_, which is now
          * the relocation magic and will crash. However, zone->needsBarrier()
          * must still be set correctly so that allocations we make in minor
@@ -332,18 +330,18 @@ class MinorCollectionTracer : public JST
                 if (!ArrayBufferObject::saveArrayBufferList(c, liveArrayBuffers))
                     CrashAtUnhandlableOOM("OOM while saving live array buffers");
                 ArrayBufferObject::resetArrayBufferList(c);
             }
         }
     }
 
     ~MinorCollectionTracer() {
-        runtime->setNeedsBarrier(savedRuntimeNeedBarrier);
-        if (runtime->gcIncrementalState != NO_INCREMENTAL)
+        runtime()->setNeedsBarrier(savedRuntimeNeedBarrier);
+        if (runtime()->gcIncrementalState != NO_INCREMENTAL)
             ArrayBufferObject::restoreArrayBufferLists(liveArrayBuffers);
     }
 };
 
 } /* namespace gc */
 } /* namespace js */
 
 static AllocKind
@@ -531,17 +529,17 @@ js::Nursery::markSlot(MinorCollectionTra
     JSObject *tenured = static_cast<JSObject*>(moveToTenured(trc, obj));
     slotp->unsafeGet()->setObject(*tenured);
 }
 
 void *
 js::Nursery::moveToTenured(MinorCollectionTracer *trc, JSObject *src)
 {
     Zone *zone = src->zone();
-    AllocKind dstKind = GetObjectAllocKindForCopy(trc->runtime, src);
+    AllocKind dstKind = GetObjectAllocKindForCopy(trc->runtime(), src);
     JSObject *dst = static_cast<JSObject *>(allocateFromTenured(zone, dstKind));
     if (!dst)
         CrashAtUnhandlableOOM("Failed to allocate object while tenuring.");
 
     trc->tenuredSize += moveObjectToTenured(dst, src, dstKind);
 
     RelocationOverlay *overlay = reinterpret_cast<RelocationOverlay *>(src);
     overlay->forwardTo(dst);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -83,20 +83,20 @@ MarkExactStackRootList(JSTracer *trc, Ro
         rooter = rooter->previous();
     }
 }
 
 static void
 MarkExactStackRoots(JSTracer *trc)
 {
     for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
-        for (ContextIter cx(trc->runtime); !cx.done(); cx.next())
+        for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
             MarkExactStackRootList(trc, cx->thingGCRooters[i], ThingRootKind(i));
 
-        MarkExactStackRootList(trc, trc->runtime->mainThread.thingGCRooters[i], ThingRootKind(i));
+        MarkExactStackRootList(trc, trc->runtime()->mainThread.thingGCRooters[i], ThingRootKind(i));
     }
 }
 #endif /* JSGC_USE_EXACT_ROOTING */
 
 enum ConservativeGCTest
 {
     CGCT_VALID,
     CGCT_LOWBITSET, /* excluded because one of the low bits was set */
@@ -192,17 +192,17 @@ IsAddressableGCThing(JSRuntime *rt, uint
  */
 static inline ConservativeGCTest
 MarkIfGCThingWord(JSTracer *trc, uintptr_t w)
 {
     void *thing;
     ArenaHeader *aheader;
     AllocKind thingKind;
     ConservativeGCTest status =
-        IsAddressableGCThing(trc->runtime, w, IS_GC_MARKING_TRACER(trc),
+        IsAddressableGCThing(trc->runtime(), w, IS_GC_MARKING_TRACER(trc),
                              &thingKind, &aheader, &thing);
     if (status != CGCT_VALID)
         return status;
 
     /*
      * Check if the thing is free. We must use the list of free spans as at
      * this point we no longer have the mark bits from the previous GC run and
      * we must account for newly allocated things.
@@ -210,26 +210,26 @@ MarkIfGCThingWord(JSTracer *trc, uintptr
     if (InFreeList(aheader, thing))
         return CGCT_NOTLIVE;
 
     JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind);
 #ifdef DEBUG
     const char pattern[] = "machine_stack %p";
     char nameBuf[sizeof(pattern) - 2 + sizeof(thing) * 2];
     JS_snprintf(nameBuf, sizeof(nameBuf), pattern, thing);
-    JS_SET_TRACING_NAME(trc, nameBuf);
+    trc->setTracingName(nameBuf);
 #endif
-    JS_SET_TRACING_LOCATION(trc, (void *)w);
+    trc->setTracingLocation((void *)w);
     void *tmp = thing;
     MarkKind(trc, &tmp, traceKind);
     JS_ASSERT(tmp == thing);
 
 #ifdef DEBUG
-    if (trc->runtime->gcIncrementalState == MARK_ROOTS)
-        trc->runtime->mainThread.gcSavedRoots.append(
+    if (trc->runtime()->gcIncrementalState == MARK_ROOTS)
+        trc->runtime()->mainThread.gcSavedRoots.append(
             PerThreadData::SavedGCRoot(thing, traceKind));
 #endif
 
     return CGCT_VALID;
 }
 
 #ifndef JSGC_USE_EXACT_ROOTING
 static void
@@ -281,25 +281,25 @@ MarkRangeConservativelyAndSkipIon(JSTrac
 
     // Mark everything after the most recent Ion activation.
     MarkRangeConservatively(trc, i, end);
 }
 
 static MOZ_NEVER_INLINE void
 MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
 {
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
 
 #ifdef DEBUG
     if (useSavedRoots) {
         for (PerThreadData::SavedGCRoot *root = rt->mainThread.gcSavedRoots.begin();
              root != rt->mainThread.gcSavedRoots.end();
              root++)
         {
-            JS_SET_TRACING_NAME(trc, "cstack");
+            trc->setTracingName("cstack");
             MarkKind(trc, &root->thing, root->kind);
         }
         return;
     }
 
     if (rt->gcIncrementalState == MARK_ROOTS)
         rt->mainThread.gcSavedRoots.clearAndFree();
 #endif
@@ -464,17 +464,17 @@ AutoGCRooter::trace(JSTracer *trc)
         MarkScriptRootRange(trc, vector.length(), vector.begin(), "js::AutoScriptVector.vector");
         return;
       }
 
       case OBJOBJHASHMAP: {
         AutoObjectObjectHashMap::HashMapImpl &map = static_cast<AutoObjectObjectHashMap *>(this)->map;
         for (AutoObjectObjectHashMap::Enum e(map); !e.empty(); e.popFront()) {
             MarkObjectRoot(trc, &e.front().value(), "AutoObjectObjectHashMap value");
-            JS_SET_TRACING_LOCATION(trc, (void *)&e.front().key());
+            trc->setTracingLocation((void *)&e.front().key());
             JSObject *key = e.front().key();
             MarkObjectRoot(trc, &key, "AutoObjectObjectHashMap key");
             if (key != e.front().key())
                 e.rekeyFront(key);
         }
         return;
       }
 
@@ -557,26 +557,26 @@ AutoGCRooter::trace(JSTracer *trc)
     JS_ASSERT(tag_ >= 0);
     if (Value *vp = static_cast<AutoArrayRooter *>(this)->array)
         MarkValueRootRange(trc, tag_, vp, "JS::AutoArrayRooter.array");
 }
 
 /* static */ void
 AutoGCRooter::traceAll(JSTracer *trc)
 {
-    for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
+    for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) {
         for (js::AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down)
             gcr->trace(trc);
     }
 }
 
 /* static */ void
 AutoGCRooter::traceAllWrappers(JSTracer *trc)
 {
-    for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
+    for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) {
         for (js::AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) {
             if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
                 gcr->trace(trc);
         }
     }
 }
 
 void
@@ -640,17 +640,17 @@ struct PersistentRootedMarker
     }
 };
 }
 }
 
 void
 js::gc::MarkPersistentRootedChains(JSTracer *trc)
 {
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
 
     // Mark the PersistentRooted chains of types that may be null.
     PersistentRootedMarker<JSFunction*>::markChainIfNotNull<MarkObjectRoot>(
         trc, rt->functionPersistentRooteds, "PersistentRooted<JSFunction *>");
     PersistentRootedMarker<JSObject*>::markChainIfNotNull<MarkObjectRoot>(
         trc, rt->objectPersistentRooteds, "PersistentRooted<JSObject *>");
     PersistentRootedMarker<JSScript*>::markChainIfNotNull<MarkScriptRoot>(
         trc, rt->scriptPersistentRooteds, "PersistentRooted<JSScript *>");
@@ -662,17 +662,17 @@ js::gc::MarkPersistentRootedChains(JSTra
                                                         "PersistentRooted<jsid>");
     PersistentRootedMarker<Value>::markChain<MarkValueRoot>(trc, rt->valuePersistentRooteds,
                                                             "PersistentRooted<Value>");
 }
 
 void
 js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
 {
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
     JS_ASSERT(trc->callback != GCMarker::GrayCallback);
 
     JS_ASSERT(!rt->mainThread.suppressGC);
 
     if (IS_GC_MARKING_TRACER(trc)) {
         for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
             if (!c->zone()->isCollecting())
                 c->markCrossCompartmentWrappers(trc);
@@ -713,17 +713,17 @@ js::gc::MarkRuntime(JSTracer *trc, bool 
     MarkPersistentRootedChains(trc);
 
     if (rt->scriptAndCountsVector) {
         ScriptAndCountsVector &vec = *rt->scriptAndCountsVector;
         for (size_t i = 0; i < vec.length(); i++)
             MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
     }
 
-    if (!rt->isBeingDestroyed() && !trc->runtime->isHeapMinorCollecting()) {
+    if (!rt->isBeingDestroyed() && !trc->runtime()->isHeapMinorCollecting()) {
         if (!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment()->zone()->isCollecting()) {
             MarkPermanentAtoms(trc);
             MarkAtoms(trc);
 #ifdef JS_ION
             jit::JitRuntime::Mark(trc);
 #endif
         }
     }
@@ -744,17 +744,17 @@ js::gc::MarkRuntime(JSTracer *trc, bool 
                     JS_ASSERT(script == i.get<JSScript>());
                 }
             }
         }
     }
 
     /* We can't use GCCompartmentsIter if we're called from TraceRuntime. */
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
-        if (trc->runtime->isHeapMinorCollecting())
+        if (trc->runtime()->isHeapMinorCollecting())
             c->globalWriteBarriered = false;
 
         if (IS_GC_MARKING_TRACER(trc) && !c->zone()->isCollecting())
             continue;
 
         /* During a GC, these are treated as weak pointers. */
         if (!IS_GC_MARKING_TRACER(trc)) {
             if (c->watchpointMap)
@@ -799,14 +799,14 @@ js::gc::MarkRuntime(JSTracer *trc, bool 
                 (*op)(trc, rt->gcGrayRootTracer.data);
         }
     }
 }
 
 void
 js::gc::BufferGrayRoots(GCMarker *gcmarker)
 {
-    JSRuntime *rt = gcmarker->runtime;
+    JSRuntime *rt = gcmarker->runtime();
     gcmarker->startBufferingGrayRoots();
     if (JSTraceDataOp op = rt->gcGrayRootTracer.op)
         (*op)(gcmarker, rt->gcGrayRootTracer.data);
     gcmarker->endBufferingGrayRoots();
 }
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -21,17 +21,17 @@ using mozilla::ReentrancyGuard;
 
 /*** Edges ***/
 
 void
 StoreBuffer::SlotsEdge::mark(JSTracer *trc)
 {
     JSObject *obj = object();
 
-    if (trc->runtime->gcNursery.isInside(obj))
+    if (trc->runtime()->gcNursery.isInside(obj))
         return;
 
     if (!obj->isNative()) {
         const Class *clasp = obj->getClass();
         if (clasp)
             clasp->trace(trc, obj);
         return;
     }
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -15,18 +15,18 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ReentrancyGuard.h"
 
 #include "jsalloc.h"
 
 #include "ds/LifoAlloc.h"
 #include "gc/Nursery.h"
+#include "gc/Tracer.h"
 #include "js/MemoryMetrics.h"
-#include "js/Tracer.h"
 
 namespace js {
 
 void
 CrashAtUnhandlableOOM(const char *reason);
 
 namespace gc {
 
@@ -56,17 +56,17 @@ class HashKeyRef : public BufferableRef
   public:
     HashKeyRef(Map *m, const Key &k) : map(m), key(k) {}
 
     void mark(JSTracer *trc) {
         Key prior = key;
         typename Map::Ptr p = map->lookup(key);
         if (!p)
             return;
-        JS_SET_TRACING_LOCATION(trc, (void*)&*p);
+        trc->setTracingLocation(&*p);
         Mark(trc, &key, "HashKeyRef");
         map->rekeyIfMoved(prior, key);
     }
 };
 
 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> EdgeSet;
 
 /* The size of a single block of store buffer storage space. */
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -1,15 +1,15 @@
 /* -*- 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 "js/Tracer.h"
+#include "gc/Tracer.h"
 
 #include "jsapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsprf.h"
 #include "jsscript.h"
 #include "NamespaceImports.h"
 
@@ -86,38 +86,32 @@ JS_CallHeapFunctionTracer(JSTracer *trc,
 
 JS_PUBLIC_API(void)
 JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name)
 {
     JSObject *obj = objp->getPtr();
     if (!obj)
         return;
 
-    JS_SET_TRACING_LOCATION(trc, (void*)objp);
+    trc->setTracingLocation((void*)objp);
     MarkObjectUnbarriered(trc, &obj, name);
 
     objp->setPtr(obj);
 }
 
 JS_PUBLIC_API(void)
-JS_TracerInit(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback)
-{
-    InitTracer(trc, rt, callback);
-}
-
-JS_PUBLIC_API(void)
 JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     js::TraceChildren(trc, thing, kind);
 }
 
 JS_PUBLIC_API(void)
 JS_TraceRuntime(JSTracer *trc)
 {
-    AssertHeapIsIdle(trc->runtime);
+    AssertHeapIsIdle(trc->runtime());
     TraceRuntime(trc);
 }
 
 static size_t
 CountDecimalDigits(size_t num)
 {
     size_t numDigits = 0;
     do {
@@ -240,25 +234,95 @@ JS_GetTraceThingInfo(char *buf, size_t b
           case JSTRACE_BASE_SHAPE:
           case JSTRACE_TYPE_OBJECT:
             break;
         }
     }
     buf[bufsize - 1] = '\0';
 }
 
-extern JS_PUBLIC_API(const char *)
-JS_GetTraceEdgeName(JSTracer *trc, char *buffer, int bufferSize)
+JSTracer::JSTracer(JSRuntime *rt, JSTraceCallback traceCallback,
+                   WeakMapTraceKind weakTraceKind /* = TraceWeakMapValues */)
+  : callback(traceCallback)
+  , runtime_(rt)
+  , debugPrinter_(nullptr)
+  , debugPrintArg_(nullptr)
+  , debugPrintIndex_(size_t(-1))
+  , eagerlyTraceWeakMaps_(weakTraceKind)
+#ifdef JS_GC_ZEAL
+  , realLocation_(nullptr)
+#endif
+{
+}
+
+bool
+JSTracer::hasTracingDetails() const
 {
-    if (trc->debugPrinter) {
-        trc->debugPrinter(trc, buffer, bufferSize);
+    return debugPrinter_ || debugPrintArg_;
+}
+
+const char *
+JSTracer::tracingName(const char *fallback) const
+{
+    JS_ASSERT(hasTracingDetails());
+    return debugPrinter_ ? fallback : (const char *)debugPrintArg_;
+}
+
+const char *
+JSTracer::getTracingEdgeName(char *buffer, size_t bufferSize)
+{
+    if (debugPrinter_) {
+        debugPrinter_(this, buffer, bufferSize);
+        return buffer;
+    }
+    if (debugPrintIndex_ != size_t(-1)) {
+        JS_snprintf(buffer, bufferSize, "%s[%lu]",
+                    (const char *)debugPrintArg_,
+                    debugPrintIndex_);
         return buffer;
     }
-    if (trc->debugPrintIndex != (size_t) - 1) {
-        JS_snprintf(buffer, bufferSize, "%s[%lu]",
-                    (const char *)trc->debugPrintArg,
-                    trc->debugPrintIndex);
-        return buffer;
-    }
-    return (const char*)trc->debugPrintArg;
+    return (const char*)debugPrintArg_;
+}
+
+JSTraceNamePrinter
+JSTracer::debugPrinter() const
+{
+    return debugPrinter_;
+}
+
+const void *
+JSTracer::debugPrintArg() const
+{
+    return debugPrintArg_;
+}
+
+size_t
+JSTracer::debugPrintIndex() const
+{
+    return debugPrintIndex_;
 }
 
+void
+JSTracer::setTraceCallback(JSTraceCallback traceCallback)
+{
+    callback = traceCallback;
+}
 
+#ifdef JS_GC_ZEAL
+void
+JSTracer::setTracingLocation(void *location)
+{
+    if (!realLocation_ || !location)
+        realLocation_ = location;
+}
+
+void
+JSTracer::unsetTracingLocation()
+{
+    realLocation_ = nullptr;
+}
+
+void **
+JSTracer::tracingLocation(void **thingp)
+{
+    return realLocation_ ? (void **)realLocation_ : thingp;
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/js/src/gc/Tracer.h
@@ -0,0 +1,12 @@
+/* -*- 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/. */
+
+#ifndef js_Tracer_h
+#define js_Tracer_h
+
+#include "js/TracingAPI.h"
+
+#endif /* js_Tracer_h */
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -54,17 +54,17 @@ using namespace mozilla;
  *   generational pointers we find is a subset of the pointers recorded in our
  *   StoreBuffer.
  */
 
 struct EdgeValue
 {
     void *thing;
     JSGCTraceKind kind;
-    char *label;
+    const char *label;
 };
 
 struct VerifyNode
 {
     void *thing;
     JSGCTraceKind kind;
     uint32_t count;
     EdgeValue edges[1];
@@ -97,46 +97,48 @@ struct VerifyPreTracer : JSTracer
 
     /* This graph represents the initial GC "snapshot". */
     VerifyNode *curnode;
     VerifyNode *root;
     char *edgeptr;
     char *term;
     NodeMap nodemap;
 
-    VerifyPreTracer(JSRuntime *rt) : noggc(rt), root(nullptr) {}
+    VerifyPreTracer(JSRuntime *rt, JSTraceCallback callback)
+      : JSTracer(rt, callback), noggc(rt), number(rt->gcNumber), count(0), root(nullptr)
+    {}
 
     ~VerifyPreTracer() {
         js_free(root);
     }
 };
 
 /*
  * This function builds up the heap snapshot by adding edges to the current
  * node.
  */
 static void
 AccumulateEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
 {
     VerifyPreTracer *trc = (VerifyPreTracer *)jstrc;
 
-    JS_ASSERT(!IsInsideNursery(trc->runtime, *(uintptr_t **)thingp));
+    JS_ASSERT(!IsInsideNursery(trc->runtime(), *(uintptr_t **)thingp));
 
     trc->edgeptr += sizeof(EdgeValue);
     if (trc->edgeptr >= trc->term) {
         trc->edgeptr = trc->term;
         return;
     }
 
     VerifyNode *node = trc->curnode;
     uint32_t i = node->count;
 
     node->edges[i].thing = *thingp;
     node->edges[i].kind = kind;
-    node->edges[i].label = trc->debugPrinter ? nullptr : (char *)trc->debugPrintArg;
+    node->edges[i].label = trc->tracingName("<unknown>");
     node->count++;
 }
 
 static VerifyNode *
 MakeNode(VerifyPreTracer *trc, void *thing, JSGCTraceKind kind)
 {
     NodeMap::AddPtr p = trc->nodemap.lookupForAdd(thing);
     if (!p) {
@@ -186,25 +188,27 @@ gc::StartVerifyPreBarriers(JSRuntime *rt
     AutoPrepareForTracing prep(rt, WithAtoms);
 
     if (!IsIncrementalGCSafe(rt))
         return;
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
 
-    VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt);
+    rt->gcNumber++;
+
+    VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr));
     if (!trc)
         return;
 
-    rt->gcNumber++;
-    trc->number = rt->gcNumber;
-    trc->count = 0;
-
-    JS_TracerInit(trc, rt, AccumulateEdge);
+    /*
+     * Passing a function pointer directly to js_new trips a compiler bug in
+     * MSVC. Work around by filling the pointer after allocating with nullptr.
+     */
+    trc->setTraceCallback(AccumulateEdge);
 
     const size_t size = 64 * 1024 * 1024;
     trc->root = (VerifyNode *)js_malloc(size);
     if (!trc->root)
         goto oom;
     trc->edgeptr = (char *)trc->root;
     trc->term = trc->edgeptr + size;
 
@@ -300,17 +304,17 @@ AssertMarkedOrAllocated(const EdgeValue 
     if (!edge.thing || IsMarkedOrAllocated(static_cast<Cell *>(edge.thing)))
         return;
 
     // Permanent atoms aren't marked during graph traversal.
     if (edge.kind == JSTRACE_STRING && static_cast<JSString *>(edge.thing)->isPermanentAtom())
         return;
 
     char msgbuf[1024];
-    const char *label = edge.label ? edge.label : "<unknown>";
+    const char *label = edge.label;
 
     JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", label);
     MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
     MOZ_CRASH();
 }
 
 void
 gc::EndVerifyPreBarriers(JSRuntime *rt)
@@ -342,17 +346,17 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
      */
     JS_ASSERT(trc->number == rt->gcNumber);
     rt->gcNumber++;
 
     rt->gcVerifyPreData = nullptr;
     rt->gcIncrementalState = NO_INCREMENTAL;
 
     if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
-        JS_TracerInit(trc, rt, CheckEdge);
+        trc->setTraceCallback(CheckEdge);
 
         /* Start after the roots. */
         VerifyNode *node = NextNode(trc->root);
         while ((char *)node < trc->edgeptr) {
             trc->curnode = node;
             JS_TraceChildren(trc, node->thing, node->kind);
 
             if (node->count <= MAX_VERIFIER_EDGES) {
@@ -367,26 +371,31 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
     rt->gcMarker.reset();
     rt->gcMarker.stop();
 
     js_delete(trc);
 }
 
 /*** Post-Barrier Verifyier ***/
 
-struct VerifyPostTracer : JSTracer {
+struct VerifyPostTracer : JSTracer
+{
     /* The gcNumber when the verification began. */
     uint64_t number;
 
     /* This counts up to gcZealFrequency to decide whether to verify. */
     int count;
 
     /* The set of edges in the StoreBuffer at the end of verification. */
     typedef HashSet<void **, PointerHasher<void **, 3>, SystemAllocPolicy> EdgeSet;
     EdgeSet *edges;
+
+    VerifyPostTracer(JSRuntime *rt, JSTraceCallback callback)
+      : JSTracer(rt, callback), number(rt->gcNumber), count(0)
+    {}
 };
 
 /*
  * The post-barrier verifier runs the full store buffer and a fake nursery when
  * running and when it stops, walks the full heap to ensure that all the
  * important edges were inserted into the storebuffer.
  */
 void
@@ -396,48 +405,47 @@ gc::StartVerifyPostBarriers(JSRuntime *r
     if (rt->gcVerifyPostData ||
         rt->gcIncrementalState != NO_INCREMENTAL)
     {
         return;
     }
 
     MinorGC(rt, JS::gcreason::EVICT_NURSERY);
 
-    VerifyPostTracer *trc = js_new<VerifyPostTracer>();
+    rt->gcNumber++;
+
+    VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr));
     if (!trc)
         return;
 
     rt->gcVerifyPostData = trc;
-    rt->gcNumber++;
-    trc->number = rt->gcNumber;
-    trc->count = 0;
 #endif
 }
 
 #ifdef JSGC_GENERATIONAL
 void
 PostVerifierCollectStoreBufferEdges(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
 {
     VerifyPostTracer *trc = (VerifyPostTracer *)jstrc;
 
     /* The nursery only stores objects. */
     if (kind != JSTRACE_OBJECT)
         return;
 
     /* The store buffer may store extra, non-cross-generational edges. */
     JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
-    if (trc->runtime->gcNursery.isInside(thingp) || !trc->runtime->gcNursery.isInside(dst))
+    if (trc->runtime()->gcNursery.isInside(thingp) || !trc->runtime()->gcNursery.isInside(dst))
         return;
 
     /*
      * Values will be unpacked to the stack before getting here. However, the
      * only things that enter this callback are marked by the store buffer. The
      * store buffer ensures that the real tracing location is set correctly.
      */
-    void **loc = trc->realLocation != nullptr ? (void **)trc->realLocation : thingp;
+    void **loc = trc->tracingLocation(thingp);
 
     trc->edges->put(loc);
 }
 
 static void
 AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet *edges, void **loc, JSObject *dst)
 {
     if (edges->has(loc))
@@ -455,51 +463,51 @@ PostVerifierVisitEdge(JSTracer *jstrc, v
 {
     VerifyPostTracer *trc = (VerifyPostTracer *)jstrc;
 
     /* The nursery only stores objects. */
     if (kind != JSTRACE_OBJECT)
         return;
 
     /* Filter out non cross-generational edges. */
-    JS_ASSERT(!trc->runtime->gcNursery.isInside(thingp));
+    JS_ASSERT(!trc->runtime()->gcNursery.isInside(thingp));
     JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
-    if (!trc->runtime->gcNursery.isInside(dst))
+    if (!trc->runtime()->gcNursery.isInside(dst))
         return;
 
     /*
      * Values will be unpacked to the stack before getting here. However, the
      * only things that enter this callback are marked by the JS_TraceChildren
      * below. Since ObjectImpl::markChildren handles this, the real trace
      * location will be set correctly in these cases.
      */
-    void **loc = trc->realLocation != nullptr ? (void **)trc->realLocation : thingp;
+    void **loc = trc->tracingLocation(thingp);
 
     AssertStoreBufferContainsEdge(trc->edges, loc, dst);
 }
 #endif
 
 void
 js::gc::EndVerifyPostBarriers(JSRuntime *rt)
 {
 #ifdef JSGC_GENERATIONAL
     VerifyPostTracer::EdgeSet edges;
     AutoPrepareForTracing prep(rt, SkipAtoms);
 
     VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData;
 
     /* Visit every entry in the store buffer and put the edges in a hash set. */
-    JS_TracerInit(trc, rt, PostVerifierCollectStoreBufferEdges);
+    trc->setTraceCallback(PostVerifierCollectStoreBufferEdges);
     if (!edges.init())
         goto oom;
     trc->edges = &edges;
     rt->gcStoreBuffer.markAll(trc);
 
     /* Walk the heap to find any edges not the the |edges| set. */
-    JS_TracerInit(trc, rt, PostVerifierVisitEdge);
+    trc->setTraceCallback(PostVerifierVisitEdge);
     for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
         for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) {
             for (CellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) {
                 Cell *src = cells.getCell();
                 JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind)));
             }
         }
     }
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -320,17 +320,17 @@ BacktrackingAllocator::groupAndQueueRegi
     }
 
     // Try to group phis with their inputs.
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         LBlock *block = graph.getBlock(i);
         for (size_t j = 0; j < block->numPhis(); j++) {
             LPhi *phi = block->getPhi(j);
             uint32_t output = phi->getDef(0)->virtualRegister();
-            for (size_t k = 0; k < phi->numOperands(); k++) {
+            for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) {
                 uint32_t input = phi->getOperand(k)->toUse()->virtualRegister();
                 if (!tryGroupRegisters(input, output))
                     return false;
             }
         }
     }
 
     // Virtual register number 0 is unused.
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -70,16 +70,20 @@ MethodStatus
 BaselineCompiler::compile()
 {
     IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
             script->filename(), script->lineno(), script.get());
 
     IonSpew(IonSpew_Codegen, "# Emitting baseline code for script %s:%d",
             script->filename(), script->lineno());
 
+    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
+    AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
+    AutoTraceLog logCompile(logger, TraceLogger::BaselineCompilation);
+
     if (!script->ensureHasTypes(cx))
         return Method_Error;
 
     // Only need to analyze scripts which are marked |argumensHasVarBinding|, to
     // compute |needsArgsObj| flag.
     if (script->argumentsHasVarBinding()) {
         if (!script->ensureRanAnalysis(cx))
             return Method_Error;
--- a/js/src/jit/C1Spewer.cpp
+++ b/js/src/jit/C1Spewer.cpp
@@ -16,17 +16,17 @@
 
 using namespace js;
 using namespace js::jit;
 
 bool
 C1Spewer::init(const char *path)
 {
     spewout_ = fopen(path, "w");
-    return (spewout_ != nullptr);
+    return spewout_ != nullptr;
 }
 
 void
 C1Spewer::beginFunction(MIRGraph *graph, HandleScript script)
 {
     if (!spewout_)
         return;
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -560,36 +560,36 @@ FinishAllOffThreadCompilations(JSCompart
         }
     }
 #endif
 }
 
 /* static */ void
 JitRuntime::Mark(JSTracer *trc)
 {
-    JS_ASSERT(!trc->runtime->isHeapMinorCollecting());
-    Zone *zone = trc->runtime->atomsCompartment()->zone();
+    JS_ASSERT(!trc->runtime()->isHeapMinorCollecting());
+    Zone *zone = trc->runtime()->atomsCompartment()->zone();
     for (gc::CellIterUnderGC i(zone, gc::FINALIZE_JITCODE); !i.done(); i.next()) {
         JitCode *code = i.get<JitCode>();
         MarkJitCodeRoot(trc, &code, "wrapper");
     }
 }
 
 void
 JitCompartment::mark(JSTracer *trc, JSCompartment *compartment)
 {
     // Cancel any active or pending off thread compilations. Note that the
     // MIR graph does not hold any nursery pointers, so there's no need to
     // do this for minor GCs.
-    JS_ASSERT(!trc->runtime->isHeapMinorCollecting());
+    JS_ASSERT(!trc->runtime()->isHeapMinorCollecting());
     CancelOffThreadIonCompile(compartment, nullptr);
     FinishAllOffThreadCompilations(compartment);
 
     // Free temporary OSR buffer.
-    trc->runtime->jitRuntime()->freeOsrTempData();
+    trc->runtime()->jitRuntime()->freeOsrTempData();
 
     // Mark scripts with parallel IonScripts if we should preserve them.
     if (activeParallelEntryScripts_) {
         for (ScriptSet::Enum e(*activeParallelEntryScripts_); !e.empty(); e.popFront()) {
             JSScript *script = e.front();
 
             // If the script has since been invalidated or was attached by an
             // off-thread worker too late (i.e., the ForkJoin finished with
@@ -602,17 +602,17 @@ JitCompartment::mark(JSTracer *trc, JSCo
             }
 
             // Check and increment the age. If the script is below the max
             // age, mark it.
             //
             // Subtlety: We depend on the tracing of the parallel IonScript's
             // callTargetEntries to propagate the parallel age to the entire
             // call graph.
-            if (ShouldPreserveParallelJITCode(trc->runtime, script, /* increase = */ true)) {
+            if (ShouldPreserveParallelJITCode(trc->runtime(), script, /* increase = */ true)) {
                 MarkScript(trc, const_cast<EncapsulatedPtrScript *>(&e.front()), "par-script");
                 MOZ_ASSERT(script == e.front());
             }
         }
     }
 }
 
 void
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -170,17 +170,17 @@ IsIonInlinablePC(jsbytecode *pc) {
     // GETPROP, CALLPROP, and LENGTH. (Inlined Getters)
     // SETPROP, SETNAME, SETGNAME (Inlined Setters)
     return IsCallPC(pc) || IsGetPropPC(pc) || IsSetPropPC(pc);
 }
 
 inline bool
 TooManyArguments(unsigned nargs)
 {
-    return (nargs >= SNAPSHOT_MAX_NARGS || nargs > js_JitOptions.maxStackArgs);
+    return nargs >= SNAPSHOT_MAX_NARGS || nargs > js_JitOptions.maxStackArgs;
 }
 
 void ForbidCompilation(JSContext *cx, JSScript *script);
 void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode);
 
 void PurgeCaches(JSScript *script, JS::Zone *zone);
 size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
 void DestroyIonScripts(FreeOp *fop, JSScript *script);
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -916,31 +916,31 @@ UpdateIonJSFrameForMinorGC(JSTracer *trc
     const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
     SafepointReader safepoint(ionScript, si);
 
     GeneralRegisterSet slotsRegs = safepoint.slotsOrElementsSpills();
     uintptr_t *spill = frame.spillBase();
     for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
         --spill;
         if (slotsRegs.has(*iter))
-            trc->runtime->gcNursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
+            trc->runtime()->gcNursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
     }
 
     // Skip to the right place in the safepoint
     uint32_t slot;
     while (safepoint.getGcSlot(&slot));
     while (safepoint.getValueSlot(&slot));
 #ifdef JS_NUNBOX32
     LAllocation type, payload;
     while (safepoint.getNunboxSlot(&type, &payload));
 #endif
 
     while (safepoint.getSlotsOrElementsSlot(&slot)) {
         HeapSlot **slots = reinterpret_cast<HeapSlot **>(layout->slotRef(slot));
-        trc->runtime->gcNursery.forwardBufferPointer(slots);
+        trc->runtime()->gcNursery.forwardBufferPointer(slots);
     }
 }
 #endif
 
 static void
 MarkBaselineStubFrame(JSTracer *trc, const IonFrameIterator &frame)
 {
     // Mark the ICStub pointer stored in the stub frame. This is necessary
@@ -1190,17 +1190,17 @@ MarkJitActivations(JSRuntime *rt, JSTrac
     for (JitActivationIterator activations(rt); !activations.done(); ++activations)
         MarkJitActivation(trc, activations);
 }
 
 #ifdef JSGC_GENERATIONAL
 void
 UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc)
 {
-    JS_ASSERT(trc->runtime->isHeapMinorCollecting());
+    JS_ASSERT(trc->runtime()->isHeapMinorCollecting());
     for (JitActivationIterator activations(rt); !activations.done(); ++activations) {
         for (IonFrameIterator frames(activations); !frames.done(); ++frames) {
             if (frames.type() == JitFrame_IonJS)
                 UpdateIonJSFrameForMinorGC(trc, frames);
         }
     }
 }
 #endif
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -5582,23 +5582,21 @@ class LGuardClass : public LInstructionH
 class MPhi;
 
 // Phi is a pseudo-instruction that emits no code, and is an annotation for the
 // register allocator. Like its equivalent in MIR, phis are collected at the
 // top of blocks and are meant to be executed in parallel, choosing the input
 // corresponding to the predecessor taken in the control flow graph.
 class LPhi MOZ_FINAL : public LInstruction
 {
-    uint32_t numInputs_;
     LAllocation *inputs_;
     LDefinition def_;
 
-    bool init(MIRGenerator *gen);
-
-    LPhi(MPhi *mir);
+    LPhi()
+    { }
 
   public:
     LIR_HEADER(Phi)
 
     static LPhi *New(MIRGenerator *gen, MPhi *phi);
 
     size_t numDefs() const {
         return 1;
@@ -5607,17 +5605,17 @@ class LPhi MOZ_FINAL : public LInstructi
         JS_ASSERT(index == 0);
         return &def_;
     }
     void setDef(size_t index, const LDefinition &def) {
         JS_ASSERT(index == 0);
         def_ = def;
     }
     size_t numOperands() const {
-        return numInputs_;
+        return mir_->toPhi()->numOperands();
     }
     LAllocation *getOperand(size_t index) {
         JS_ASSERT(index < numOperands());
         return &inputs_[index];
     }
     void setOperand(size_t index, const LAllocation &a) {
         JS_ASSERT(index < numOperands());
         inputs_[index] = a;
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -192,34 +192,26 @@ LSnapshot::rewriteRecoveredInput(LUse in
     // Mark any operands to this snapshot with the same value as input as being
     // equal to the instruction's result.
     for (size_t i = 0; i < numEntries(); i++) {
         if (getEntry(i)->isUse() && getEntry(i)->toUse()->virtualRegister() == input.virtualRegister())
             setEntry(i, LUse(input.virtualRegister(), LUse::RECOVERED_INPUT));
     }
 }
 
-bool
-LPhi::init(MIRGenerator *gen)
-{
-    inputs_ = gen->allocate<LAllocation>(numInputs_);
-    return !!inputs_;
-}
-
-LPhi::LPhi(MPhi *mir)
-  : numInputs_(mir->numOperands())
-{
-}
-
 LPhi *
 LPhi::New(MIRGenerator *gen, MPhi *ins)
 {
-    LPhi *phi = new(gen->alloc()) LPhi(ins);
-    if (!phi->init(gen))
+    LPhi *phi = new (gen->alloc()) LPhi();
+    LAllocation *inputs = gen->allocate<LAllocation>(ins->numOperands());
+    if (!inputs)
         return nullptr;
+
+    phi->inputs_ = inputs;
+    phi->setMir(ins);
     return phi;
 }
 
 void
 LInstruction::printName(FILE *fp, Opcode op)
 {
     static const char * const names[] =
     {
@@ -384,17 +376,17 @@ LInstruction::dump(FILE *fp)
         fprintf(fp, " t=(");
         for (size_t i = 0; i < numTemps(); i++) {
             PrintDefinition(fp, *getTemp(i));
             if (i != numTemps() - 1)
                 fprintf(fp, ", ");
         }
         fprintf(fp, ")");
     }
-    fprintf(stderr, "\n");
+    fprintf(fp, "\n");
 }
 
 void
 LInstruction::dump()
 {
     return dump(stderr);
 }
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -489,17 +489,17 @@ LIRGenerator::visitCall(MCall *call)
 
             // Even though this is just a temp reg, use the same API to avoid
             // register collisions.
             mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
             MOZ_ASSERT(ok, "How can we not have four temp registers?");
 
             LCallNative *lir = new(alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
                                                         tempFixed(vpReg), tempFixed(tmpReg));
-            return (defineReturn(lir, call) && assignSafepoint(lir, call));
+            return defineReturn(lir, call) && assignSafepoint(lir, call);
         }
 
         LCallKnown *lir = new(alloc()) LCallKnown(useFixed(call->getFunction(), CallTempReg0),
                                                   tempFixed(CallTempReg2));
         return defineReturn(lir, call) && assignSafepoint(lir, call);
     }
 
     // Call anything, using the most generic code.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -90,26 +90,24 @@ EvaluateConstantOperands(TempAllocator &
         break;
       case MDefinition::Op_BitOr:
         ret = Int32Value(lhs.toInt32() | rhs.toInt32());
         break;
       case MDefinition::Op_BitXor:
         ret = Int32Value(lhs.toInt32() ^ rhs.toInt32());
         break;
       case MDefinition::Op_Lsh:
-        ret = Int32Value(lhs.toInt32() << (rhs.toInt32() & 0x1F));
+        ret = Int32Value(uint32_t(lhs.toInt32()) << (rhs.toInt32() & 0x1F));
         break;
       case MDefinition::Op_Rsh:
         ret = Int32Value(lhs.toInt32() >> (rhs.toInt32() & 0x1F));
         break;
-      case MDefinition::Op_Ursh: {
-        uint32_t unsignedLhs = (uint32_t)lhs.toInt32();
-        ret.setNumber(uint32_t(unsignedLhs >> (rhs.toInt32() & 0x1F)));
+      case MDefinition::Op_Ursh:
+        ret.setNumber(uint32_t(lhs.toInt32()) >> (rhs.toInt32() & 0x1F));
         break;
-      }
       case MDefinition::Op_Add:
         ret.setNumber(lhs.toNumber() + rhs.toNumber());
         break;
       case MDefinition::Op_Sub:
         ret.setNumber(lhs.toNumber() - rhs.toNumber());
         break;
       case MDefinition::Op_Mul:
         ret.setNumber(lhs.toNumber() * rhs.toNumber());
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -24,17 +24,16 @@ using namespace js;
 using namespace js::jit;
 
 using mozilla::Abs;
 using mozilla::CountLeadingZeroes32;
 using mozilla::NumberEqualsInt32;
 using mozilla::ExponentComponent;
 using mozilla::FloorLog2;
 using mozilla::IsInfinite;
-using mozilla::IsFinite;
 using mozilla::IsNaN;
 using mozilla::IsNegative;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 using mozilla::Swap;
 using JS::GenericNaN;
 
 // This algorithm is based on the paper "Eliminating Range Checks Using
@@ -586,18 +585,17 @@ Range::setDouble(double l, double h)
     canHaveFractionalPart_ = crossesZero || minExp < MaxTruncatableExponent;
 
     optimize();
 }
 
 static inline bool
 MissingAnyInt32Bounds(const Range *lhs, const Range *rhs)
 {
-    return !lhs->hasInt32LowerBound() || !lhs->hasInt32UpperBound() ||
-           !rhs->hasInt32LowerBound() || !rhs->hasInt32UpperBound();
+    return !lhs->hasInt32Bounds() || !rhs->hasInt32Bounds();
 }
 
 Range *
 Range::add(TempAllocator &alloc, const Range *lhs, const Range *rhs)
 {
     int64_t l = (int64_t) lhs->lower_ + (int64_t) rhs->lower_;
     if (!lhs->hasInt32LowerBound() || !rhs->hasInt32LowerBound())
         l = NoInt32LowerBound;
@@ -915,17 +913,17 @@ Range *
 Range::abs(TempAllocator &alloc, const Range *op)
 {
     int32_t l = op->lower_;
     int32_t u = op->upper_;
 
     return new(alloc) Range(Max(Max(int32_t(0), l), u == INT32_MIN ? INT32_MAX : -u),
                             true,
                             Max(Max(int32_t(0), u), l == INT32_MIN ? INT32_MAX : -l),
-                            op->hasInt32LowerBound_ && op->hasInt32UpperBound_ && l != INT32_MIN,
+                            op->hasInt32Bounds() && l != INT32_MIN,
                             op->canHaveFractionalPart_,
                             op->max_exponent_);
 }
 
 Range *
 Range::min(TempAllocator &alloc, const Range *lhs, const Range *rhs)
 {
     // If either operand is NaN, the result is NaN.
--- a/js/src/jit/RegisterAllocator.cpp
+++ b/js/src/jit/RegisterAllocator.cpp
@@ -37,17 +37,17 @@ AllocationIntegrityState::record()
             blockInfo.phis.infallibleAppend(InstructionInfo());
             InstructionInfo &info = blockInfo.phis[j];
             LPhi *phi = block->getPhi(j);
             JS_ASSERT(phi->numDefs() == 1);
             uint32_t vreg = phi->getDef(0)->virtualRegister();
             virtualRegisters[vreg] = phi->getDef(0);
             if (!info.outputs.append(*phi->getDef(0)))
                 return false;
-            for (size_t k = 0; k < phi->numOperands(); k++) {
+            for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) {
                 if (!info.inputs.append(*phi->getOperand(k)))
                     return false;
             }
         }
 
         for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
             LInstruction *ins = *iter;
             InstructionInfo &info = instructions[ins->id()];
@@ -227,29 +227,29 @@ AllocationIntegrityState::checkIntegrity
     // Phis are effectless, but change the vreg we are tracking. Check if there
     // is one which produced this vreg. We need to follow back through the phi
     // inputs as it is not guaranteed the register allocator filled in physical
     // allocations for the inputs and outputs of the phis.
     for (size_t i = 0; i < block->numPhis(); i++) {
         const InstructionInfo &info = blocks[block->mir()->id()].phis[i];
         LPhi *phi = block->getPhi(i);
         if (info.outputs[0].virtualRegister() == vreg) {
-            for (size_t j = 0; j < phi->numOperands(); j++) {
+            for (size_t j = 0, jend = phi->numOperands(); j < jend; j++) {
                 uint32_t newvreg = info.inputs[j].toUse()->virtualRegister();
                 LBlock *predecessor = graph.getBlock(block->mir()->getPredecessor(j)->id());
                 if (!addPredecessor(predecessor, newvreg, alloc))
                     return false;
             }
             return true;
         }
     }
 
     // No phi which defined the vreg we are tracking, follow back through all
     // predecessors with the existing vreg.
-    for (size_t i = 0; i < block->mir()->numPredecessors(); i++) {
+    for (size_t i = 0, iend = block->mir()->numPredecessors(); i < iend; i++) {
         LBlock *predecessor = graph.getBlock(block->mir()->getPredecessor(i)->id());
         if (!addPredecessor(predecessor, vreg, alloc))
             return false;
     }
 
     return true;
 }
 
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -358,28 +358,28 @@ InstMovWT::asTHIS(Instruction &i)
 void
 InstMovWT::extractImm(Imm16 *imm)
 {
     *imm = Imm16(*this);
 }
 bool
 InstMovWT::checkImm(Imm16 imm)
 {
-    return (imm.decode() == Imm16(*this).decode());
+    return imm.decode() == Imm16(*this).decode();
 }
 
 void
 InstMovWT::extractDest(Register *dest)
 {
     *dest = toRD(*this);
 }
 bool
 InstMovWT::checkDest(Register dest)
 {
-    return (dest == toRD(*this));
+    return dest == toRD(*this);
 }
 
 bool
 InstMovW::isTHIS(const Instruction &i)
 {
     return (i.encode() & IsWTMask) == IsW;
 }
 
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -360,17 +360,17 @@ MacroAssemblerARM::ma_alu(Register src1,
     // and add{,s} dest, src, 0xff00; add{,s} dest, dest, 0xff is not
     // guaranteed to set the overflow flag the same as the (theoretical)
     // one instruction variant.
     if (alu_dbl(src1, imm, dest, op, sc, c))
         return;
 
     // And try with its negative.
     if (negOp != op_invalid &&
-        alu_dbl(src1, negImm, dest, negOp, sc, c))
+        alu_dbl(src1, negImm, negDest, negOp, sc, c))
         return;
 
     // Well, damn. We can use two 16 bit mov's, then do the op
     // or we can do a single load from a pool then op.
     if (hasMOVWT()) {
         // Try to load the immediate into a scratch register
         // then use that
         as_movw(ScratchRegister, imm.value & 0xffff, c);
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -299,17 +299,17 @@ class CodeGeneratorShared : public LInst
     OutOfLineCode *oolTruncateDouble(const FloatRegister &src, const Register &dest);
     bool emitTruncateDouble(const FloatRegister &src, const Register &dest);
     bool emitTruncateFloat32(const FloatRegister &src, const Register &dest);
 
     void emitPreBarrier(Register base, const LAllocation *index, MIRType type);
     void emitPreBarrier(Address address, MIRType type);
 
     inline bool isNextBlock(LBlock *block) {
-        return (current->mir()->id() + 1 == block->mir()->id());
+        return current->mir()->id() + 1 == block->mir()->id();
     }
 
   public:
     // Save and restore all volatile registers to/from the stack, excluding the
     // specified register(s), before a function call made using callWithABI and
     // after storing the function call's return value to an output register.
     // (The only registers that don't need to be saved/restored are 1) the
     // temporary register used to store the return value of the function call,
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -77,28 +77,26 @@ MacroAssemblerX64::loadConstantFloat32(f
     JmpSrc j = masm.movss_ripr(dest.code());
     JmpSrc prev = JmpSrc(flt.uses.use(j.offset()));
     masm.setNextJump(j, prev);
 }
 
 void
 MacroAssemblerX64::finish()
 {
-    JS_STATIC_ASSERT(CodeAlignment >= sizeof(double));
-
-    if (!doubles_.empty() || !floats_.empty())
+    if (!doubles_.empty())
         masm.align(sizeof(double));
-
     for (size_t i = 0; i < doubles_.length(); i++) {
         Double &dbl = doubles_[i];
         bind(&dbl.uses);
         masm.doubleConstant(dbl.value);
     }
 
-    // No need to align on sizeof(float) as we are aligned on sizeof(double);
+    if (!floats_.empty())
+        masm.align(sizeof(float));
     for (size_t i = 0; i < floats_.length(); i++) {
         Float &flt = floats_[i];
         bind(&flt.uses);
         masm.floatConstant(flt.value);
     }
 
     MacroAssemblerX86Shared::finish();
 }
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -108,27 +108,28 @@ MacroAssemblerX86::addConstantFloat32(fl
         return;
     masm.addss_mr(reinterpret_cast<const void *>(flt->uses.prev()), dest.code());
     flt->uses.setPrev(masm.size());
 }
 
 void
 MacroAssemblerX86::finish()
 {
-    if (doubles_.empty() && floats_.empty())
-        return;
-
-    masm.align(sizeof(double));
+    if (!doubles_.empty())
+        masm.align(sizeof(double));
     for (size_t i = 0; i < doubles_.length(); i++) {
         CodeLabel cl(doubles_[i].uses);
         writeDoubleConstant(doubles_[i].value, cl.src());
         enoughMemory_ &= addCodeLabel(cl);
         if (!enoughMemory_)
             return;
     }
+
+    if (!floats_.empty())
+        masm.align(sizeof(float));
     for (size_t i = 0; i < floats_.length(); i++) {
         CodeLabel cl(floats_[i].uses);
         writeFloatConstant(floats_[i].value, cl.src());
         enoughMemory_ &= addCodeLabel(cl);
         if (!enoughMemory_)
             return;
     }
 }
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -27,17 +27,17 @@
 #include "js/MemoryMetrics.h"
 #include "js/OldDebugAPI.h"
 #include "js/ProfilingStack.h"
 #include "js/PropertyKey.h"
 #include "js/RequiredDefines.h"
 #include "js/RootingAPI.h"
 #include "js/SliceBudget.h"
 #include "js/StructuredClone.h"
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 #include "js/WeakMapPtr.h"
 #include "jsapi-tests/tests.h"
 
 /*
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1640,34 +1640,40 @@ struct JSHeapDumpNode {
     JSHeapDumpNode  *parent;        /* node with the thing that refer to thing
                                        from this node */
     char            edgeName[1];    /* name of the edge from parent->thing
                                        into thing */
 };
 
 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet;
 
-typedef struct JSDumpingTracer {
+class DumpingTracer
+{
+  public:
+    DumpingTracer(JSRuntime *rt, JSTraceCallback callback)
+      : base(rt, callback)
+    {}
+
     JSTracer            base;
     VisitedSet          visited;
     bool                ok;
     void                *startThing;
     void                *thingToFind;
     void                *thingToIgnore;
     JSHeapDumpNode      *parentNode;
     JSHeapDumpNode      **lastNodep;
     char                buffer[200];
-} JSDumpingTracer;
+};
 
 static void
 DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
     JS_ASSERT(trc->callback == DumpNotify);
 
-    JSDumpingTracer *dtrc = (JSDumpingTracer *)trc;
+    DumpingTracer *dtrc = (DumpingTracer *)trc;
     void *thing = *thingp;
 
     if (!dtrc->ok || thing == dtrc->thingToIgnore)
         return;
 
     /*
      * Check if we have already seen thing unless it is thingToFind to include
      * it to the graph each time we reach it and print all live things that
@@ -1689,17 +1695,17 @@ DumpNotify(JSTracer *trc, void **thingp,
         if (p)
             return;
         if (!dtrc->visited.add(p, thing)) {
             dtrc->ok = false;
             return;
         }
     }
 
-    const char *edgeName = JS_GetTraceEdgeName(&dtrc->base, dtrc->buffer, sizeof(dtrc->buffer));
+    const char *edgeName = dtrc->base.getTracingEdgeName(dtrc->buffer, sizeof(dtrc->buffer));
     size_t edgeNameSize = strlen(edgeName) + 1;
     size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize;
     JSHeapDumpNode *node = (JSHeapDumpNode *) js_malloc(bytes);
     if (!node) {
         dtrc->ok = false;
         return;
     }
 
@@ -1711,17 +1717,17 @@ DumpNotify(JSTracer *trc, void **thingp,
 
     JS_ASSERT(!*dtrc->lastNodep);
     *dtrc->lastNodep = node;
     dtrc->lastNodep = &node->next;
 }
 
 /* Dump node and the chain that leads to thing it contains. */
 static bool
-DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
+DumpNode(DumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
 {
     JSHeapDumpNode *prev, *following;
     size_t chainLimit;
     enum { MAX_PARENTS_TO_PRINT = 10 };
 
     JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
                          &dtrc->base, node->thing, node->kind, true);
     if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
@@ -1781,20 +1787,19 @@ DumpNode(JSDumpingTracer *dtrc, FILE* fp
 
 JS_PUBLIC_API(bool)
 JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind startKind,
             void *thingToFind, size_t maxDepth, void *thingToIgnore)
 {
     if (maxDepth == 0)
         return true;
 
-    JSDumpingTracer dtrc;
+    DumpingTracer dtrc(rt, DumpNotify);
     if (!dtrc.visited.init())
         return false;
-    JS_TracerInit(&dtrc.base, rt, DumpNotify);
     dtrc.ok = true;
     dtrc.startThing = startThing;
     dtrc.thingToFind = thingToFind;
     dtrc.thingToIgnore = thingToIgnore;
     dtrc.parentNode = nullptr;
     JSHeapDumpNode *node = nullptr;
     dtrc.lastNodep = &node;
     if (!startThing) {
@@ -4336,16 +4341,18 @@ JS::ReadOnlyCompileOptions::copyPODOptio
     forEval = rhs.forEval;
     noScriptRval = rhs.noScriptRval;
     selfHostingMode = rhs.selfHostingMode;
     canLazilyParse = rhs.canLazilyParse;
     strictOption = rhs.strictOption;
     extraWarningsOption = rhs.extraWarningsOption;
     werrorOption = rhs.werrorOption;
     asmJSOption = rhs.asmJSOption;
+    forceAsync = rhs.forceAsync;
+    installedFile = rhs.installedFile;
     sourcePolicy = rhs.sourcePolicy;
     introductionType = rhs.introductionType;
     introductionLineno = rhs.introductionLineno;
     introductionOffset = rhs.introductionOffset;
     hasIntroductionInfo = rhs.hasIntroductionInfo;
 }
 
 JSPrincipals *
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -22,24 +22,23 @@
 #include "jspubtd.h"
 
 #include "js/CallArgs.h"
 #include "js/Class.h"
 #include "js/HashTable.h"
 #include "js/Id.h"
 #include "js/Principals.h"
 #include "js/RootingAPI.h"
+#include "js/TracingAPI.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 
 /************************************************************************/
 
-struct JSTracer;
-
 namespace JS {
 
 class Latin1CharsZ;
 class TwoByteChars;
 
 #if defined JS_THREADSAFE && defined JS_DEBUG
 
 class JS_PUBLIC_API(AutoCheckRequestDepth)
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -184,34 +184,34 @@ JSRuntime::finishAtoms()
     commonNames = nullptr;
     permanentAtoms = nullptr;
     emptyString = nullptr;
 }
 
 void
 js::MarkAtoms(JSTracer *trc)
 {
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
     for (AtomSet::Enum e(rt->atoms()); !e.empty(); e.popFront()) {
         const AtomStateEntry &entry = e.front();
         if (!entry.isTagged())
             continue;
 
         JSAtom *atom = entry.asPtr();
         bool tagged = entry.isTagged();
         MarkStringRoot(trc, &atom, "interned_atom");
         if (entry.asPtr() != atom)
             e.rekeyFront(AtomHasher::Lookup(atom), AtomStateEntry(atom, tagged));
     }
 }
 
 void
 js::MarkPermanentAtoms(JSTracer *trc)
 {
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
 
     // Permanent atoms only need to be marked in the runtime which owns them.
     if (rt->parentRuntime)
         return;
 
     // Static strings are not included in the permanent atoms table.
     if (rt->staticStrings)
         rt->staticStrings->trace(trc);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -523,17 +523,17 @@ JSCompartment::trace(JSTracer *trc)
 {
     // At the moment, this is merely ceremonial, but any live-compartment-only tracing should go
     // here.
 }
 
 void
 JSCompartment::markRoots(JSTracer *trc)
 {
-    JS_ASSERT(!trc->runtime->isHeapMinorCollecting());
+    JS_ASSERT(!trc->runtime()->isHeapMinorCollecting());
 
 #ifdef JS_ION
     if (jitCompartment_)
         jitCompartment_->mark(trc, this);
 #endif
 
     /*
      * If a compartment is on-stack, we mark its global so that
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -655,17 +655,17 @@ digits(size_t *result, const jschar *s, 
     size_t init = *i;
     *result = 0;
     while (*i < limit &&
            ('0' <= s[*i] && s[*i] <= '9')) {
         *result *= 10;
         *result += (s[*i] - '0');
         ++(*i);
     }
-    return (*i != init);
+    return *i != init;
 }
 
 /*
  * Read and convert decimal digits to the right of a decimal point,
  * representing a fractional integer, from s[*i] into *result
  * while *i < limit.
  *
  * Succeed if any digits are converted. Advance *i only
@@ -678,33 +678,33 @@ fractional(double *result, const jschar 
     size_t init = *i;
     *result = 0.0;
     while (*i < limit &&
            ('0' <= s[*i] && s[*i] <= '9')) {
         *result += (s[*i] - '0') * factor;
         factor *= 0.1;
         ++(*i);
     }
-    return (*i != init);
+    return *i != init;
 }
 
 /*
  * Read and convert exactly n decimal digits from s[*i]
  * to s[min(*i+n,limit)] into *result.
  *
  * Succeed if exactly n digits are converted. Advance *i only
  * on success.
  */
 static bool
 ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
 {
     size_t init = *i;
 
     if (digits(result, s, i, Min(limit, init+n)))
-        return ((*i - init) == n);
+        return (*i - init) == n;
 
     *i = init;
     return false;
 }
 
 static int
 DaysInMonth(int year, int month)
 {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -715,116 +715,114 @@ js_DumpObject(JSObject *obj)
         fprintf(stderr, "NULL\n");
         return;
     }
     obj->dump();
 }
 
 #endif
 
-struct JSDumpHeapTracer : public JSTracer
+struct DumpHeapTracer : public JSTracer
 {
     FILE   *output;
 
-    JSDumpHeapTracer(FILE *fp)
-      : output(fp)
+    DumpHeapTracer(FILE *fp, JSRuntime *rt, JSTraceCallback callback,
+                   WeakMapTraceKind weakTraceKind)
+      : JSTracer(rt, callback, weakTraceKind), output(fp)
     {}
 };
 
 static char
 MarkDescriptor(void *thing)
 {
     gc::Cell *cell = static_cast<gc::Cell*>(thing);
     if (cell->isMarked(gc::BLACK))
         return cell->isMarked(gc::GRAY) ? 'G' : 'B';
     else
         return cell->isMarked(gc::GRAY) ? 'X' : 'W';
 }
 
 static void
 DumpHeapVisitZone(JSRuntime *rt, void *data, Zone *zone)
 {
-    JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
+    DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
     fprintf(dtrc->output, "# zone %p\n", (void *)zone);
 }
 
 static void
 DumpHeapVisitCompartment(JSRuntime *rt, void *data, JSCompartment *comp)
 {
     char name[1024];
     if (rt->compartmentNameCallback)
         (*rt->compartmentNameCallback)(rt, comp, name, sizeof(name));
     else
         strcpy(name, "<unknown>");
 
-    JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
+    DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
     fprintf(dtrc->output, "# compartment %s [in zone %p]\n", name, (void *)comp->zone());
 }
 
 static void
 DumpHeapVisitArena(JSRuntime *rt, void *data, gc::Arena *arena,
                    JSGCTraceKind traceKind, size_t thingSize)
 {
-    JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
+    DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
     fprintf(dtrc->output, "# arena allockind=%u size=%u\n",
             unsigned(arena->aheader.getAllocKind()), unsigned(thingSize));
 }
 
 static void
 DumpHeapVisitCell(JSRuntime *rt, void *data, void *thing,
                   JSGCTraceKind traceKind, size_t thingSize)
 {
-    JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
+    DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
     char cellDesc[1024 * 32];
     JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true);
     fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc);
     JS_TraceChildren(dtrc, thing, traceKind);
 }
 
 static void
 DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
-    if (gc::IsInsideNursery(trc->runtime, *thingp))
+    if (gc::IsInsideNursery(trc->runtime(), *thingp))
         return;
 
-    JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
+    DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc);
     char buffer[1024];
     fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp),
-            JS_GetTraceEdgeName(dtrc, buffer, sizeof(buffer)));
+            dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
 }
 
 static void
 DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
-    if (gc::IsInsideNursery(trc->runtime, *thingp))
+    if (gc::IsInsideNursery(trc->runtime(), *thingp))
         return;
 
-    JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
+    DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc);
     char buffer[1024];
     fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp),
-            JS_GetTraceEdgeName(dtrc, buffer, sizeof(buffer)));
+            dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
 }
 
 void
 js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour)
 {
-    JSDumpHeapTracer dtrc(fp);
-
 #ifdef JSGC_GENERATIONAL
     if (nurseryBehaviour == js::CollectNurseryBeforeDump)
         MinorGC(rt, JS::gcreason::API);
 #endif
 
-    JS_TracerInit(&dtrc, rt, DumpHeapVisitRoot);
-    dtrc.eagerlyTraceWeakMaps = TraceWeakMapKeysValues;
+    DumpHeapTracer dtrc(fp, rt, DumpHeapVisitRoot, TraceWeakMapKeysValues);
     TraceRuntime(&dtrc);
 
     fprintf(dtrc.output, "==========\n");
 
-    JS_TracerInit(&dtrc, rt, DumpHeapVisitChild);
+    dtrc.setTraceCallback(DumpHeapVisitChild);
     IterateZonesCompartmentsArenasCells(rt, &dtrc,
                                         DumpHeapVisitZone,
                                         DumpHeapVisitCompartment,
                                         DumpHeapVisitArena,
                                         DumpHeapVisitCell);
 
     fflush(dtrc.output);
 }
@@ -913,17 +911,17 @@ JS_FRIEND_API(bool)
 JS::IsIncrementalGCEnabled(JSRuntime *rt)
 {
     return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL;
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalGCInProgress(JSRuntime *rt)
 {
-    return (rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData);
+    return rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData;
 }
 
 JS_FRIEND_API(void)
 JS::DisableIncrementalGC(JSRuntime *rt)
 {
     rt->gcIncrementalEnabled = false;
 }
 
@@ -967,17 +965,17 @@ extern JS_FRIEND_API(bool)
 JS::IsGenerationalGCEnabled(JSRuntime *rt)
 {
     return rt->gcGenerationalDisabled == 0;
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalBarrierNeeded(JSRuntime *rt)
 {
-    return (rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy());
+    return rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy();
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalBarrierNeeded(JSContext *cx)
 {
     return IsIncrementalBarrierNeeded(cx->runtime());
 }
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1802,30 +1802,16 @@ template void *
 ArenaLists::refillFreeList<CanGC>(ThreadSafeContext *cx, AllocKind thingKind);
 
 JSGCTraceKind
 js_GetGCThingTraceKind(void *thing)
 {
     return GetGCThingTraceKind(thing);
 }
 
-void
-js::InitTracer(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback)
-{
-    trc->runtime = rt;
-    trc->callback = callback;
-    trc->debugPrinter = nullptr;
-    trc->debugPrintArg = nullptr;
-    trc->debugPrintIndex = size_t(-1);
-    trc->eagerlyTraceWeakMaps = TraceWeakMapValues;
-#ifdef JS_GC_ZEAL
-    trc->realLocation = nullptr;
-#endif
-}
-
 /* static */ int64_t
 SliceBudget::TimeBudget(int64_t millis)
 {
     return millis * PRMJ_USEC_PER_MSEC;
 }
 
 /* static */ int64_t
 SliceBudget::WorkBudget(int64_t work)
@@ -1858,25 +1844,29 @@ bool
 SliceBudget::checkOverBudget()
 {
     bool over = PRMJ_Now() > deadline;
     if (!over)
         counter = CounterReset;
     return over;
 }
 
+/*
+ * DoNotTraceWeakMaps: the GC is recomputing the liveness of WeakMap entries,
+ * so we delay visting entries.
+ */
 GCMarker::GCMarker(JSRuntime *rt)
-  : stack(size_t(-1)),
+  : JSTracer(rt, nullptr, DoNotTraceWeakMaps),
+    stack(size_t(-1)),
     color(BLACK),
     started(false),
     unmarkedArenaStackTop(nullptr),
     markLaterArenas(0),
     grayBufferState(GRAY_BUFFER_UNUSED)
 {
-    InitTracer(this, rt, nullptr);
 }
 
 bool
 GCMarker::init(JSGCMode gcMode)
 {
     return stack.init(gcMode);
 }
 
@@ -1885,21 +1875,16 @@ GCMarker::start()
 {
     JS_ASSERT(!started);
     started = true;
     color = BLACK;
 
     JS_ASSERT(!unmarkedArenaStackTop);
     JS_ASSERT(markLaterArenas == 0);
 
-    /*
-     * The GC is recomputing the liveness of WeakMap entries, so we delay
-     * visting entries.
-     */
-    eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
 }
 
 void
 GCMarker::stop()
 {
     JS_ASSERT(isDrained());
 
     JS_ASSERT(started);
@@ -1996,18 +1981,18 @@ GCMarker::markDelayedChildren(ArenaHeade
      * allocatedDuringIncremental flag if we continue marking.
      */
 }
 
 bool
 GCMarker::markDelayedChildren(SliceBudget &budget)
 {
     gcstats::MaybeAutoPhase ap;
-    if (runtime->gcIncrementalState == MARK)
-        ap.construct(runtime->gcStats, gcstats::PHASE_MARK_DELAYED);
+    if (runtime()->gcIncrementalState == MARK)
+        ap.construct(runtime()->gcStats, gcstats::PHASE_MARK_DELAYED);
 
     JS_ASSERT(unmarkedArenaStackTop);
     do {
         /*
          * If marking gets delayed at the same arena again, we must repeat
          * marking of its things. For that we pop arena from the stack and
          * clear its hasDelayedMarking flag before we begin the marking.
          */
@@ -2044,17 +2029,17 @@ GCMarker::hasBufferedGrayRoots() const
     return grayBufferState == GRAY_BUFFER_OK;
 }
 
 void
 GCMarker::startBufferingGrayRoots()
 {
     JS_ASSERT(grayBufferState == GRAY_BUFFER_UNUSED);
     grayBufferState = GRAY_BUFFER_OK;
-    for (GCZonesIter zone(runtime); !zone.done(); zone.next())
+    for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
         JS_ASSERT(zone->gcGrayRoots.empty());
 
     JS_ASSERT(!callback);
     callback = GrayCallback;
     JS_ASSERT(IS_GC_MARKING_TRACER(this));
 }
 
 void
@@ -2065,52 +2050,50 @@ GCMarker::endBufferingGrayRoots()
     JS_ASSERT(IS_GC_MARKING_TRACER(this));
     JS_ASSERT(grayBufferState == GRAY_BUFFER_OK ||
               grayBufferState == GRAY_BUFFER_FAILED);
 }
 
 void
 GCMarker::resetBufferedGrayRoots()
 {
-    for (GCZonesIter zone(runtime); !zone.done(); zone.next())
+    for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
         zone->gcGrayRoots.clearAndFree();
 }
 
 void
 GCMarker::markBufferedGrayRoots(JS::Zone *zone)
 {
     JS_ASSERT(grayBufferState == GRAY_BUFFER_OK);
     JS_ASSERT(zone->isGCMarkingGray());
 
     for (GrayRoot *elem = zone->gcGrayRoots.begin(); elem != zone->gcGrayRoots.end(); elem++) {
 #ifdef DEBUG
-        debugPrinter = elem->debugPrinter;
-        debugPrintArg = elem->debugPrintArg;
-        debugPrintIndex = elem->debugPrintIndex;
+        setTracingDetails(elem->debugPrinter, elem->debugPrintArg, elem->debugPrintIndex);
 #endif
         void *tmp = elem->thing;
-        JS_SET_TRACING_LOCATION(this, (void *)&elem->thing);
+        setTracingLocation((void *)&elem->thing);
         MarkKind(this, &tmp, elem->kind);
         JS_ASSERT(tmp == elem->thing);
     }
 }
 
 void
 GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind)
 {
     JS_ASSERT(started);
 
     if (grayBufferState == GRAY_BUFFER_FAILED)
         return;
 
     GrayRoot root(thing, kind);
 #ifdef DEBUG
-    root.debugPrinter = debugPrinter;
-    root.debugPrintArg = debugPrintArg;
-    root.debugPrintIndex = debugPrintIndex;
+    root.debugPrinter = debugPrinter();
+    root.debugPrintArg = debugPrintArg();
+    root.debugPrintIndex = debugPrintIndex();
 #endif
 
     Zone *zone = static_cast<Cell *>(thing)->tenuredZone();
     if (zone->isCollecting()) {
         zone->maybeAlive = true;
         if (!zone->gcGrayRoots.append(root)) {
             resetBufferedGrayRoots();
             grayBufferState = GRAY_BUFFER_FAILED;
@@ -2126,17 +2109,17 @@ GCMarker::GrayCallback(JSTracer *trc, vo
     GCMarker *gcmarker = static_cast<GCMarker *>(trc);
     gcmarker->appendGrayRoot(*thingp, kind);
 }
 
 size_t
 GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
     size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
-    for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next())
+    for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
         size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
     return size;
 }
 
 void
 js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
 {
     JS_ASSERT(!rt->isHeapBusy());
@@ -2898,18 +2881,23 @@ ShouldPreserveJITCode(JSCompartment *com
         return true;
     if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime)
         return true;
 
     return false;
 }
 
 #ifdef DEBUG
-struct CompartmentCheckTracer : public JSTracer
-{
+class CompartmentCheckTracer : public JSTracer
+{
+  public:
+    CompartmentCheckTracer(JSRuntime *rt, JSTraceCallback callback)
+      : JSTracer(rt, callback)
+    {}
+
     Cell *src;
     JSGCTraceKind srcKind;
     Zone *zone;
     JSCompartment *compartment;
 };
 
 static bool
 InCrossCompartmentMap(JSObject *src, Cell *dst, JSGCTraceKind dstKind)
@@ -2936,17 +2924,17 @@ InCrossCompartmentMap(JSObject *src, Cel
     return false;
 }
 
 static void
 CheckCompartment(CompartmentCheckTracer *trc, JSCompartment *thingCompartment,
                  Cell *thing, JSGCTraceKind kind)
 {
     JS_ASSERT(thingCompartment == trc->compartment ||
-              trc->runtime->isAtomsCompartment(thingCompartment) ||
+              trc->runtime()->isAtomsCompartment(thingCompartment) ||
               (trc->srcKind == JSTRACE_OBJECT &&
                InCrossCompartmentMap((JSObject *)trc->src, thing, kind)));
 }
 
 static JSCompartment *
 CompartmentOfCell(Cell *thing, JSGCTraceKind kind)
 {
     if (kind == JSTRACE_OBJECT)
@@ -2967,29 +2955,27 @@ CheckCompartmentCallback(JSTracer *trcAr
     CompartmentCheckTracer *trc = static_cast<CompartmentCheckTracer *>(trcArg);
     Cell *thing = (Cell *)*thingp;
 
     JSCompartment *comp = CompartmentOfCell(thing, kind);
     if (comp && trc->compartment) {
         CheckCompartment(trc, comp, thing, kind);
     } else {
         JS_ASSERT(thing->tenuredZone() == trc->zone ||
-                  trc->runtime->isAtomsZone(thing->tenuredZone()));
+                  trc->runtime()->isAtomsZone(thing->tenuredZone()));
     }
 }
 
 static void
 CheckForCompartmentMismatches(JSRuntime *rt)
 {
     if (rt->gcDisableStrictProxyCheckingCount)
         return;
 
-    CompartmentCheckTracer trc;
-    JS_TracerInit(&trc, rt, CheckCompartmentCallback);
-
+    CompartmentCheckTracer trc(rt, CheckCompartmentCallback);
     for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
         trc.zone = zone;
         for (size_t thingKind = 0; thingKind < FINALIZE_LAST; thingKind++) {
             for (CellIterUnderGC i(zone, AllocKind(thingKind)); !i.done(); i.next()) {
                 trc.src = i.getCell();
                 trc.srcKind = MapAllocToTraceKind(AllocKind(thingKind));
                 trc.compartment = CompartmentOfCell(trc.src, trc.srcKind);
                 JS_TraceChildren(&trc, trc.src, trc.srcKind);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -10,19 +10,19 @@
 #define jsgc_h
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "jslock.h"
 #include "jsobj.h"
 
+#include "gc/Tracer.h"
 #include "js/GCAPI.h"
 #include "js/SliceBudget.h"
-#include "js/Tracer.h"
 #include "js/Vector.h"
 
 class JSAtom;
 struct JSCompartment;
 class JSFlatString;
 class JSLinearString;
 
 namespace js {
@@ -771,19 +771,16 @@ extern void
 NotifyGCNukeWrapper(JSObject *o);
 
 extern unsigned
 NotifyGCPreSwap(JSObject *a, JSObject *b);
 
 extern void
 NotifyGCPostSwap(JSObject *a, JSObject *b, unsigned preResult);
 
-void
-InitTracer(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback);
-
 /*
  * Helper that implements sweeping and allocation for kinds that can be swept
  * and allocated off the main thread.
  *
  * In non-threadsafe builds, all actual sweeping and allocation is performed
  * on the main thread, but GCHelperThread encapsulates this from clients as
  * much as possible.
  */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3789,17 +3789,17 @@ class NewTypeObjectsSetRef : public Buff
 
   public:
     NewTypeObjectsSetRef(TypeObjectWithNewScriptSet *s, const Class *clasp, JSObject *proto, JSFunction *newFunction)
         : set(s), clasp(clasp), proto(proto), newFunction(newFunction)
     {}
 
     void mark(JSTracer *trc) {
         JSObject *prior = proto;
-        JS_SET_TRACING_LOCATION(trc, (void*)&*prior);
+        trc->setTracingLocation(&*prior);
         Mark(trc, &proto, "newTypeObjects set prototype");
         if (prior == proto)
             return;
 
         TypeObjectWithNewScriptSet::Ptr p = set->lookup(TypeObjectWithNewScriptSet::Lookup(clasp, prior, proto, newFunction));
         JS_ASSERT(p);  // newTypeObjects set must still contain original entry.
 
         set->rekeyAs(TypeObjectWithNewScriptSet::Lookup(clasp, prior, proto, newFunction),
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -63,17 +63,17 @@ class MathCache
      */
     double lookup(UnaryFunType f, double x) {
         unsigned index = hash(x);
         Entry &e = table[index];
         if (e.in == x && e.f == f)
             return e.out;
         e.in = x;
         e.f = f;
-        return (e.out = f(x));
+        return e.out = f(x);
     }
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 } /* namespace js */
 
 /*
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -5544,20 +5544,20 @@ js::ToObjectSlow(JSContext *cx, HandleVa
     }
 
     return PrimitiveToObject(cx, val);
 }
 
 void
 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
 {
-    JS_ASSERT(trc->debugPrinter == js_GetObjectSlotName);
-
-    JSObject *obj = (JSObject *)trc->debugPrintArg;
-    uint32_t slot = uint32_t(trc->debugPrintIndex);
+    JS_ASSERT(trc->debugPrinter() == js_GetObjectSlotName);
+
+    JSObject *obj = (JSObject *)trc->debugPrintArg();
+    uint32_t slot = uint32_t(trc->debugPrintIndex());
 
     Shape *shape;
     if (obj->isNative()) {
         shape = obj->lastProperty();
         while (shape && (!shape->hasSlot() || shape->slot() != slot))
             shape = shape->previous();
     } else {
         shape = nullptr;
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1927,17 +1927,17 @@ js::CallResultEscapes(jsbytecode *pc)
         return true;
 
     if (*pc == JSOP_POP)
         return false;
 
     if (*pc == JSOP_NOT)
         pc += JSOP_NOT_LENGTH;
 
-    return (*pc != JSOP_IFEQ);
+    return *pc != JSOP_IFEQ;
 }
 
 extern bool
 js::IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset)
 {
     // This could be faster (by following jump instructions if the target is <= offset).
     for (BytecodeRange r(cx, script); !r.empty(); r.popFront()) {
         size_t here = r.frontOffset();
--- a/js/src/jsopcodeinlines.h
+++ b/js/src/jsopcodeinlines.h
@@ -28,29 +28,29 @@ GetDefCount(JSScript *script, unsigned o
         return 1;
       case JSOP_PICK:
         /*
          * Pick pops and pushes how deep it looks in the stack + 1
          * items. i.e. if the stack were |a b[2] c[1] d[0]|, pick 2
          * would pop b, c, and d to rearrange the stack to |a c[0]
          * d[1] b[2]|.
          */
-        return (pc[1] + 1);
+        return pc[1] + 1;
       default:
         return StackDefs(script, pc);
     }
 }
 
 static inline unsigned
 GetUseCount(JSScript *script, unsigned offset)
 {
     jsbytecode *pc = script->offsetToPC(offset);
 
     if (JSOp(*pc) == JSOP_PICK)
-        return (pc[1] + 1);
+        return pc[1] + 1;
     if (js_CodeSpec[*pc].nuses == -1)
         return StackUses(script, pc);
     return js_CodeSpec[*pc].nuses;
 }
 
 static inline JSOp
 ReverseCompareOp(JSOp op)
 {
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -3009,17 +3009,17 @@ js::proxy_Trace(JSTracer *trc, JSObject 
 }
 
 /* static */ void
 ProxyObject::trace(JSTracer *trc, JSObject *obj)
 {
     ProxyObject *proxy = &obj->as<ProxyObject>();
 
 #ifdef DEBUG
-    if (!trc->runtime->gcDisableStrictProxyCheckingCount && proxy->is<WrapperObject>()) {
+    if (!trc->runtime()->gcDisableStrictProxyCheckingCount && proxy->is<WrapperObject>()) {
         JSObject *referent = &proxy->private_().toObject();
         if (referent->compartment() != proxy->compartment()) {
             /*
              * Assert that this proxy is tracked in the wrapper map. We maintain
              * the invariant that the wrapped object is the key in the wrapper map.
              */
             Value key = ObjectValue(*referent);
             WrapperMap::Ptr p = proxy->compartment()->lookupWrapper(key);
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -130,19 +130,19 @@ struct JSPrincipals;
 struct JSPropertyDescriptor;
 struct JSPropertyName;
 struct JSPropertySpec;
 struct JSRuntime;
 struct JSSecurityCallbacks;
 struct JSStructuredCloneCallbacks;
 struct JSStructuredCloneReader;
 struct JSStructuredCloneWriter;
-struct JSTracer;
+class JS_PUBLIC_API(JSTracer);
 
-class                                       JSFlatString;
+class JSFlatString;
 
 #ifdef JS_THREADSAFE
 typedef struct PRCallOnceType   JSCallOnceType;
 #else
 typedef bool                    JSCallOnceType;
 #endif
 typedef bool                    (*JSInitCallback)(void);
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3293,17 +3293,17 @@ JSScript::clearTraps(FreeOp *fop)
 void
 JSScript::markChildren(JSTracer *trc)
 {
     // NOTE: this JSScript may be partially initialized at this point.  E.g. we
     // may have created it and partially initialized it with
     // JSScript::Create(), but not yet finished initializing it with
     // fullyInitFromEmitter() or fullyInitTrivial().
 
-    JS_ASSERT_IF(trc->runtime->gcStrictCompartmentChecking, zone()->isCollecting());
+    JS_ASSERT_IF(trc->runtime()->gcStrictCompartmentChecking, zone()->isCollecting());
 
     for (uint32_t i = 0; i < natoms(); ++i) {
         if (atoms[i])
             MarkString(trc, &atoms[i], "atom");
     }
 
     if (hasObjects()) {
         ObjectArray *objarray = objects();
@@ -3333,17 +3333,17 @@ JSScript::markChildren(JSTracer *trc)
 
     if (maybeLazyScript())
         MarkLazyScriptUnbarriered(trc, &lazyScript, "lazyScript");
 
     if (IS_GC_MARKING_TRACER(trc)) {
         compartment()->mark();
 
         if (code())
-            MarkScriptData(trc->runtime, code());
+            MarkScriptData(trc->runtime(), code());
     }
 
     bindings.trace(trc);
 
     if (hasAnyBreakpointsOrStepMode()) {
         for (unsigned i = 0; i < length(); i++) {
             BreakpointSite *site = debugScript()->breakpoints[i];
             if (site && site->trapHandler)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1375,17 +1375,17 @@ class JSScript : public js::gc::Barriere
     size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
 
     uint32_t numNotes();  /* Number of srcnote slots in the srcnotes section */
 
     /* Script notes are allocated right after the code. */
     jssrcnote *notes() { return (jssrcnote *)(code() + length()); }
 
     bool hasArray(ArrayKind kind) {
-        return (hasArrayBits & (1 << kind));
+        return hasArrayBits & (1 << kind);
     }
     void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
     void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; }
 
     bool hasConsts()        { return hasArray(CONSTS);      }
     bool hasObjects()       { return hasArray(OBJECTS);     }
     bool hasRegexps()       { return hasArray(REGEXPS);     }
     bool hasTrynotes()      { return hasArray(TRYNOTES);    }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3169,17 +3169,17 @@ class SplitMatchResult {
     size_t length_;
 
   public:
     void setFailure() {
         JS_STATIC_ASSERT(SIZE_MAX > JSString::MAX_LENGTH);
         endIndex_ = SIZE_MAX;
     }
     bool isFailure() const {
-        return (endIndex_ == SIZE_MAX);
+        return endIndex_ == SIZE_MAX;
     }
     size_t endIndex() const {
         JS_ASSERT(!isFailure());
         return endIndex_;
     }
     size_t length() const {
         JS_ASSERT(!isFailure());
         return length_;
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -43,34 +43,34 @@ class WeakMapBase {
     virtual ~WeakMapBase();
 
     void trace(JSTracer *tracer) {
         if (IS_GC_MARKING_TRACER(tracer)) {
             // We don't do anything with a WeakMap at trace time. Rather, we wait until as
             // many keys as possible have been marked, and add ourselves to the list of
             // known-live WeakMaps to be scanned in the iterative marking phase, by
             // markAllIteratively.
-            JS_ASSERT(tracer->eagerlyTraceWeakMaps == DoNotTraceWeakMaps);
+            JS_ASSERT(tracer->eagerlyTraceWeakMaps() == DoNotTraceWeakMaps);
 
             // Add ourselves to the list if we are not already in the list. We can already
             // be in the list if the weak map is marked more than once due delayed marking.
             if (next == WeakMapNotInList) {
                 next = compartment->gcWeakMapList;
                 compartment->gcWeakMapList = this;
             }
         } else {
             // If we're not actually doing garbage collection, the keys won't be marked
             // nicely as needed by the true ephemeral marking algorithm --- custom tracers
             // such as the cycle collector must use their own means for cycle detection.
             // So here we do a conservative approximation: pretend all keys are live.
-            if (tracer->eagerlyTraceWeakMaps == DoNotTraceWeakMaps)
+            if (tracer->eagerlyTraceWeakMaps() == DoNotTraceWeakMaps)
                 return;
 
             nonMarkingTraceValues(tracer);
-            if (tracer->eagerlyTraceWeakMaps == TraceWeakMapKeysValues)
+            if (tracer->eagerlyTraceWeakMaps() == TraceWeakMapKeysValues)
                 nonMarkingTraceKeys(tracer);
         }
     }
 
     // Garbage collector entry points.
 
     // Check all weak maps in a compartment that have been marked as live in this garbage
     // collection, and mark the values of all entries that have become strong references
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -530,17 +530,17 @@ GlobalWorkerThreadState::notifyOne(CondV
     PR_NotifyCondVar((which == CONSUMER) ? consumerWakeup : producerWakeup);
 }
 
 bool
 GlobalWorkerThreadState::canStartAsmJSCompile()
 {
     // Don't execute an AsmJS job if an earlier one failed.
     JS_ASSERT(isLocked());
-    return (!asmJSWorklist().empty() && !numAsmJSFailedJobs);
+    return !asmJSWorklist().empty() && !numAsmJSFailedJobs;
 }
 
 bool
 GlobalWorkerThreadState::canStartIonCompile()
 {
     // A worker thread can begin an Ion compilation if (a) there is some script
     // which is waiting to be compiled, and (b) no other worker thread is
     // currently compiling a script. The latter condition ensures that two
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -79,17 +79,17 @@ EXPORTS.js += [
     '../public/OldDebugAPI.h',
     '../public/Principals.h',
     '../public/ProfilingStack.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
     '../public/SliceBudget.h',
     '../public/StructuredClone.h',
-    '../public/Tracer.h',
+    '../public/TracingAPI.h',
     '../public/TypeDecls.h',
     '../public/Utility.h',
     '../public/Value.h',
     '../public/Vector.h',
     '../public/WeakMapPtr.h',
 ]
 
 UNIFIED_SOURCES += [
--- a/js/src/shell/jsheaptools.cpp
+++ b/js/src/shell/jsheaptools.cpp
@@ -149,22 +149,22 @@ class HeapReverser : public JSTracer, pu
      * The result of a reversal is a map from Cells' addresses to Node
      * structures describing their incoming edges.
      */
     typedef HashMap<void *, Node, DefaultHasher<void *>, SystemAllocPolicy> Map;
     Map map;
 
     /* Construct a HeapReverser for |context|'s heap. */
     HeapReverser(JSContext *cx)
-      : JS::CustomAutoRooter(cx),
+      : JSTracer(cx->runtime(), traverseEdgeWithThis),
+        JS::CustomAutoRooter(cx),
         noggc(JS_GetRuntime(cx)),
         runtime(JS_GetRuntime(cx)),
         parent(nullptr)
     {
-        JS_TracerInit(this, runtime, traverseEdgeWithThis);
     }
 
     bool init() { return map.init(); }
 
     /* Build a reversed map of the heap in |map|. */
     bool reverseHeap();
 
   private:
@@ -303,35 +303,35 @@ HeapReverser::reverseHeap()
     }
 
     return true;
 }
 
 char *
 HeapReverser::getEdgeDescription()
 {
-    if (!debugPrinter && debugPrintIndex == (size_t) -1) {
-        const char *arg = static_cast<const char *>(debugPrintArg);
+    if (!debugPrinter() && debugPrintIndex() == (size_t) -1) {
+        const char *arg = static_cast<const char *>(debugPrintArg());
         char *name = js_pod_malloc<char>(strlen(arg) + 1);
         if (!name)
             return nullptr;
         strcpy(name, arg);
         return name;
     }
 
     /* Lovely; but a fixed size is required by JSTraceNamePrinter. */
     static const int nameSize = 200;
     char *name = js_pod_malloc<char>(nameSize);
     if (!name)
         return nullptr;
-    if (debugPrinter)
-        debugPrinter(this, name, nameSize);
+    if (debugPrinter())
+        debugPrinter()(this, name, nameSize);
     else
         JS_snprintf(name, nameSize, "%s[%lu]",
-                    static_cast<const char *>(debugPrintArg), debugPrintIndex);
+                    static_cast<const char *>(debugPrintArg()), debugPrintIndex());
 
     /* Shrink storage to fit. */
     return static_cast<char *>(js_realloc(name, strlen(name) + 1));
 }
 
 
 /*** class ReferenceFinder ***********************************************************************/
 
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -790,17 +790,17 @@ ArrayBufferObject::finalize(FreeOp *fop,
 
     if (buffer.ownsData())
         buffer.releaseData(fop);
 }
 
 /* static */ void
 ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
 {
-    if (!IS_GC_MARKING_TRACER(trc) && !trc->runtime->isHeapMinorCollecting())
+    if (!IS_GC_MARKING_TRACER(trc) && !trc->runtime()->isHeapMinorCollecting())
         return;
 
     // ArrayBufferObjects need to maintain a list of possibly-weak pointers to
     // their views. The straightforward way to update the weak pointers would
     // be in the views' finalizers, but giving views finalizers means they
     // cannot be swept in the background. This results in a very high
     // performance cost.  Instead, ArrayBufferObjects with a single view hold a
     // strong pointer to the view. This can entrain garbage when the single
@@ -810,17 +810,17 @@ ArrayBufferObject::obj_trace(JSTracer *t
     // multiple views are collected into a linked list during collection, and
     // then swept to prune out their dead views.
 
     ArrayBufferObject &buffer = AsArrayBuffer(obj);
     ArrayBufferViewObject *viewsHead = buffer.viewList();
     if (!viewsHead)
         return;
 
-    buffer.setViewList(UpdateObjectIfRelocated(trc->runtime, &viewsHead));
+    buffer.setViewList(UpdateObjectIfRelocated(trc->runtime(), &viewsHead));
 
     if (viewsHead->nextView() == nullptr) {
         // Single view: mark it, but only if we're actually doing a GC pass
         // right now. Otherwise, the tracing pass for barrier verification will
         // fail if we add another view and the pointer becomes weak.
         MarkObjectUnbarriered(trc, &viewsHead, "arraybuffer.singleview");
         buffer.setViewListNoBarrier(viewsHead);
     } else {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1423,27 +1423,27 @@ Debugger::slowPathOnNewGlobalObject(JSCo
     }
     JS_ASSERT(!cx->isExceptionPending());
 }
 
 
 /*** Debugger JSObjects **************************************************************************/
 
 void
-Debugger::markKeysInCompartment(JSTracer *tracer)
+Debugger::markKeysInCompartment(JSTracer *trc)
 {
     /*
      * WeakMap::Range is deliberately private, to discourage C++ code from
      * enumerating WeakMap keys. However in this case we need access, so we
      * make a base-class reference. Range is public in HashMap.
      */
-    objects.markKeys(tracer);
-    environments.markKeys(tracer);
-    scripts.markKeys(tracer);
-    sources.markKeys(tracer);
+    objects.markKeys(trc);
+    environments.markKeys(trc);
+    scripts.markKeys(trc);
+    sources.markKeys(trc);
 }
 
 /*
  * Ordinarily, WeakMap keys and values are marked because at some point it was
  * discovered that the WeakMap was live; that is, some object containing the
  * WeakMap was marked during mark phase.
  *
  * However, during compartment GC, we have to do something about
@@ -1459,27 +1459,27 @@ Debugger::markKeysInCompartment(JSTracer
  * We must scan all Debugger objects regardless of whether they *currently*
  * have any debuggees in a compartment being GC'd, because the WeakMap
  * entries persist even when debuggees are removed.
  *
  * This happens during the initial mark phase, not iterative marking, because
  * all the edges being reported here are strong references.
  */
 void
-Debugger::markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer)
-{
-    JSRuntime *rt = tracer->runtime;
+Debugger::markCrossCompartmentDebuggerObjectReferents(JSTracer *trc)
+{
+    JSRuntime *rt = trc->runtime();
 
     /*
      * Mark all objects in comp that are referents of Debugger.Objects in other
      * compartments.
      */
     for (Debugger *dbg = rt->debuggerList.getFirst(); dbg; dbg = dbg->getNext()) {
         if (!dbg->object->zone()->isCollecting())
-            dbg->markKeysInCompartment(tracer);
+            dbg->markKeysInCompartment(trc);
     }
 }
 
 /*
  * This method has two tasks:
  *   1. Mark Debugger objects that are unreachable except for debugger hooks that
  *      may yet be called.
  *   2. Mark breakpoint handlers.
@@ -1492,17 +1492,17 @@ bool
 Debugger::markAllIteratively(GCMarker *trc)
 {
     bool markedAny = false;
 
     /*
      * Find all Debugger objects in danger of GC. This code is a little
      * convoluted since the easiest way to find them is via their debuggees.
      */
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         GlobalObjectSet &debuggees = c->getDebuggees();
         for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
             GlobalObject *global = e.front();
             if (!IsObjectMarked(&global))
                 continue;
             else if (global != e.front())
                 e.rekeyFront(global);
@@ -1561,17 +1561,17 @@ Debugger::markAllIteratively(GCMarker *t
 /*
  * Mark all debugger-owned GC things unconditionally. This is used by the minor
  * GC: the minor GC cannot apply the weak constraints of the full GC because it
  * visits only part of the heap.
  */
 void
 Debugger::markAll(JSTracer *trc)
 {
-    JSRuntime *rt = trc->runtime;
+    JSRuntime *rt = trc->runtime();
     for (Debugger *dbg = rt->debuggerList.getFirst(); dbg; dbg = dbg->getNext()) {
         GlobalObjectSet &debuggees = dbg->debuggees;
         for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
             GlobalObject *global = e.front();
 
             MarkObjectUnbarriered(trc, &global, "Global Object");
             if (global != e.front())
                 e.rekeyFront(global);
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -208,17 +208,17 @@ VectorMatchPairs::allocOrExpandArray(siz
 static void
 regexp_trace(JSTracer *trc, JSObject *obj)
 {
      /*
       * We have to check both conditions, since:
       *   1. During TraceRuntime, isHeapBusy() is true
       *   2. When a write barrier executes, IS_GC_MARKING_TRACER is true.
       */
-    if (trc->runtime->isHeapBusy() && IS_GC_MARKING_TRACER(trc))
+    if (trc->runtime()->isHeapBusy() && IS_GC_MARKING_TRACER(trc))
         obj->setPrivate(nullptr);
 }
 
 const Class RegExpObject::class_ = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -365,17 +365,17 @@ class NewObjectCache
   private:
     bool lookup(const Class *clasp, gc::Cell *key, gc::AllocKind kind, EntryIndex *pentry) {
         uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + kind;
         *pentry = hash % mozilla::ArrayLength(entries);
 
         Entry *entry = &entries[*pentry];
 
         /* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
-        return (entry->clasp == clasp && entry->key == key);
+        return entry->clasp == clasp && entry->key == key;
     }
 
     void fill(EntryIndex entry_, const Class *clasp, gc::Cell *key, gc::AllocKind kind, JSObject *obj) {
         JS_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
         Entry *entry = &entries[entry_];
 
         JS_ASSERT(!obj->hasDynamicSlots() && !obj->hasDynamicElements());
 
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1597,17 +1597,17 @@ class DebugScopes::MissingScopesRef : pu
   public:
     MissingScopesRef(MissingScopeMap *m, const ScopeIterKey &k) : map(m), key(k) {}
 
     void mark(JSTracer *trc) {
         ScopeIterKey prior = key;
         MissingScopeMap::Ptr p = map->lookup(key);
         if (!p)
             return;
-        JS_SET_TRACING_LOCATION(trc, &const_cast<ScopeIterKey &>(p->key()).enclosingScope());
+        trc->setTracingLocation(&const_cast<ScopeIterKey &>(p->key()).enclosingScope());
         Mark(trc, &key.enclosingScope(), "MissingScopesRef");
         map->rekeyIfMoved(prior, key);
     }
 };
 #endif
 
 /* static */ MOZ_ALWAYS_INLINE void
 DebugScopes::missingScopesPostWriteBarrier(JSRuntime *rt, MissingScopeMap *map,
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1167,17 +1167,17 @@ class Shape : public gc::BarrieredCell<S
 
     void setSlot(uint32_t slot) {
         JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
         slotInfo = slotInfo & ~Shape::SLOT_MASK;
         slotInfo = slotInfo | slot;
     }
 
     uint32_t numFixedSlots() const {
-        return (slotInfo >> FIXED_SLOTS_SHIFT);
+        return slotInfo >> FIXED_SLOTS_SHIFT;
     }
 
     void setNumFixedSlots(uint32_t nfixed) {
         JS_ASSERT(nfixed < FIXED_SLOTS_MAX);
         slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
         slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
     }
 
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -639,28 +639,28 @@ StaticStrings::trace(JSTracer *trc)
 }
 
 bool
 StaticStrings::isStatic(JSAtom *atom)
 {
     const jschar *chars = atom->chars();
     switch (atom->length()) {
       case 1:
-        return (chars[0] < UNIT_STATIC_LIMIT);
+        return chars[0] < UNIT_STATIC_LIMIT;
       case 2:
-        return (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]));
+        return fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]);
       case 3:
         if ('1' <= chars[0] && chars[0] <= '9' &&
             '0' <= chars[1] && chars[1] <= '9' &&
             '0' <= chars[2] && chars[2] <= '9') {
             int i = (chars[0] - '0') * 100 +
                       (chars[1] - '0') * 10 +
                       (chars[2] - '0');
 
-            return (unsigned(i) < INT_STATIC_LIMIT);
+            return unsigned(i) < INT_STATIC_LIMIT;
         }
         return false;
       default:
         return false;
     }
 }
 
 #ifdef DEBUG
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -376,17 +376,17 @@ class JSString : public js::gc::Barriere
 
     MOZ_ALWAYS_INLINE
     bool isUndepended() const {
         return (d.lengthAndFlags & FLAGS_MASK) == UNDEPENDED_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     bool isAtom() const {
-        return (d.lengthAndFlags & ATOM_BIT);
+        return d.lengthAndFlags & ATOM_BIT;
     }
 
     MOZ_ALWAYS_INLINE
     bool isPermanentAtom() const {
         return (d.lengthAndFlags & FLAGS_MASK) == PERMANENT_ATOM_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
@@ -394,17 +394,17 @@ class JSString : public js::gc::Barriere
         JS_ASSERT(isAtom());
         return *(JSAtom *)this;
     }
 
     /* Only called by the GC for dependent or undepended strings. */
 
     inline bool hasBase() const {
         JS_STATIC_ASSERT((DEPENDENT_FLAGS | JS_BIT(1)) == UNDEPENDED_FLAGS);
-        return (d.lengthAndFlags & HAS_BASE_BIT);
+        return d.lengthAndFlags & HAS_BASE_BIT;
     }
 
     inline JSLinearString *base() const;
 
     inline void markBase(JSTracer *trc);
 
     /* Only called by the GC for strings with the FINALIZE_STRING kind. */
 
@@ -735,17 +735,17 @@ class JSAtom : public JSFlatString
   public:
     /* Returns the PropertyName for this.  isIndex() must be false. */
     inline js::PropertyName *asPropertyName();
 
     inline void finalize(js::FreeOp *fop);
 
     MOZ_ALWAYS_INLINE
     bool isPermanent() const {
-        return (d.lengthAndFlags & PERMANENT_BIT);
+        return d.lengthAndFlags & PERMANENT_BIT;
     }
 
     // Transform this atom into a permanent atom. This is only done during
     // initialization of the runtime.
     MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
         d.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
     }
 
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -56,61 +56,28 @@ rdtsc(void)
             "\tcmpw    %2,%0        \n"
             "\tbne     0b         \n"
             : "=r"(upper),"=r"(lower),"=r"(tmp)
             );
     result = upper;
     result = result<<32;
     result = result|lower;
 
-    return(result);
+    return result;
 }
 #endif
 
 TraceLogging traceLoggers;
 
-// The text that will get logged for eagerly created logged text.
-// When adding/removing something here, you must update the enum
-// Tracelogger::TextId in TraceLogging.h too.
-const char* const text[] = {
+static const char* const text[] =
+{
     "TraceLogger failed to process text",
-    "Bailout",
-    "Baseline",
-    "GC",
-    "GCAllocation",
-    "GCSweeping",
-    "Interpreter",
-    "Invalidation",
-    "IonCompilation",
-    "IonLinking",
-    "IonMonkey",
-    "MinorGC",
-    "ParserCompileFunction",
-    "ParserCompileLazy",
-    "ParserCompileScript",
-    "TraceLogger",
-    "YarrCompile",
-    "YarrInterpret",
-    "YarrJIT",
-    "VM",
-    "SplitCriticalEdges",
-    "RenumberBlocks",
-    "DominatorTree",
-    "PhiAnalysis",
-    "ApplyTypes",
-    "ParallelSafetyAnalysis",
-    "AliasAnalysis",
-    "GVN",
-    "UCE",
-    "LICM",
-    "RangeAnalysis",
-    "EffectiveAddressAnalysis",
-    "EliminateDeadCode",
-    "EdgeCaseAnalysis",
-    "EliminateRedundantChecks"
+#define NAME(x) #x,
+    TRACELOGGER_TEXT_ID_LIST(NAME)
+#undef NAME
 };
 
 TraceLogger::TraceLogger()
  : enabled(false),
    enabledTimes(0),
    failed(false),
    nextTextId(0),
    treeOffset(0),
@@ -828,16 +795,17 @@ TraceLogging::lazyInit()
         enabledTextIds[i] = ContainsFlag(env, text[i]);
 
     enabledTextIds[TraceLogger::TL_Error] = true;
     enabledTextIds[TraceLogger::TL] = true;
 
     if (ContainsFlag(env, "Default") || strlen(env) == 0) {
         enabledTextIds[TraceLogger::Bailout] = true;
         enabledTextIds[TraceLogger::Baseline] = true;
+        enabledTextIds[TraceLogger::BaselineCompilation] = true;
         enabledTextIds[TraceLogger::GC] = true;
         enabledTextIds[TraceLogger::GCAllocation] = true;
         enabledTextIds[TraceLogger::GCSweeping] = true;
         enabledTextIds[TraceLogger::Interpreter] = true;
         enabledTextIds[TraceLogger::IonCompilation] = true;
         enabledTextIds[TraceLogger::IonLinking] = true;
         enabledTextIds[TraceLogger::IonMonkey] = true;
         enabledTextIds[TraceLogger::MinorGC] = true;
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -103,16 +103,55 @@ namespace jit {
  *    or the duration:
  *    - TraceLogStartEvent(logger, textId);
  *    - TraceLogStopEvent(logger, textId);
  *
  *    or the duration with a RAII class:
  *    - AutoTraceLog logger(logger, textId);
  */
 
+#define TRACELOGGER_TEXT_ID_LIST(_)                   \
+    _(Bailout)                                        \
+    _(Baseline)                                       \
+    _(BaselineCompilation)                            \
+    _(GC)                                             \
+    _(GCAllocation)                                   \
+    _(GCSweeping)                                     \
+    _(Interpreter)                                    \
+    _(Invalidation)                                   \
+    _(IonCompilation)                                 \
+    _(IonLinking)                                     \
+    _(IonMonkey)                                      \
+    _(MinorGC)                                        \
+    _(ParserCompileFunction)                          \
+    _(ParserCompileLazy)                              \
+    _(ParserCompileScript)                            \
+    _(TL)                                             \
+    _(YarrCompile)                                    \
+    _(YarrInterpret)                                  \
+    _(YarrJIT)                                        \
+    _(VM)                                             \
+                                                      \
+    /* Specific passes during ion compilation */      \
+    _(SplitCriticalEdges)                             \
+    _(RenumberBlocks)                                 \
+    _(DominatorTree)                                  \
+    _(PhiAnalysis)                                    \
+    _(ApplyTypes)                                     \
+    _(ParallelSafetyAnalysis)                         \
+    _(AliasAnalysis)                                  \
+    _(GVN)                                            \
+    _(UCE)                                            \
+    _(LICM)                                           \
+    _(RangeAnalysis)                                  \
+    _(EffectiveAddressAnalysis)                       \
+    _(EliminateDeadCode)                              \
+    _(EdgeCaseAnalysis)                               \
+    _(EliminateRedundantChecks)
+
 class AutoTraceLog;
 
 template <class T>
 class ContinuousSpace {
     T *data_;
     uint32_t next_;
     uint32_t capacity_;
 
@@ -203,58 +242,22 @@ class ContinuousSpace {
     }
 };
 
 class TraceLogger
 {
   public:
     // Predefined IDs for common operations. These IDs can be used
     // without using TraceLogCreateTextId, because there are already created.
-    // When changing the enum here, you must update the array containing the
-    // actual logged text in TraceLogging.cpp.
     enum TextId {
-      TL_Error,
-      Bailout,
-      Baseline,
-      GC,
-      GCAllocation,
-      GCSweeping,
-      Interpreter,
-      Invalidation,
-      IonCompilation,
-      IonLinking,
-      IonMonkey,
-      MinorGC,
-      ParserCompileFunction,
-      ParserCompileLazy,
-      ParserCompileScript,
-      TL,
-      YarrCompile,
-      YarrInterpret,
-      YarrJIT,
-      VM,
-
-      // Specific passes during ion compilation:
-      SplitCriticalEdges,
-      RenumberBlocks,
-      DominatorTree,
-      PhiAnalysis,
-      ApplyTypes,
-      ParallelSafetyAnalysis,
-      AliasAnalysis,
-      GVN,
-      UCE,
-      LICM,
-      RangeAnalysis,
-      EffectiveAddressAnalysis,
-      EliminateDeadCode,
-      EdgeCaseAnalysis,
-      EliminateRedundantChecks,
-
-      LAST
+        TL_Error = 0,
+#   define DEFINE_TEXT_ID(textId) textId,
+        TRACELOGGER_TEXT_ID_LIST(DEFINE_TEXT_ID)
+#   undef DEFINE_TEXT_ID
+        LAST
     };
 
 #ifdef JS_TRACE_LOGGING
   private:
     typedef HashMap<const void *,
                     uint32_t,
                     PointerHasher<const void *, 3>,
                     SystemAllocPolicy> PointerHashMap;
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -161,17 +161,17 @@ js::ClampDoubleToUint8(const double x)
         /*
          * It was a tie (since adding 0.5 gave us the exact integer
          * we want).  Since we rounded up, we either already have an
          * even number or we have an odd number but the number we
          * want is one less.  So just unconditionally masking out the
          * ones bit should do the trick to get us the value we
          * want.
          */
-        return (y & ~1);
+        return y & ~1;
     }
 
     return y;
 }
 
 template<typename NativeType> static inline const int TypeIDOfType();
 template<> inline const int TypeIDOfType<int8_t>() { return ScalarTypeDescr::TYPE_INT8; }
 template<> inline const int TypeIDOfType<uint8_t>() { return ScalarTypeDescr::TYPE_UINT8; }
@@ -2054,17 +2054,17 @@ const JSFunctionSpec _typedArray##Object
       return TypedArrayObjectTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset,      \
                                                               length, js::NullPtr());           \
   }                                                                                             \
   JS_FRIEND_API(bool) JS_Is ## Name ## Array(JSObject *obj)                                     \
   {                                                                                             \
       if (!(obj = CheckedUnwrap(obj)))                                                          \
           return false;                                                                         \
       const Class *clasp = obj->getClass();                                                     \
-      return (clasp == &TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()]); \
+      return clasp == &TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()]; \
   }
 
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped, uint8_clamped)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16, int16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16, uint16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32, int32_t)
--- a/js/src/vtune/VTuneWrapper.h
+++ b/js/src/vtune/VTuneWrapper.h
@@ -7,12 +7,12 @@
 #ifndef vtunewrapper_h
 #define vtunewrapper_h
 
 #include "vtune/jitprofiling.h"
 
 inline bool
 IsVTuneProfilingActive()
 {
-    return (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON);
+    return iJIT_IsProfilingActive() == iJIT_SAMPLING_ON;
 }
 
 #endif // vtunewrapper_h
--- a/js/xpconnect/idl/mozIJSSubScriptLoader.idl
+++ b/js/xpconnect/idl/mozIJSSubScriptLoader.idl
@@ -1,17 +1,21 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * 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 "nsISupports.idl"
 
-[scriptable, uuid(b21f1579-d994-4e99-a85d-a685140f3ec1)]
+interface nsIURI;
+interface nsIPrincipal;
+interface nsIObserver;
+
+[scriptable, uuid(19533e7b-f321-4ef1-bc59-6e812dc2a733)]
 interface mozIJSSubScriptLoader : nsISupports
 {
     /**
      * This method should only be called from JS!
      * In JS, the signature looks like:
      * rv loadSubScript (url [, obj] [, charset]);
      * @param url the url of the sub-script, it MUST be either a file:,
      *            resource:, or chrome: url, and MUST be local.
@@ -34,9 +38,27 @@ interface mozIJSSubScriptLoader : nsISup
      * @param optionsObject an object with parameters. Valid parameters are:
      *                      - charset: specifying the character encoding of the file (default: ASCII)
      *                      - target:  an object to evaluate onto (default: global object of the caller)
      *                      - ignoreCache: if set to true, will bypass the cache for reading the file.
      * @retval rv the value returned by the sub-script
      */
     [implicit_jscontext]
     jsval loadSubScriptWithOptions(in AString url, in jsval options);
+
+    /*
+     * Compiles a JS script off the main thread and calls back the
+     * observer once it's done.
+     * The script will be cached in temporary or persistent storage depending
+     * on the principal used.
+     * We fire the notification callback in all cases - there is no fatal
+     * error there.
+     * @param uri       the uri of the script to load.
+     * @param principal the principal from which we get the app id if any.
+     * @param observer  this observer will be called once the script has
+     *                  been precompiled. The notification topic will be
+     *                  'script-precompiled' and the subject the uri of the
+     *                  script as a nsIURI.
+     */
+    void precompileScript(in nsIURI uri,
+                          in nsIPrincipal principal,
+                          in nsIObserver observer);
 };
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -13,30 +13,34 @@
 #include "nsIIOService.h"
 #include "nsIChannel.h"
 #include "nsIInputStream.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIFileURL.h"
 #include "nsScriptLoader.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsThreadUtils.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h" // For xpc::SystemErrorReporter
 #include "xpcprivate.h" // For xpc::OptionsBase
+#include "jswrapper.h"
 
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
+#include "mozilla/unused.h"
 
 using namespace mozilla::scache;
 using namespace JS;
 using namespace xpc;
+using namespace mozilla;
 
 class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase {
 public:
     LoadSubScriptOptions(JSContext *cx = xpc_GetSafeJSContext(),
                          JSObject *options = nullptr)
         : OptionsBase(cx, options)
         , target(cx)
         , charset(NullString())
@@ -360,8 +364,216 @@ mozJSSubScriptLoader::DoLoadSubScriptWit
     }
 
     if (cache && ok && writeScript) {
         WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script);
     }
 
     return NS_OK;
 }
+
+/**
+  * Let us compile scripts from a URI off the main thread.
+  */
+
+class ScriptPrecompiler : public nsIStreamLoaderObserver
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSISTREAMLOADEROBSERVER
+
+    ScriptPrecompiler(nsIObserver* aObserver,
+                      nsIPrincipal* aPrincipal,
+                      nsIChannel* aChannel)
+        : mObserver(aObserver)
+        , mPrincipal(aPrincipal)
+        , mChannel(aChannel)
+    {}
+
+    virtual ~ScriptPrecompiler()
+    {}
+
+    static void OffThreadCallback(void *aToken, void *aData);
+
+    /* Sends the "done" notification back. Main thread only. */
+    void SendObserverNotification();
+
+private:
+    nsRefPtr<nsIObserver> mObserver;
+    nsRefPtr<nsIPrincipal> mPrincipal;
+    nsRefPtr<nsIChannel> mChannel;
+    nsString mScript;
+};
+
+NS_IMPL_ISUPPORTS1(ScriptPrecompiler, nsIStreamLoaderObserver);
+
+class NotifyPrecompilationCompleteRunnable : public nsRunnable
+{
+public:
+    NS_DECL_NSIRUNNABLE
+
+    NotifyPrecompilationCompleteRunnable(ScriptPrecompiler* aPrecompiler)
+        : mPrecompiler(aPrecompiler)
+        , mToken(nullptr)
+    {}
+
+    void SetToken(void* aToken) {
+        MOZ_ASSERT(aToken && !mToken);
+        mToken = aToken;
+    }
+
+protected:
+    nsRefPtr<ScriptPrecompiler> mPrecompiler;
+    void* mToken;
+};
+
+/* RAII helper class to send observer notifications */
+class AutoSendObserverNotification {
+public:
+    AutoSendObserverNotification(ScriptPrecompiler* aPrecompiler)
+        : mPrecompiler(aPrecompiler)
+    {}
+
+    ~AutoSendObserverNotification() {
+        if (mPrecompiler) {
+            mPrecompiler->SendObserverNotification();
+        }
+    }
+
+    void Disarm() {
+        mPrecompiler = nullptr;
+    }
+
+private:
+    ScriptPrecompiler* mPrecompiler;
+};
+
+NS_IMETHODIMP
+NotifyPrecompilationCompleteRunnable::Run(void)
+{
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mPrecompiler);
+
+    AutoSendObserverNotification notifier(mPrecompiler);
+
+    if (mToken) {
+        JSRuntime *rt = XPCJSRuntime::Get()->Runtime();
+        NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE);
+        JS::FinishOffThreadScript(nullptr, rt, mToken);
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptPrecompiler::OnStreamComplete(nsIStreamLoader* aLoader,
+                                    nsISupports* aContext,
+                                    nsresult aStatus,
+                                    uint32_t aLength,
+                                    const uint8_t* aString)
+{
+    AutoSendObserverNotification notifier(this);
+
+    // Just notify that we are done with this load.
+    NS_ENSURE_SUCCESS(aStatus, NS_OK);
+
+    // Convert data to jschar* and prepare to call CompileOffThread.
+    nsAutoString hintCharset;
+    nsresult rv =
+        nsScriptLoader::ConvertToUTF16(mChannel, aString, aLength,
+                                       hintCharset, nullptr, mScript);
+
+    NS_ENSURE_SUCCESS(rv, NS_OK);
+
+    // Our goal is to cache persistently the compiled script and to avoid quota
+    // checks. Since the caching mechanism decide the persistence type based on
+    // the principal, we create a new global with the app's principal.
+    // We then enter its compartment to compile with its principal.
+    AutoSafeJSContext cx;
+    RootedValue v(cx);
+    SandboxOptions sandboxOptions;
+    sandboxOptions.sandboxName.AssignASCII("asm.js precompilation");
+    sandboxOptions.invisibleToDebugger = true;
+    rv = CreateSandboxObject(cx, &v, mPrincipal, sandboxOptions);
+    NS_ENSURE_SUCCESS(rv, NS_OK);
+
+    JSAutoCompartment ac(cx, js::UncheckedUnwrap(&v.toObject()));
+
+    JS::CompileOptions options(cx, JSVERSION_DEFAULT);
+    options.setSourcePolicy(CompileOptions::NO_SOURCE);
+    options.forceAsync = true;
+    options.compileAndGo = true;
+    options.installedFile = true;
+
+    nsCOMPtr<nsIURI> uri;
+    mChannel->GetURI(getter_AddRefs(uri));
+    nsAutoCString spec;
+    uri->GetSpec(spec);
+    options.setFile(spec.get());
+
+    if (!JS::CanCompileOffThread(cx, options, mScript.Length())) {
+        NS_WARNING("Can't compile script off thread!");
+        return NS_OK;
+    }
+
+    nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable =
+        new NotifyPrecompilationCompleteRunnable(this);
+
+    if (!JS::CompileOffThread(cx, options,
+                              mScript.get(), mScript.Length(),
+                              OffThreadCallback,
+                              static_cast<void*>(runnable))) {
+        NS_WARNING("Failed to compile script off thread!");
+        return NS_OK;
+    }
+
+    unused << runnable.forget();
+    notifier.Disarm();
+
+    return NS_OK;
+}
+
+/* static */
+void
+ScriptPrecompiler::OffThreadCallback(void* aToken, void* aData)
+{
+    nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable =
+        dont_AddRef(static_cast<NotifyPrecompilationCompleteRunnable*>(aData));
+    runnable->SetToken(aToken);
+
+    NS_DispatchToMainThread(runnable);
+}
+
+void
+ScriptPrecompiler::SendObserverNotification()
+{
+    MOZ_ASSERT(mChannel && mObserver);
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIURI> uri;
+    mChannel->GetURI(getter_AddRefs(uri));
+    mObserver->Observe(uri, "script-precompiled", nullptr);
+}
+
+NS_IMETHODIMP
+mozJSSubScriptLoader::PrecompileScript(nsIURI* aURI,
+                                       nsIPrincipal* aPrincipal,
+                                       nsIObserver *aObserver)
+{
+    nsCOMPtr<nsIChannel> channel;
+    nsresult rv = NS_NewChannel(getter_AddRefs(channel),
+                                aURI, nullptr, nullptr, nullptr,
+                                nsIRequest::LOAD_NORMAL, nullptr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsRefPtr<ScriptPrecompiler> loadObserver =
+        new ScriptPrecompiler(aObserver, aPrincipal, channel);
+
+    nsCOMPtr<nsIStreamLoader> loader;
+    rv = NS_NewStreamLoader(getter_AddRefs(loader), loadObserver);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIStreamListener> listener = loader.get();
+    rv = channel->AsyncOpen(listener, nullptr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+}
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -65,25 +65,25 @@ XPCTraceableVariant::~XPCTraceableVarian
 
     if (!JSVAL_IS_NULL(val))
         RemoveFromRootSet();
 }
 
 void XPCTraceableVariant::TraceJS(JSTracer* trc)
 {
     MOZ_ASSERT(mJSVal.isMarkable());
-    JS_SET_TRACING_DETAILS(trc, GetTraceName, this, 0);
+    trc->setTracingDetails(GetTraceName, this, 0);
     JS_CallHeapValueTracer(trc, &mJSVal, "XPCTraceableVariant::mJSVal");
 }
 
 // static
 void
 XPCTraceableVariant::GetTraceName(JSTracer* trc, char *buf, size_t bufsize)
 {
-    JS_snprintf(buf, bufsize, "XPCVariant[0x%p].mJSVal", trc->debugPrintArg);
+    JS_snprintf(buf, bufsize, "XPCVariant[0x%p].mJSVal", trc->debugPrintArg());
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant)
     JS::Value val = tmp->GetJSValPreserveColor();
     if (val.isObjectOrNull()) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal");
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -279,26 +279,26 @@ nsXPCWrappedJS::DeleteCycleCollectable(v
 {
     delete this;
 }
 
 void
 nsXPCWrappedJS::TraceJS(JSTracer* trc)
 {
     MOZ_ASSERT(mRefCnt >= 2 && IsValid(), "must be strongly referenced");
-    JS_SET_TRACING_DETAILS(trc, GetTraceName, this, 0);
+    trc->setTracingDetails(GetTraceName, this, 0);
     JS_CallHeapObjectTracer(trc, &mJSObj, "nsXPCWrappedJS::mJSObj");
 }
 
 // static
 void
 nsXPCWrappedJS::GetTraceName(JSTracer* trc, char *buf, size_t bufsize)
 {
     const nsXPCWrappedJS* self = static_cast<const nsXPCWrappedJS*>
-                                            (trc->debugPrintArg);
+                                            (trc->debugPrintArg());
     JS_snprintf(buf, bufsize, "nsXPCWrappedJS[%s,0x%p:0x%p].mJSObj",
                 self->GetClass()->GetInterfaceName(), self, self->mXPTCStub);
 }
 
 NS_IMETHODIMP
 nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
 {
     if (!IsRootWrapper())
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -2672,26 +2672,26 @@ XPCJSObjectHolder::XPCJSObjectHolder(JSO
 XPCJSObjectHolder::~XPCJSObjectHolder()
 {
     RemoveFromRootSet();
 }
 
 void
 XPCJSObjectHolder::TraceJS(JSTracer *trc)
 {
-    JS_SET_TRACING_DETAILS(trc, GetTraceName, this, 0);
+    trc->setTracingDetails(GetTraceName, this, 0);
     JS_CallHeapObjectTracer(trc, &mJSObj, "XPCJSObjectHolder::mJSObj");
 }
 
 // static
 void
 XPCJSObjectHolder::GetTraceName(JSTracer* trc, char *buf, size_t bufsize)
 {
     JS_snprintf(buf, bufsize, "XPCJSObjectHolder[0x%p].mJSObj",
-                trc->debugPrintArg);
+                trc->debugPrintArg());
 }
 
 // static
 XPCJSObjectHolder*
 XPCJSObjectHolder::newHolder(JSObject* obj)
 {
     if (!obj) {
         NS_ERROR("bad param");
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -318,28 +318,31 @@ nsXPConnect::InitClasses(JSContext * aJS
 
     if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj))
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return NS_OK;
 }
 
 #ifdef DEBUG
-struct VerifyTraceXPCGlobalCalledTracer
-{
-    JSTracer base;
-    bool ok;
-};
-
 static void
 VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
     // We don't do anything here, we only want to verify that TraceXPCGlobal
     // was called.
 }
+
+struct VerifyTraceXPCGlobalCalledTracer : public JSTracer
+{
+    bool ok;
+
+    VerifyTraceXPCGlobalCalledTracer(JSRuntime *rt)
+      : JSTracer(rt, VerifyTraceXPCGlobalCalled), ok(false)
+    {}
+};
 #endif
 
 void
 TraceXPCGlobal(JSTracer *trc, JSObject *obj)
 {
 #ifdef DEBUG
     if (trc->callback == VerifyTraceXPCGlobalCalled) {
         // We don't do anything here, we only want to verify that TraceXPCGlobal
@@ -374,20 +377,18 @@ CreateGlobalObject(JSContext *cx, const 
     (void) new XPCWrappedNativeScope(cx, global);
 
 #ifdef DEBUG
     // Verify that the right trace hook is called. Note that this doesn't
     // work right for wrapped globals, since the tracing situation there is
     // more complicated. Manual inspection shows that they do the right thing.
     if (!((const js::Class*)clasp)->ext.isWrappedNative)
     {
-        VerifyTraceXPCGlobalCalledTracer trc;
-        JS_TracerInit(&trc.base, JS_GetRuntime(cx), VerifyTraceXPCGlobalCalled);
-        trc.ok = false;
-        JS_TraceChildren(&trc.base, global, JSTRACE_OBJECT);
+        VerifyTraceXPCGlobalCalledTracer trc(JS_GetRuntime(cx));
+        JS_TraceChildren(&trc, global, JSTRACE_OBJECT);
         MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
     }
 #endif
 
     if (clasp->flags & JSCLASS_DOM_GLOBAL) {
         const char* className = clasp->name;
         AllocateProtoAndIfaceCache(global,
                                    (strcmp(className, "Window") == 0 ||
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -85,17 +85,17 @@
 #include "mozilla/TimeStamp.h"
 
 #include <math.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "xpcpublic.h"
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 #include "js/WeakMapPtr.h"
 #include "pldhash.h"
 #include "nscore.h"
 #include "nsXPCOM.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"
 #include "nsISupports.h"
--- a/mobile/android/chrome/content/CastingApps.js
+++ b/mobile/android/chrome/content/CastingApps.js
@@ -58,16 +58,57 @@ var CastingApps = {
       case "Casting:Stop":
         if (this.session) {
           this.closeExternal();
         }
         break;
     }
   },
 
+  _sendEventToVideo: function _sendEventToVideo(aElement, aData) {
+    let event = aElement.ownerDocument.createEvent("CustomEvent");
+    event.initCustomEvent("media-videoCasting", false, true, JSON.stringify(aData));
+    aElement.dispatchEvent(event);
+  },
+
+  handleVideoBindingAttached: function handleVideoBindingAttached(aTab, aEvent) {
+    // Let's figure out if we have everything needed to cast a video. The binding
+    // defaults to |false| so we only need to send an event if |true|.
+    let video = aEvent.target;
+    if (!video instanceof HTMLVideoElement) {
+      return;
+    }
+
+    if (SimpleServiceDiscovery.services.length == 0) {
+      return;
+    }
+
+    if (!this.getVideo(video, 0, 0)) {
+      return;
+    }
+
+    // Let the binding know casting is allowed
+    this._sendEventToVideo(video, { allow: true });
+  },
+
+  handleVideoBindingCast: function handleVideoBindingCast(aTab, aEvent) {
+    // The binding wants to start a casting session
+    let video = aEvent.target;
+    if (!video instanceof HTMLVideoElement) {
+      return;
+    }
+
+    // Close an existing session first. closeExternal has checks for an exsting
+    // session and handles remote and video binding shutdown.
+    this.closeExternal();
+
+    // Start the new session
+    this.openExternal(video, 0, 0);
+  },
+
   makeURI: function makeURI(aURL, aOriginCharset, aBaseURI) {
     return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
   },
 
   getVideo: function(aElement, aX, aY) {
     // Fast path: Is the given element a video element
     let video = this._getVideo(aElement);
     if (video) {
@@ -216,42 +257,54 @@ var CastingApps = {
             this.session = {
               service: aService,
               app: app,
               remoteMedia: aRemoteMedia,
               data: {
                 title: video.title,
                 source: video.source,
                 poster: video.poster
-              }
+              },
+              videoRef: Cu.getWeakReference(video.element)
             };
           }.bind(this), this);
         }.bind(this));
       }.bind(this));
     }.bind(this));
   },
 
   closeExternal: function() {
     if (!this.session) {
       return;
     }
 
     this.session.remoteMedia.shutdown();
     this.session.app.stop();
+
+    let video = this.session.videoRef.get();
+    if (video) {
+      this._sendEventToVideo(video, { active: false });
+    }
+
     delete this.session;
   },
 
   // RemoteMedia callback API methods
   onRemoteMediaStart: function(aRemoteMedia) {
     if (!this.session) {
       return;
     }
 
     aRemoteMedia.load(this.session.data);
     sendMessageToJava({ type: "Casting:Started", device: this.session.service.friendlyName });
+
+    let video = this.session.videoRef.get();
+    if (video) {
+      this._sendEventToVideo(video, { active: true });
+    }
   },
 
   onRemoteMediaStop: function(aRemoteMedia) {
     sendMessageToJava({ type: "Casting:Stopped" });
   },
 
   onRemoteMediaStatus: function(aRemoteMedia) {
     if (!this.session) {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3005,20 +3005,23 @@ Tab.prototype = {
     this.browser.addEventListener("DOMLinkAdded", this, true);
     this.browser.addEventListener("DOMTitleChanged", this, true);
     this.browser.addEventListener("DOMWindowClose", this, true);
     this.browser.addEventListener("DOMWillOpenModalDialog", this, true);
     this.browser.addEventListener("DOMAutoComplete", this, true);
     this.browser.addEventListener("blur", this, true);
     this.browser.addEventListener("scroll", this, true);
     this.browser.addEventListener("MozScrolledAreaChanged", this, true);
+    this.browser.addEventListener("pageshow", this, true);
+    this.browser.addEventListener("MozApplicationManifest", this, true);
+
     // Note that the XBL binding is untrusted
     this.browser.addEventListener("PluginBindingAttached", this, true, true);
-    this.browser.addEventListener("pageshow", this, true);
-    this.browser.addEventListener("MozApplicationManifest", this, true);
+    this.browser.addEventListener("VideoBindingAttached", this, true, true);
+    this.browser.addEventListener("VideoBindingCast", this, true, true);
 
     Services.obs.addObserver(this, "before-first-paint", false);
     Services.obs.addObserver(this, "after-viewport-change", false);
     Services.prefs.addObserver("browser.ui.zoom.force-user-scalable", this, false);
 
     if (aParams.delayLoad) {
       // If this is a zombie tab, attach restore data so the tab will be
       // restored when selected
@@ -3174,20 +3177,23 @@ Tab.prototype = {
     this.browser.removeEventListener("DOMLinkAdded", this, true);
     this.browser.removeEventListener("DOMTitleChanged", this, true);
     this.browser.removeEventListener("DOMWindowClose", this, true);
     this.browser.removeEventListener("DOMWillOpenModalDialog", this, true);
     this.browser.removeEventListener("DOMAutoComplete", this, true);
     this.browser.removeEventListener("blur", this, true);
     this.browser.removeEventListener("scroll", this, true);
     this.browser.removeEventListener("MozScrolledAreaChanged", this, true);
-    this.browser.removeEventListener("PluginBindingAttached", this, true);
     this.browser.removeEventListener("pageshow", this, true);
     this.browser.removeEventListener("MozApplicationManifest", this, true);
 
+    this.browser.removeEventListener("PluginBindingAttached", this, true, true);
+    this.browser.removeEventListener("VideoBindingAttached", this, true, true);
+    this.browser.removeEventListener("VideoBindingCast", this, true, true);
+
     Services.obs.removeObserver(this, "before-first-paint");
     Services.obs.removeObserver(this, "after-viewport-change");
     Services.prefs.removeObserver("browser.ui.zoom.force-user-scalable", this);
 
     // Make sure the previously selected panel remains selected. The selected panel of a deck is
     // not stable when panels are removed.
     let selectedPanel = BrowserApp.deck.selectedPanel;
     BrowserApp.deck.removeChild(this.browser);
@@ -3929,16 +3935,26 @@ Tab.prototype = {
         break;
       }
 
       case "PluginBindingAttached": {
         PluginHelper.handlePluginBindingAttached(this, aEvent);
         break;
       }
 
+      case "VideoBindingAttached": {
+        CastingApps.handleVideoBindingAttached(this, aEvent);
+        break;
+      }
+
+      case "VideoBindingCast": {
+        CastingApps.handleVideoBindingCast(this, aEvent);
+        break;
+      }
+
       case "MozApplicationManifest": {
         OfflineApps.offlineAppRequested(aEvent.originalTarget.defaultView);
         break;
       }
 
       case "pageshow": {
         // only send pageshow for the top-level document
         if (aEvent.originalTarget.defaultView != this.browser.contentWindow)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1be34d5bb94ff9d942472b99a8eaacf271c1ba57
GIT binary patch
literal 684
zc$@*O0#p5oP)<h;3K|Lk000e1NJLTq001fg001fo1^@s6#ly*400001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^n-
z0}DB7W41~F00JyYL_t(o!|m8hsEtt+2k_syo^geg!BK=#9x-r)k+;DyV4%EH_YQ6t
z7%0WWtEkJ60ZEd3BTAHG;87TuoXmv?9Wj!w2-h)Lr*=XL-?^7>)$Uts?fupNTaW+#
z_Ab=xb^SqF^b^T}=0J0xe@F(VMyXQkQ(RRo7Yljnn*p?t^+;3wZ#2^nB&!B1<UE=K
z&4D%n=ykm75A?JggRr1aMzmC^jZ1u=a3iq~;eB68{fkni)`MHvg^9_U-I$4+eWgZ+
zV-XJGF|J~6%sq;-*puN-^<AJ(@a3EBtc-g&jZrbb9~<$pDL|{`;v|g5Ds(463fPSM
zm=(Tmv}GOHmgH~xEiPjNrsI49W+Lt;Y|s_8oO#!Gl`6G%j7@5CEtcX{_(sHs%n7>_
z*Rqc2dYnWJXD}iBw=gf73r6B1#zeF`(9?{aX#h6i0k(zjDHg{^z<3-B{dq(-GobCb
zg3n<O!BHFu`x(}uH|#Z782W)fbQJleu0K^R7gu5$ZYT3Qus!rUIG)VyZALSV3Hu?I
z;B2y{6H`Oqmu#mCFeCKYQM11_es-_WNd3!FrFIOhk>2(svV)U4d>z!(kPY#?pRmJU
zt<gc)8tH8f!rzkA><UZ{{ao_?vg81G`>&q->h=1!S2-uD<zh#a#09Jl|ITW;c(_!l
z4aJ*ixLypamWv;=rYC4CRca05zm)jrN8^16`fAYGluXXj`5k@^Gza>h0sRW1yPPwR
Si`nu30000<MNUMnLSTYRjXBBy
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5966ee1b0c65c42635f6252c071c8b532ed04f23
GIT binary patch
literal 542
zc$@(q0^$9MP)<h;3K|Lk000e1NJLTq001fg001fo1^@s6#ly*400001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^n&
z4krUjhY$n+00Ev!L_t(o!|j(lO9Md^g-?88AtDHA1RwYSL9h@D8x;i$8~=lr7FHIv
zHa4~vVk1f*Vj*H-A&8v_VlRjy7_byk@kKtHS-5UAm7Ce%99XhB_e}V5cXoC*1E?BQ
zqbgAV4WI$^k5u=Am$vmP6E1zFE`3ScJ&17E2hac-K&u$^NYZmPEcjEB>Lrb(>Va?G
znc5^3Qo=>KP05|4CrQVWmLzqhwWIv-uMQ<GOFBzaM{gt*V}WT&r;;`$wfLP3V2@^C
z2FL+#eAhKF7|SPhSP4+Ma1W3Nie}IwFy<RH2h0K4*q{mE-VA&IhJAuY`UJLs4pZv{
zu1w|@X!Q*m=@pna^>(0O>Um$Fv%o&^5eu%G%&6;lq;a1&Q!j853on@Zn(<G3fZ91%
z3v8S48_@4+S>VOg2An@cGAaRmcin1o-y33`Juuk~<F7a`6I&e;1C4ZHVEfISEdt%n
zpEUV%^BX&r1O-?({;u&Co!97Ag=jfzNcti0+YWzLQr4aC8GpomzDl}u=e3ghD!F?K
g?@R$Sfc^*2FBq&X=UzfRy#N3J07*qoM6N<$g6VD4L;wH)
--- a/mobile/android/themes/core/jar.mn
+++ b/mobile/android/themes/core/jar.mn
@@ -57,16 +57,18 @@ chrome.jar:
   skin/images/certerror-warning.png         (images/certerror-warning.png)
   skin/images/errorpage-larry-white.png     (images/errorpage-larry-white.png)
   skin/images/errorpage-larry-black.png     (images/errorpage-larry-black.png)
   skin/images/marketplace-logo.png          (images/marketplace-logo.png)
   skin/images/throbber.png                  (images/throbber.png)
   skin/images/search-clear-30.png           (images/search-clear-30.png)
   skin/images/play-hdpi.png                 (images/play-hdpi.png)
   skin/images/pause-hdpi.png                (images/pause-hdpi.png)
+  skin/images/cast-ready-hdpi.png           (images/cast-ready-hdpi.png)
+  skin/images/cast-active-hdpi.png          (images/cast-active-hdpi.png)
   skin/images/mute-hdpi.png                 (images/mute-hdpi.png)
   skin/images/unmute-hdpi.png               (images/unmute-hdpi.png)
   skin/images/scrubber-hdpi.png             (images/scrubber-hdpi.png)
   skin/images/about-btn-darkgrey.png        (images/about-btn-darkgrey.png)
   skin/images/logo-hdpi.png                 (images/logo-hdpi.png)
   skin/images/wordmark-hdpi.png             (images/wordmark-hdpi.png)
   skin/images/reader-plus-icon-mdpi.png     (images/reader-plus-icon-mdpi.png)
   skin/images/reader-plus-icon-hdpi.png     (images/reader-plus-icon-hdpi.png)
--- a/mobile/android/themes/core/touchcontrols.css
+++ b/mobile/android/themes/core/touchcontrols.css
@@ -23,32 +23,41 @@
 }
 
 .controlsSpacer {
   display: none;
   -moz-box-flex: 0;
 }
 
 .playButton,
+.castingButton,
 .muteButton {
   -moz-appearance: none;
   min-height: 42px;
   min-width: 42px;
   border: none !important;
 }
 
 .playButton {
   -moz-transform: translateX(21px);
   background: url("chrome://browser/skin/images/pause-hdpi.png") no-repeat center;
 }
 
 .playButton[paused="true"] {
   background: url("chrome://browser/skin/images/play-hdpi.png") no-repeat center;
 }
 
+.castingButton {
+  background: url("chrome://browser/skin/images/cast-ready-hdpi.png") no-repeat center;
+}
+
+.castingButton[active="true"] {
+  background: url("chrome://browser/skin/images/cast-active-hdpi.png") no-repeat center;
+}
+
 .muteButton {
   background: url("chrome://browser/skin/images/mute-hdpi.png") no-repeat center;
 }
 
 .muteButton[muted="true"] {
   background: url("chrome://browser/skin/images/unmute-hdpi.png") no-repeat center;
 }
 
--- a/security/manager/ssl/src/CryptoTask.cpp
+++ b/security/manager/ssl/src/CryptoTask.cpp
@@ -13,27 +13,16 @@ CryptoTask::~CryptoTask()
   MOZ_ASSERT(mReleasedNSSResources);
 
   nsNSSShutDownPreventionLock lock;
   if (!isAlreadyShutDown()) {
     shutdown(calledFromObject);
   }
 }
 
-nsresult
-CryptoTask::Dispatch(const nsACString & taskThreadName)
-{
-  nsCOMPtr<nsIThread> thread;
-  nsresult rv = NS_NewThread(getter_AddRefs(thread), this);
-  if (thread) {
-    NS_SetThreadName(thread, taskThreadName);
-  }
-  return rv;
-}
-
 NS_IMETHODIMP
 CryptoTask::Run()
 {
   if (!NS_IsMainThread()) {
     nsNSSShutDownPreventionLock locker;
     if (isAlreadyShutDown()) {
       mRv = NS_ERROR_NOT_AVAILABLE;
     } else {
@@ -47,16 +36,23 @@ CryptoTask::Run()
     // CryptoTasks have consistent behavior regardless of whether NSS is shut
     // down between CalculateResult being called and CallCallback being called.
     if (!mReleasedNSSResources) {
       mReleasedNSSResources = true;
       ReleaseNSSResources();
     }
 
     CallCallback(mRv);
+
+    // Not all uses of CryptoTask use a transient thread
+    if (mThread) {
+      // Don't leak threads!
+      mThread->Shutdown(); // can't Shutdown from the thread itself, darn
+      mThread = nullptr;
+    }
   }
 
   return NS_OK;
 }
 
 void
 CryptoTask::virtualDestroyNSSReference()
 {
--- a/security/manager/ssl/src/CryptoTask.h
+++ b/security/manager/ssl/src/CryptoTask.h
@@ -34,17 +34,22 @@ class CryptoTask : public nsRunnable,
                    public nsNSSShutDownObject
 {
 public:
   template <size_t LEN>
   nsresult Dispatch(const char (&taskThreadName)[LEN])
   {
     static_assert(LEN <= 15,
                   "Thread name must be no more than 15 characters");
-    return Dispatch(nsDependentCString(taskThreadName));
+    // Can't add 'this' as the event to run, since mThread may not be set yet
+    nsresult rv = NS_NewNamedThread(taskThreadName, getter_AddRefs(mThread));
+    if (NS_SUCCEEDED(rv)) {
+      rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
+    }
+    return rv;
   }
 
 protected:
   CryptoTask()
     : mRv(NS_ERROR_NOT_INITIALIZED),
       mReleasedNSSResources(false)
   {
   }
@@ -71,17 +76,17 @@ protected:
    * be called.
    */
   virtual void CallCallback(nsresult rv) = 0;
 
 private:
   NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL;
   virtual void virtualDestroyNSSReference() MOZ_OVERRIDE MOZ_FINAL;
 
-  nsresult Dispatch(const nsACString & taskThreadName);
-
   nsresult mRv;
   bool mReleasedNSSResources;
+
+  nsCOMPtr<nsIThread> mThread;
 };
 
 } // namespace mozilla
 
 #endif // mozilla__CryptoTask_h
--- a/security/manager/ssl/src/nsCrypto.cpp
+++ b/security/manager/ssl/src/nsCrypto.cpp
@@ -2440,30 +2440,16 @@ nsCrypto::ImportUserCertificates(const n
     CMMF_DestroyCertRepContent(certRepContent);
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
-void
-nsCrypto::PopChallengeResponse(const nsAString& aChallenge,
-                               nsAString& aReturn,
-                               ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
-void
-nsCrypto::Random(int32_t aNumBytes, nsAString& aReturn, ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
 static void
 GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
 {
   // Get the script context.
   nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
   if (!scriptContext) {
     return;
   }
@@ -2826,22 +2812,16 @@ nsCrypto::Logout(ErrorResult& aRv)
   }
 
   rv = nssComponent->LogoutAuthenticatedPK11();
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
-void
-nsCrypto::DisableRightClick(ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
 CRMFObject::CRMFObject()
 {
   MOZ_COUNT_CTOR(CRMFObject);
 }
 
 CRMFObject::~CRMFObject()
 {
   MOZ_COUNT_DTOR(CRMFObject);
--- a/security/manager/ssl/src/nsCrypto.h
+++ b/security/manager/ssl/src/nsCrypto.h
@@ -75,34 +75,24 @@ public:
                       mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual void ImportUserCertificates(const nsAString& aNickname,
                                       const nsAString& aCmmfResponse,
                                       bool aDoForcedBackup,
                                       nsAString& aReturn,
                                       mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual void PopChallengeResponse(const nsAString& aChallenge,
-                                    nsAString& aReturn,
-                                    mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
-
-  virtual void Random(int32_t aNumBytes,
-                      nsAString& aReturn,
-                      mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
-
   virtual void SignText(JSContext* aContext,
                         const nsAString& aStringToSign,
                         const nsAString& aCaOption,
                         const mozilla::dom::Sequence<nsCString>& aArgs,
                         nsAString& aReturn) MOZ_OVERRIDE;
 
   virtual void Logout(mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual void DisableRightClick(mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
-
 private:
   static already_AddRefed<nsIPrincipal> GetScriptPrincipal(JSContext *cx);
 
   bool mEnableSmartCardEvents;
 };
 #endif // MOZ_DISABLE_CRYPTOLEGACY
 
 #include "nsIPKCS11.h"
--- a/testing/config/mozharness/b2g_emulator_config.py
+++ b/testing/config/mozharness/b2g_emulator_config.py
@@ -14,17 +14,17 @@ config = {
     ],
 
     "mochitest_options": [
         "--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--console-level=INFO",
         "--emulator=%(emulator)s", "--logcat-dir=%(logcat_dir)s",
         "--remote-webserver=%(remote_webserver)s", "%(test_manifest)s",
         "--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
         "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
-        "--quiet",
+        "--quiet", "--certificate-path=%(certificate_path)s",
     ],
 
     "reftest_options": [
         "--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
         "--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
         "--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
         "--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
         "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
--- a/toolkit/content/tests/chrome/test_bug437844.xul
+++ b/toolkit/content/tests/chrome/test_bug437844.xul
@@ -32,17 +32,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     </div>
     <pre id="test">
     </pre>
   </body>
 
   <script class="testbody" type="application/javascript">
     <![CDATA[
 
-      SimpleTest.expectAssertions(20);
+      SimpleTest.expectAssertions(20, 21);
 
       /** Test for Bug 437844 and Bug 348233 **/
       SimpleTest.waitForExplicitFinish();
 
       let prefs = Components.classes["@mozilla.org/preferences-service;1"]
                             .getService(Components.interfaces.nsIPrefBranch);
       prefs.setCharPref("intl.uidirection.en-US", "rtl");
 
--- a/toolkit/content/widgets/editor.xml
+++ b/toolkit/content/widgets/editor.xml
@@ -82,16 +82,55 @@
         <parameter name="containingWindow"/>
         <body>
         <![CDATA[
           var editor = this.editingSession.getEditorForWindow(containingWindow);
           return editor.QueryInterface(Components.interfaces.nsIHTMLEditor);
         ]]>
         </body>
       </method>
+
+      <field name="_finder">null</field>
+      <property name="finder" readonly="true">
+        <getter><![CDATA[
+          if (!this._finder) {
+            if (!this.docShell)
+              return null;
+
+            let Finder = Components.utils.import("resource://gre/modules/Finder.jsm", {}).Finder;
+            this._finder = new Finder(this.docShell);
+          }
+          return this._finder;
+        ]]></getter>
+      </property>
+
+      <field name="_fastFind">null</field>
+      <property name="fastFind"
+                readonly="true">
+        <getter>
+        <![CDATA[
+          if (!this._fastFind) {
+            if (!("@mozilla.org/typeaheadfind;1" in Components.classes))
+              return null;
+
+            if (!this.docShell)
+              return null;
+
+            this._fastFind = Components.classes["@mozilla.org/typeaheadfind;1"]
+                                       .createInstance(Components.interfaces.nsITypeAheadFind);
+            this._fastFind.init(this.docShell);
+          }
+          return this._fastFind;
+        ]]>
+        </getter>
+      </property>
+
+      <field name="_lastSearchString">null</field>
+      <field name="_lastSearchHighlight">false</field>
+
       <property name="editortype"
                 onget="return this.getAttribute('editortype');"
                 onset="this.setAttribute('editortype', val); return val;"/>
       <property name="webNavigation"
                 onget="return this.docShell.QueryInterface(Components.interfaces.nsIWebNavigation);"
                 readonly="true"/>
       <property name="contentDocument" readonly="true"
                 onget="return this.webNavigation.document;"/>
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -1550,16 +1550,18 @@
 
             <vbox class="controlsOverlay">
                 <spacer class="controlsSpacer" flex="1"/>
                 <box flex="1" hidden="true">
                     <box class="clickToPlay" hidden="true" flex="1"/>
                 </box>
                 <vbox class="controlBar" hidden="true">
                     <hbox class="buttonsBar">
+                        <button class="castingButton" hidden="true"
+                                aria-label="&castingButton.castingLabel;"/>
                         <button class="fullscreenButton"
                             enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
                             exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
                         <spacer flex="1"/>
                         <button class="playButton"
                                 playlabel="&playButton.playLabel;"
                                 pauselabel="&playButton.pauseLabel;"/>
                         <spacer flex="1"/>
@@ -1589,19 +1591,21 @@
 
     <implementation>
 
         <constructor>
           <![CDATA[
           this.isTouchControl = true;
           this.TouchUtils = {
             videocontrols: null,
-            controlsTimer : null,
-            controlsTimeout : 5000,
+            video: null,
+            controlsTimer: null,
+            controlsTimeout: 5000,
             positionLabel: null,
+            castingButton: null,
 
             get Utils() {
               return this.videocontrols.Utils;
             },
 
             get visible() {
               return !this.Utils.controlBar.hasAttribute("fadeout") &&
                      !(this.Utils.controlBar.getAttribute("hidden") == "true");
@@ -1663,55 +1667,113 @@
 
             },
 
             terminateEventListeners : function () {
               for each (var event in this.videoEvents)
                 this.Utils.video.removeEventListener(event, this, false);
             },
 
+            isVideoCasting : function () {
+              let unwrappedVideo = XPCNativeWrapper.unwrap(this.video);
+              if (unwrappedVideo.mozIsCasting)
+                return true;
+              return false;
+            },
+
+            updateCasting : function (eventDetail) {
+              let unwrappedVideo = XPCNativeWrapper.unwrap(this.video);
+              let castingData = JSON.parse(eventDetail);
+              if ("allow" in castingData) {
+                if (castingData.allow)
+                  unwrappedVideo.mozAllowCasting = true;
+                else
+                  delete unwrappedVideo.mozAllowCasting;
+              }
+
+              if ("active" in castingData) {
+                if (castingData.active)
+                  unwrappedVideo.mozIsCasting = true;
+                else
+                  delete unwrappedVideo.mozIsCasting;
+              }
+              this.setCastButtonState();
+            },
+
+            startCasting : function () {
+              this.videocontrols.dispatchEvent(new CustomEvent("VideoBindingCast"));
+            },
+
+            setCastButtonState : function () {
+              let unwrappedVideo = XPCNativeWrapper.unwrap(this.video);
+              if (this.isAudioOnly || !unwrappedVideo.mozAllowCasting) {
+                this.castingButton.hidden = true;
+                return;
+              }
+
+              if (unwrappedVideo.mozIsCasting) {
+                this.castingButton.setAttribute("active", "true");
+              } else {
+                this.castingButton.removeAttribute("active");
+              }
+
+              this.castingButton.hidden = false;
+            },
+
             init : function (binding) {
               this.videocontrols = binding;
-              var video = binding.parentNode;
+              this.video = binding.parentNode;
 
               let self = this;
               this.Utils.playButton.addEventListener("command", function() {
-                if (!self.Utils.video.paused)
+                if (!self.video.paused)
                     self.delayHideControls(0);
                 else
                     self.showControls();
               }, false);
               this.Utils.scrubber.addEventListener("touchstart", function() {
                 self.clearTimer();
               }, false);
               this.Utils.scrubber.addEventListener("touchend", function() {
                 self.delayHideControls(self.controlsTimeout);
               }, false);
               this.Utils.muteButton.addEventListener("click", function() { self.delayHideControls(self.controlsTimeout); }, false);
 
+              this.castingButton = document.getAnonymousElementByAttribute(binding, "class", "castingButton");
+              this.castingButton.addEventListener("command", function() {
+                self.startCasting();
+              }, false);
+
+              this.video.addEventListener("media-videoCasting", function (e) {
+                if (!e.isTrusted)
+                  return;
+                self.updateCasting(e.detail);
+              }, false, true);
+
               // The first time the controls appear we want to just display
               // a play button that does not fade away. The firstShow property
               // makes that happen. But because of bug 718107 this init() method
               // may be called again when we switch in or out of fullscreen
               // mode. So we only set firstShow if we're not autoplaying and
               // if we are at the beginning of the video and not already playing
-              if (!video.autoplay && this.Utils.dynamicControls && video.paused &&
-                  video.currentTime === 0)
+              if (!this.video.autoplay && this.Utils.dynamicControls && this.video.paused &&
+                  this.video.currentTime === 0)
                 this.firstShow = true;
 
               // If the video is not at the start, then we probably just
               // transitioned into or out of fullscreen mode, and we don't want
               // the controls to remain visible. this.controlsTimeout is a full
               // 5s, which feels too long after the transition.
-              if (video.currentTime !== 0) {
+              if (this.video.currentTime !== 0) {
                 this.delayHideControls(this.Utils.HIDE_CONTROLS_TIMEOUT_MS);
               }
             }
           };
           this.TouchUtils.init(this);
+          this.dispatchEvent(new CustomEvent("VideoBindingAttached"));
       ]]>
       </constructor>
       <destructor>
           <![CDATA[
           // XBL destructors don't appear to be inherited properly, so we need
           // to do this here in addition to the videoControls destructor. :-(
           delete this.randomID;
           ]]>
--- a/toolkit/locales/en-US/chrome/global/videocontrols.dtd
+++ b/toolkit/locales/en-US/chrome/global/videocontrols.dtd
@@ -3,16 +3,17 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY playButton.playLabel "Play">
 <!ENTITY playButton.pauseLabel "Pause">
 <!ENTITY muteButton.muteLabel "Mute">
 <!ENTITY muteButton.unmuteLabel "Unmute">
 <!ENTITY fullscreenButton.enterfullscreenlabel "Full Screen">
 <!ENTITY fullscreenButton.exitfullscreenlabel "Exit Full Screen">
+<!ENTITY castingButton.castingLabel "Cast to Screen">
 
 <!ENTITY stats.media "Media">
 <!ENTITY stats.size "Size">
 <!ENTITY stats.activity "Activity">
 <!ENTITY stats.activityPaused "Paused">
 <!ENTITY stats.activityPlaying "Playing">
 <!ENTITY stats.activityEnded "Ended">
 <!ENTITY stats.activitySeeking "(seeking)">
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -112,20 +112,23 @@ public:
 } // namespace mozilla
 
 inline bool
 AddToCCKind(JSGCTraceKind kind)
 {
   return kind == JSTRACE_OBJECT || kind == JSTRACE_SCRIPT;
 }
 
+static void
+TraceWeakMappingChild(JSTracer* trc, void** thingp, JSGCTraceKind kind);
+
 struct NoteWeakMapChildrenTracer : public JSTracer
 {
-  NoteWeakMapChildrenTracer(nsCycleCollectionNoteRootCallback& cb)
-  : mCb(cb)
+  NoteWeakMapChildrenTracer(JSRuntime *rt, nsCycleCollectionNoteRootCallback& cb)
+  : JSTracer(rt, TraceWeakMappingChild), mCb(cb)
   {
   }
   nsCycleCollectionNoteRootCallback& mCb;
   bool mTracedAny;
   JSObject* mMap;
   void* mKey;
   void* mKeyDelegate;
 };
@@ -153,19 +156,18 @@ TraceWeakMappingChild(JSTracer* trc, voi
     JS_TraceChildren(trc, thing, kind);
   }
 }
 
 struct NoteWeakMapsTracer : public js::WeakMapTracer
 {
   NoteWeakMapsTracer(JSRuntime* rt, js::WeakMapTraceCallback cb,
                      nsCycleCollectionNoteRootCallback& cccb)
-  : js::WeakMapTracer(rt, cb), mCb(cccb), mChildTracer(cccb)
+  : js::WeakMapTracer(rt, cb), mCb(cccb), mChildTracer(rt, cccb)
   {
-    JS_TracerInit(&mChildTracer, rt, TraceWeakMappingChild);
   }
   nsCycleCollectionNoteRootCallback& mCb;
   NoteWeakMapChildrenTracer mChildTracer;
 };
 
 static void
 TraceWeakMapping(js::WeakMapTracer* trc, JSObject* m,
                void* k, JSGCTraceKind kkind,
@@ -354,19 +356,23 @@ JSZoneParticipant::Traverse(void* p, nsC
 
   MOZ_ASSERT(!cb.WantAllTraces());
   JS::Zone* zone = static_cast<JS::Zone*>(p);
 
   runtime->TraverseZone(zone, cb);
   return NS_OK;
 }
 
+static void
+NoteJSChildTracerShim(JSTracer* aTrc, void** aThingp, JSGCTraceKind aTraceKind);
+
 struct TraversalTracer : public JSTracer
 {
-  TraversalTracer(nsCycleCollectionTraversalCallback& aCb) : mCb(aCb)
+  TraversalTracer(JSRuntime *rt, nsCycleCollectionTraversalCallback& aCb)
+    : JSTracer(rt, NoteJSChildTracerShim, DoNotTraceWeakMaps), mCb(aCb)
   {
   }
   nsCycleCollectionTraversalCallback& mCb;
 };
 
 static void
 NoteJSChild(JSTracer* aTrc, void* aThing, JSGCTraceKind aTraceKind)
 {
@@ -380,31 +386,31 @@ NoteJSChild(JSTracer* aTrc, void* aThing
   /*
    * This function needs to be careful to avoid stack overflow. Normally, when
    * AddToCCKind is true, the recursion terminates immediately as we just add
    * |thing| to the CC graph. So overflow is only possible when there are long
    * chains of non-AddToCCKind GC things. Currently, this only can happen via
    * shape parent pointers. The special JSTRACE_SHAPE case below handles
    * parent pointers iteratively, rather than recursively, to avoid overflow.
    */
-if (AddToCCKind(aTraceKind)) {
+  if (AddToCCKind(aTraceKind)) {
     if (MOZ_UNLIKELY(tracer->mCb.WantDebugInfo())) {
-      // based on DumpNotify in jsapi.c
-      if (tracer->debugPrinter) {
+      // based on DumpNotify in jsapi.cpp
+      if (tracer->debugPrinter()) {
         char buffer[200];
-        tracer->debugPrinter(aTrc, buffer, sizeof(buffer));
+        tracer->debugPrinter()(aTrc, buffer, sizeof(buffer));
         tracer->mCb.NoteNextEdgeName(buffer);
-      } else if (tracer->debugPrintIndex != (size_t)-1) {
+      } else if (tracer->debugPrintIndex() != (size_t)-1) {
         char buffer[200];
         JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
-                    static_cast<const char *>(tracer->debugPrintArg),
-                    tracer->debugPrintIndex);
+                    static_cast<const char *>(tracer->debugPrintArg()),
+                    tracer->debugPrintIndex());
         tracer->mCb.NoteNextEdgeName(buffer);
       } else {
-        tracer->mCb.NoteNextEdgeName(static_cast<const char*>(tracer->debugPrintArg));
+        tracer->mCb.NoteNextEdgeName(static_cast<const char*>(tracer->debugPrintArg()));
       }
     }
     tracer->mCb.NoteJSChild(aThing);
   } else if (aTraceKind == JSTRACE_SHAPE) {
     JS_TraceShapeCycleCollectorChildren(aTrc, aThing);
   } else if (aTraceKind != JSTRACE_STRING) {
     JS_TraceChildren(aTrc, aThing, aTraceKind);
   }
@@ -571,19 +577,17 @@ CycleCollectedJSRuntime::DescribeGCThing
 }
 
 void
 CycleCollectedJSRuntime::NoteGCThingJSChildren(void* aThing,
                                                JSGCTraceKind aTraceKind,
                                                nsCycleCollectionTraversalCallback& aCb) const
 {
   MOZ_ASSERT(mJSRuntime);
-  TraversalTracer trc(aCb);
-  JS_TracerInit(&trc, mJSRuntime, NoteJSChildTracerShim);
-  trc.eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
+  TraversalTracer trc(mJSRuntime, aCb);
   JS_TraceChildren(&trc, aThing, aTraceKind);
 }
 
 void
 CycleCollectedJSRuntime::NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
                                                   nsCycleCollectionTraversalCallback& aCb) const
 {
   MOZ_ASSERT(aClasp);
@@ -667,19 +671,17 @@ CycleCollectedJSRuntime::TraverseZone(JS
   /*
    * Every JS child of everything in the zone is either in the zone
    * or is a cross-compartment wrapper. In the former case, we don't need to
    * represent these edges in the CC graph because JS objects are not ref counted.
    * In the latter case, the JS engine keeps a map of these wrappers, which we
    * iterate over. Edges between compartments in the same zone will add
    * unnecessary loop edges to the graph (bug 842137).
    */
-  TraversalTracer trc(aCb);
-  JS_TracerInit(&trc, mJSRuntime, NoteJSChildTracerShim);
-  trc.eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
+  TraversalTracer trc(mJSRuntime, aCb);
   js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc);
 
   /*
    * To find C++ children of things in the zone, we scan every JS Object in
    * the zone. Only JS Objects can have C++ children.
    */
   TraverseObjectShimClosure closure = { aCb, this };
   js::IterateGrayObjects(aZone, TraverseObjectShim, &closure);
--- a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
+++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
@@ -10,17 +10,17 @@
  * implemented for nsTArrays that contain JavaScript Values.
  */
 
 #include "jsapi.h"
 #include "nsTArray.h"
 
 #include "gtest/gtest.h"
 
-#include "js/Tracer.h"
+#include "js/TracingAPI.h"
 #include "js/HeapAPI.h"
 
 #include "mozilla/CycleCollectedJSRuntime.h"
 
 using namespace JS;
 using namespace mozilla;
 
 template <class ArrayT>