Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 23 Apr 2014 15:04:22 +0200
changeset 180174 07d2ac9298f788a5512a94d14892e96f98dd48ae
parent 180173 18c0f7152372bd81141e07a4a25a4c7efcf0862c (current diff)
parent 180148 b79c2995d25e5e2ed11ba1706a42a62ee07d35f3 (diff)
child 180175 aeb23b70637031829a4c7af6aed78d12ba851216
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-c to fx-team
toolkit/mozapps/extensions/content/extensions.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -596,16 +596,22 @@ pref("dom.forms.number", true);
 
 // Don't enable <input type=color> yet as we don't have a color picker
 // implemented for b2g (bug 875751)
 pref("dom.forms.color", false);
 
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
 
+// This preference instructs the JS engine to discard the
+// source of any privileged JS after compilation. This saves
+// memory, but makes things like Function.prototype.toSource()
+// fail.
+pref("javascript.options.discardSystemSource", true);
+
 // XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
 pref("javascript.options.mem.log", false);
 
 // Increase mark slice time from 10ms to 30ms
 pref("javascript.options.mem.gc_incremental_slice_ms", 30);
 
 // Increase time to get more high frequency GC on benchmarks from 1000ms to 1500ms
 pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1500);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -141,16 +141,17 @@ Components.utils.import('resource://gre/
   // from configure.in, defaults to 1.0.0 if this value is not exist.
 #filter attemptSubstitution
   let os_version = '@MOZ_B2G_VERSION@';
   let os_name = '@MOZ_B2G_OS_NAME@';
 #unfilter attemptSubstitution
 
   let appInfo = Cc["@mozilla.org/xre/app-info;1"]
                   .getService(Ci.nsIXULAppInfo);
+  let update_channel = Services.prefs.getCharPref('app.update.channel');
 
   // Get the hardware info and firmware revision from device properties.
   let hardware_info = null;
   let firmware_revision = null;
   let product_model = null;
 #ifdef MOZ_WIDGET_GONK
     hardware_info = libcutils.property_get('ro.hardware');
     firmware_revision = libcutils.property_get('ro.firmware_revision');
@@ -158,16 +159,17 @@ Components.utils.import('resource://gre/
 #endif
 
   let software = os_name + ' ' + os_version;
   let setting = {
     'deviceinfo.os': os_version,
     'deviceinfo.software': software,
     'deviceinfo.platform_version': appInfo.platformVersion,
     'deviceinfo.platform_build_id': appInfo.platformBuildID,
+    'deviceinfo.update_channel': update_channel,
     'deviceinfo.hardware': hardware_info,
     'deviceinfo.firmware_revision': firmware_revision,
     'deviceinfo.product_model': product_model
   }
   window.navigator.mozSettings.createLock().set(setting);
 })();
 
 // =================== DevTools ====================
@@ -539,17 +541,16 @@ function setUpdateTrackingId() {
       Services.prefs.setCharPref('app.update.custom', trackingId);
     }
   } catch(e) {
     dump('Error getting tracking ID ' + e + '\n');
   }
 }
 setUpdateTrackingId();
 
-
 // ================ Debug ================
 (function Composer2DSettingToPref() {
   //layers.composer.enabled can be enabled in three ways
   //In order of precedence they are:
   //
   //1. mozSettings "layers.composer.enabled"
   //2. a gecko pref "layers.composer.enabled"
   //3. presence of ro.display.colorfill at the Gonk level
@@ -674,71 +675,48 @@ let settingsToObserve = {
     defaultValue: false
   },
   'debug.paint-flashing.enabled': {
     prefName: 'nglayout.debug.paint_flashing',
     defaultValue: false
   },
   'layers.draw-borders': false,
   'app.update.interval': 86400,
-  'app.update.url': {
-    resetToPref: true
-  },
-  'app.update.channel': {
-    resetToPref: true
-  },
   'debug.log-animations.enabled': {
     prefName: 'layers.offmainthreadcomposition.log-animations',
     defaultValue: false
   }
 };
 
 for (let key in settingsToObserve) {
   let setting = settingsToObserve[key];
 
-  // Allow setting to contain flags redefining prefName and defaultValue.
-  let prefName = setting.prefName || key;
-  let defaultValue = setting.defaultValue || setting;
-
-  let prefs = Services.prefs;
-
-  // If requested, reset setting value and defaultValue to the pref value.
-  if (setting.resetToPref) {
-    switch (prefs.getPrefType(prefName)) {
-      case Ci.nsIPrefBranch.PREF_BOOL:
-        defaultValue = prefs.getBoolPref(prefName);
-        break;
+  // By default, assume the setting name and the pref name are the same.
+  let prefName = key;
+  let defaultValue = setting;
 
-      case Ci.nsIPrefBranch.PREF_INT:
-        defaultValue = prefs.getIntPref(prefName);
-        break;
-
-      case Ci.nsIPrefBranch.PREF_STRING:
-        defaultValue = prefs.getCharPref(prefName);
-        break;
-    }
-
-    let setting = {};
-    setting[key] = defaultValue;
-    window.navigator.mozSettings.createLock().set(setting);
+  // Check if the pref name has been overidden.
+  if (typeof setting == 'object') {
+    prefName = setting.prefName;
+    defaultValue = setting.defaultValue;
   }
 
-  // Figure out the right setter function for this type of pref.
-  let setPref;
-  switch(typeof defaultValue) {
+  switch (typeof defaultValue) {
     case 'boolean':
-      setPref = prefs.setBoolPref.bind(prefs);
+      SettingsListener.observe(key, defaultValue, function(value) {
+        Services.prefs.setBoolPref(prefName, value);
+      });
+      break;
+
+    case 'string':
+      SettingsListener.observe(key, defaultValue, function(value) {
+        Services.prefs.setCharPref(prefName, value);
+      });
       break;
 
     case 'number':
-      setPref = prefs.setIntPref.bind(prefs);
-      break;
-
-    case 'string':
-      setPref = prefs.setCharPref.bind(prefs);
+      SettingsListener.observe(key, defaultValue, function(value) {
+        Services.prefs.setIntPref(prefName, value);
+      });
       break;
   }
-
-  SettingsListener.observe(key, defaultValue, function(value) {
-    setPref(prefName, value);
-  });
 };
 
--- 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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="85f9690323b235f4dcf2901ea2240d3c60fc22a0"/>
   <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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"/>
--- 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="65fba428f8d76336b33ddd9e15900357953600ba">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="85f9690323b235f4dcf2901ea2240d3c60fc22a0"/>
   <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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": "b693850589c0660403571fa2af7a7edae3d89f31", 
+    "revision": "53a228b0c1d211dea4d99cba0ebc027bdb3feafc", 
     "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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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"/>
--- 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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d8904c5af6152f5d647a93a0c31227171ddecd87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33b5bcb1a092172c983ef178766869aba738ad4d"/>
   <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/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -74,24 +74,18 @@ this.__defineGetter__("AddonManager", fu
   Cu.import("resource://gre/modules/AddonManager.jsm", tmp);
   return this.AddonManager = tmp.AddonManager;
 });
 this.__defineSetter__("AddonManager", function (val) {
   delete this.AddonManager;
   return this.AddonManager = val;
 });
 
-this.__defineGetter__("PluralForm", function() {
-  Cu.import("resource://gre/modules/PluralForm.jsm");
-  return this.PluralForm;
-});
-this.__defineSetter__("PluralForm", function (val) {
-  delete this.PluralForm;
-  return this.PluralForm = val;
-});
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+  "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
   "resource://gre/modules/TelemetryStopwatch.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gCustomizeMode", function() {
   let scope = {};
   Cu.import("resource:///modules/CustomizeMode.jsm", scope);
   return new scope.CustomizeMode(window);
--- a/browser/components/preferences/aboutPermissions.js
+++ b/browser/components/preferences/aboutPermissions.js
@@ -1,22 +1,25 @@
 /* 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/. */
 
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 let Cu = Components.utils;
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/ForgetAboutSite.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
 let gFaviconService = Cc["@mozilla.org/browser/favicon-service;1"].
                       getService(Ci.nsIFaviconService);
 
 let gPlacesDatabase = Cc["@mozilla.org/browser/nav-history-service;1"].
                       getService(Ci.nsPIPlacesDatabase).
                       DBConnection.
                       clone(true);
 
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -6,28 +6,31 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["StyleEditorUI"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 Cu.import("resource:///modules/devtools/SplitView.jsm");
 Cu.import("resource:///modules/devtools/StyleSheetEditor.jsm");
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const { PrefObserver, PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils");
 
 const LOAD_ERROR = "error-load";
 const STYLE_EDITOR_TEMPLATE = "stylesheet";
 
 /**
  * StyleEditorUI is controls and builds the UI of the Style Editor, including
--- a/browser/devtools/styleinspector/computed-view.js
+++ b/browser/devtools/styleinspector/computed-view.js
@@ -12,20 +12,22 @@ const {ELEMENT_STYLE} = require("devtool
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const {EventEmitter} = require("devtools/toolkit/event-emitter");
 const {OutputParser} = require("devtools/output-parser");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/styleeditor/utils");
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/devtools/Templater.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
 const FILTER_CHANGED_TIMEOUT = 300;
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
  * Helper for long-running processes that should yield occasionally to
  * the mainloop.
  *
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -6,19 +6,21 @@
 
 this.EXPORTED_SYMBOLS = ["webrtcUI"];
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
 XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService",
                                    "@mozilla.org/mediaManagerService;1",
                                    "nsIMediaManagerService");
 
 this.webrtcUI = {
   init: function () {
     Services.obs.addObserver(handleRequest, "getUserMedia:request", false);
     Services.obs.addObserver(updateIndicators, "recording-device-events", false);
--- a/config/system-headers
+++ b/config/system-headers
@@ -1042,18 +1042,16 @@ X11/Xft/Xft.h
 X11/Xfuncproto.h
 X11/X.h
 X11/XKBlib.h
 X11/Xlib.h
 X11/Xlibint.h
 X11/Xlocale.h
 X11/Xos.h
 X11/Xutil.h
-xpt_struct.h
-xpt_xdr.h
 zmouse.h
 speex/speex_resampler.h
 soundtouch/SoundTouch.h
 #if MOZ_NATIVE_PNG==1
 png.h
 #endif
 #if MOZ_NATIVE_ZLIB==1
 zlib.h
--- a/content/base/public/nsDeprecatedOperationList.h
+++ b/content/base/public/nsDeprecatedOperationList.h
@@ -34,8 +34,9 @@ DEPRECATED_OPERATION(GetSetUserData)
 DEPRECATED_OPERATION(MozGetAsFile)
 DEPRECATED_OPERATION(UseOfCaptureEvents)
 DEPRECATED_OPERATION(UseOfReleaseEvents)
 DEPRECATED_OPERATION(UseOfDOM3LoadMethod)
 DEPRECATED_OPERATION(ShowModalDialog)
 DEPRECATED_OPERATION(Window_Content)
 DEPRECATED_OPERATION(SyncXMLHttpRequest)
 DEPRECATED_OPERATION(DataContainerEvent)
+DEPRECATED_OPERATION(SendAsBinary)
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2256,16 +2256,20 @@ nsXMLHttpRequest::SendAsBinary(const nsA
                                ErrorResult& aRv)
 {
   char *data = static_cast<char*>(NS_Alloc(aBody.Length() + 1));
   if (!data) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
+  if (GetOwner() && GetOwner()->GetExtantDoc()) {
+    GetOwner()->GetExtantDoc()->WarnOnceAbout(nsIDocument::eSendAsBinary);
+  }
+
   nsAString::const_iterator iter, end;
   aBody.BeginReading(iter);
   aBody.EndReading(end);
   char *p = data;
   while (iter != end) {
     if (*iter & 0xFF00) {
       NS_Free(data);
       aRv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -214,21 +214,19 @@ support-files =
   somedatas.resource
   somedatas.resource^headers^
   variable_style_sheet.sjs
   viewport_helpers.js
   w3element_traversal.svg
   wholeTexty-helper.xml
 
 [test_CrossSiteXHR.html]
-skip-if = toolkit == 'android'
 [test_CrossSiteXHR_cache.html]
-skip-if = toolkit == 'android'
 [test_CrossSiteXHR_origin.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(https not working, bug 907770) b2g-debug(https not working, bug 907770) b2g-desktop(https not working, bug 907770)
+skip-if = buildapp == 'b2g' || e10s # last test fails to trigger onload on e10s/b2g
 [test_DOMException.html]
 [test_EventSource_redirects.html]
 [test_NodeIterator_basics_filters.xhtml]
 [test_NodeIterator_mutations_1.xhtml]
 [test_NodeIterator_mutations_2.html]
 [test_NodeIterator_mutations_3.html]
 [test_XHR.html]
 [test_XHRDocURI.html]
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -622,16 +622,30 @@ bool OmxDecoder::SetVideoFormat() {
     NS_WARNING("stride not available, assuming width");
   }
 
   if (!mVideoSource->getFormat()->findInt32(kKeySliceHeight, &mVideoSliceHeight)) {
     mVideoSliceHeight = mVideoHeight;
     NS_WARNING("slice height not available, assuming height");
   }
 
+  // Since ICS, valid video side is caluculated from kKeyCropRect.
+  // kKeyWidth means decoded video buffer width.
+  // kKeyHeight means decoded video buffer height.
+  // On some hardwares, decoded video buffer and valid video size are different.
+  int32_t crop_left, crop_top, crop_right, crop_bottom;
+  if (mVideoSource->getFormat()->findRect(kKeyCropRect,
+                                          &crop_left,
+                                          &crop_top,
+                                          &crop_right,
+                                          &crop_bottom)) {
+    mVideoWidth = crop_right - crop_left + 1;
+    mVideoHeight = crop_bottom - crop_top + 1;
+  }
+
   if (!mVideoSource->getFormat()->findInt32(kKeyRotation, &mVideoRotation)) {
     mVideoRotation = 0;
     NS_WARNING("rotation not available, assuming 0");
   }
 
   LOG(PR_LOG_DEBUG, "display width: %d display height %d width: %d height: %d component: %s format: %d stride: %d sliceHeight: %d rotation: %d",
       mDisplayWidth, mDisplayHeight, mVideoWidth, mVideoHeight, componentName,
       mVideoColorFormat, mVideoStride, mVideoSliceHeight, mVideoRotation);
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2640,18 +2640,17 @@ nsXULPrototypeScript::Compile(const char
     NS_ENSURE_TRUE(JSVersion(mLangVersion) != JSVERSION_UNKNOWN, NS_OK);
     JS::CompileOptions options(cx);
     options.setIntroductionType("scriptElement")
            .setFileAndLine(urlspec.get(), aLineNo)
            .setVersion(JSVersion(mLangVersion));
     // If the script was inline, tell the JS parser to save source for
     // Function.prototype.toSource(). If it's out of line, we retrieve the
     // source from the files on demand.
-    options.setSourcePolicy(mOutOfLine ? JS::CompileOptions::LAZY_SOURCE
-                                       : JS::CompileOptions::SAVE_SOURCE);
+    options.setSourceIsLazy(mOutOfLine);
     JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
     if (scope) {
       JS::ExposeObjectToActiveJS(scope);
     }
 
     if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options, aTextLength)) {
         if (!JS::CompileOffThread(cx, options,
                                   static_cast<const jschar*>(aText), aTextLength,
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -116,17 +116,20 @@ public:
                     uint64_t aPictureSize, uint64_t aVideosSize,
                     uint64_t aMusicSize, uint64_t aTotalSize);
 
 private:
   friend class InvalidateRunnable;
 
   struct CacheEntry
   {
-    NS_INLINE_DECL_REFCOUNTING(DeviceStorageUsedSpaceCache::CacheEntry)
+    // Technically, this doesn't need to be threadsafe, but the implementation
+    // of the non-thread safe one causes ASSERTS due to the underlying thread
+    // associated with a LazyIdleThread changing from time to time.
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceStorageUsedSpaceCache::CacheEntry)
 
     bool mDirty;
     nsString mStorageName;
     int64_t  mFreeBytes;
     uint64_t mPicturesUsedSize;
     uint64_t mVideosUsedSize;
     uint64_t mMusicUsedSize;
     uint64_t mTotalUsedSize;
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3529,44 +3529,46 @@ EventStateManager::DispatchMouseOrPointe
       NS_WARNING("Should have pointer locked element, but didn't.");
       return nullptr;
     }
     nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
     return mPresContext->GetPrimaryFrameFor(content);
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
-  nsAutoPtr<WidgetPointerEvent> newPointerEvent;
-  nsAutoPtr<WidgetMouseEvent> newMouseEvent;
-  WidgetMouseEvent* event = nullptr;
+  nsAutoPtr<WidgetMouseEvent> event;
   WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
   if (sourcePointer) {
     PROFILER_LABEL("Input", "DispatchPointerEvent");
+    nsAutoPtr<WidgetPointerEvent> newPointerEvent;
     newPointerEvent =
       new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
                              aMouseEvent->widget);
     newPointerEvent->isPrimary = sourcePointer->isPrimary;
     newPointerEvent->pointerId = sourcePointer->pointerId;
     newPointerEvent->width = sourcePointer->width;
     newPointerEvent->height = sourcePointer->height;
     newPointerEvent->inputSource = sourcePointer->inputSource;
-    event = newPointerEvent.get();
+    newPointerEvent->relatedTarget = nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
+                                       ? nullptr
+                                       : aRelatedContent;
+    event = newPointerEvent.forget();
   } else {
     PROFILER_LABEL("Input", "DispatchMouseEvent");
-    newMouseEvent =
+    event =
       new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
                            aMouseEvent->widget, WidgetMouseEvent::eReal);
-    event = newMouseEvent.get();
+    event->relatedTarget = aRelatedContent;
   }
   event->refPoint = aMouseEvent->refPoint;
   event->modifiers = aMouseEvent->modifiers;
   event->button = aMouseEvent->button;
   event->buttons = aMouseEvent->buttons;
+  event->pressure = aMouseEvent->pressure;
   event->pluginEvent = aMouseEvent->pluginEvent;
-  event->relatedTarget = aRelatedContent;
   event->inputSource = aMouseEvent->inputSource;
 
   nsWeakFrame previousTarget = mCurrentTarget;
 
   mCurrentTargetContent = aTargetContent;
 
   nsIFrame* targetFrame = nullptr;
   if (aTargetContent) {
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -128,36 +128,43 @@ FilePickerParent::SendFiles(const nsCOMA
   unused << Send__delete__(this, infiles, mResult);
 }
 
 void
 FilePickerParent::Done(int16_t aResult)
 {
   mResult = aResult;
 
+  if (mResult != nsIFilePicker::returnOK) {
+    unused << Send__delete__(this, void_t(), mResult);
+    return;
+  }
+
   nsCOMArray<nsIDOMFile> domfiles;
-
   if (mMode == nsIFilePicker::modeOpenMultiple) {
     nsCOMPtr<nsISimpleEnumerator> iter;
     NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
 
     nsCOMPtr<nsISupports> supports;
-    nsCOMPtr<nsIFile> file;
     bool loop = true;
     while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
       iter->GetNext(getter_AddRefs(supports));
-      file = do_QueryInterface(supports);
-      nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
-      domfiles.AppendElement(domfile);
+      if (supports) {
+        nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
+        nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
+        domfiles.AppendElement(domfile);
+      }
     }
   } else {
     nsCOMPtr<nsIFile> file;
     mFilePicker->GetFile(getter_AddRefs(file));
-    nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
-    domfiles.AppendElement(domfile);
+    if (file) {
+      nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
+      domfiles.AppendElement(domfile);
+    }
   }
 
   MOZ_ASSERT(!mRunnable);
   mRunnable = new FileSizeAndDateRunnable(this, domfiles);
   if (!mRunnable->Dispatch()) {
     unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
   }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -113,16 +113,23 @@ static TabChildMap* sTabChildren;
 TabChildBase::TabChildBase()
   : mOldViewportWidth(0.0f)
   , mContentDocumentIsDisplayed(false)
   , mTabChildGlobal(nullptr)
   , mInnerSize(0, 0)
 {
 }
 
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChildBase)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_2(TabChildBase, mTabChildGlobal, mGlobal)
+
 void
 TabChildBase::InitializeRootMetrics()
 {
   // Calculate a really simple resolution that we probably won't
   // be keeping, as well as putting the scroll offset back to
   // the top-left of the page.
   mLastRootMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
   mLastRootMetrics.mCompositionBounds = ParentLayerIntRect(
@@ -1348,25 +1355,16 @@ TabChild::ActorDestroy(ActorDestroyReaso
 TabChild::~TabChild()
 {
     DestroyWindow();
 
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
     if (webBrowser) {
       webBrowser->SetContainerWindow(nullptr);
     }
-    mGlobal = nullptr;
-
-    if (mTabChildGlobal) {
-      EventListenerManager* elm = mTabChildGlobal->GetExistingListenerManager();
-      if (elm) {
-        elm->Disconnect();
-      }
-      mTabChildGlobal->mTabChild = nullptr;
-    }
 }
 
 void
 TabChild::SetProcessNameToAppName()
 {
   nsCOMPtr<mozIApplication> app = GetOwnApp();
   if (!app) {
     return;
@@ -2717,18 +2715,18 @@ void
 TabChildGlobal::Init()
 {
   NS_ASSERTION(!mMessageManager, "Re-initializing?!?");
   mMessageManager = new nsFrameMessageManager(mTabChild,
                                               nullptr,
                                               MM_CHILD);
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED_1(TabChildGlobal, DOMEventTargetHelper,
-                                     mMessageManager)
+NS_IMPL_CYCLE_COLLECTION_INHERITED_2(TabChildGlobal, DOMEventTargetHelper,
+                                     mMessageManager, mTabChild)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChildGlobal)
   NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)
   NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
   NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
   NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
   NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
   NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -133,38 +133,41 @@ public:
     return NS_OK;
   }
 
   virtual JSContext* GetJSContextForEventHandlers() MOZ_OVERRIDE;
   virtual nsIPrincipal* GetPrincipal() MOZ_OVERRIDE;
   virtual JSObject* GetGlobalJSObject() MOZ_OVERRIDE;
 
   nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
-  TabChildBase* mTabChild;
+  nsRefPtr<TabChildBase> mTabChild;
 };
 
 class ContentListener MOZ_FINAL : public nsIDOMEventListener
 {
 public:
   ContentListener(TabChild* aTabChild) : mTabChild(aTabChild) {}
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 protected:
   TabChild* mTabChild;
 };
 
 // This is base clase which helps to share Viewport and touch related functionality
 // between b2g/android FF/embedlite clients implementation.
 // It make sense to place in this class all helper functions, and functionality which could be shared between
 // Cross-process/Cross-thread implmentations.
-class TabChildBase : public nsFrameScriptExecutor,
+class TabChildBase : public nsISupports,
+                     public nsFrameScriptExecutor,
                      public ipc::MessageManagerCallback
 {
 public:
     TabChildBase();
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(TabChildBase)
 
     virtual nsIWebNavigation* WebNavigation() = 0;
     virtual nsIWidget* WebWidget() = 0;
     nsIPrincipal* GetPrincipal() { return mPrincipal; }
     bool IsAsyncPanZoomEnabled();
     // Recalculates the display state, including the CSS
     // viewport. This should be called whenever we believe the
     // viewport data on a document may have changed. If it didn't
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -141,8 +141,10 @@ UseOfDOM3LoadMethodWarning=Use of docume
 ShowModalDialogWarning=Use of window.showModalDialog() is deprecated. Use window.open() instead. For more help https://developer.mozilla.org/en-US/docs/Web/API/Window.open
 # LOCALIZATION NOTE: Do not translate "window._content" or "window.content"
 Window_ContentWarning=window._content is deprecated.  Please use window.content instead.
 # LOCALIZATION NOTE: Do not translate "XMLHttpRequest"
 SyncXMLHttpRequestWarning=Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help http://xhr.spec.whatwg.org/
 ImplicitMetaViewportTagFallback=No meta-viewport tag found. Please explicitly specify one to prevent unexpected behavioural changes in future versions. For more help https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
 # LOCALIZATION NOTE: Do not translate "DataContainerEvent" or "CustomEvent"
 DataContainerEventWarning=Use of DataContainerEvent is deprecated. Use CustomEvent instead.
+# LOCALIZATION NOTE: Do not translate "sendAsBinary" or "send(Blob data)"
+SendAsBinaryWarning=The non-standard sendAsBinary method is deprecated and will soon be removed. Use the standard send(Blob data) method instead.
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -345,17 +345,17 @@ RTCPeerConnection.prototype = {
           "RTCPeerConnection is gone (did you enter Offline mode?)");
     }
     return this._pc;
   },
 
   _initIdp: function() {
     let prefName = "media.peerconnection.identity.timeout";
     let idpTimeout = Services.prefs.getIntPref(prefName);
-    let warningFunc = this.reportWarning.bind(this);
+    let warningFunc = this.logWarning.bind(this);
     this._localIdp = new PeerConnectionIdp(this._win, idpTimeout, warningFunc,
                                            this.dispatchEvent.bind(this));
     this._remoteIdp = new PeerConnectionIdp(this._win, idpTimeout, warningFunc,
                                             this.dispatchEvent.bind(this));
   },
 
   /**
    * Add a function to the queue or run it immediately if the queue is empty.
@@ -495,51 +495,48 @@ RTCPeerConnection.prototype = {
     }
   },
 
   dispatchEvent: function(event) {
     this.__DOM_IMPL__.dispatchEvent(event);
   },
 
   // Log error message to web console and window.onerror, if present.
-  reportError: function(msg, file, line) {
-    this.reportMsg(msg, file, line, Ci.nsIScriptError.exceptionFlag);
+  logErrorAndCallOnError: function(msg, file, line) {
+    this.logMsg(msg, file, line, Ci.nsIScriptError.exceptionFlag);
+
+    // Safely call onerror directly if present (necessary for testing)
+    try {
+      if (typeof this._win.onerror === "function") {
+        this._win.onerror(msg, file, line);
+      }
+    } catch(e) {
+      // If onerror itself throws, service it.
+      try {
+        this.logError(e.message, e.fileName, e.lineNumber);
+      } catch(e) {}
+    }
   },
 
-  reportWarning: function(msg, file, line) {
-    this.reportMsg(msg, file, line, Ci.nsIScriptError.warningFlag);
+  logError: function(msg, file, line) {
+    this.logMsg(msg, file, line, Ci.nsIScriptError.errorFlag);
   },
 
-  reportMsg: function(msg, file, line, flag) {
+  logWarning: function(msg, file, line) {
+    this.logMsg(msg, file, line, Ci.nsIScriptError.warningFlag);
+  },
+
+  logMsg: function(msg, file, line, flag) {
     let scriptErrorClass = Cc["@mozilla.org/scripterror;1"];
     let scriptError = scriptErrorClass.createInstance(Ci.nsIScriptError);
     scriptError.initWithWindowID(msg, file, null, line, 0, flag,
                                  "content javascript", this._winID);
     let console = Cc["@mozilla.org/consoleservice;1"].
       getService(Ci.nsIConsoleService);
     console.logMessage(scriptError);
-
-    if (flag != Ci.nsIScriptError.warningFlag) {
-      // Safely call onerror directly if present (necessary for testing)
-      try {
-        if (typeof this._win.onerror === "function") {
-          this._win.onerror(msg, file, line);
-        }
-      } catch(e) {
-        // If onerror itself throws, service it.
-        try {
-          let scriptError = scriptErrorClass.createInstance(Ci.nsIScriptError);
-          scriptError.initWithWindowID(e.message, e.fileName, null, e.lineNumber,
-                                       0, Ci.nsIScriptError.exceptionFlag,
-                                       "content javascript",
-                                       this._winID);
-          console.logMessage(scriptError);
-        } catch(e) {}
-      }
-    }
   },
 
   getEH: function(type) {
     return this.__DOM_IMPL__.getEventHandler(type);
   },
 
   setEH: function(type, handler) {
     this.__DOM_IMPL__.setEventHandler(type, handler);
@@ -658,17 +655,17 @@ RTCPeerConnection.prototype = {
         throw new this._win.DOMError("",
             "Invalid type " + desc.type + " provided to setRemoteDescription");
     }
 
     try {
       let processIdentity = this._processIdentity.bind(this);
       this._remoteIdp.verifyIdentityFromSDP(desc.sdp, processIdentity);
     } catch (e) {
-      this.reportWarning(e.message, e.fileName, e.lineNumber);
+      this.logWarning(e.message, e.fileName, e.lineNumber);
       // only happens if processing the SDP for identity doesn't work
       // let _setRemoteDescription do the error reporting
     }
 
     this._queueOrRun({
       func: this._setRemoteDescription,
       args: [type, desc.sdp, onSuccess, onError],
       wait: true,
@@ -858,30 +855,30 @@ RTCPeerConnection.prototype = {
 
   createDataChannel: function(label, dict) {
     this._checkClosed();
     if (dict == undefined) {
       dict = {};
     }
     if (dict.maxRetransmitNum != undefined) {
       dict.maxRetransmits = dict.maxRetransmitNum;
-      this.reportWarning("Deprecated RTCDataChannelInit dictionary entry maxRetransmitNum used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry maxRetransmitNum used!", null, 0);
     }
     if (dict.outOfOrderAllowed != undefined) {
       dict.ordered = !dict.outOfOrderAllowed; // the meaning is swapped with
                                               // the name change
-      this.reportWarning("Deprecated RTCDataChannelInit dictionary entry outOfOrderAllowed used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry outOfOrderAllowed used!", null, 0);
     }
     if (dict.preset != undefined) {
       dict.negotiated = dict.preset;
-      this.reportWarning("Deprecated RTCDataChannelInit dictionary entry preset used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry preset used!", null, 0);
     }
     if (dict.stream != undefined) {
       dict.id = dict.stream;
-      this.reportWarning("Deprecated RTCDataChannelInit dictionary entry stream used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry stream used!", null, 0);
     }
 
     if (dict.maxRetransmitTime != undefined &&
         dict.maxRetransmits != undefined) {
       throw new this._win.DOMError("",
           "Both maxRetransmitTime and maxRetransmits cannot be provided");
     }
     let protocol;
@@ -970,17 +967,19 @@ PeerConnectionObserver.prototype = {
   callCB: function(callback, arg) {
     if (callback) {
       try {
         callback(arg);
       } catch(e) {
         // A content script (user-provided) callback threw an error. We don't
         // want this to take down peerconnection, but we still want the user
         // to see it, so we catch it, report it, and move on.
-        this._dompc.reportError(e.message, e.fileName, e.lineNumber);
+        this._dompc.logErrorAndCallOnError(e.message,
+                                           e.fileName,
+                                           e.lineNumber);
       }
     }
   },
 
   onCreateOfferSuccess: function(sdp) {
     let pc = this._dompc;
     let fp = pc._impl.fingerprint;
     pc._localIdp.appendIdentityToSDP(sdp, fp, function(sdp, assertion) {
@@ -1111,16 +1110,17 @@ PeerConnectionObserver.prototype = {
   //   closed        The ICE Agent has shut down and is no longer responding to
   //                 STUN requests.
 
   handleIceConnectionStateChange: function(iceConnectionState) {
     var histogram = Services.telemetry.getHistogramById("WEBRTC_ICE_SUCCESS_RATE");
 
     if (iceConnectionState === 'failed') {
       histogram.add(false);
+      this._dompc.logError("ICE failed, see about:webrtc for more details", null, 0);
     }
     if (this._dompc.iceConnectionState === 'checking' &&
         (iceConnectionState === 'completed' ||
          iceConnectionState === 'connected')) {
           histogram.add(true);
     }
     this._dompc.changeIceConnectionState(iceConnectionState);
   },
@@ -1181,17 +1181,17 @@ PeerConnectionObserver.prototype = {
         // No-op
         break;
 
       case "SipccState":
         // No-op
         break;
 
       default:
-        this._dompc.reportWarning("Unhandled state type: " + state, null, 0);
+        this._dompc.logWarning("Unhandled state type: " + state, null, 0);
         break;
     }
   },
 
   onGetStatsSuccess: function(dict) {
     let chromeobj = new RTCStatsReport(this._dompc._win, dict);
     let webidlobj = this._dompc._win.RTCStatsReport._create(this._dompc._win,
                                                             chromeobj);
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -114,20 +114,20 @@ public:
       sPluginContext->fGenTextures(1, &mTextureInfo.mTexture);
     }
 
     mLock.Lock();
     return mTextureInfo;
   }
 
   void Release(nsNPAPIPluginInstance::TextureInfo& aTextureInfo)
-  { 
+  {
     mTextureInfo = aTextureInfo;
     mLock.Unlock();
-  } 
+  }
 
   SharedTextureHandle CreateSharedHandle()
   {
     MutexAutoLock lock(mLock);
 
     if (!EnsureGLContext())
       return 0;
 
@@ -139,28 +139,28 @@ public:
                              gl::SharedTextureShareType::SameProcess,
                              (void*)mTextureInfo.mTexture,
                              gl::SharedTextureBufferType::TextureID);
 
     // We want forget about this now, so delete the texture. Assigning it to zero
     // ensures that we create a new one in Lock()
     sPluginContext->fDeleteTextures(1, &mTextureInfo.mTexture);
     mTextureInfo.mTexture = 0;
-    
+
     return handle;
   }
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~SharedPluginTexture()
   {
   }
 
   nsNPAPIPluginInstance::TextureInfo mTextureInfo;
- 
+
   Mutex mLock;
 };
 
 static std::map<NPP, nsNPAPIPluginInstance*> sPluginNPPMap;
 
 #endif
 
 using namespace mozilla;
@@ -226,17 +226,17 @@ void
 nsNPAPIPluginInstance::Destroy()
 {
   Stop();
   mPlugin = nullptr;
 
 #if MOZ_WIDGET_ANDROID
   if (mContentSurface)
     mContentSurface->SetFrameAvailableCallback(nullptr);
-  
+
   mContentTexture = nullptr;
   mContentSurface = nullptr;
 
   std::map<void*, VideoInfo*>::iterator it;
   for (it = mVideos.begin(); it != mVideos.end(); it++) {
     it->second->mSurfaceTexture->SetFrameAvailableCallback(nullptr);
     delete it->second;
   }
@@ -262,17 +262,17 @@ nsresult nsNPAPIPluginInstance::Initiali
   mOwner = aOwner;
 
   if (aMIMEType) {
     mMIMEType = (char*)PR_Malloc(strlen(aMIMEType) + 1);
     if (mMIMEType) {
       PL_strcpy(mMIMEType, aMIMEType);
     }
   }
-  
+
   return Start();
 }
 
 nsresult nsNPAPIPluginInstance::Stop()
 {
   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Stop this=%p\n",this));
 
   // Make sure the plugin didn't leave popups enabled.
@@ -432,26 +432,26 @@ nsNPAPIPluginInstance::Start()
   const char* const* names = nullptr;
   const char* const* values = nullptr;
   nsPluginTagType tagtype;
   nsresult rv = GetTagType(&tagtype);
   if (NS_SUCCEEDED(rv)) {
     // Note: If we failed to get the tag type, we may be a full page plugin, so no arguments
     rv = GetAttributes(count, names, values);
     NS_ENSURE_SUCCESS(rv, rv);
-    
+
     // nsPluginTagType_Object or Applet may also have PARAM tags
     // Note: The arrays handed back by GetParameters() are
     // crafted specially to be directly behind the arrays from GetAttributes()
     // with a null entry as a separator. This is for 4.x backwards compatibility!
     // see bug 111008 for details
     if (tagtype != nsPluginTagType_Embed) {
       uint16_t pcount = 0;
       const char* const* pnames = nullptr;
-      const char* const* pvalues = nullptr;    
+      const char* const* pvalues = nullptr;
       if (NS_SUCCEEDED(GetParameters(pcount, pnames, pvalues))) {
         // Android expects an empty string as the separator instead of null
 #ifdef MOZ_WIDGET_ANDROID
         NS_ASSERTION(PL_strcmp(values[count], "") == 0, "attribute/parameter array not setup correctly for Android NPAPI plugins");
 #else
         NS_ASSERTION(!values[count], "attribute/parameter array not setup correctly for NPAPI plugins");
 #endif
         if (pcount)
@@ -548,17 +548,17 @@ nsNPAPIPluginInstance::Start()
   ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n",
   this, &mNPP, mimetype, mode, count, error));
 
   if (NS_FAILED(newResult) || error != NPERR_NO_ERROR) {
     mRunning = DESTROYED;
     nsJSNPRuntime::OnPluginDestroy(&mNPP);
     return NS_ERROR_FAILURE;
   }
-  
+
   return NS_OK;
 }
 
 nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
 {
   // NPAPI plugins don't want a SetWindow(nullptr).
   if (!window || RUNNING != mRunning)
     return NS_OK;
@@ -702,17 +702,17 @@ nsresult nsNPAPIPluginInstance::HandleEv
 #if defined(XP_WIN)
     NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this,
                             aSafeToReenterGecko);
 #else
     MAIN_THREAD_JNI_REF_GUARD;
     tmpResult = (*pluginFunctions->event)(&mNPP, event);
 #endif
     NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
-      ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n", 
+      ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n",
       this, &mNPP, event, tmpResult));
 
     if (result)
       *result = tmpResult;
     mCurrentPluginEvent = nullptr;
   }
 
   return NS_OK;
@@ -729,33 +729,33 @@ nsresult nsNPAPIPluginInstance::GetValue
 
   if (pluginFunctions->getvalue && RUNNING == mRunning) {
     PluginDestructionGuard guard(this);
 
     NPError pluginError = NPERR_GENERIC_ERROR;
     NS_TRY_SAFE_CALL_RETURN(pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this,
                             NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
-    ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n", 
+    ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n",
     this, &mNPP, variable, value, pluginError));
 
     if (pluginError == NPERR_NO_ERROR) {
       rv = NS_OK;
     }
   }
 
   return rv;
 }
 
 nsNPAPIPlugin* nsNPAPIPluginInstance::GetPlugin()
 {
   return mPlugin;
 }
 
-nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP) 
+nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP)
 {
   if (aNPP)
     *aNPP = &mNPP;
   else
     return NS_ERROR_NULL_POINTER;
 
   return NS_OK;
 }
@@ -895,17 +895,17 @@ void nsNPAPIPluginInstance::NotifySize(n
 
 void nsNPAPIPluginInstance::SetANPDrawingModel(uint32_t aModel)
 {
   mANPDrawingModel = aModel;
 }
 
 void* nsNPAPIPluginInstance::GetJavaSurface()
 {
-  void* surface = nullptr; 
+  void* surface = nullptr;
   nsresult rv = GetValueFromPlugin(kJavaSurface_ANPGetValue, &surface);
   if (NS_FAILED(rv))
     return nullptr;
 
   return surface;
 }
 
 void nsNPAPIPluginInstance::PostEvent(void* event)
@@ -1105,17 +1105,17 @@ nsresult nsNPAPIPluginInstance::IsRemote
 {
 #ifdef XP_MACOSX
   if (!mPlugin)
       return NS_ERROR_FAILURE;
 
   PluginLibrary* library = mPlugin->GetLibrary();
   if (!library)
       return NS_ERROR_FAILURE;
-  
+
   return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing);
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
 nsresult nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
 {
@@ -1125,17 +1125,17 @@ nsresult nsNPAPIPluginInstance::Contents
 
   PluginLibrary* library = mPlugin->GetLibrary();
   if (!library)
       return NS_ERROR_FAILURE;
 
   // We only need to call this if the plugin is running OOP.
   if (!library->IsOOP())
       return NS_OK;
-  
+
   return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
 nsresult
 nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject)
@@ -1355,17 +1355,17 @@ nsNPAPIPluginInstance::PopPopupsEnabledS
   if (!window)
     return NS_ERROR_FAILURE;
 
   PopupControlState &oldState = mPopupStates[last];
 
   window->PopPopupControlState(oldState);
 
   mPopupStates.RemoveElementAt(last);
-  
+
   return NS_OK;
 }
 
 nsresult
 nsNPAPIPluginInstance::GetPluginAPIVersion(uint16_t* version)
 {
   NS_ENSURE_ARG_POINTER(version);
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -160,17 +160,17 @@ public:
   // These are really mozilla::dom::ScreenOrientation, but it's
   // difficult to include that here
   uint32_t FullScreenOrientation() { return mFullScreenOrientation; }
   void SetFullScreenOrientation(uint32_t orientation);
 
   void SetWakeLock(bool aLock);
 
   mozilla::gl::GLContext* GLContext();
-  
+
   // For ANPOpenGL
   class TextureInfo {
   public:
     TextureInfo() :
       mTexture(0), mWidth(0), mHeight(0), mInternalFormat(0)
     {
     }
 
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -694,16 +694,30 @@ ScriptExecutorRunnable::WorkerRun(JSCont
     if (!loadInfo.mExecutionResult) {
       return true;
     }
   }
 
   JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
   NS_ASSERTION(global, "Must have a global by now!");
 
+  // Determine whether we want to be discarding source on this global to save
+  // memory. It would make more sense to do this when we create the global, but
+  // the information behind UsesSystemPrincipal() et al isn't finalized until
+  // the call to SetPrincipal during the first script load. After that, however,
+  // it never changes. So we can just idempotently set the bits here.
+  //
+  // Note that we read a pref that is cached on the main thread. This is benignly
+  // racey.
+  if (xpc::ShouldDiscardSystemSource()) {
+    bool discard = aWorkerPrivate->UsesSystemPrincipal() ||
+                   aWorkerPrivate->IsInPrivilegedApp();
+    JS::CompartmentOptionsRef(global).setDiscardSource(discard);
+  }
+
   for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) {
     ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
 
     NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
     NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
     NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
 
     if (NS_FAILED(loadInfo.mLoadResult)) {
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -151,17 +151,17 @@ protected:
   RefPtr<gl::GLContext> mGL;
   nsTArray<GLuint> mCreatedTextures;
   nsTArray<GLuint> mUnusedTextures;
 };
 
 class CompositorOGL : public Compositor
 {
   typedef mozilla::gl::GLContext GLContext;
-  
+
   friend class GLManagerCompositor;
 
   std::map<ShaderConfigOGL, ShaderProgramOGL*> mPrograms;
 public:
   CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth = -1, int aSurfaceHeight = -1,
                 bool aUseExternalSurfaceSize = false);
 
   virtual ~CompositorOGL();
@@ -177,17 +177,17 @@ public:
   {
     return TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL,
                                     XRE_GetProcessType(),
                                     GetMaxTextureSize(),
                                     mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
                                     SupportsPartialTextureUpdate());
   }
 
-  virtual TemporaryRef<CompositingRenderTarget> 
+  virtual TemporaryRef<CompositingRenderTarget>
   CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) MOZ_OVERRIDE;
 
   virtual TemporaryRef<CompositingRenderTarget>
   CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                const CompositingRenderTarget *aSource,
                                const gfx::IntPoint &aSourcePoint) MOZ_OVERRIDE;
 
   virtual void SetRenderTarget(CompositingRenderTarget *aSurface) MOZ_OVERRIDE;
@@ -280,17 +280,17 @@ public:
 private:
   virtual void DrawQuadInternal(const gfx::Rect& aRect,
                                 const gfx::Rect& aClipRect,
                                 const EffectChain &aEffectChain,
                                 gfx::Float aOpacity,
                                 const gfx::Matrix4x4 &aTransformi,
                                 GLuint aDrawMode);
 
-  /** 
+  /**
    * Context target, nullptr when drawing directly to our swap chain.
    */
   RefPtr<gfx::DrawTarget> mTarget;
 
   /** Widget associated with this compositor */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
   nsRefPtr<GLContext> mGLContext;
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -744,27 +744,21 @@ gfxDWriteFontList::GetDefaultFont(const 
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                    const nsAString& aFullname)
 {
     gfxFontEntry *lookup;
 
-    // initialize name lookup tables if needed
-    if (!mFaceNamesInitialized) {
-        InitFaceNameLists();
+    lookup = LookupInFaceNameLists(aFullname);
+    if (!lookup) {
+        return nullptr;
     }
 
-    // lookup in name lookup tables, return null if not found
-    if (!(lookup = mExtraNames->mPostscriptNames.GetWeak(aFullname)) &&
-        !(lookup = mExtraNames->mFullnames.GetWeak(aFullname)))
-    {
-        return nullptr;
-    }
     gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
     gfxDWriteFontEntry *fe =
         new gfxDWriteFontEntry(lookup->Name(),
                                dwriteLookup->mFont,
                                aProxyEntry->Weight(),
                                aProxyEntry->Stretch(),
                                aProxyEntry->IsItalic());
     fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -721,25 +721,18 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLO
 }
 
 gfxFontEntry* 
 gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFullname)
 {
     gfxFontEntry *lookup;
 
-    // initialize name lookup tables if needed
-    if (!mFaceNamesInitialized) {
-        InitFaceNameLists();
-    }
-
-    // lookup in name lookup tables, return null if not found
-    if (!(lookup = mExtraNames->mPostscriptNames.GetWeak(aFullname)) &&
-        !(lookup = mExtraNames->mFullnames.GetWeak(aFullname)))
-    {
+    lookup = LookupInFaceNameLists(aFullname);
+    if (!lookup) {
         return nullptr;
     }
 
     bool isCFF = false; // jtdfix -- need to determine this
     
     // use the face name from the lookup font entry, which will be the localized
     // face name which GDI mapping tables use (e.g. with the system locale set to
     // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1059,17 +1059,17 @@ gfxPlatform::CreateOffscreenContentDrawT
   return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
 }
 
 RefPtr<DrawTarget>
 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
 {
   NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
   if (mContentBackend == BackendType::CAIRO) {
-    nsRefPtr<gfxImageSurface> image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat)); 
+    nsRefPtr<gfxImageSurface> image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat));
     return Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), aSize);
   }
   return Factory::CreateDrawTargetForData(mContentBackend, aData, aSize, aStride, aFormat);
 }
 
 /* static */ BackendType
 gfxPlatform::BackendTypeForName(const nsCString& aName)
 {
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -122,17 +122,17 @@ gfxPlatformFontList::gfxPlatformFontList
       mPrefFonts(10), mBadUnderlineFamilyNames(10), mSharedCmaps(16),
       mStartIndex(0), mIncrement(1), mNumFamilies(0)
 {
     mOtherFamilyNamesInitialized = false;
 
     if (aNeedFullnamePostscriptNames) {
         mExtraNames = new ExtraNames();
     }
-    mFaceNamesInitialized = false;
+    mFaceNameListsInitialized = false;
 
     LoadBadUnderlineList();
 
     // pref changes notification setup
     NS_ASSERTION(!gFontListPrefObserver,
                  "There has been font list pref observer already");
     gFontListPrefObserver = new gfxFontListPrefObserver();
     NS_ADDREF(gFontListPrefObserver);
@@ -154,17 +154,17 @@ gfxPlatformFontList::InitFontList()
 {
     mFontFamilies.Clear();
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = false;
     if (mExtraNames) {
         mExtraNames->mFullnames.Clear();
         mExtraNames->mPostscriptNames.Clear();
     }
-    mFaceNamesInitialized = false;
+    mFaceNameListsInitialized = false;
     mPrefFonts.Clear();
     mReplacementCharFallbackFamily = nullptr;
     CancelLoader();
 
     // initialize ranges of characters for which system-wide font search should be skipped
     mCodepointsWithNoFonts.reset();
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
@@ -176,77 +176,194 @@ gfxPlatformFontList::InitFontList()
 
 void
 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
 {
     aResult = aKeyName;
     ToLowerCase(aResult);
 }
 
+struct InitOtherNamesData {
+    InitOtherNamesData(gfxPlatformFontList *aFontList,
+                       TimeStamp aStartTime)
+        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
+    {}
+
+    gfxPlatformFontList *mFontList;
+    TimeStamp mStartTime;
+    bool mTimedOut;
+};
+
 void 
 gfxPlatformFontList::InitOtherFamilyNames()
 {
-    mOtherFamilyNamesInitialized = true;
+    if (mOtherFamilyNamesInitialized) {
+        return;
+    }
+
     TimeStamp start = TimeStamp::Now();
 
     // iterate over all font families and read in other family names
-    mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc, this);
+    InitOtherNamesData otherNamesData(this, start);
 
+    mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
+                            &otherNamesData);
+
+    if (!otherNamesData.mTimedOut) {
+        mOtherFamilyNamesInitialized = true;
+    }
     TimeStamp end = TimeStamp::Now();
     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
                                    start, end);
+
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED()) {
         TimeDuration elapsed = end - start;
-        LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms",
-                      elapsed.ToMilliseconds()));
+        LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
+                      elapsed.ToMilliseconds(),
+                      (otherNamesData.mTimedOut ? "timeout" : "")));
     }
 #endif
 }
-                                                         
+
+#define OTHERNAMES_TIMEOUT 200
+
 PLDHashOperator
 gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
                                               nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                               void* userArg)
 {
-    gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
-    aFamilyEntry->ReadOtherFamilyNames(fc);
+    InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
+
+    aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
+    TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
+    if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
+        data->mTimedOut = true;
+        return PL_DHASH_STOP;
+    }
     return PL_DHASH_NEXT;
 }
+ 
+struct ReadFaceNamesData {
+    ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
+        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
+    {}
 
-void
-gfxPlatformFontList::InitFaceNameLists()
+    gfxPlatformFontList *mFontList;
+    TimeStamp mStartTime;
+    bool mTimedOut;
+
+    // if mFirstChar is not empty, only load facenames for families
+    // that start with this character
+    nsString mFirstChar;
+};
+
+gfxFontEntry*
+gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
 {
-    mFaceNamesInitialized = true;
+    TimeStamp start = TimeStamp::Now();
+    gfxFontEntry *lookup = nullptr;
+
+    ReadFaceNamesData faceNameListsData(this, start);
 
-    TimeStamp start = TimeStamp::Now();
-
-    // iterate over all font families and read in other family names
-    mFontFamilies.Enumerate(gfxPlatformFontList::InitFaceNameListsProc, this);
+    // iterate over familes starting with the same letter
+    faceNameListsData.mFirstChar.Assign(aFaceName.CharAt(0));
+    ToLowerCase(faceNameListsData.mFirstChar);
+    mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
+                            &faceNameListsData);
+    lookup = FindFaceName(aFaceName);
 
     TimeStamp end = TimeStamp::Now();
     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
                                    start, end);
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED()) {
         TimeDuration elapsed = end - start;
-        LOG_FONTINIT(("(fontinit) InitFaceNameLists took %8.2f ms",
-                      elapsed.ToMilliseconds()));
+        LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
+                      elapsed.ToMilliseconds(),
+                      (lookup ? "found name" : ""),
+                      (faceNameListsData.mTimedOut ? "timeout" : "")));
     }
 #endif
+
+    return lookup;
 }
 
+// time limit for loading facename lists (ms)
+#define NAMELIST_TIMEOUT  200
+
 PLDHashOperator
-gfxPlatformFontList::InitFaceNameListsProc(nsStringHashKey::KeyType aKey,
-                                           nsRefPtr<gfxFontFamily>& aFamilyEntry,
-                                           void* userArg)
+gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
+                                       nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                                       void* userArg)
+{
+    ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
+    gfxPlatformFontList *fc = data->mFontList;
+
+    // when filtering, skip names that don't start with the filter character
+    if (!(data->mFirstChar.IsEmpty())) {
+        char16_t firstChar = aKey.CharAt(0);
+        nsAutoString firstCharStr(&firstChar, 1);
+        ToLowerCase(firstCharStr);
+        if (!firstCharStr.Equals(data->mFirstChar)) {
+            return PL_DHASH_NEXT;
+        }
+    }
+    aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
+
+    TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
+    if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
+        data->mTimedOut = true;
+        return PL_DHASH_STOP;
+    }
+    return PL_DHASH_NEXT;
+}
+
+gfxFontEntry*
+gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
 {
-    gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
-    aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
-    return PL_DHASH_NEXT;
+    gfxFontEntry *lookup;
+
+    // lookup in name lookup tables, return null if not found
+    if (mExtraNames &&
+        ((lookup = mExtraNames->mPostscriptNames.GetWeak(aFaceName)) ||
+         (lookup = mExtraNames->mFullnames.GetWeak(aFaceName)))) {
+        return lookup;
+    }
+
+    return nullptr;
+}
+
+gfxFontEntry*
+gfxPlatformFontList::LookupInFaceNameLists(const nsAString& aFaceName)
+{
+    gfxFontEntry *lookup = nullptr;
+
+    // initialize facename lookup tables if needed
+    // note: this can terminate early or time out, in which case
+    //       mFaceNameListsInitialized remains false
+    if (!mFaceNameListsInitialized) {
+        lookup = SearchFamiliesForFaceName(aFaceName);
+        if (lookup) {
+            return lookup;
+        }
+    }
+
+    // lookup in name lookup tables, return null if not found
+    if (!(lookup = FindFaceName(aFaceName))) {
+        // names not completely initialized, so keep track of lookup misses
+        if (!mFaceNameListsInitialized) {
+            if (!mFaceNamesMissed) {
+                mFaceNamesMissed = new nsTHashtable<nsStringHashKey>(4);
+            }
+            mFaceNamesMissed->PutEntry(aFaceName);
+        }
+    }
+
+    return lookup;
 }
 
 void
 gfxPlatformFontList::PreloadNamesList()
 {
     nsAutoTArray<nsString, 10> preloadFonts;
     gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
 
@@ -616,16 +733,23 @@ gfxPlatformFontList::FindFamily(const ns
     // initialize the rest of the list and try again.  this is done lazily
     // since reading name table entries is expensive.
     // although ASCII localized family names are possible they don't occur
     // in practice so avoid pulling in names at startup
     if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
         InitOtherFamilyNames();
         if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
             return CheckFamily(familyEntry);
+        } else if (!mOtherFamilyNamesInitialized) {
+            // localized family names load timed out, add name to list of
+            // names to check after localized names are loaded
+            if (!mOtherNamesMissed) {
+                mOtherNamesMissed = new nsTHashtable<nsStringHashKey>(4);
+            }
+            mOtherNamesMissed->PutEntry(key);
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry*
 gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
@@ -810,39 +934,109 @@ gfxPlatformFontList::LoadFontInfo()
         TimeDuration elapsed = TimeStamp::Now() - start;
         LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
                       elapsed.ToMilliseconds(), (done ? "true" : "false")));
     }
 #endif
 
     if (done) {
         mOtherFamilyNamesInitialized = true;
-        mFaceNamesInitialized = true;
+        mFaceNameListsInitialized = true;
     }
 
     return done;
 }
 
+struct LookupMissedFaceNamesData {
+    LookupMissedFaceNamesData(gfxPlatformFontList *aFontList)
+        : mFontList(aFontList), mFoundName(false) {}
+
+    gfxPlatformFontList *mFontList;
+    bool mFoundName;
+};
+
+/*static*/ PLDHashOperator
+gfxPlatformFontList::LookupMissedFaceNamesProc(nsStringHashKey *aKey,
+                                               void *aUserArg)
+{
+    LookupMissedFaceNamesData *data =
+        reinterpret_cast<LookupMissedFaceNamesData*>(aUserArg);
+
+    if (data->mFontList->FindFaceName(aKey->GetKey())) {
+        data->mFoundName = true;
+        return PL_DHASH_STOP;
+    }
+    return PL_DHASH_NEXT;
+}
+
+struct LookupMissedOtherNamesData {
+    LookupMissedOtherNamesData(gfxPlatformFontList *aFontList)
+        : mFontList(aFontList), mFoundName(false) {}
+
+    gfxPlatformFontList *mFontList;
+    bool mFoundName;
+};
+
+/*static*/ PLDHashOperator
+gfxPlatformFontList::LookupMissedOtherNamesProc(nsStringHashKey *aKey,
+                                                void *aUserArg)
+{
+    LookupMissedOtherNamesData *data =
+        reinterpret_cast<LookupMissedOtherNamesData*>(aUserArg);
+
+    if (data->mFontList->FindFamily(aKey->GetKey())) {
+        data->mFoundName = true;
+        return PL_DHASH_STOP;
+    }
+    return PL_DHASH_NEXT;
+}
+
 void 
 gfxPlatformFontList::CleanupLoader()
 {
     mFontFamiliesToLoad.Clear();
     mNumFamilies = 0;
+    bool rebuilt = false, forceReflow = false;
+
+    // if had missed face names that are now available, force reflow all
+    if (mFaceNamesMissed &&
+        mFaceNamesMissed->Count() != 0) {
+        LookupMissedFaceNamesData namedata(this);
+        mFaceNamesMissed->EnumerateEntries(LookupMissedFaceNamesProc, &namedata);
+        if (namedata.mFoundName) {
+            rebuilt = true;
+            mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
+        }
+        mFaceNamesMissed = nullptr;
+    }
+
+    if (mOtherNamesMissed) {
+        LookupMissedOtherNamesData othernamesdata(this);
+        mOtherNamesMissed->EnumerateEntries(LookupMissedOtherNamesProc,
+                                            &othernamesdata);
+        mOtherNamesMissed = nullptr;
+        if (othernamesdata.mFoundName) {
+            forceReflow = true;
+            ForceGlobalReflow();
+        }
+    }
 
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED() && mFontInfo) {
         LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
                       "%d families %d fonts %d cmaps "
-                      "%d facenames %d othernames",
+                      "%d facenames %d othernames %s %s",
                       mLoadTime.ToMilliseconds(),
                       mFontInfo->mLoadStats.families,
                       mFontInfo->mLoadStats.fonts,
                       mFontInfo->mLoadStats.cmaps,
                       mFontInfo->mLoadStats.facenames,
-                      mFontInfo->mLoadStats.othernames));
+                      mFontInfo->mLoadStats.othernames,
+                      (rebuilt ? "(userfont sets rebuilt)" : ""),
+                      (forceReflow ? "(global reflow)" : "")));
     }
 #endif
 
     gfxFontInfoLoader::CleanupLoader();
 }
 
 void
 gfxPlatformFontList::GetPrefsAndStartLoader()
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -220,29 +220,46 @@ protected:
 
     // whether system-based font fallback is used or not
     // if system fallback is used, no need to load all cmaps
     virtual bool UsesSystemFallback() { return false; }
 
     // verifies that a family contains a non-zero font count
     gfxFontFamily* CheckFamily(gfxFontFamily *aFamily);
 
-    // separate initialization for reading in name tables, since this is expensive
+    // initialize localized family names
     void InitOtherFamilyNames();
 
-    static PLDHashOperator InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
-                                                    nsRefPtr<gfxFontFamily>& aFamilyEntry,
-                                                    void* userArg);
+    static PLDHashOperator
+    InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
+                             nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                             void* userArg);
+
+    // search through font families, looking for a given name, initializing
+    // facename lists along the way. first checks all families with names
+    // close to face name, then searchs all families if not found.
+    gfxFontEntry* SearchFamiliesForFaceName(const nsAString& aFaceName);
 
-    // read in all fullname/Postscript names for all font faces
-    void InitFaceNameLists();
+    static PLDHashOperator
+    ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
+                      nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                      void* userArg);
+
+    // helper method for finding fullname/postscript names in facename lists
+    gfxFontEntry* FindFaceName(const nsAString& aFaceName);
 
-    static PLDHashOperator InitFaceNameListsProc(nsStringHashKey::KeyType aKey,
-                                                 nsRefPtr<gfxFontFamily>& aFamilyEntry,
-                                                 void* userArg);
+    // look up a font by name, for cases where platform font list
+    // maintains explicit mappings of fullname/psname ==> font
+    virtual gfxFontEntry* LookupInFaceNameLists(const nsAString& aFontName);
+
+    static PLDHashOperator LookupMissedFaceNamesProc(nsStringHashKey *aKey,
+                                                     void *aUserArg);
+
+    static PLDHashOperator LookupMissedOtherNamesProc(nsStringHashKey *aKey,
+                                                      void *aUserArg);
 
     // commonly used fonts for which the name table should be loaded at startup
     virtual void PreloadNamesList();
 
     // load the bad underline blacklist from pref.
     void LoadBadUnderlineList();
 
     // explicitly set fixed-pitch flag for all faces
@@ -281,27 +298,33 @@ protected:
     // other family name ==> family entry (not unique, can have multiple names per
     // family entry, only names *other* than the canonical names are stored here)
     nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> mOtherFamilyNames;
 
     // flag set after InitOtherFamilyNames is called upon first name lookup miss
     bool mOtherFamilyNamesInitialized;
 
     // flag set after fullname and Postcript name lists are populated
-    bool mFaceNamesInitialized;
+    bool mFaceNameListsInitialized;
 
     struct ExtraNames {
       ExtraNames() : mFullnames(100), mPostscriptNames(100) {}
       // fullname ==> font entry (unique, one name per font entry)
       nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> mFullnames;
       // Postscript name ==> font entry (unique, one name per font entry)
       nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> mPostscriptNames;
     };
     nsAutoPtr<ExtraNames> mExtraNames;
 
+    // face names missed when face name loading takes a long time
+    nsAutoPtr<nsTHashtable<nsStringHashKey> > mFaceNamesMissed;
+
+    // localized family names missed when face name loading takes a long time
+    nsAutoPtr<nsTHashtable<nsStringHashKey> > mOtherNamesMissed;
+
     // cached pref font lists
     // maps list of family names ==> array of family entries, one per lang group
     nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<gfxFontFamily> > > mPrefFonts;
 
     // when system-wide font lookup fails for a character, cache it to skip future searches
     gfxSparseBitSet mCodepointsWithNoFonts;
 
     // the family to use for U+FFFD fallback, to avoid expensive search every time
--- a/intl/strres/src/nsStringBundle.cpp
+++ b/intl/strres/src/nsStringBundle.cpp
@@ -468,33 +468,33 @@ nsresult nsExtensibleStringBundle::GetSi
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
 #define MAX_CACHED_BUNDLES 16
 
 struct bundleCacheEntry_t MOZ_FINAL : public LinkedListElement<bundleCacheEntry_t> {
-  nsAutoPtr<nsCStringKey> mHashKey;
+  nsCString mHashKey;
   nsCOMPtr<nsIStringBundle> mBundle;
 
   bundleCacheEntry_t()
   {
     MOZ_COUNT_CTOR(bundleCacheEntry_t);
   }
 
   ~bundleCacheEntry_t()
   {
     MOZ_COUNT_DTOR(bundleCacheEntry_t);
   }
 };
 
 
 nsStringBundleService::nsStringBundleService() :
-  mBundleMap(MAX_CACHED_BUNDLES, true)
+  mBundleMap(MAX_CACHED_BUNDLES)
 {
   mErrorService = do_GetService(kErrorServiceCID);
   NS_ASSERTION(mErrorService, "Couldn't get error service");
 }
 
 NS_IMPL_ISUPPORTS3(nsStringBundleService,
                    nsIStringBundleService,
                    nsIObserver,
@@ -543,17 +543,17 @@ nsStringBundleService::Observe(nsISuppor
 
   return NS_OK;
 }
 
 void
 nsStringBundleService::flushBundleCache()
 {
   // release all bundles in the cache
-  mBundleMap.Reset();
+  mBundleMap.Clear();
 
   while (!mBundleCache.isEmpty()) {
     delete mBundleCache.popFirst();
   }
 }
 
 NS_IMETHODIMP
 nsStringBundleService::FlushBundles()
@@ -561,70 +561,68 @@ nsStringBundleService::FlushBundles()
   flushBundleCache();
   return NS_OK;
 }
 
 nsresult
 nsStringBundleService::getStringBundle(const char *aURLSpec,
                                        nsIStringBundle **aResult)
 {
-  nsCStringKey completeKey(aURLSpec);
-
-  bundleCacheEntry_t* cacheEntry =
-    (bundleCacheEntry_t*)mBundleMap.Get(&completeKey);
+  nsDependentCString key(aURLSpec);
+  bundleCacheEntry_t* cacheEntry = mBundleMap.Get(key);
 
   if (cacheEntry) {
     // cache hit!
     // remove it from the list, it will later be reinserted
     // at the head of the list
     cacheEntry->remove();
 
   } else {
 
     // hasn't been cached, so insert it into the hash table
     nsRefPtr<nsStringBundle> bundle = new nsStringBundle(aURLSpec, mOverrideStrings);
-    cacheEntry = insertIntoCache(bundle.forget(), &completeKey);
+    cacheEntry = insertIntoCache(bundle.forget(), key);
   }
 
   // at this point the cacheEntry should exist in the hashtable,
   // but is not in the LRU cache.
   // put the cache entry at the front of the list
   mBundleCache.insertFront(cacheEntry);
 
   // finally, return the value
   *aResult = cacheEntry->mBundle;
   NS_ADDREF(*aResult);
 
   return NS_OK;
 }
 
 bundleCacheEntry_t *
 nsStringBundleService::insertIntoCache(already_AddRefed<nsIStringBundle> aBundle,
-                                       nsCStringKey* aHashKey)
+                                       nsCString &aHashKey)
 {
   bundleCacheEntry_t *cacheEntry;
 
   if (mBundleMap.Count() < MAX_CACHED_BUNDLES) {
     // cache not full - create a new entry
     cacheEntry = new bundleCacheEntry_t();
   } else {
     // cache is full
     // take the last entry in the list, and recycle it.
     cacheEntry = mBundleCache.getLast();
 
     // remove it from the hash table and linked list
-    NS_ASSERTION(mBundleMap.Exists(cacheEntry->mHashKey),
+    NS_ASSERTION(mBundleMap.Contains(cacheEntry->mHashKey),
                  "Element will not be removed!");
     mBundleMap.Remove(cacheEntry->mHashKey);
     cacheEntry->remove();
   }
 
   // at this point we have a new cacheEntry that doesn't exist
   // in the hashtable, so set up the cacheEntry
-  cacheEntry->mHashKey = (nsCStringKey*)aHashKey->Clone();
+  cacheEntry->mHashKey = aHashKey;
   cacheEntry->mBundle = aBundle;
 
   // insert the entry into the cache and map, make it the MRU
   mBundleMap.Put(cacheEntry->mHashKey, cacheEntry);
 
   return cacheEntry;
 }
 
--- a/intl/strres/src/nsStringBundleService.h
+++ b/intl/strres/src/nsStringBundleService.h
@@ -2,17 +2,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsStringBundleService_h__
 #define nsStringBundleService_h__
 
 #include "nsCOMPtr.h"
-#include "nsHashtable.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIStringBundle.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsIErrorService.h"
 #include "nsIStringBundleOverride.h"
 
 #include "mozilla/LinkedList.h"
@@ -24,31 +25,31 @@ class nsStringBundleService : public nsI
                               public nsSupportsWeakReference
 {
 public:
   nsStringBundleService();
   virtual ~nsStringBundleService();
 
   nsresult Init();
 
-  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_ISUPPORTS
   NS_DECL_NSISTRINGBUNDLESERVICE
   NS_DECL_NSIOBSERVER
 
 private:
   nsresult getStringBundle(const char *aUrl, nsIStringBundle** aResult);
   nsresult FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
                             uint32_t argCount, char16_t** argArray,
                             char16_t* *result);
 
   void flushBundleCache();
 
   bundleCacheEntry_t *insertIntoCache(already_AddRefed<nsIStringBundle> aBundle,
-                                      nsCStringKey *aHashKey);
+                                      nsCString &aHashKey);
 
-  nsHashtable mBundleMap;
+  nsDataHashtable<nsCStringHashKey, bundleCacheEntry_t*> mBundleMap;
   mozilla::LinkedList<bundleCacheEntry_t> mBundleCache;
 
-  nsCOMPtr<nsIErrorService>     mErrorService;
+  nsCOMPtr<nsIErrorService> mErrorService;
   nsCOMPtr<nsIStringBundleOverride> mOverrideStrings;
 };
 
 #endif
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -94,19 +94,20 @@ void ExecutableAllocator::reprotectRegio
 
 void
 ExecutablePool::toggleAllCodeAsAccessible(bool accessible)
 {
     char* begin = m_allocation.pages;
     size_t size = m_freePtr - begin;
 
     if (size) {
-        int flags = accessible
-                    ? PROT_READ | PROT_WRITE | PROT_EXEC
-                    : PROT_READ | PROT_WRITE;
+        // N.B. Some systems, like 32bit Mac OS 10.6, implicitly add PROT_EXEC
+        // when mprotect'ing memory with any flag other than PROT_NONE. Be
+        // sure to use PROT_NONE when making inaccessible.
+        int flags = accessible ? PROT_READ | PROT_WRITE | PROT_EXEC : PROT_NONE;
         if (mprotect(begin, size, flags))
             MOZ_CRASH();
     }
 }
 
 }
 
 #endif // HAVE(ASSEMBLER)
--- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
@@ -111,18 +111,20 @@ void ExecutableAllocator::systemRelease(
 
 void
 ExecutablePool::toggleAllCodeAsAccessible(bool accessible)
 {
     char* begin = m_allocation.pages;
     size_t size = m_freePtr - begin;
 
     if (size) {
+        // N.B. DEP is not on automatically in Windows XP, so be sure to use
+        // PAGE_NOACCESS instead of PAGE_READWRITE when making inaccessible.
         DWORD oldProtect;
-        int flags = accessible ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+        int flags = accessible ? PAGE_EXECUTE_READWRITE : PAGE_NOACCESS;
         if (!VirtualProtect(begin, size, flags, &oldProtect))
             MOZ_CRASH();
     }
 }
 
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
 #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
 #endif
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -141,17 +141,18 @@ MaybeCheckEvalFreeVariables(ExclusiveCon
     return true;
 }
 
 static inline bool
 CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
 {
     return options.canLazilyParse &&
         options.compileAndGo &&
-        options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
+        !cx->compartment()->options().discardSource() &&
+        !options.sourceIsLazy &&
         !(cx->compartment()->debugMode() &&
           cx->compartment()->runtimeFromAnyThread()->debugHooks.newScriptHook);
 }
 
 void
 frontend::MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
                                  const jschar *chars, size_t length)
 {
@@ -207,37 +208,32 @@ frontend::CompileScript(ExclusiveContext
      * and non-zero static level requires callerFrame.
      */
     JS_ASSERT_IF(evalCaller, options.compileAndGo);
     JS_ASSERT_IF(evalCaller, options.forEval);
     JS_ASSERT_IF(staticLevel != 0, evalCaller);
 
     if (!CheckLength(cx, length))
         return nullptr;
-    JS_ASSERT_IF(staticLevel != 0, options.sourcePolicy != CompileOptions::LAZY_SOURCE);
+    JS_ASSERT_IF(staticLevel != 0, !options.sourceIsLazy);
 
     RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
     if (!sourceObject)
         return nullptr;
 
     ScriptSource *ss = sourceObject->source();
 
     SourceCompressionTask mysct(cx);
     SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
 
-    switch (options.sourcePolicy) {
-      case CompileOptions::SAVE_SOURCE:
-        if (!ss->setSourceCopy(cx, chars, length, false, sct))
+    if (!cx->compartment()->options().discardSource()) {
+        if (options.sourceIsLazy)
+            ss->setSourceRetrievable();
+        else if (!ss->setSourceCopy(cx, chars, length, false, sct))
             return nullptr;
-        break;
-      case CompileOptions::LAZY_SOURCE:
-        ss->setSourceRetrievable();
-        break;
-      case CompileOptions::NO_SOURCE:
-        break;
     }
 
     bool canLazilyParse = CanLazilyParse(cx, options);
 
     Maybe<Parser<SyntaxParseHandler> > syntaxParser;
     if (canLazilyParse) {
         syntaxParser.construct(cx, alloc, options, chars, length, /* foldConstants = */ false,
                                (Parser<SyntaxParseHandler> *) nullptr,
@@ -512,18 +508,18 @@ CompileFunctionBody(JSContext *cx, Mutab
         return false;
 
     RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
     if (!sourceObject)
         return nullptr;
     ScriptSource *ss = sourceObject->source();
 
     SourceCompressionTask sct(cx);
-    JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE);
-    if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) {
+    JS_ASSERT(!options.sourceIsLazy);
+    if (!cx->compartment()->options().discardSource()) {
         if (!ss->setSourceCopy(cx, chars, length, true, &sct))
             return false;
     }
 
     bool canLazilyParse = CanLazilyParse(cx, options);
 
     Maybe<Parser<SyntaxParseHandler> > syntaxParser;
     if (canLazilyParse) {
--- a/js/src/jit-test/tests/basic/withSourceHook.js
+++ b/js/src/jit-test/tests/basic/withSourceHook.js
@@ -30,27 +30,27 @@ withSourceHook(function (url) {
       // and verify that it is in force.
       assertEq(withSourceHook(function (url) {
                                 log += 'i';
                                 assertEq(url, 'inner');
                                 return '(function inner() { 1; })';
                               }, function () {
                                 log += 'I';
                                 return evaluate('(function inner() { 2; })',
-                                                { fileName: 'inner', sourcePolicy: 'LAZY_SOURCE' })
+                                                { fileName: 'inner', sourceIsLazy: true })
                                        .toSource();
                               }),
                '(function inner() { 1; })');
       // Verify that the source hook that throws has been reinstated.
       evaluate('(function middle() { })',
-               { fileName: 'middle', sourcePolicy: 'LAZY_SOURCE' })
+               { fileName: 'middle', sourceIsLazy: true })
       .toSource();
     });
   }, 'borborygmus');
 
   // Verify that the outermost source hook has been restored.
   assertEq(evaluate('(function outer() { 4; })',
-                    { fileName: 'outer', sourcePolicy: 'LAZY_SOURCE' })
+                    { fileName: 'outer', sourceIsLazy: true })
            .toSource(),
            '(function outer() { 3; })');
 });
 
 assertEq(log, 'OMIimo');
--- a/js/src/jit-test/tests/debug/Source-text-lazy.js
+++ b/js/src/jit-test/tests/debug/Source-text-lazy.js
@@ -23,17 +23,17 @@ function test(source) {
     return frobbed;
   }, () => {
     dbg.onDebuggerStatement = function (frame) {
       log += 'd';
       assertEq(frame.script.source.text, frobbed);
     }
 
     g.evaluate(source, { fileName: "BanalBivalve.jsm",
-                         sourcePolicy: "LAZY_SOURCE"});
+                         sourceIsLazy: true });
   });
 
   assertEq(log, 'ds');
 }
 
 test("debugger; // Ignominious Iguana");
 test("(function () { debugger; /* Meretricious Marmoset */})();");
 test("(() => { debugger; })(); // Gaunt Gibbon");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/iloop.js
@@ -0,0 +1,4 @@
+// |jit-test| exitstatus: 6;
+
+timeout(1);
+for(;;);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/gc-timeout.js
@@ -0,0 +1,27 @@
+// |jit-test| exitstatus: 6;
+
+// One sneaky way to run GC during a parallel section is to invoke the
+// gc() function during the parallel timeout!
+
+load(libdir + "parallelarray-helpers.js");
+
+function iterate(x) {
+  while (x == 2046) {
+    // for exactly one index, this infinitely loops!
+    // this ensures that the warmup doesn't loop.
+  }
+  return 22;
+}
+
+function timeoutfunc() {
+  print("Timed out, invoking the GC");
+  gc();
+  return false;
+}
+
+timeout(1, timeoutfunc);
+
+if (getBuildConfiguration().parallelJS)
+  Array.buildPar(2048, iterate);
+else
+  while(true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/timeout.js
@@ -0,0 +1,17 @@
+// |jit-test| exitstatus: 6;
+
+load(libdir + "parallelarray-helpers.js");
+
+function iterate(x) {
+  while (x == 2046) {
+    // for exactly one index, this infinitely loops!
+    // this ensures that the warmup doesn't loop.
+  }
+  return 22;
+}
+
+timeout(1);
+if (getBuildConfiguration().parallelJS)
+  Array.buildPar(2048, iterate);
+else
+  while (true);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4042,17 +4042,17 @@ CodeGenerator::visitGetArgumentsObjectAr
     ValueOperand out = ToOutValue(lir);
 
     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
     masm.loadValue(argAddr, out);
 #ifdef DEBUG
     Label success;
     masm.branchTestMagic(Assembler::NotEqual, out, &success);
-    masm.assumeUnreachable("Result from ArgumentObject shouldn't be MIRType_Magic.");
+    masm.assumeUnreachable("Result from ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
     masm.bind(&success);
 #endif
     return true;
 }
 
 bool
 CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir)
 {
@@ -4061,17 +4061,17 @@ CodeGenerator::visitSetArgumentsObjectAr
     ValueOperand value = ToValue(lir, LSetArgumentsObjectArg::ValueIndex);
 
     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
     emitPreBarrier(argAddr, MIRType_Value);
 #ifdef DEBUG
     Label success;
     masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
-    masm.assumeUnreachable("Result in ArgumentObject shouldn't be MIRType_Magic.");
+    masm.assumeUnreachable("Result in ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
     masm.bind(&success);
 #endif
     masm.storeValue(value, argAddr);
     return true;
 }
 
 bool
 CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -437,16 +437,32 @@ class TypeAnalyzer
 };
 
 } /* anonymous namespace */
 
 // Try to specialize this phi based on its non-cyclic inputs.
 static MIRType
 GuessPhiType(MPhi *phi, bool *hasInputsWithEmptyTypes)
 {
+#ifdef DEBUG
+    // Check that different magic constants aren't flowing together.
+    MIRType magicType = MIRType_None;
+    for (size_t i = 0; i < phi->numOperands(); i++) {
+        MDefinition *in = phi->getOperand(i);
+        if (in->type() == MIRType_MagicOptimizedArguments ||
+            in->type() == MIRType_MagicHole ||
+            in->type() == MIRType_MagicIsConstructing)
+        {
+            if (magicType == MIRType_None)
+                magicType = in->type();
+            MOZ_ASSERT(magicType == in->type());
+        }
+    }
+#endif
+
     *hasInputsWithEmptyTypes = false;
 
     MIRType type = MIRType_None;
     bool convertibleToFloat32 = false;
     bool hasPhiInputs = false;
     for (size_t i = 0, e = phi->numOperands(); i < e; i++) {
         MDefinition *in = phi->getOperand(i);
         if (in->isPhi()) {
@@ -709,17 +725,17 @@ TypeAnalyzer::replaceRedundantPhi(MPhi *
     js::Value v;
     switch (phi->type()) {
       case MIRType_Undefined:
         v = UndefinedValue();
         break;
       case MIRType_Null:
         v = NullValue();
         break;
-      case MIRType_Magic:
+      case MIRType_MagicOptimizedArguments:
         v = MagicValue(JS_OPTIMIZED_ARGUMENTS);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("unexpected type");
     }
     MConstant *c = MConstant::New(alloc(), v);
     // The instruction pass will insert the box
     block->insertBefore(*(block->begin()), c);
@@ -732,17 +748,20 @@ TypeAnalyzer::insertConversions()
     // Instructions are processed in reverse postorder: all uses are defs are
     // seen before uses. This ensures that output adjustment (which may rewrite
     // inputs of uses) does not conflict with input adjustment.
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
         if (mir->shouldCancel("Insert Conversions"))
             return false;
 
         for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd();) {
-            if (phi->type() <= MIRType_Null || phi->type() == MIRType_Magic) {
+            if (phi->type() == MIRType_Undefined ||
+                phi->type() == MIRType_Null ||
+                phi->type() == MIRType_MagicOptimizedArguments)
+            {
                 replaceRedundantPhi(*phi);
                 phi = block->discardPhiAt(phi);
             } else {
                 adjustPhiInputs(*phi);
                 phi++;
             }
         }
         for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) {
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -472,17 +472,17 @@ IonBuilder::analyzeNewLoopTypes(MBasicBl
         MPhi *phi = entry->getSlot(slot)->toPhi();
 
         if (*last == JSOP_POS)
             last = earlier;
 
         if (js_CodeSpec[*last].format & JOF_TYPESET) {
             types::TemporaryTypeSet *typeSet = bytecodeTypes(last);
             if (!typeSet->empty()) {
-                MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
+                MIRType type = typeSet->getKnownMIRType();
                 if (!phi->addBackedgeType(type, typeSet))
                     return false;
             }
         } else if (*last == JSOP_GETLOCAL || *last == JSOP_GETARG) {
             uint32_t slot = (*last == JSOP_GETLOCAL)
                             ? info().localSlot(GET_LOCALNO(last))
                             : info().argSlotUnchecked(GET_ARGNO(last));
             if (slot < info().firstStackSlot()) {
@@ -884,19 +884,17 @@ IonBuilder::buildInline(IonBuilder *call
 }
 
 void
 IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex)
 {
     JS_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg());
 
     types::TemporaryTypeSet *types = param->resultTypeSet();
-    JSValueType definiteType = types->getKnownTypeTag();
-
-    MDefinition *actual = ensureDefiniteType(param, definiteType);
+    MDefinition *actual = ensureDefiniteType(param, types->getKnownMIRType());
     if (actual == param)
         return;
 
     // Careful! We leave the original MParameter in the entry resume point. The
     // arguments still need to be checked unless proven otherwise at the call
     // site, and these checks can bailout. We can end up:
     //   v0 = Parameter(0)
     //   v1 = Unbox(v0, INT32)
@@ -1028,17 +1026,17 @@ IonBuilder::addOsrValueTypeBarrier(uint3
 
     if (typeSet && !typeSet->unknown()) {
         MInstruction *barrier = MTypeBarrier::New(alloc(), def, typeSet);
         osrBlock->insertBefore(osrBlock->lastIns(), barrier);
         osrBlock->rewriteSlot(slot, barrier);
         def = barrier;
     } else if (type == MIRType_Null ||
                type == MIRType_Undefined ||
-               type == MIRType_Magic)
+               type == MIRType_MagicOptimizedArguments)
     {
         // No unbox instruction will be added below, so check the type by
         // adding a type barrier for a singleton type set.
         types::Type ntype = types::Type::PrimitiveType(ValueTypeFromMIRType(type));
         typeSet = alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
         if (!typeSet)
             return false;
         MInstruction *barrier = MTypeBarrier::New(alloc(), def, typeSet);
@@ -1074,17 +1072,17 @@ IonBuilder::addOsrValueTypeBarrier(uint3
       {
         MConstant *c = MConstant::New(alloc(), UndefinedValue());
         osrBlock->insertBefore(osrBlock->lastIns(), c);
         osrBlock->rewriteSlot(slot, c);
         def = c;
         break;
       }
 
-      case MIRType_Magic:
+      case MIRType_MagicOptimizedArguments:
         JS_ASSERT(lazyArguments_);
         osrBlock->rewriteSlot(slot, lazyArguments_);
         def = lazyArguments_;
         break;
 
       default:
         break;
     }
@@ -4940,24 +4938,24 @@ IonBuilder::jsop_funapply(uint32_t argc)
             return false;
         return makeCall(native, callInfo, false);
     }
 
     // Disable compilation if the second argument to |apply| cannot be guaranteed
     // to be either definitely |arguments| or definitely not |arguments|.
     MDefinition *argument = current->peek(-1);
     if (script()->argumentsHasVarBinding() &&
-        argument->mightBeType(MIRType_Magic) &&
-        argument->type() != MIRType_Magic)
+        argument->mightBeType(MIRType_MagicOptimizedArguments) &&
+        argument->type() != MIRType_MagicOptimizedArguments)
     {
         return abort("fun.apply with MaybeArguments");
     }
 
     // Fallback to regular call if arg 2 is not definitely |arguments|.
-    if (argument->type() != MIRType_Magic) {
+    if (argument->type() != MIRType_MagicOptimizedArguments) {
         CallInfo callInfo(alloc(), false);
         if (!callInfo.init(current, argc))
             return false;
         return makeCall(native, callInfo, false);
     }
 
     if (!native ||
         !native->isNative() ||
@@ -5189,17 +5187,17 @@ ArgumentTypesMatch(MDefinition *def, typ
     }
 
     if (def->type() == MIRType_Value)
         return false;
 
     if (def->type() == MIRType_Object)
         return calleeTypes->unknownObject();
 
-    return calleeTypes->mightBeType(ValueTypeFromMIRType(def->type()));
+    return calleeTypes->mightBeMIRType(def->type());
 }
 
 bool
 IonBuilder::testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo)
 {
     // If we have a known target, check if the caller arg types are a subset of callee.
     // Since typeset accumulates and can't decrease that means we don't need to check
     // the arguments anymore.
@@ -5214,17 +5212,17 @@ IonBuilder::testNeedsArgumentCheck(JSFun
     if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript)))
         return true;
     uint32_t expected_args = Min<uint32_t>(callInfo.argc(), target->nargs());
     for (size_t i = 0; i < expected_args; i++) {
         if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i)))
             return true;
     }
     for (size_t i = callInfo.argc(); i < target->nargs(); i++) {
-        if (!types::TypeScript::ArgTypes(targetScript, i)->mightBeType(JSVAL_TYPE_UNDEFINED))
+        if (!types::TypeScript::ArgTypes(targetScript, i)->mightBeMIRType(MIRType_Undefined))
             return true;
     }
 
     return false;
 }
 
 MCall *
 IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite)
@@ -5315,17 +5313,17 @@ DOMCallNeedsBarrier(const JSJitInfo* jit
         return true;
 
     // JSVAL_TYPE_OBJECT doesn't tell us much; we still have to barrier on the
     // actual type of the object.
     if (jitinfo->returnType() == JSVAL_TYPE_OBJECT)
         return true;
 
     // No need for a barrier if we're already expecting the type we'll produce.
-    return jitinfo->returnType() != types->getKnownTypeTag();
+    return MIRTypeFromValueType(jitinfo->returnType()) != types->getKnownMIRType();
 }
 
 bool
 IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite)
 {
     // Constructor calls to non-constructors should throw. We don't want to use
     // CallKnown in this case.
     JS_ASSERT_IF(callInfo.constructing() && target,
@@ -5368,18 +5366,18 @@ IonBuilder::jsop_eval(uint32_t argc)
 
         if (!info().funMaybeLazy())
             return abort("Direct eval in global code");
 
         // The 'this' value for the outer and eval scripts must be the
         // same. This is not guaranteed if a primitive string/number/etc.
         // is passed through to the eval invoke as the primitive may be
         // boxed into different objects if accessed via 'this'.
-        JSValueType type = thisTypes->getKnownTypeTag();
-        if (type != JSVAL_TYPE_OBJECT && type != JSVAL_TYPE_NULL && type != JSVAL_TYPE_UNDEFINED)
+        MIRType type = thisTypes->getKnownMIRType();
+        if (type != MIRType_Object && type != MIRType_Null && type != MIRType_Undefined)
             return abort("Direct eval from script with maybe-primitive 'this'");
 
         CallInfo callInfo(alloc(), /* constructing = */ false);
         if (!callInfo.init(current, argc))
             return false;
         callInfo.setImplicitlyUsedUnchecked();
 
         callInfo.fun()->setImplicitlyUsedUnchecked();
@@ -5528,17 +5526,17 @@ IonBuilder::jsop_initelem_array()
     MDefinition *value = current->pop();
     MDefinition *obj = current->peek(-1);
 
     // Make sure that arrays have the type being written to them by the
     // intializer, and that arrays are marked as non-packed when writing holes
     // to them during initialization.
     bool needStub = false;
     types::TypeObjectKey *initializer = obj->resultTypeSet()->getObject(0);
-    if (value->isConstant() && value->toConstant()->value().isMagic(JS_ELEMENTS_HOLE)) {
+    if (value->type() == MIRType_MagicHole) {
         if (!initializer->hasFlags(constraints(), types::OBJECT_FLAG_NON_PACKED))
             needStub = true;
     } else if (!initializer->unknownProperties()) {
         types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID);
         if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
             elemTypes.freeze(constraints());
             needStub = true;
         }
@@ -5953,17 +5951,17 @@ IonBuilder::newPendingLoopHeader(MBasicB
             else
                 existingType = baselineFrame_->varTypes[var];
 
             // Extract typeset from value.
             types::TemporaryTypeSet *typeSet =
                 alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(existingType);
             if (!typeSet)
                 return nullptr;
-            MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
+            MIRType type = typeSet->getKnownMIRType();
             if (!phi->addBackedgeType(type, typeSet))
                 return nullptr;
         }
     }
 
     return block;
 }
 
@@ -6254,18 +6252,17 @@ IonBuilder::pushTypeBarrier(MDefinition 
 
     // If the instruction has no side effects, we'll resume the entire operation.
     // The actual type barrier will occur in the interpreter. If the
     // instruction is effectful, even if it has a singleton type, there
     // must be a resume point capturing the original def, and resuming
     // to that point will explicitly monitor the new type.
 
     if (!needsBarrier) {
-        JSValueType type = observed->getKnownTypeTag();
-        MDefinition *replace = ensureDefiniteType(def, type);
+        MDefinition *replace = ensureDefiniteType(def, observed->getKnownMIRType());
         if (replace != def) {
             current->pop();
             current->push(replace);
         }
         replace->setResultTypeSet(observed);
         return true;
     }
 
@@ -6289,82 +6286,81 @@ IonBuilder::pushTypeBarrier(MDefinition 
 bool
 IonBuilder::pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func)
 {
     JS_ASSERT(func && func->isNative() && func->jitInfo());
 
     const JSJitInfo *jitinfo = func->jitInfo();
     bool barrier = DOMCallNeedsBarrier(jitinfo, observed);
     // Need to be a bit careful: if jitinfo->returnType is JSVAL_TYPE_DOUBLE but
-    // types->getKnownTypeTag() is JSVAL_TYPE_INT32, then don't unconditionally
+    // types->getKnownMIRType() is MIRType_Int32, then don't unconditionally
     // unbox as a double.  Instead, go ahead and barrier on having an int type,
     // since we know we need a barrier anyway due to the type mismatch.  This is
     // the only situation in which TI actually has more information about the
     // JSValueType than codegen can, short of jitinfo->returnType just being
     // JSVAL_TYPE_UNKNOWN.
     MDefinition* replace = ins;
     if (jitinfo->returnType() != JSVAL_TYPE_DOUBLE ||
-        observed->getKnownTypeTag() != JSVAL_TYPE_INT32) {
+        observed->getKnownMIRType() != MIRType_Int32) {
         JS_ASSERT(jitinfo->returnType() == JSVAL_TYPE_UNKNOWN ||
-                  observed->getKnownTypeTag() == JSVAL_TYPE_UNKNOWN ||
-                  jitinfo->returnType() == observed->getKnownTypeTag());
-        replace = ensureDefiniteType(ins, jitinfo->returnType());
+                  observed->getKnownMIRType() == MIRType_Value ||
+                  MIRTypeFromValueType(jitinfo->returnType()) == observed->getKnownMIRType());
+        replace = ensureDefiniteType(ins, MIRTypeFromValueType(jitinfo->returnType()));
         if (replace != ins) {
             current->pop();
             current->push(replace);
         }
     } else {
         JS_ASSERT(barrier);
     }
 
     return pushTypeBarrier(replace, observed, barrier);
 }
 
 MDefinition *
-IonBuilder::ensureDefiniteType(MDefinition *def, JSValueType definiteType)
+IonBuilder::ensureDefiniteType(MDefinition *def, MIRType definiteType)
 {
     MInstruction *replace;
     switch (definiteType) {
-      case JSVAL_TYPE_UNDEFINED:
+      case MIRType_Undefined:
         def->setImplicitlyUsedUnchecked();
         replace = MConstant::New(alloc(), UndefinedValue());
         break;
 
-      case JSVAL_TYPE_NULL:
+      case MIRType_Null:
         def->setImplicitlyUsedUnchecked();
         replace = MConstant::New(alloc(), NullValue());
         break;
 
-      case JSVAL_TYPE_UNKNOWN:
+      case MIRType_Value:
         return def;
 
       default: {
-        MIRType replaceType = MIRTypeFromValueType(definiteType);
         if (def->type() != MIRType_Value) {
-            JS_ASSERT(def->type() == replaceType);
+            JS_ASSERT(def->type() == definiteType);
             return def;
         }
-        replace = MUnbox::New(alloc(), def, replaceType, MUnbox::Infallible);
+        replace = MUnbox::New(alloc(), def, definiteType, MUnbox::Infallible);
         break;
       }
     }
 
     current->add(replace);
     return replace;
 }
 
 MDefinition *
 IonBuilder::ensureDefiniteTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
 {
     // We cannot arbitrarily add a typeset to a definition. It can be shared
     // in another path. So we always need to create a new MIR.
 
     // Use ensureDefiniteType to do unboxing. If that happened the type can
     // be added on the newly created unbox operation.
-    MDefinition *replace = ensureDefiniteType(def, types->getKnownTypeTag());
+    MDefinition *replace = ensureDefiniteType(def, types->getKnownMIRType());
     if (replace != def) {
         replace->setResultTypeSet(types);
         return replace;
     }
 
     // Create a NOP mir instruction to filter the typeset.
     MFilterTypeSet *filter = MFilterTypeSet::New(alloc(), def, types);
     current->add(filter);
@@ -6423,32 +6419,32 @@ IonBuilder::getStaticName(JSObject *stat
     }
 
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
     bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticType,
                                                 name, types, /* updateObserved = */ true);
 
     JSObject *singleton = types->getSingleton();
 
-    JSValueType knownType = types->getKnownTypeTag();
+    MIRType knownType = types->getKnownMIRType();
     if (!barrier) {
         if (singleton) {
             // Try to inline a known constant value.
             if (testSingletonProperty(staticObject, name) == singleton)
                 return pushConstant(ObjectValue(*singleton));
         }
-        if (knownType == JSVAL_TYPE_UNDEFINED)
+        if (knownType == MIRType_Undefined)
             return pushConstant(UndefinedValue());
-        if (knownType == JSVAL_TYPE_NULL)
+        if (knownType == MIRType_Null)
             return pushConstant(NullValue());
     }
 
     MInstruction *obj = constant(ObjectValue(*staticObject));
 
-    MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
+    MIRType rvalType = types->getKnownMIRType();
     if (barrier)
         rvalType = MIRType_Value;
 
     return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
                     rvalType, barrier, types);
 }
 
 // Whether 'types' includes all possible values represented by input/inputTypes.
@@ -6461,17 +6457,17 @@ jit::TypeSetIncludes(types::TypeSet *typ
     switch (input) {
       case MIRType_Undefined:
       case MIRType_Null:
       case MIRType_Boolean:
       case MIRType_Int32:
       case MIRType_Double:
       case MIRType_Float32:
       case MIRType_String:
-      case MIRType_Magic:
+      case MIRType_MagicOptimizedArguments:
         return types->hasType(types::Type::PrimitiveType(ValueTypeFromMIRType(input)));
 
       case MIRType_Object:
         return types->unknownObject() || (inputTypes && inputTypes->isSubset(types));
 
       case MIRType_Value:
         return types->unknown() || (inputTypes && inputTypes->isSubset(types));
 
@@ -6521,19 +6517,19 @@ IonBuilder::setStaticName(JSObject *stat
     JS_ASSERT(&obj->toConstant()->value().toObject() == staticObject);
 
     if (NeedsPostBarrier(info(), value))
         current->add(MPostWriteBarrier::New(alloc(), obj, value));
 
     // If the property has a known type, we may be able to optimize typed stores by not
     // storing the type tag.
     MIRType slotType = MIRType_None;
-    JSValueType knownType = property.knownTypeTag(constraints());
-    if (knownType != JSVAL_TYPE_UNKNOWN)
-        slotType = MIRTypeFromValueType(knownType);
+    MIRType knownType = property.knownMIRType(constraints());
+    if (knownType != MIRType_Value)
+        slotType = knownType;
 
     bool needsBarrier = property.needsBarrier(constraints());
     return storeSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
                      value, needsBarrier, slotType);
 }
 
 bool
 IonBuilder::jsop_getgname(PropertyName *name)
@@ -6588,21 +6584,20 @@ IonBuilder::jsop_getname(PropertyName *n
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
     return pushTypeBarrier(ins, types, true);
 }
 
 bool
 IonBuilder::jsop_intrinsic(PropertyName *name)
 {
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
-    JSValueType type = types->getKnownTypeTag();
 
     // If we haven't executed this opcode yet, we need to get the intrinsic
     // value and monitor the result.
-    if (type == JSVAL_TYPE_UNKNOWN) {
+    if (types->empty()) {
         MCallGetIntrinsicValue *ins = MCallGetIntrinsicValue::New(alloc(), name);
 
         current->add(ins);
         current->push(ins);
 
         if (!resumeAfter(ins))
             return false;
 
@@ -6627,33 +6622,33 @@ IonBuilder::jsop_bindname(PropertyName *
     MBindNameCache *ins = MBindNameCache::New(alloc(), scopeChain, name, script(), pc);
 
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
-static JSValueType
+static MIRType
 GetElemKnownType(bool needsHoleCheck, types::TemporaryTypeSet *types)
 {
-    JSValueType knownType = types->getKnownTypeTag();
+    MIRType knownType = types->getKnownMIRType();
 
     // Null and undefined have no payload so they can't be specialized.
     // Since folding null/undefined while building SSA is not safe (see the
     // comment in IsPhiObservable), we just add an untyped load instruction
     // and rely on pushTypeBarrier and DCE to replace it with a null/undefined
     // constant.
-    if (knownType == JSVAL_TYPE_UNDEFINED || knownType == JSVAL_TYPE_NULL)
-        knownType = JSVAL_TYPE_UNKNOWN;
+    if (knownType == MIRType_Undefined || knownType == MIRType_Null)
+        knownType = MIRType_Value;
 
     // Different architectures may want typed element reads which require
     // hole checks to be done as either value or typed reads.
     if (needsHoleCheck && !LIRGenerator::allowTypedElementHoleCheck())
-        knownType = JSVAL_TYPE_UNKNOWN;
+        knownType = MIRType_Value;
 
     return knownType;
 }
 
 bool
 IonBuilder::jsop_getelem()
 {
     MDefinition *index = current->pop();
@@ -6677,17 +6672,17 @@ IonBuilder::jsop_getelem()
         return emitted;
 
     if (!getElemTryArguments(&emitted, obj, index) || emitted)
         return emitted;
 
     if (!getElemTryArgumentsInlined(&emitted, obj, index) || emitted)
         return emitted;
 
-    if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_Magic))
+    if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_MagicOptimizedArguments))
         return abort("Type is not definitely lazy arguments.");
 
     if (!getElemTryCache(&emitted, obj, index) || emitted)
         return emitted;
 
     // Emit call.
     MInstruction *ins = MCallGetElement::New(alloc(), obj, index);
 
@@ -7113,17 +7108,17 @@ IonBuilder::getElemTryString(bool *emitt
 bool
 IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *index)
 {
     JS_ASSERT(*emitted == false);
 
     if (inliningDepth_ > 0)
         return true;
 
-    if (obj->type() != MIRType_Magic)
+    if (obj->type() != MIRType_MagicOptimizedArguments)
         return true;
 
     // Emit GetFrameArgument.
 
     JS_ASSERT(!info().argsObjAliasesFormals());
 
     // Type Inference has guaranteed this is an optimized arguments object.
     obj->setImplicitlyUsedUnchecked();
@@ -7156,17 +7151,17 @@ IonBuilder::getElemTryArguments(bool *em
 bool
 IonBuilder::getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinition *index)
 {
     JS_ASSERT(*emitted == false);
 
     if (inliningDepth_ == 0)
         return true;
 
-    if (obj->type() != MIRType_Magic)
+    if (obj->type() != MIRType_MagicOptimizedArguments)
         return true;
 
     // Emit inlined arguments.
     obj->setImplicitlyUsedUnchecked();
 
     JS_ASSERT(!info().argsObjAliasesFormals());
 
     // When the id is constant, we can just return the corresponding inlined argument
@@ -7232,20 +7227,20 @@ IonBuilder::getElemTryCache(bool *emitte
     current->push(ins);
 
     if (!resumeAfter(ins))
         return false;
 
     // Spice up type information.
     if (index->type() == MIRType_Int32 && !barrier) {
         bool needHoleCheck = !ElementAccessIsPacked(constraints(), obj);
-        JSValueType knownType = GetElemKnownType(needHoleCheck, types);
-
-        if (knownType != JSVAL_TYPE_UNKNOWN && knownType != JSVAL_TYPE_DOUBLE)
-            ins->setResultType(MIRTypeFromValueType(knownType));
+        MIRType knownType = GetElemKnownType(needHoleCheck, types);
+
+        if (knownType != MIRType_Value && knownType != MIRType_Double)
+            ins->setResultType(knownType);
     }
 
     if (!pushTypeBarrier(ins, types, barrier))
         return false;
 
     *emitted = true;
     return true;
 }
@@ -7267,17 +7262,17 @@ IonBuilder::jsop_getelem_dense(MDefiniti
 
     // Reads which are on holes in the object do not have to bail out if
     // undefined values have been observed at this access site and the access
     // cannot hit another indexed property on the object or its prototypes.
     bool readOutOfBounds =
         types->hasType(types::Type::UndefinedType()) &&
         !ElementAccessHasExtraIndexedProperty(constraints(), obj);
 
-    JSValueType knownType = JSVAL_TYPE_UNKNOWN;
+    MIRType knownType = MIRType_Value;
     if (!barrier)
         knownType = GetElemKnownType(needsHoleCheck, types);
 
     // Ensure index is an integer.
     MInstruction *idInt32 = MToInt32::New(alloc(), index);
     current->add(idInt32);
     index = idInt32;
 
@@ -7300,17 +7295,17 @@ IonBuilder::jsop_getelem_dense(MDefiniti
     types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
     ExecutionMode executionMode = info().executionMode();
     bool loadDouble =
         executionMode == SequentialExecution &&
         !barrier &&
         loopDepth_ &&
         !readOutOfBounds &&
         !needsHoleCheck &&
-        knownType == JSVAL_TYPE_DOUBLE &&
+        knownType == MIRType_Double &&
         objTypes &&
         objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles;
     if (loadDouble)
         elements = addConvertElementsToDoubles(elements);
 
     MInstruction *load;
 
     if (!readOutOfBounds) {
@@ -7327,17 +7322,17 @@ IonBuilder::jsop_getelem_dense(MDefiniti
         // or that we can read out-of-bounds accesses. In this case, the bounds
         // check is part of the opcode.
         load = MLoadElementHole::New(alloc(), elements, index, initLength, needsHoleCheck);
         current->add(load);
 
         // If maybeUndefined was true, the typeset must have undefined, and
         // then either additional types or a barrier. This means we should
         // never have a typed version of LoadElementHole.
-        JS_ASSERT(knownType == JSVAL_TYPE_UNKNOWN);
+        JS_ASSERT(knownType == MIRType_Value);
     }
 
     // If the array is being converted to doubles, but we've observed
     // just int, substitute a type set of int+double into the observed
     // type set. The reason for this is that, in the
     // interpreter+baseline, such arrays may consist of mixed
     // ints/doubles, but when we enter ion code, we will be coercing
     // all inputs to doubles. Therefore, the type barrier checking for
@@ -7348,30 +7343,30 @@ IonBuilder::jsop_getelem_dense(MDefiniti
     // and doubles. There is perhaps a tradeoff here, so we limit this
     // optimization to parallel code, where it is needed to prevent
     // perpetual bailouts in some extreme cases. (Bug 977853)
     //
     // NB: we have not added a MConvertElementsToDoubles MIR, so we
     // cannot *assume* the result is a double.
     if (executionMode == ParallelExecution &&
         barrier &&
-        types->getKnownTypeTag() == JSVAL_TYPE_INT32 &&
+        types->getKnownMIRType() == MIRType_Int32 &&
         objTypes &&
         objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles)
     {
         // Note: double implies int32 as well for typesets
         types = alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(types::Type::DoubleType());
         if (!types)
             return false;
 
         barrier = false; // Don't need a barrier anymore
     }
 
-    if (knownType != JSVAL_TYPE_UNKNOWN)
-        load->setResultType(MIRTypeFromValueType(knownType));
+    if (knownType != MIRType_Value)
+        load->setResultType(knownType);
 
     current->push(load);
     return pushTypeBarrier(load, types, barrier);
 }
 
 MInstruction *
 IonBuilder::getTypedArrayLength(MDefinition *obj)
 {
@@ -7573,17 +7568,17 @@ IonBuilder::jsop_setelem()
         return emitted;
 
     if (!setElemTryDense(&emitted, object, index, value) || emitted)
         return emitted;
 
     if (!setElemTryArguments(&emitted, object, index, value) || emitted)
         return emitted;
 
-    if (script()->argumentsHasVarBinding() && object->mightBeType(MIRType_Magic))
+    if (script()->argumentsHasVarBinding() && object->mightBeType(MIRType_MagicOptimizedArguments))
         return abort("Type is not definitely lazy arguments.");
 
     if (!setElemTryCache(&emitted, object, index, value) || emitted)
         return emitted;
 
     // Emit call.
     MInstruction *ins = MCallSetElement::New(alloc(), object, index, value);
     current->add(ins);
@@ -7784,17 +7779,17 @@ IonBuilder::setElemTryDense(bool *emitte
 }
 
 bool
 IonBuilder::setElemTryArguments(bool *emitted, MDefinition *object,
                                 MDefinition *index, MDefinition *value)
 {
     JS_ASSERT(*emitted == false);
 
-    if (object->type() != MIRType_Magic)
+    if (object->type() != MIRType_MagicOptimizedArguments)
         return true;
 
     // Arguments are not supported yet.
     return abort("NYI arguments[]=");
 }
 
 bool
 IonBuilder::setElemTryCache(bool *emitted, MDefinition *object,
@@ -8044,17 +8039,17 @@ IonBuilder::jsop_length()
     return jsop_getprop(name);
 }
 
 bool
 IonBuilder::jsop_length_fastPath()
 {
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
 
-    if (types->getKnownTypeTag() != JSVAL_TYPE_INT32)
+    if (types->getKnownMIRType() != MIRType_Int32)
         return false;
 
     MDefinition *obj = current->peek(-1);
 
     if (obj->mightBeType(MIRType_String)) {
         if (obj->mightBeType(MIRType_Object))
             return false;
         current->pop();
@@ -8588,19 +8583,22 @@ IonBuilder::jsop_getprop(PropertyName *n
 
     return pushTypeBarrier(call, types, true);
 }
 
 bool
 IonBuilder::getPropTryArgumentsLength(bool *emitted)
 {
     JS_ASSERT(*emitted == false);
-    if (current->peek(-1)->type() != MIRType_Magic) {
-        if (script()->argumentsHasVarBinding() && current->peek(-1)->mightBeType(MIRType_Magic))
+    if (current->peek(-1)->type() != MIRType_MagicOptimizedArguments) {
+        if (script()->argumentsHasVarBinding() &&
+            current->peek(-1)->mightBeType(MIRType_MagicOptimizedArguments))
+        {
             return abort("Type is not definitely lazy arguments.");
+        }
         return true;
     }
     if (JSOp(*pc) != JSOP_LENGTH)
         return true;
 
     *emitted = true;
     return jsop_arguments_length();
 }
@@ -8734,17 +8732,17 @@ IonBuilder::getPropTryDefiniteSlot(bool 
     if (obj->type() != MIRType_Object) {
         MGuardObject *guard = MGuardObject::New(alloc(), obj);
         current->add(guard);
         useObj = guard;
     }
 
     MLoadFixedSlot *fixed = MLoadFixedSlot::New(alloc(), useObj, property.maybeTypes()->definiteSlot());
     if (!barrier)
-        fixed->setResultType(MIRTypeFromValueType(types->getKnownTypeTag()));
+        fixed->setResultType(types->getKnownMIRType());
 
     current->add(fixed);
     current->push(fixed);
 
     if (!pushTypeBarrier(fixed, types, barrier))
         return false;
 
     *emitted = true;
@@ -8792,17 +8790,17 @@ IonBuilder::getPropTryCommonGetter(bool 
         if (!pushDOMTypeBarrier(get, types, commonGetter))
             return false;
 
         *emitted = true;
         return true;
     }
 
     // Don't call the getter with a primitive value.
-    if (objTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT) {
+    if (objTypes->getKnownMIRType() != MIRType_Object) {
         MGuardObject *guardObj = MGuardObject::New(alloc(), obj);
         current->add(guardObj);
         obj = guardObj;
     }
 
     // Spoof stack to expected state for call.
 
     // Make sure there's enough room
@@ -8868,17 +8866,17 @@ IonBuilder::getPropTryInlineAccess(bool 
 
     BaselineInspector::ShapeVector shapes(alloc());
     if (!inspector->maybeShapesForPropertyOp(pc, shapes))
         return false;
 
     if (shapes.empty() || !CanInlinePropertyOpShapes(shapes))
         return true;
 
-    MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
+    MIRType rvalType = types->getKnownMIRType();
     if (barrier || IsNullOrUndefined(rvalType))
         rvalType = MIRType_Value;
 
     MDefinition *obj = current->pop();
     if (shapes.length() == 1) {
         // In the monomorphic case, use separate ShapeGuard and LoadSlot
         // instructions.
         spew("Inlining monomorphic GETPROP");
@@ -8970,17 +8968,17 @@ IonBuilder::getPropTryCache(bool *emitte
     }
 
     current->add(load);
     current->push(load);
 
     if (load->isEffectful() && !resumeAfter(load))
         return false;
 
-    MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
+    MIRType rvalType = types->getKnownMIRType();
     if (barrier || IsNullOrUndefined(rvalType))
         rvalType = MIRType_Value;
     load->setResultType(rvalType);
 
     if (!pushTypeBarrier(load, types, barrier))
         return false;
 
     *emitted = true;
@@ -9079,17 +9077,17 @@ IonBuilder::setPropTryCommonSetter(bool 
     // Try emitting dom call.
     if (!setPropTryCommonDOMSetter(emitted, obj, value, commonSetter, isDOM))
         return false;
 
     if (*emitted)
         return true;
 
     // Don't call the setter with a primitive value.
-    if (objTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT) {
+    if (objTypes->getKnownMIRType() != MIRType_Object) {
         MGuardObject *guardObj = MGuardObject::New(alloc(), obj);
         current->add(guardObj);
         obj = guardObj;
     }
 
     // Dummy up the stack, as in getprop. We are pushing an extra value, so
     // ensure there is enough space.
     if (!current->ensureHasSlots(3))
@@ -9579,17 +9577,17 @@ IonBuilder::jsop_this()
     }
 
     if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
         // No need to wrap primitive |this| in strict mode or self-hosted code.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
-    if (thisTypes->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
+    if (thisTypes->getKnownMIRType() == MIRType_Object ||
         (thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))
     {
         // This is safe, because if the entry type of |this| is an object, it
         // will necessarily be an object throughout the entire function. OSR
         // can introduce a phi, but this phi will be specialized.
         current->pushSlot(info().thisSlot());
         return true;
     }
@@ -10032,17 +10030,17 @@ IonBuilder::lookupTypeDescrSet(MDefiniti
     return typeSetToTypeDescrSet(types, out);
 }
 
 bool
 IonBuilder::typeSetToTypeDescrSet(types::TemporaryTypeSet *types,
                                   TypeDescrSet *out)
 {
     // Extract TypeDescrSet directly if we can
-    if (!types || types->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
+    if (!types || types->getKnownMIRType() != MIRType_Object)
         return true;
 
     // And only known objects.
     if (types->unknownObject())
         return true;
 
     TypeDescrSetBuilder set;
     for (uint32_t i = 0; i < types->getObjectCount(); i++) {
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -349,17 +349,17 @@ class IonBuilder : public MIRGenerator
     // on observed and the JSFunction that we're planning to call. The
     // JSFunction must be a DOM method or getter.
     bool pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func);
 
     // If definiteType is not known or def already has the right type, just
     // returns def.  Otherwise, returns an MInstruction that has that definite
     // type, infallibly unboxing ins as needed.  The new instruction will be
     // added to |current| in this case.
-    MDefinition *ensureDefiniteType(MDefinition* def, JSValueType definiteType);
+    MDefinition *ensureDefiniteType(MDefinition* def, MIRType definiteType);
 
     // Creates a MDefinition based on the given def improved with type as TypeSet.
     MDefinition *ensureDefiniteTypeSet(MDefinition* def, types::TemporaryTypeSet *types);
 
     JSObject *getSingletonPrototype(JSFunction *target);
 
     MDefinition *createThisScripted(MDefinition *callee);
     MDefinition *createThisScriptedSingleton(JSFunction *target, MDefinition *callee);
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -122,22 +122,26 @@ class MacroAssembler : public MacroAssem
           : Branch(cond, reg, jump),
             type_(type)
         { }
 
         void emit(MacroAssembler &masm) {
             JS_ASSERT(isInitialized());
             MIRType mirType = MIRType_None;
 
-            if (type_.isPrimitive())
-                mirType = MIRTypeFromValueType(type_.primitive());
-            else if (type_.isAnyObject())
+            if (type_.isPrimitive()) {
+                if (type_.isMagicArguments())
+                    mirType = MIRType_MagicOptimizedArguments;
+                else
+                    mirType = MIRTypeFromValueType(type_.primitive());
+            } else if (type_.isAnyObject()) {
                 mirType = MIRType_Object;
-            else
+            } else {
                 MOZ_ASSUME_UNREACHABLE("Unknown conversion to mirtype");
+            }
 
             if (mirType == MIRType_Double)
                 masm.branchTestNumber(cond(), reg(), jump());
             else
                 masm.branchTestMIRType(cond(), reg(), mirType, jump());
         }
 
     };
@@ -327,24 +331,26 @@ class MacroAssembler : public MacroAssem
         loadPrivate(handlerAddr, scratch);
         Address familyAddr(scratch, BaseProxyHandler::offsetOfFamily());
         branchPtr(cond, familyAddr, ImmPtr(handlerp), label);
     }
 
     template <typename Value>
     void branchTestMIRType(Condition cond, const Value &val, MIRType type, Label *label) {
         switch (type) {
-          case MIRType_Null:        return branchTestNull(cond, val, label);
-          case MIRType_Undefined:   return branchTestUndefined(cond, val, label);
-          case MIRType_Boolean:     return branchTestBoolean(cond, val, label);
-          case MIRType_Int32:       return branchTestInt32(cond, val, label);
-          case MIRType_String:      return branchTestString(cond, val, label);
-          case MIRType_Object:      return branchTestObject(cond, val, label);
-          case MIRType_Double:      return branchTestDouble(cond, val, label);
-          case MIRType_Magic:       return branchTestMagic(cond, val, label);
+          case MIRType_Null:      return branchTestNull(cond, val, label);
+          case MIRType_Undefined: return branchTestUndefined(cond, val, label);
+          case MIRType_Boolean:   return branchTestBoolean(cond, val, label);
+          case MIRType_Int32:     return branchTestInt32(cond, val, label);
+          case MIRType_String:    return branchTestString(cond, val, label);
+          case MIRType_Object:    return branchTestObject(cond, val, label);
+          case MIRType_Double:    return branchTestDouble(cond, val, label);
+          case MIRType_MagicOptimizedArguments: // Fall through.
+          case MIRType_MagicIsConstructing:
+          case MIRType_MagicHole: return branchTestMagic(cond, val, label);
           default:
             MOZ_ASSUME_UNREACHABLE("Bad MIRType");
         }
     }
 
     // Branches to |label| if |reg| is false. |reg| should be a C++ bool.
     void branchIfFalseBool(Register reg, Label *label) {
         // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -65,17 +65,17 @@ BailoutKindString(BailoutKind kind)
         return "Bailout_ShapeGuard";
       case Bailout_BaselineInfo:
         return "Bailout_BaselineInfo";
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid BailoutKind");
     }
 }
 
-static const uint32_t ELEMENT_TYPE_BITS = 4;
+static const uint32_t ELEMENT_TYPE_BITS = 5;
 static const uint32_t ELEMENT_TYPE_SHIFT = 0;
 static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1;
 static const uint32_t VECTOR_SCALE_BITS = 2;
 static const uint32_t VECTOR_SCALE_SHIFT = ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT;
 static const uint32_t VECTOR_SCALE_MASK = (1 << VECTOR_SCALE_BITS) - 1;
 
 // The ordering of this enumeration is important: Anything < Value is a
 // specialized type. Furthermore, anything < String has trivial conversion to
@@ -85,24 +85,26 @@ enum MIRType
     MIRType_Undefined,
     MIRType_Null,
     MIRType_Boolean,
     MIRType_Int32,
     MIRType_Double,
     MIRType_Float32,
     MIRType_String,
     MIRType_Object,
-    MIRType_Magic,
+    MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value.
+    MIRType_MagicHole,               // JS_ELEMENTS_HOLE magic value.
+    MIRType_MagicIsConstructing,     // JS_IS_CONSTRUCTING magic value.
     MIRType_Value,
-    MIRType_None,          // Invalid, used as a placeholder.
-    MIRType_Slots,         // A slots vector
-    MIRType_Elements,      // An elements vector
-    MIRType_Pointer,       // An opaque pointer that receives no special treatment
-    MIRType_Shape,         // A Shape pointer.
-    MIRType_ForkJoinContext, // js::ForkJoinContext*
+    MIRType_None,                    // Invalid, used as a placeholder.
+    MIRType_Slots,                   // A slots vector
+    MIRType_Elements,                // An elements vector
+    MIRType_Pointer,                 // An opaque pointer that receives no special treatment
+    MIRType_Shape,                   // A Shape pointer.
+    MIRType_ForkJoinContext,         // js::ForkJoinContext*
     MIRType_Last = MIRType_ForkJoinContext,
     MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
     MIRType_Int32x4   = MIRType_Int32   | (2 << VECTOR_SCALE_SHIFT),
     MIRType_Doublex2  = MIRType_Double  | (1 << VECTOR_SCALE_SHIFT)
 };
 
 static inline MIRType
 ElementType(MIRType type)
@@ -115,33 +117,33 @@ static inline uint32_t
 VectorSize(MIRType type)
 {
     return 1 << ((type >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK);
 }
 
 static inline MIRType
 MIRTypeFromValueType(JSValueType type)
 {
+    // This function does not deal with magic types. Magic constants should be
+    // filtered out in MIRTypeFromValue.
     switch (type) {
       case JSVAL_TYPE_DOUBLE:
         return MIRType_Double;
       case JSVAL_TYPE_INT32:
         return MIRType_Int32;
       case JSVAL_TYPE_UNDEFINED:
         return MIRType_Undefined;
       case JSVAL_TYPE_STRING:
         return MIRType_String;
       case JSVAL_TYPE_BOOLEAN:
         return MIRType_Boolean;
       case JSVAL_TYPE_NULL:
         return MIRType_Null;
       case JSVAL_TYPE_OBJECT:
         return MIRType_Object;
-      case JSVAL_TYPE_MAGIC:
-        return MIRType_Magic;
       case JSVAL_TYPE_UNKNOWN:
         return MIRType_Value;
       default:
         MOZ_ASSUME_UNREACHABLE("unexpected jsval type");
     }
 }
 
 static inline JSValueType
@@ -156,17 +158,19 @@ ValueTypeFromMIRType(MIRType type)
       return JSVAL_TYPE_BOOLEAN;
     case MIRType_Int32:
       return JSVAL_TYPE_INT32;
     case MIRType_Float32: // Fall through, there's no JSVAL for Float32
     case MIRType_Double:
       return JSVAL_TYPE_DOUBLE;
     case MIRType_String:
       return JSVAL_TYPE_STRING;
-    case MIRType_Magic:
+    case MIRType_MagicOptimizedArguments:
+    case MIRType_MagicHole:
+    case MIRType_MagicIsConstructing:
       return JSVAL_TYPE_MAGIC;
     default:
       JS_ASSERT(type == MIRType_Object);
       return JSVAL_TYPE_OBJECT;
   }
 }
 
 static inline JSValueTag
@@ -190,18 +194,22 @@ StringFromMIRType(MIRType type)
     case MIRType_Double:
       return "Double";
     case MIRType_Float32:
       return "Float32";
     case MIRType_String:
       return "String";
     case MIRType_Object:
       return "Object";
-    case MIRType_Magic:
-      return "Magic";
+    case MIRType_MagicOptimizedArguments:
+      return "MagicOptimizedArguments";
+    case MIRType_MagicHole:
+      return "MagicHole";
+    case MIRType_MagicIsConstructing:
+      return "MagicIsConstructing";
     case MIRType_Value:
       return "Value";
     case MIRType_None:
       return "None";
     case MIRType_Slots:
       return "Slots";
     case MIRType_Elements:
       return "Elements";
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -197,17 +197,17 @@ IonBuilder::getInlineReturnTypeSet()
 {
     return bytecodeTypes(pc);
 }
 
 MIRType
 IonBuilder::getInlineReturnType()
 {
     types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
-    return MIRTypeFromValueType(returnTypes->getKnownTypeTag());
+    return returnTypes->getKnownMIRType();
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function)
 {
     if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
@@ -1532,17 +1532,17 @@ IonBuilder::inlineNewDenseArrayForSequen
 
 IonBuilder::InliningStatus
 IonBuilder::inlineNewDenseArrayForParallelExecution(CallInfo &callInfo)
 {
     // Create the new parallel array object.  Parallel arrays have specially
     // constructed type objects, so we can only perform the inlining if we
     // already have one of these type objects.
     types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
-    if (returnTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
+    if (returnTypes->getKnownMIRType() != MIRType_Object)
         return InliningStatus_NotInlined;
     if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
         return InliningStatus_NotInlined;
     if (callInfo.getArg(0)->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
     types::TypeObject *typeObject = returnTypes->getTypeObject(0);
 
     JSObject *templateObject = inspector->getTemplateObjectForNative(pc, intrinsic_NewDenseArray);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -543,18 +543,24 @@ MConstant::printOpcode(FILE *fp) const
             break;
         }
         fprintf(fp, "object %p (%s)", (void *)&value().toObject(),
                 value().toObject().getClass()->name);
         break;
       case MIRType_String:
         fprintf(fp, "string %p", (void *)value().toString());
         break;
-      case MIRType_Magic:
-        fprintf(fp, "magic");
+      case MIRType_MagicOptimizedArguments:
+        fprintf(fp, "magic lazyargs");
+        break;
+      case MIRType_MagicHole:
+        fprintf(fp, "magic hole");
+        break;
+      case MIRType_MagicIsConstructing:
+        fprintf(fp, "magic is-constructing");
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("unexpected type");
     }
 }
 
 bool
 MConstant::canProduceFloat32() const
@@ -1117,17 +1123,17 @@ MPhi::typeIncludes(MDefinition *def)
     if (def->type() == MIRType_Int32 && this->type() == MIRType_Double)
         return true;
 
     if (types::TemporaryTypeSet *types = def->resultTypeSet()) {
         if (this->resultTypeSet())
             return types->isSubset(this->resultTypeSet());
         if (this->type() == MIRType_Value || types->empty())
             return true;
-        return this->type() == MIRTypeFromValueType(types->getKnownTypeTag());
+        return this->type() == types->getKnownMIRType();
     }
 
     if (def->type() == MIRType_Value) {
         // This phi must be able to be any value.
         return this->type() == MIRType_Value
             && (!this->resultTypeSet() || this->resultTypeSet()->unknown());
     }
 
@@ -1690,17 +1696,19 @@ MUrsh::fallible() const
     return !range() || !range()->hasInt32Bounds();
 }
 
 static inline bool
 KnownNonStringPrimitive(MDefinition *op)
 {
     return !op->mightBeType(MIRType_Object)
         && !op->mightBeType(MIRType_String)
-        && !op->mightBeType(MIRType_Magic);
+        && !op->mightBeType(MIRType_MagicOptimizedArguments)
+        && !op->mightBeType(MIRType_MagicHole)
+        && !op->mightBeType(MIRType_MagicIsConstructing);
 }
 
 void
 MBinaryArithInstruction::infer(TempAllocator &alloc, BaselineInspector *inspector, jsbytecode *pc)
 {
     JS_ASSERT(this->type() == MIRType_Value);
 
     specialization_ = MIRType_None;
@@ -1814,17 +1822,19 @@ SafelyCoercesToDouble(MDefinition *op)
 
 static bool
 ObjectOrSimplePrimitive(MDefinition *op)
 {
     // Return true if op is either undefined/null/boolean/int32 or an object.
     return !op->mightBeType(MIRType_String)
         && !op->mightBeType(MIRType_Double)
         && !op->mightBeType(MIRType_Float32)
-        && !op->mightBeType(MIRType_Magic);
+        && !op->mightBeType(MIRType_MagicOptimizedArguments)
+        && !op->mightBeType(MIRType_MagicHole)
+        && !op->mightBeType(MIRType_MagicIsConstructing);
 }
 
 static bool
 CanDoValueBitwiseCmp(MDefinition *lhs, MDefinition *rhs, bool looseEq)
 {
     // Only primitive (not double/string) or objects are supported.
     // I.e. Undefined/Null/Boolean/Int32 and Object
     if (!ObjectOrSimplePrimitive(lhs) || !ObjectOrSimplePrimitive(rhs))
@@ -3060,17 +3070,17 @@ jit::DenseNativeElementType(types::Compi
         if (!object)
             continue;
 
         if (object->unknownProperties())
             return MIRType_None;
 
         types::HeapTypeSetKey elementTypes = object->property(JSID_VOID);
 
-        MIRType type = MIRTypeFromValueType(elementTypes.knownTypeTag(constraints));
+        MIRType type = elementTypes.knownMIRType(constraints);
         if (type == MIRType_None)
             return MIRType_None;
 
         if (elementType == MIRType_None)
             elementType = type;
         else if (elementType != type)
             return MIRType_None;
     }
@@ -3337,17 +3347,17 @@ TryAddTypeBarrierForWrite(TempAllocator 
             {
                 return false;
             }
         }
     }
 
     JS_ASSERT(!aggregateProperty.empty());
 
-    MIRType propertyType = MIRTypeFromValueType(aggregateProperty.ref().knownTypeTag(constraints));
+    MIRType propertyType = aggregateProperty.ref().knownMIRType(constraints);
     switch (propertyType) {
       case MIRType_Boolean:
       case MIRType_Int32:
       case MIRType_Double:
       case MIRType_String: {
         // The property is a particular primitive type, guard by unboxing the
         // value before the write.
         if (!(*pvalue)->mightBeType(propertyType)) {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -37,16 +37,28 @@ class BaselineInspector;
 class ValueNumberData;
 class Range;
 
 static const inline
 MIRType MIRTypeFromValue(const js::Value &vp)
 {
     if (vp.isDouble())
         return MIRType_Double;
+    if (vp.isMagic()) {
+        switch (vp.whyMagic()) {
+          case JS_OPTIMIZED_ARGUMENTS:
+            return MIRType_MagicOptimizedArguments;
+          case JS_ELEMENTS_HOLE:
+            return MIRType_MagicHole;
+          case JS_IS_CONSTRUCTING:
+            return MIRType_MagicIsConstructing;
+          default:
+            MOZ_ASSERT(!"Unexpected magic constant");
+        }
+    }
     return MIRTypeFromValueType(vp.extractNonDoubleType());
 }
 
 #define MIR_FLAG_LIST(_)                                                        \
     _(InWorklist)                                                               \
     _(EmittedAtUses)                                                            \
     _(LoopInvariant)                                                            \
     _(Commutative)                                                              \
@@ -450,25 +462,25 @@ class MDefinition : public MNode
     }
 
     types::TemporaryTypeSet *resultTypeSet() const {
         return resultTypeSet_;
     }
     bool emptyResultTypeSet() const;
 
     bool mightBeType(MIRType type) const {
-        JS_ASSERT(type != MIRType_Value);
+        MOZ_ASSERT(type != MIRType_Value);
 
         if (type == this->type())
             return true;
 
         if (MIRType_Value != this->type())
             return false;
 
-        return !resultTypeSet() || resultTypeSet()->mightBeType(ValueTypeFromMIRType(type));
+        return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
     }
 
     // Float32 specialization operations (see big comment in IonAnalysis before the Float32
     // specialization algorithm).
     virtual bool isFloat32Commutative() const { return false; }
     virtual bool canProduceFloat32() const { return false; }
     virtual bool canConsumeFloat32(MUse *use) const { return false; }
     virtual void trySpecializeFloat32(TempAllocator &alloc) {}
@@ -8983,19 +8995,17 @@ class MGuardThreadExclusive
 
 class MFilterTypeSet
   : public MUnaryInstruction
 {
     MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
       : MUnaryInstruction(def)
     {
         JS_ASSERT(!types->unknown());
-
-        MIRType type = MIRTypeFromValueType(types->getKnownTypeTag());
-        setResultType(type);
+        setResultType(types->getKnownMIRType());
         setResultTypeSet(types);
     }
 
   public:
     INSTRUCTION_HEADER(FilterTypeSet)
 
     static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
         return new(alloc) MFilterTypeSet(def, types);
@@ -9017,19 +9027,17 @@ class MFilterTypeSet
 class MTypeBarrier
   : public MUnaryInstruction,
     public TypeBarrierPolicy
 {
     MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types)
       : MUnaryInstruction(def)
     {
         JS_ASSERT(!types->unknown());
-
-        MIRType type = MIRTypeFromValueType(types->getKnownTypeTag());
-        setResultType(type);
+        setResultType(types->getKnownMIRType());
         setResultTypeSet(types);
 
         setGuard();
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(TypeBarrier)
@@ -9052,17 +9060,17 @@ class MTypeBarrier
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
     }
 
     bool alwaysBails() const {
         // If mirtype of input doesn't agree with mirtype of barrier,
         // we will definitely bail.
-        MIRType type = MIRTypeFromValueType(resultTypeSet()->getKnownTypeTag());
+        MIRType type = resultTypeSet()->getKnownMIRType();
         if (type == MIRType_Value)
             return false;
         if (input()->type() == MIRType_Value)
             return false;
         return input()->type() != type;
     }
 };
 
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -288,18 +288,19 @@ TypeBarrierPolicy::adjustInputs(TempAllo
         ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // Input is a value. Unbox the input to the requested type.
     if (inputType == MIRType_Value) {
         JS_ASSERT(outputType != MIRType_Value);
 
-        // We can't unbox a value to null/undefined. So keep output also a value.
-        if (IsNullOrUndefined(outputType) || outputType == MIRType_Magic) {
+        // We can't unbox a value to null/undefined/lazyargs. So keep output
+        // also a value.
+        if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
             JS_ASSERT(ins->defUseCount() == 0);
             ins->setResultType(MIRType_Value);
             return true;
         }
 
         MUnbox *unbox = MUnbox::New(alloc, ins->getOperand(0), outputType, MUnbox::TypeBarrier);
         ins->block()->insertBefore(ins, unbox);
         ins->replaceOperand(0, unbox);
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -188,17 +188,17 @@ CodeGeneratorShared::encodeAllocations(L
                 MConstant *constant = mir->toConstant();
                 uint32_t index;
                 if (!graph.addConstantToPool(constant->value(), &index))
                     return false;
                 alloc = RValueAllocation::ConstantPool(index);
             }
             break;
           }
-          case MIRType_Magic:
+          case MIRType_MagicOptimizedArguments:
           {
             uint32_t index;
             if (!graph.addConstantToPool(MagicValue(JS_OPTIMIZED_ARGUMENTS), &index))
                 return false;
             alloc = RValueAllocation::ConstantPool(index);
             break;
           }
           default:
--- a/js/src/jsapi-tests/testSourcePolicy.cpp
+++ b/js/src/jsapi-tests/testSourcePolicy.cpp
@@ -4,17 +4,17 @@
 
 #include "jsscript.h"
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testBug795104)
 {
     JS::CompileOptions opts(cx);
-    opts.setSourcePolicy(JS::CompileOptions::NO_SOURCE);
+    JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(true);
     const size_t strLen = 60002;
     char *s = static_cast<char *>(JS_malloc(cx, strLen));
     CHECK(s);
     s[0] = '"';
     memset(s + 1, 'x', strLen - 2);
     s[strLen - 1] = '"';
     CHECK(JS::Evaluate(cx, global, opts, s, strLen));
     CHECK(JS::CompileFunction(cx, global, opts, "f", 0, nullptr, s, strLen));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2475,16 +2475,22 @@ JS::CompartmentOptions::setSameZoneAs(JS
 
 JS::CompartmentOptions &
 JS::CompartmentOptionsRef(JSCompartment *compartment)
 {
     return compartment->options();
 }
 
 JS::CompartmentOptions &
+JS::CompartmentOptionsRef(JSObject *obj)
+{
+    return obj->compartment()->options();
+}
+
+JS::CompartmentOptions &
 JS::CompartmentOptionsRef(JSContext *cx)
 {
     return cx->compartment()->options();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals,
                    JS::OnNewGlobalHookOption hookOption,
@@ -4343,17 +4349,17 @@ JS::ReadOnlyCompileOptions::copyPODOptio
     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;
+    sourceIsLazy = rhs.sourceIsLazy;
     introductionType = rhs.introductionType;
     introductionLineno = rhs.introductionLineno;
     introductionOffset = rhs.introductionOffset;
     hasIntroductionInfo = rhs.hasIntroductionInfo;
 }
 
 JSPrincipals *
 JS::ReadOnlyCompileOptions::originPrincipals(ExclusiveContext *cx) const
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2530,16 +2530,17 @@ class JS_PUBLIC_API(CompartmentOptions)
 
         Mode mode_;
     };
 
     explicit CompartmentOptions()
       : version_(JSVERSION_UNKNOWN)
       , invisibleToDebugger_(false)
       , mergeable_(false)
+      , discardSource_(false)
       , traceGlobal_(nullptr)
       , singletonsAsTemplates_(true)
     {
         zone_.spec = JS::FreshZone;
     }
 
     JSVersion version() const { return version_; }
     CompartmentOptions &setVersion(JSVersion aVersion) {
@@ -2563,16 +2564,25 @@ class JS_PUBLIC_API(CompartmentOptions)
     // allowed if this flag is set.  The invisibleToDebugger flag must also be
     // set for such compartments.
     bool mergeable() const { return mergeable_; }
     CompartmentOptions &setMergeable(bool flag) {
         mergeable_ = flag;
         return *this;
     }
 
+    // For certain globals, we know enough about the code that will run in them
+    // that we can discard script source entirely.
+    bool discardSource() const { return discardSource_; }
+    CompartmentOptions &setDiscardSource(bool flag) {
+        discardSource_ = flag;
+        return *this;
+    }
+
+
     bool cloneSingletons(JSContext *cx) const;
     Override &cloneSingletonsOverride() { return cloneSingletonsOverride_; }
 
     void *zonePointer() const {
         JS_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone));
         return zone_.pointer;
     }
     ZoneSpecifier zoneSpecifier() const { return zone_.spec; }
@@ -2593,16 +2603,17 @@ class JS_PUBLIC_API(CompartmentOptions)
     JSTraceOp getTrace() const {
         return traceGlobal_;
     }
 
   private:
     JSVersion version_;
     bool invisibleToDebugger_;
     bool mergeable_;
+    bool discardSource_;
     Override cloneSingletonsOverride_;
     union {
         ZoneSpecifier spec;
         void *pointer; // js::Zone* is not exposed in the API.
     } zone_;
     JSTraceOp traceGlobal_;
 
     // To XDR singletons, we need to ensure that all singletons are all used as
@@ -2610,16 +2621,19 @@ class JS_PUBLIC_API(CompartmentOptions)
     // singleton, instead of returning the value which is baked in the JSScript.
     bool singletonsAsTemplates_;
 };
 
 JS_PUBLIC_API(CompartmentOptions &)
 CompartmentOptionsRef(JSCompartment *compartment);
 
 JS_PUBLIC_API(CompartmentOptions &)
+CompartmentOptionsRef(JSObject *obj);
+
+JS_PUBLIC_API(CompartmentOptions &)
 CompartmentOptionsRef(JSContext *cx);
 
 // During global creation, we fire notifications to callbacks registered
 // via the Debugger API. These callbacks are arbitrary script, and can touch
 // the global in arbitrary ways. When that happens, the global should not be
 // in a half-baked state. But this creates a problem for consumers that need
 // to set slots on the global to put it in a consistent state.
 //
@@ -3383,17 +3397,17 @@ class JS_FRIEND_API(ReadOnlyCompileOptio
         selfHostingMode(false),
         canLazilyParse(true),
         strictOption(false),
         extraWarningsOption(false),
         werrorOption(false),
         asmJSOption(false),
         forceAsync(false),
         installedFile(false),
-        sourcePolicy(SAVE_SOURCE),
+        sourceIsLazy(false),
         introductionType(nullptr),
         introductionLineno(0),
         introductionOffset(0),
         hasIntroductionInfo(false)
     { }
 
     // Set all POD options (those not requiring reference counts, copies,
     // rooting, or other hand-holding) to their values in |rhs|.
@@ -3423,21 +3437,17 @@ class JS_FRIEND_API(ReadOnlyCompileOptio
     bool selfHostingMode;
     bool canLazilyParse;
     bool strictOption;
     bool extraWarningsOption;
     bool werrorOption;
     bool asmJSOption;
     bool forceAsync;
     bool installedFile;  // 'true' iff pre-compiling js file in packaged app
-    enum SourcePolicy {
-        NO_SOURCE,
-        LAZY_SOURCE,
-        SAVE_SOURCE
-    } sourcePolicy;
+    bool sourceIsLazy;
 
     // |introductionType| is a statically allocated C string:
     // one of "eval", "Function", or "GeneratorFunction".
     const char *introductionType;
     unsigned introductionLineno;
     uint32_t introductionOffset;
     bool hasIntroductionInfo;
 
@@ -3519,17 +3529,17 @@ class JS_FRIEND_API(OwningCompileOptions
     OwningCompileOptions &setUTF8(bool u) { utf8 = u; return *this; }
     OwningCompileOptions &setColumn(unsigned c) { column = c; return *this; }
     OwningCompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
     OwningCompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
     OwningCompileOptions &setDefineOnScope(bool define) { defineOnScope = define; return *this; }
     OwningCompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
     OwningCompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
     OwningCompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
-    OwningCompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
+    OwningCompileOptions &setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; }
     OwningCompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; }
     bool setIntroductionInfo(JSContext *cx, const char *introducerFn, const char *intro,
                              unsigned line, JSScript *script, uint32_t offset)
     {
         if (!setIntroducerFilename(cx, introducerFn))
             return false;
         introductionType = intro;
         introductionLineno = line;
@@ -3605,17 +3615,17 @@ class MOZ_STACK_CLASS JS_FRIEND_API(Comp
     CompileOptions &setUTF8(bool u) { utf8 = u; return *this; }
     CompileOptions &setColumn(unsigned c) { column = c; return *this; }
     CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
     CompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
     CompileOptions &setDefineOnScope(bool define) { defineOnScope = define; return *this; }
     CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
     CompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
     CompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
-    CompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
+    CompileOptions &setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; }
     CompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; }
     CompileOptions &setIntroductionInfo(const char *introducerFn, const char *intro,
                                         unsigned line, JSScript *script, uint32_t offset)
     {
         introducerFilename_ = introducerFn;
         introductionType = intro;
         introductionLineno = line;
         introductionScriptRoot = script;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -378,38 +378,38 @@ extern JS_FRIEND_API(bool)
 proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
 extern JS_FRIEND_API(bool)
 proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
             JS::HandleObject result);
 
 /*
  * A class of objects that return source code on demand.
  *
- * When code is compiled with CompileOptions::LAZY_SOURCE, SpiderMonkey
- * doesn't retain the source code (and doesn't do lazy bytecode
- * generation). If we ever need the source code, say, in response to a call
- * to Function.prototype.toSource or Debugger.Source.prototype.text, then
- * we call the 'load' member function of the instance of this class that
- * has hopefully been registered with the runtime, passing the code's URL,
- * and hope that it will be able to find the source.
+ * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't
+ * retain the source code (and doesn't do lazy bytecode generation). If we ever
+ * need the source code, say, in response to a call to Function.prototype.
+ * toSource or Debugger.Source.prototype.text, then we call the 'load' member
+ * function of the instance of this class that has hopefully been registered
+ * with the runtime, passing the code's URL, and hope that it will be able to
+ * find the source.
  */
 class SourceHook {
   public:
     virtual ~SourceHook() { }
 
     /*
      * Set |*src| and |*length| to refer to the source code for |filename|.
      * On success, the caller owns the buffer to which |*src| points, and
      * should use JS_free to free it.
      */
     virtual bool load(JSContext *cx, const char *filename, jschar **src, size_t *length) = 0;
 };
 
 /*
- * Have |rt| use |hook| to retrieve LAZY_SOURCE source code. See the
+ * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the
  * comments for SourceHook. The runtime takes ownership of the hook, and
  * will delete it when the runtime itself is deleted, or when a new hook is
  * set.
  */
 extern JS_FRIEND_API(void)
 SetSourceHook(JSRuntime *rt, SourceHook *hook);
 
 /* Remove |rt|'s source hook, and return it. The caller now owns the hook. */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -306,25 +306,55 @@ TemporaryTypeSet::TemporaryTypeSet(Type 
         flags |= TYPE_FLAG_ANYOBJECT;
     } else {
         setBaseObjectCount(1);
         objectSet = reinterpret_cast<TypeObjectKey**>(type.objectKey());
     }
 }
 
 bool
-TypeSet::mightBeType(JSValueType type)
+TypeSet::mightBeMIRType(jit::MIRType type)
 {
     if (unknown())
         return true;
 
-    if (type == JSVAL_TYPE_OBJECT)
+    if (type == jit::MIRType_Object)
         return unknownObject() || baseObjectCount() != 0;
 
-    return baseFlags() & PrimitiveTypeFlag(type);
+    switch (type) {
+      case jit::MIRType_Undefined:
+        return baseFlags() & TYPE_FLAG_UNDEFINED;
+      case jit::MIRType_Null:
+        return baseFlags() & TYPE_FLAG_NULL;
+      case jit::MIRType_Boolean:
+        return baseFlags() & TYPE_FLAG_BOOLEAN;
+      case jit::MIRType_Int32:
+        return baseFlags() & TYPE_FLAG_INT32;
+      case jit::MIRType_Float32: // Fall through, there's no JSVAL for Float32.
+      case jit::MIRType_Double:
+        return baseFlags() & TYPE_FLAG_DOUBLE;
+      case jit::MIRType_String:
+        return baseFlags() & TYPE_FLAG_STRING;
+      case jit::MIRType_MagicOptimizedArguments:
+        return baseFlags() & TYPE_FLAG_LAZYARGS;
+      case jit::MIRType_MagicHole:
+      case jit::MIRType_MagicIsConstructing:
+        // These magic constants do not escape to script and are not observed
+        // in the type sets.
+        //
+        // The reason we can return false here is subtle: if Ion is asking the
+        // type set if it has seen such a magic constant, then the MIR in
+        // question is the most generic type, MIRType_Value. A magic constant
+        // could only be emitted by a MIR of MIRType_Value if that MIR is a
+        // phi, and we check that different magic constants do not flow to the
+        // same join point in GuessPhiType.
+        return false;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad MIR type");
+    }
 }
 
 bool
 TypeSet::isSubset(TypeSet *other)
 {
     if ((baseFlags() & other->baseFlags()) != baseFlags())
         return false;
 
@@ -1137,92 +1167,92 @@ void
 HeapTypeSetKey::freeze(CompilerConstraintList *constraints)
 {
     LifoAlloc *alloc = constraints->alloc();
 
     typedef CompilerConstraintInstance<ConstraintDataFreeze> T;
     constraints->add(alloc->new_<T>(alloc, *this, ConstraintDataFreeze()));
 }
 
-static inline JSValueType
-GetValueTypeFromTypeFlags(TypeFlags flags)
+static inline jit::MIRType
+GetMIRTypeFromTypeFlags(TypeFlags flags)
 {
     switch (flags) {
       case TYPE_FLAG_UNDEFINED:
-        return JSVAL_TYPE_UNDEFINED;
+        return jit::MIRType_Undefined;
       case TYPE_FLAG_NULL:
-        return JSVAL_TYPE_NULL;
+        return jit::MIRType_Null;
       case TYPE_FLAG_BOOLEAN:
-        return JSVAL_TYPE_BOOLEAN;
+        return jit::MIRType_Boolean;
       case TYPE_FLAG_INT32:
-        return JSVAL_TYPE_INT32;
+        return jit::MIRType_Int32;
       case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE):
-        return JSVAL_TYPE_DOUBLE;
+        return jit::MIRType_Double;
       case TYPE_FLAG_STRING:
-        return JSVAL_TYPE_STRING;
+        return jit::MIRType_String;
       case TYPE_FLAG_LAZYARGS:
-        return JSVAL_TYPE_MAGIC;
+        return jit::MIRType_MagicOptimizedArguments;
       case TYPE_FLAG_ANYOBJECT:
-        return JSVAL_TYPE_OBJECT;
+        return jit::MIRType_Object;
       default:
-        return JSVAL_TYPE_UNKNOWN;
+        return jit::MIRType_Value;
     }
 }
 
-JSValueType
-TemporaryTypeSet::getKnownTypeTag()
+jit::MIRType
+TemporaryTypeSet::getKnownMIRType()
 {
     TypeFlags flags = baseFlags();
-    JSValueType type;
+    jit::MIRType type;
 
     if (baseObjectCount())
-        type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT;
+        type = flags ? jit::MIRType_Value : jit::MIRType_Object;
     else
-        type = GetValueTypeFromTypeFlags(flags);
+        type = GetMIRTypeFromTypeFlags(flags);
 
     /*
      * If the type set is totally empty then it will be treated as unknown,
      * but we still need to record the dependency as adding a new type can give
      * it a definite type tag. This is not needed if there are enough types
      * that the exact tag is unknown, as it will stay unknown as more types are
      * added to the set.
      */
     DebugOnly<bool> empty = flags == 0 && baseObjectCount() == 0;
-    JS_ASSERT_IF(empty, type == JSVAL_TYPE_UNKNOWN);
+    JS_ASSERT_IF(empty, type == jit::MIRType_Value);
 
     return type;
 }
 
-JSValueType
-HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
+jit::MIRType
+HeapTypeSetKey::knownMIRType(CompilerConstraintList *constraints)
 {
     TypeSet *types = maybeTypes();
 
     if (!types || types->unknown())
-        return JSVAL_TYPE_UNKNOWN;
+        return jit::MIRType_Value;
 
     TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
-    JSValueType type;
+    jit::MIRType type;
 
     if (types->unknownObject() || types->getObjectCount())
-        type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT;
+        type = flags ? jit::MIRType_Value : jit::MIRType_Object;
     else
-        type = GetValueTypeFromTypeFlags(flags);
-
-    if (type != JSVAL_TYPE_UNKNOWN)
+        type = GetMIRTypeFromTypeFlags(flags);
+
+    if (type != jit::MIRType_Value)
         freeze(constraints);
 
     /*
      * If the type set is totally empty then it will be treated as unknown,
      * but we still need to record the dependency as adding a new type can give
      * it a definite type tag. This is not needed if there are enough types
      * that the exact tag is unknown, as it will stay unknown as more types are
      * added to the set.
      */
-    JS_ASSERT_IF(types->empty(), type == JSVAL_TYPE_UNKNOWN);
+    JS_ASSERT_IF(types->empty(), type == jit::MIRType_Value);
 
     return type;
 }
 
 bool
 HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints)
 {
     if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->nonDataProperty()))
@@ -1666,17 +1696,17 @@ TemporaryTypeSet::convertDoubleElements(
             dontConvert = true;
             alwaysConvert = false;
             continue;
         }
 
         // Only bother with converting known packed arrays whose possible
         // element types are int or double. Other arrays require type tests
         // when elements are accessed regardless of the conversion.
-        if (property.knownTypeTag(constraints) == JSVAL_TYPE_DOUBLE &&
+        if (property.knownMIRType(constraints) == jit::MIRType_Double &&
             !type->hasFlags(constraints, OBJECT_FLAG_NON_PACKED))
         {
             maybeConvert = true;
         } else {
             alwaysConvert = false;
         }
     }
 
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -15,16 +15,17 @@
 #include "jsalloc.h"
 #include "jsfriendapi.h"
 #include "jstypes.h"
 
 #include "ds/IdValuePair.h"
 #include "ds/LifoAlloc.h"
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
+#include "jit/IonTypes.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 namespace js {
 
 class TypeDescr;
 
 class TaggedProto
@@ -218,16 +219,20 @@ class Type
         return (uintptr_t) type == data;
     }
 
     JSValueType primitive() const {
         JS_ASSERT(isPrimitive());
         return (JSValueType) data;
     }
 
+    bool isMagicArguments() const {
+        return primitive() == JSVAL_TYPE_MAGIC;
+    }
+
     bool isSomeObject() const {
         return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
     }
 
     bool isAnyObject() const {
         return data == JSVAL_TYPE_OBJECT;
     }
 
@@ -557,17 +562,17 @@ class TypeSet
     }
     void setDefinite(unsigned slot) {
         JS_ASSERT(canSetDefinite(slot));
         flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
         JS_ASSERT(definiteSlot() == slot);
     }
 
     /* Whether any values in this set might have the specified type. */
-    bool mightBeType(JSValueType type);
+    bool mightBeMIRType(jit::MIRType type);
 
     /*
      * Get whether this type set is known to be a subset of other.
      * This variant doesn't freeze constraints. That variant is called knownSubset
      */
     bool isSubset(TypeSet *other);
 
     /* Forward all types in this set to the specified constraint. */
@@ -649,19 +654,19 @@ class TemporaryTypeSet : public TypeSet
      *
      * Methods for JIT compilation. These must be used when a script is
      * currently being compiled (see AutoEnterCompilation) and will add
      * constraints ensuring that if the return value change in the future due
      * to new type information, the script's jitcode will be discarded.
      */
 
     /* Get any type tag which all values in this set must have. */
-    JSValueType getKnownTypeTag();
+    jit::MIRType getKnownMIRType();
 
-    bool isMagicArguments() { return getKnownTypeTag() == JSVAL_TYPE_MAGIC; }
+    bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; }
 
     /* Whether this value may be an object. */
     bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
 
     /*
      * Whether this typeset represents a potentially sentineled object value:
      * the value may be an object or null or undefined.
      * Returns false if the value cannot ever be an object.
@@ -1398,17 +1403,17 @@ class HeapTypeSetKey
 
     TypeObjectKey *object() const { return object_; }
     jsid id() const { return id_; }
     HeapTypeSet *maybeTypes() const { return maybeTypes_; }
 
     bool instantiate(JSContext *cx);
 
     void freeze(CompilerConstraintList *constraints);
-    JSValueType knownTypeTag(CompilerConstraintList *constraints);
+    jit::MIRType knownMIRType(CompilerConstraintList *constraints);
     bool nonData(CompilerConstraintList *constraints);
     bool nonWritable(CompilerConstraintList *constraints);
     bool isOwnProperty(CompilerConstraintList *constraints);
     bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
     JSObject *singleton(CompilerConstraintList *constraints);
     bool needsBarrier(CompilerConstraintList *constraints);
 };
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -861,38 +861,20 @@ ParseCompileOptions(JSContext *cx, Compi
         return false;
     if (!v.isUndefined()) {
         uint32_t u;
         if (!ToUint32(cx, v, &u))
             return false;
         options.setLine(u);
     }
 
-    if (!JS_GetProperty(cx, opts, "sourcePolicy", &v))
-        return false;
-    if (!v.isUndefined()) {
-        RootedString s(cx, ToString(cx, v));
-        if (!s)
-            return false;
-
-        JSAutoByteString bytes;
-        char *policy = bytes.encodeUtf8(cx, s);
-        if (!policy)
-            return false;
-        if (strcmp(policy, "NO_SOURCE") == 0) {
-            options.setSourcePolicy(CompileOptions::NO_SOURCE);
-        } else if (strcmp(policy, "LAZY_SOURCE") == 0) {
-            options.setSourcePolicy(CompileOptions::LAZY_SOURCE);
-        } else if (strcmp(policy, "SAVE_SOURCE") == 0) {
-            options.setSourcePolicy(CompileOptions::SAVE_SOURCE);
-        } else {
-            JS_ReportError(cx, "bad 'sourcePolicy' option: '%s'", policy);
-            return false;
-        }
-    }
+    if (!JS_GetProperty(cx, opts, "sourceIsLazy", &v))
+        return false;
+    if (v.isBoolean())
+        options.setSourceIsLazy(v.toBoolean());
 
     return true;
 }
 
 class AutoNewContext
 {
   private:
     JSContext *oldcx;
@@ -3631,17 +3613,17 @@ OffThreadCompileScript(JSContext *cx, un
 
         RootedObject opts(cx, &args[1].toObject());
         if (!ParseCompileOptions(cx, options, opts, fileNameBytes))
             return false;
     }
 
     // These option settings must override whatever the caller requested.
     options.setCompileAndGo(true)
-           .setSourcePolicy(CompileOptions::SAVE_SOURCE);
+           .setSourceIsLazy(false);
 
     // We assume the caller wants caching if at all possible, ignoring
     // heuristics that make sense for a real browser.
     options.forceAsync = true;
 
     JSString *scriptContents = args[0].toString();
     const jschar *chars = JS_GetStringCharsZ(cx, scriptContents);
     if (!chars)
@@ -4384,19 +4366,19 @@ static const JSFunctionSpecWithHelp shel
 "         any DOM element.\n"
 "      elementAttributeName: if present and not undefined, the name of\n"
 "         property of 'element' that holds this code. This is what\n"
 "         Debugger.Source.prototype.elementAttributeName returns.\n"
 "      sourceMapURL: if present with value |v|, convert |v| to a string, and\n"
 "         provide that as the code's source map URL. If omitted, attach no\n"
 "         source map URL to the code (although the code may provide one itself,\n"
 "         via a //#sourceMappingURL comment).\n"
-"      sourcePolicy: if present, the value converted to a string must be either\n"
-"         'NO_SOURCE', 'LAZY_SOURCE', or 'SAVE_SOURCE'; use the given source\n"
-"         retention policy for this compilation.\n"
+"      sourceIsLazy: if present and true, indicates that, after compilation, \n"
+          "script source should not be cached by the JS engine and should be \n"
+          "lazily loaded from the embedding as-needed.\n"
 "      loadBytecode: if true, and if the source is a CacheEntryObject,\n"
 "         the bytecode would be loaded and decoded from the cache entry instead\n"
 "         of being parsed, then it would be executed as usual.\n"
 "      saveBytecode: if true, and if the source is a CacheEntryObject,\n"
 "         the bytecode would be encoded and saved into the cache entry after\n"
 "         the script execution.\n"
 "      assertEqBytecode: if true, and if both loadBytecode and saveBytecode are \n"
 "         true, then the loaded bytecode and the encoded bytecode are compared.\n"
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -899,17 +899,16 @@ js::FillSelfHostingCompileOptions(Compil
      * Additionally, the special syntax callFunction(fun, receiver, ...args)
      * is supported, for which bytecode is emitted that invokes |fun| with
      * |receiver| as the this-object and ...args as the arguments.
      */
     options.setIntroductionType("self-hosted");
     options.setFileAndLine("self-hosted", 1);
     options.setSelfHostingMode(true);
     options.setCanLazilyParse(false);
-    options.setSourcePolicy(CompileOptions::NO_SOURCE);
     options.setVersion(JSVERSION_LATEST);
     options.werrorOption = true;
     options.strictOption = true;
 
 #ifdef DEBUG
     options.extraWarningsOption = true;
 #endif
 }
@@ -929,18 +928,21 @@ JSRuntime::initSelfHosting(JSContext *cx
      * parented to this one, so cannot include state in the nursery.
      */
     JS::AutoDisableGenerationalGC disable(cx->runtime());
 
     bool receivesDefaultObject = !cx->options().noDefaultCompartmentObject();
     RootedObject savedGlobal(cx, receivesDefaultObject
                                  ? js::DefaultObjectForContextOrNull(cx)
                                  : nullptr);
+    JS::CompartmentOptions compartmentOptions;
+    compartmentOptions.setDiscardSource(true);
     if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
-                                                  nullptr, JS::DontFireOnNewGlobalHook)))
+                                                  nullptr, JS::DontFireOnNewGlobalHook,
+                                                  compartmentOptions)))
         return false;
     JSAutoCompartment ac(cx, selfHostingGlobal_);
     if (receivesDefaultObject)
         js::SetDefaultObjectForContext(cx, selfHostingGlobal_);
     Rooted<GlobalObject*> shg(cx, &selfHostingGlobal_->as<GlobalObject>());
     selfHostingGlobal_->compartment()->isSelfHosting = true;
     selfHostingGlobal_->compartment()->isSystem = true;
     /*
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -809,23 +809,26 @@ mozJSComponentLoader::ObjectForLocation(
 
         // If aPropagateExceptions is true, then our caller wants us to propagate
         // any exceptions out to our caller. Ensure that the engine doesn't
         // eagerly report the exception.
         AutoSaveContextOptions asco(cx);
         if (aPropagateExceptions)
             ContextOptionsRef(cx).setDontReportUncaught(true);
 
+        // Note - if mReuseLoaderGlobal is true, then we can't do lazy source,
+        // because we compile things as functions (rather than script), and lazy
+        // source isn't supported in that configuration. That's ok though,
+        // because we only do mReuseLoaderGlobal on b2g, where we invoke
+        // setDiscardSource(true) on the entire global.
         CompileOptions options(cx);
         options.setNoScriptRval(mReuseLoaderGlobal ? false : true)
                .setVersion(JSVERSION_LATEST)
                .setFileAndLine(nativePath.get(), 1)
-               .setSourcePolicy(mReuseLoaderGlobal ?
-                                CompileOptions::NO_SOURCE :
-                                CompileOptions::LAZY_SOURCE);
+               .setSourceIsLazy(!mReuseLoaderGlobal);
 
         if (realFile) {
 #ifdef HAVE_PR_MEMMAP
             int64_t fileSize;
             rv = aComponentFile->GetFileSize(&fileSize);
             if (NS_FAILED(rv)) {
                 return rv;
             }
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -159,20 +159,20 @@ mozJSSubScriptLoader::ReadScript(nsIURI 
                                    script.Length());
         } else {
             *functionp = JS::CompileFunction(cx, target_obj, options,
                                              nullptr, 0, nullptr,
                                              script.get(),
                                              script.Length());
         }
     } else {
-        // We only use LAZY_SOURCE when no special encoding is specified because
+        // We only use lazy source when no special encoding is specified because
         // the lazy source loader doesn't know the encoding.
         if (!reuseGlobal) {
-            options.setSourcePolicy(JS::CompileOptions::LAZY_SOURCE);
+            options.setSourceIsLazy(true);
             *scriptp = JS::Compile(cx, target_obj, options, buf.get(), len);
         } else {
             *functionp = JS::CompileFunction(cx, target_obj, options,
                                              nullptr, 0, nullptr, buf.get(),
                                              len);
         }
     }
 
@@ -487,23 +487,23 @@ ScriptPrecompiler::OnStreamComplete(nsIS
     // 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;
+    sandboxOptions.discardSource = 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);
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1080,16 +1080,17 @@ xpc::CreateSandboxObject(JSContext *cx, 
 
     JS::CompartmentOptions compartmentOptions;
     if (options.sameZoneAs)
         compartmentOptions.setSameZoneAs(js::UncheckedUnwrap(options.sameZoneAs));
     else
         compartmentOptions.setZone(JS::SystemZone);
 
     compartmentOptions.setInvisibleToDebugger(options.invisibleToDebugger)
+                      .setDiscardSource(options.discardSource)
                       .setTrace(TraceXPCGlobal);
 
     RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, &SandboxClass,
                                                      principal, compartmentOptions));
     if (!sandbox)
         return NS_ERROR_FAILURE;
 
     // Set up the wantXrays flag, which indicates whether xrays are desired even
@@ -1513,16 +1514,17 @@ SandboxOptions::Parse()
 {
     return ParseObject("sandboxPrototype", &proto) &&
            ParseBoolean("wantXrays", &wantXrays) &&
            ParseBoolean("wantComponents", &wantComponents) &&
            ParseBoolean("wantExportHelpers", &wantExportHelpers) &&
            ParseString("sandboxName", sandboxName) &&
            ParseObject("sameZoneAs", &sameZoneAs) &&
            ParseBoolean("invisibleToDebugger", &invisibleToDebugger) &&
+           ParseBoolean("discardSource", &discardSource) &&
            ParseGlobalProperties() &&
            ParseValue("metadata", &metadata);
 }
 
 static nsresult
 AssembleSandboxMemoryReporterName(JSContext *cx, nsCString &sandboxName)
 {
     // Use a default name when the caller did not provide a sandboxName.
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -131,24 +131,18 @@ XPCConvert::NativeData2JS(MutableHandleV
         return true;
     case nsXPTType::T_FLOAT :
         d.setNumber(*static_cast<const float*>(s));
         return true;
     case nsXPTType::T_DOUBLE:
         d.setNumber(*static_cast<const double*>(s));
         return true;
     case nsXPTType::T_BOOL  :
-    {
-        bool b = *static_cast<const bool*>(s);
-
-        NS_WARN_IF_FALSE(b == 1 || b == 0,
-                         "Passing a malformed bool through XPConnect");
-        d.setBoolean(b);
+        d.setBoolean(*static_cast<const bool*>(s));
         return true;
-    }
     case nsXPTType::T_CHAR  :
     {
         char p = *static_cast<const char*>(s);
 
 #ifdef STRICT_CHECK_OF_UNICODE
         MOZ_ASSERT(! ILLEGAL_CHAR_RANGE(p) , "passing non ASCII data");
 #endif // STRICT_CHECK_OF_UNICODE
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -35,16 +35,17 @@
 #include "jsfriendapi.h"
 #include "jsprf.h"
 #include "js/MemoryMetrics.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/dom/GeneratedAtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/WindowBinding.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "AccessCheck.h"
 #include "nsGlobalWindow.h"
 #include "nsAboutProtocolUtils.h"
 
 #include "GeckoProfiler.h"
 #include "nsIXULRuntime.h"
 #include "nsJSPrincipals.h"
@@ -79,21 +80,20 @@ const char* const XPCJSRuntime::mStrings
     "__iterator__",         // IDX_ITERATOR
     "__exposedProps__",     // IDX_EXPOSEDPROPS
     "eval",                 // IDX_EVAL
     "controllers",           // IDX_CONTROLLERS
 };
 
 /***************************************************************************/
 
-struct CX_AND_XPCRT_Data
-{
-    JSContext* cx;
-    XPCJSRuntime* rt;
-};
+static mozilla::Atomic<bool> sDiscardSystemSource(false);
+
+bool
+xpc::ShouldDiscardSystemSource() { return sDiscardSystemSource; }
 
 static void * const UNMARK_ONLY = nullptr;
 static void * const UNMARK_AND_SWEEP = (void *)1;
 
 static PLDHashOperator
 NativeInterfaceSweeper(PLDHashTable *table, PLDHashEntryHdr *hdr,
                        uint32_t number, void *arg)
 {
@@ -1555,16 +1555,18 @@ ReloadPrefsCallback(const char *pref, vo
 
     bool parallelParsing = Preferences::GetBool(JS_OPTIONS_DOT_STR "parallel_parsing");
     bool parallelIonCompilation = Preferences::GetBool(JS_OPTIONS_DOT_STR
                                                        "ion.parallel_compilation");
     bool useBaselineEager = Preferences::GetBool(JS_OPTIONS_DOT_STR
                                                  "baselinejit.unsafe_eager_compilation");
     bool useIonEager = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.unsafe_eager_compilation");
 
+    sDiscardSystemSource = Preferences::GetBool(JS_OPTIONS_DOT_STR "discardSystemSource");
+
     JS::RuntimeOptionsRef(rt).setBaseline(useBaseline)
                              .setIon(useIon)
                            .  setAsmJS(useAsmJS);
 
     JS_SetParallelParsingEnabled(rt, parallelParsing);
     JS_SetParallelIonCompilationEnabled(rt, parallelIonCompilation);
     JS_SetGlobalJitCompilerOption(rt, JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER,
                                   useBaselineEager ? 0 : -1);
@@ -3498,16 +3500,17 @@ XPCJSRuntime::GetJunkScope()
 JSObject *
 XPCJSRuntime::GetCompilationScope()
 {
     if (!mCompilationScope) {
         AutoSafeJSContext cx;
         SandboxOptions options;
         options.sandboxName.AssignLiteral("XPConnect Compilation Compartment");
         options.invisibleToDebugger = true;
+        options.discardSource = ShouldDiscardSystemSource();
         RootedValue v(cx);
         nsresult rv = CreateSandboxObject(cx, &v, /* principal = */ nullptr, options);
         NS_ENSURE_SUCCESS(rv, nullptr);
 
         mCompilationScope = js::UncheckedUnwrap(&v.toObject());
     }
     return mCompilationScope;
 }
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1545,16 +1545,21 @@ XRE_XPCShellMain(int argc, char **argv, 
             return 1;
 
         {
             JS::Rooted<JSObject*> glob(cx, holder->GetJSObject());
             if (!glob) {
                 return 1;
             }
 
+            // Even if we're building in a configuration where source is
+            // discarded, there's no reason to do that on XPCShell, and doing so
+            // might break various automation scripts.
+            JS::CompartmentOptionsRef(glob).setDiscardSource(false);
+
             backstagePass->SetGlobalObject(glob);
 
             JSAutoCompartment ac(cx, glob);
 
             if (!JS_InitReflect(cx, glob)) {
                 JS_EndRequest(cx);
                 return 1;
             }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -409,16 +409,27 @@ InitGlobalObject(JSContext* aJSContext, 
     if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
         // XPCCallContext gives us an active request needed to save/restore.
         if (!GetCompartmentPrivate(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
             !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
             return UnexpectedFailure(false);
         }
     }
 
+    if (ShouldDiscardSystemSource()) {
+        nsIPrincipal *prin = GetObjectPrincipal(aGlobal);
+        bool isSystem = nsContentUtils::IsSystemPrincipal(prin);
+        if (!isSystem) {
+            short status = prin->GetAppStatus();
+            isSystem = status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
+                       status == nsIPrincipal::APP_STATUS_CERTIFIED;
+        }
+        JS::CompartmentOptionsRef(aGlobal).setDiscardSource(isSystem);
+    }
+
     // Stuff coming through this path always ends up as a DOM global.
     MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
 
     // Init WebIDL binding constructors wanted on all XPConnect globals.
     //
     // XXX Please do not add any additional classes here without the approval of
     //     the XPConnect module owner.
     if (!PromiseBinding::GetConstructorObject(aJSContext, aGlobal) ||
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3344,29 +3344,31 @@ public:
                    JSObject *options = nullptr)
         : OptionsBase(cx, options)
         , wantXrays(true)
         , wantComponents(true)
         , wantExportHelpers(false)
         , proto(cx)
         , sameZoneAs(cx)
         , invisibleToDebugger(false)
+        , discardSource(false)
         , globalProperties(true)
         , metadata(cx)
     { }
 
     virtual bool Parse();
 
     bool wantXrays;
     bool wantComponents;
     bool wantExportHelpers;
     JS::RootedObject proto;
     nsCString sandboxName;
     JS::RootedObject sameZoneAs;
     bool invisibleToDebugger;
+    bool discardSource;
     GlobalProperties globalProperties;
     JS::RootedValue metadata;
 
 protected:
     bool ParseGlobalProperties();
 };
 
 class MOZ_STACK_CLASS CreateObjectInOptions : public OptionsBase {
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -473,16 +473,21 @@ void
 SimulateActivityCallback(bool aActive);
 
 void
 RecordAdoptedNode(JSCompartment *c);
 
 void
 RecordDonatedNode(JSCompartment *c);
 
+// This function may be used off-main-thread, in which case it is benignly
+// racey.
+bool
+ShouldDiscardSystemSource();
+
 } // namespace xpc
 
 namespace mozilla {
 namespace dom {
 
 typedef JSObject*
 (*DefineInterface)(JSContext *cx, JS::Handle<JSObject*> global,
                    JS::Handle<jsid> id, bool defineOnGlobal);
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   bug503926.xul
   file_bug618176.xul
   file_bug996069.html
+  file_discardSystemSource.html
+  worker_discardSystemSource.js
   file_evalInSandbox.html
   file_expandosharing.jsm
   outoflinexulscript.js
   subscript.js
   utf8_subscript.js
 
 [test_APIExposer.xul]
 [test_bug361111.xul]
@@ -52,16 +54,17 @@ support-files =
 [test_bug866823.xul]
 [test_bug895340.xul]
 [test_bug932906.xul]
 [test_bug996069.xul]
 [test_xrayToJS.xul]
 [test_chrometoSource.xul]
 [test_cloneInto.xul]
 [test_cows.xul]
+[test_discardSystemSource.xul]
 [test_documentdomain.xul]
 [test_doublewrappedcompartments.xul]
 [test_evalInSandbox.xul]
 [test_evalInWindow.xul]
 [test_exnstack.xul]
 [test_expandosharing.xul]
 [test_exposeInDerived.xul]
 [test_getweakmapkeys.xul]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/file_discardSystemSource.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+  function canary() {
+    var someBitOfSource = 42;
+  }
+  function inner() {
+    throw new Error("some error");
+  }
+  function throwSomething() {
+    inner();
+  }
+</script>
+</head>
+<body onload="someBitOfSource = 42">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/mochitest.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+support-files =
+  file_discardSystemSource.html
+  worker_discardSystemSource.js
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
+MOCHITEST_MANIFESTS += ['mochitest.ini']
+
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_discardSystemSource.xul
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=990353
+-->
+<window title="Mozilla Bug 990353"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=990353"
+     target="_blank">Mozilla Bug 990353</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+  /** Test for Bug 990353 **/
+  SimpleTest.waitForExplicitFinish();
+  const Cu = Components.utils;
+
+  function canary() {
+    var someBitOfSource = 42;
+  }
+
+  var gLoadCount = 0;
+  function frameLoaded() {
+    switch (++gLoadCount) {
+      case 1:
+        ok(/sourceless/.test(window[0].canary.toSource()), "System function should be sourceless: " + window[0].canary.toSource());
+        ok(/sourceless/.test(window[0].onload.toSource()), "System event handler should be sourceless: " + window[0].onload.toSource());
+        var sb = new Cu.Sandbox('http://www.example.com', { discardSource: true });
+        Cu.evalInSandbox('function canary() { var someBitOfSource = 42; }', sb);
+        ok(/sourceless/.test(sb.canary.toSource()), "Function from sandbox with explicit discarding should be sourceless");
+        try {
+          window[0].throwSomething();
+          ok(false, "should have thrown");
+        } catch (e) {
+          ok(/some error/.test(e), "Threw exception as expected: " + e);
+          ok(/throwSomething/.test(e.stack), "Exception stack trace works: " + e.stack);
+        }
+        window[0].location = "http://example.org/tests/js/xpconnect/tests/chrome/file_discardSystemSource.html";
+        break;
+      case 2:
+        ok(/someBitOfSource/.test(Cu.waiveXrays(window[0]).canary.toSource()), "Content function should have source");
+        ok(/someBitOfSource/.test(Cu.waiveXrays(window[0]).onload.toSource()), "Content event handler should have source");
+        testWorker();
+        break;
+    }
+  }
+
+  function testWorker() {
+    var worker = new window[0].wrappedJSObject.Worker('worker_discardSystemSource.js');
+    worker.onmessage = function(evt) {
+      ok(/someBitOfSource/.test(evt.data), "Non-chrome worker should have source: " + evt.data);
+      var chromeWorker = new Worker('worker_discardSystemSource.js');
+      chromeWorker.onmessage = function(evt) {
+        ok(/sourceless/.test(evt.data), "Chrome worker should not have source: " + evt.data);
+        SimpleTest.finish();
+      }
+    }
+  }
+
+  function go() {
+    // We should have our own source, because the pref wasn't enabled when we
+    // were loaded.
+    ok(/someBitOfSource/.test(canary.toSource()), "Should have own source");
+
+    window[0].frameElement.onload = frameLoaded;
+    window[0].location = "file_discardSystemSource.html";
+  }
+  addLoadEvent(function() {
+    SpecialPowers.pushPrefEnv({set: [['javascript.options.discardSystemSource', true]]}, go);
+  });
+
+  ]]>
+  </script>
+  <iframe></iframe>
+</window>
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/worker_discardSystemSource.js
@@ -0,0 +1,5 @@
+function canary() {
+  var someBitOfSource = 42;
+}
+
+postMessage(canary.toSource());
--- a/js/xpconnect/tests/moz.build
+++ b/js/xpconnect/tests/moz.build
@@ -2,16 +2,16 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_TOOL_DIRS += [
     'idl',
     'mochitest',
+    'chrome',
     'browser',
     'components/native',
     'components/js',
 ]
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
-MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6406,16 +6406,19 @@ DispatchPointerFromMouseOrTouch(PresShel
       break;
     default:
       return NS_OK;
     }
 
     WidgetPointerEvent event(*mouseEvent);
     event.message = pointerMessage;
     event.button = button;
+    event.pressure = event.buttons ?
+                     mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
+                     0.0f;
     event.convertToPointer = mouseEvent->convertToPointer = false;
     aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
   } else if (aEvent->eventStructType == NS_TOUCH_EVENT) {
     WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
     // loop over all touches and dispatch pointer events on each touch
     // copy the event
     switch (touchEvent->message) {
     case NS_TOUCH_MOVE:
--- a/media/omx-plugin/OmxPlugin.cpp
+++ b/media/omx-plugin/OmxPlugin.cpp
@@ -933,17 +933,17 @@ bool OmxDecoder::ToAudioFrame(AudioFrame
   aFrame->Set(aTimeUs, reinterpret_cast<char *>(aData) + aDataOffset, aSize, aAudioChannels, aAudioSampleRate);
   return true;
 }
 
 class ReadOptions : public MediaSource::ReadOptions
 {
   // HTC have their own version of ReadOptions with extra fields. If we don't
   // have this here, HTCOMXCodec will corrupt our stack.
-  uint32_t sadface[4];
+  uint32_t sadface[16];
 };
 
 bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs,
                            BufferCallback *aBufferCallback)
 {
   MOZ_ASSERT(aSeekTimeUs >= -1);
 
   if (!mVideoSource.get())
--- a/mobile/android/modules/WebappManager.jsm
+++ b/mobile/android/modules/WebappManager.jsm
@@ -15,20 +15,20 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import("resource://gre/modules/Webapps.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "sendMessageToJava", "resource://gre/modules/Messaging.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "Strings", function() {
   return Services.strings.createBundle("chrome://browser/locale/webapp.properties");
 });
 
 function debug(aMessage) {
   // We use *dump* instead of Services.console.logStringMessage so the messages
   // have the INFO level of severity instead of the ERROR level.  And we don't
--- a/modules/libmar/moz.build
+++ b/modules/libmar/moz.build
@@ -8,14 +8,14 @@ DIRS += ['src']
 
 if CONFIG['MOZ_ENABLE_SIGNMAR']:
     DIRS += ['sign', 'verify']
     TEST_DIRS += ['tests']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     # On Windows we don't verify with NSS and updater needs to link to it
     DIRS += ['verify']
 elif CONFIG['OS_ARCH'] == 'Darwin':
-    # On OSX 10.7+ we don't verify with NSS and updater needs to link to it
+    # On OSX we don't verify with NSS and updater needs to link to it.
     DIRS += ['verify']
 
 # If we are building ./sign and ./verify then ./tool must come after it
 DIRS += ['tool']
 
--- a/modules/libmar/tests/unit/test_sign_verify.js
+++ b/modules/libmar/tests/unit/test_sign_verify.js
@@ -20,17 +20,17 @@ function run_test() {
     do_check_true(signmarBin.isExecutable());
 
     // Setup the command line arguments to sign the MAR.
     let NSSConfigDir = do_get_file("data");
     let args = ["-d", NSSConfigDir.path];
     if (certs.length == 1 && useShortHandCmdLine) {
       args.push("-n", certs[0]);
     } else {
-      for (i = 0; i < certs.length; i++) {
+      for (var i = 0; i < certs.length; i++) {
         args.push("-n" + i, certs[i]);
       }
     }
     args.push("-s", inMAR.path, outMAR.path);
 
     process.init(signmarBin);
     try {
       process.run(true, args, args.length);
@@ -145,39 +145,38 @@ function run_test() {
     // The XPCShell test wiki indicates this is the preferred way for
     // Windows and OSX detection.
     var isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
     var isOSX = ("nsILocalFileMac" in Components.interfaces);
 
     // Setup the command line arguments to create the MAR.
     // Windows & Mac vs. Linux/... have different command line for verification
     // since on Windows we verify with CryptoAPI, on Mac with Security
-    // Transforms or NSS and on all other platforms we verify with NSS. So on
-    // Windows and Mac we use an exported DER file and on other platforms we use
-    // the NSS config db.
-    if (!isWindows) {
+    // Transforms or CDSA/CSSM and on all other platforms we verify with NSS. So
+    // on Windows and Mac we use an exported DER file and on other platforms we
+    // use the NSS config db.
+    if (isWindows || isOSX) {
+      if (certs.length == 1 && useShortHandCmdLine) {
+        args.push("-D", "data/" + certs[0] + ".der");
+      } else {
+        for (var i = 0; i < certs.length; i++) {
+          args.push("-D" + i, "data/" + certs[i] + ".der");
+        }
+      }
+    } else {
       let NSSConfigDir = do_get_file("data");
       args = ["-d", NSSConfigDir.path];
       if (certs.length == 1 && useShortHandCmdLine) {
         args.push("-n", certs[0]);
       } else {
         for (var i = 0; i < certs.length; i++) {
           args.push("-n" + i, certs[i]);
         }
       }
     }
-    if (isWindows || isOSX) {
-      if (certs.length == 1 && useShortHandCmdLine) {
-        args.push("-D", "data/" + certs[0] + ".der");
-      } else {
-        for (var i = 0; i < certs.length; i++) {
-          args.push("-D" + i, "data/" + certs[i] + ".der");
-        }
-      }
-    }
     args.push("-v", signedMAR.path);
 
     process.init(signmarBin);
     try {
       // We put this in a try block because nsIProcess doesn't like -1 returns
       process.run(true, args, args.length);
     } catch (e) {
       // On Windows negative return value throws an exception
--- a/modules/libmar/tool/mar.c
+++ b/modules/libmar/tool/mar.c
@@ -54,29 +54,21 @@ static void print_usage() {
   printf("  mar [-C workingDir] -n(i) -X "
          "signed_input_archive.mar base_64_encoded_signature_file\n");
 
   printf("Import a MAR signature:\n");
   printf("  mar [-C workingDir] -n(i) -I "
          "signed_input_archive.mar base_64_encoded_signature_file "
          "changed_signed_output.mar\n");
   printf("(i) is the index of the certificate to extract\n");
-#if defined(XP_WIN) && !defined(MAR_NSS)
+#if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(MAR_NSS))
   printf("Verify a MAR file:\n");
   printf("  mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
   printf("At most %d signature certificate DER files are specified by "
          "-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
-#elif defined(XP_MACOSX)
-  printf("Verify a MAR file:\n");
-  printf("  mar [-C workingDir] -d NSSConfigDir -n certname "
-         "-v signed_archive.mar -D DERFilePath\n");
-  printf("At most %d signature certificate names are specified by "
-         "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
-  printf("At most %d signature certificate DER files are specified by "
-         "-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
 #else
   printf("Verify a MAR file:\n");
   printf("  mar [-C workingDir] -d NSSConfigDir -n certname "
          "-v signed_archive.mar\n");
   printf("At most %d signature certificate names are specified by "
          "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
 #endif
   printf("At most %d verification certificate names are specified by "
@@ -121,39 +113,38 @@ static int mar_test(const char *path) {
 int main(int argc, char **argv) {
   char *NSSConfigDir = NULL;
   const char *certNames[MAX_SIGNATURES];
   char *MARChannelID = MAR_CHANNEL_ID;
   char *productVersion = MOZ_APP_VERSION;
   uint32_t i, k;
   int rv = -1;
   uint32_t certCount = 0;
-  uint32_t derCount = 0;
   int32_t sigIndex = -1;
-  char* DERFilePaths[MAX_SIGNATURES];
 
 #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
   HANDLE certFile;
   uint8_t *certBuffers[MAX_SIGNATURES];
 #endif
 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                  defined(XP_MACOSX))
+  char* DERFilePaths[MAX_SIGNATURES];
   uint32_t fileSizes[MAX_SIGNATURES];
   uint32_t read;
 #endif
 
   memset(certNames, 0, sizeof(certNames));
 #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
   memset(certBuffers, 0, sizeof(certBuffers));
 #endif
 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                  defined(XP_MACOSX))
+  memset(DERFilePaths, 0, sizeof(DERFilePaths));
   memset(fileSizes, 0, sizeof(fileSizes));
 #endif
-  memset(DERFilePaths, 0, sizeof(DERFilePaths));
 
   if (argc > 1 && 0 == strcmp(argv[1], "--version")) {
     print_version();
     return 0;
   }
 
   if (argc < 3) {
     print_usage();
@@ -176,22 +167,22 @@ int main(int argc, char **argv) {
     } 
 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                  defined(XP_MACOSX))
     /* -D DERFilePath, also matches -D[index] DERFilePath
        We allow an index for verifying to be symmetric
        with the import and export command line arguments. */
     else if (argv[1][0] == '-' &&
              argv[1][1] == 'D' &&
-             (argv[1][2] == (char)('0' + derCount) || argv[1][2] == '\0')) {
-      if (derCount >= MAX_SIGNATURES) {
+             (argv[1][2] == (char)('0' + certCount) || argv[1][2] == '\0')) {
+      if (certCount >= MAX_SIGNATURES) {
         print_usage();
         return -1;
       }
-      DERFilePaths[derCount++] = argv[2];
+      DERFilePaths[certCount++] = argv[2];
       argv += 2;
       argc -= 2;
     }
 #endif
     /* -d NSSConfigdir */
     else if (argv[1][0] == '-' && argv[1][1] == 'd') {
       NSSConfigDir = argv[2];
       argv += 2;
@@ -325,22 +316,22 @@ int main(int argc, char **argv) {
       print_usage();
       return -1;
     }
     return import_signature(argv[2], sigIndex, argv[3], argv[4]);
 
   case 'v':
 
 #if defined(XP_WIN) && !defined(MAR_NSS)
-    if (derCount == 0) {
+    if (certCount == 0) {
       print_usage();
       return -1;
     }
 
-    for (k = 0; k < derCount; ++k) {
+    for (k = 0; k < certCount; ++k) {
       /* If the mar program was built using CryptoAPI, then read in the buffer
         containing the cert from disk. */
       certFile = CreateFileA(DERFilePaths[k], GENERIC_READ,
                              FILE_SHARE_READ |
                              FILE_SHARE_WRITE |
                              FILE_SHARE_DELETE,
                              NULL,
                              OPEN_EXISTING,
@@ -357,18 +348,18 @@ int main(int argc, char **argv) {
           free(certBuffers[i]);
         }
         return -1;
       }
       CloseHandle(certFile);
     }
 
     rv = mar_verify_signatures(argv[2], certBuffers, fileSizes,
-                               NULL, derCount);
-    for (k = 0; k < derCount; ++k) {
+                               NULL, certCount);
+    for (k = 0; k < certCount; ++k) {
       free(certBuffers[k]);
     }
     if (rv) {
       /* Determine if the source MAR file has the new fields for signing */
       int hasSignatureBlock;
       if (get_mar_file_info(argv[2], &hasSignatureBlock, 
                             NULL, NULL, NULL, NULL)) {
         fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
@@ -376,29 +367,31 @@ int main(int argc, char **argv) {
         fprintf(stderr, "ERROR: The MAR file is in the old format so has"
                         " no signature to verify.\n");
       }
       return -1;
     }
 
     return 0;
 
+#elif defined(XP_MACOSX)
+    return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
+                                 0, NULL, certCount);
 #else
     if (!NSSConfigDir || certCount == 0) {
       print_usage();
       return -1;
     }
 
     if (NSSInitCryptoContext(NSSConfigDir)) {
       fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
       return -1;
     }
 
-    return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
-                                 0, certNames, certCount);
+    return mar_verify_signatures(argv[2], NULL, 0, certNames, certCount);
 
 #endif /* defined(XP_WIN) && !defined(MAR_NSS) */
   case 's':
     if (!NSSConfigDir || certCount == 0 || argc < 4) {
       print_usage();
       return -1;
     }
     return mar_repackage_and_sign(NSSConfigDir, certNames, certCount,
--- a/modules/libmar/tool/moz.build
+++ b/modules/libmar/tool/moz.build
@@ -17,8 +17,12 @@ HOST_PROGRAM = 'mar'
 for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'):
     DEFINES[var] = '"%s"' % CONFIG[var]
 
 if not CONFIG['MOZ_ENABLE_SIGNMAR']:
     DEFINES['NO_SIGN_VERIFY'] = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     USE_STATIC_LIBS = True
+elif CONFIG['OS_ARCH'] == 'Darwin':
+    LDFLAGS += [
+      '-framework Security',
+    ]
--- a/modules/libmar/verify/MacVerifyCrypto.cpp
+++ b/modules/libmar/verify/MacVerifyCrypto.cpp
@@ -29,24 +29,16 @@ extern "C" {
                                                           CFDataRef signature,
                                                           CFErrorRef* error);
   SecVerifyTransformCreateFunc SecVerifyTransformCreatePtr = NULL;
   typedef Boolean (*SecTransformSetAttributeFunc)(SecTransformRef transform,
                                                   CFStringRef key,
                                                   CFTypeRef value,
                                                   CFErrorRef* error);
   SecTransformSetAttributeFunc SecTransformSetAttributePtr = NULL;
-  typedef SecCertificateRef (*SecCertificateCreateWithDataFunc)
-                              (CFAllocatorRef allocator,
-                               CFDataRef data);
-  SecCertificateCreateWithDataFunc SecCertificateCreateWithDataPtr = NULL;
-  typedef OSStatus (*SecCertificateCopyPublicKeyFunc)
-                     (SecCertificateRef certificate,
-                      SecKeyRef* key);
-  SecCertificateCopyPublicKeyFunc SecCertificateCopyPublicKeyPtr = NULL;
 #ifdef __cplusplus
 }
 #endif
 
 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070
 
 static int sOnLionOrLater = -1;
 
@@ -93,16 +85,52 @@ static bool OnLionOrLater()
       int version = 0x1000 + (minor << 4);
       sOnLionOrLater = version >= MAC_OS_X_VERSION_10_7_HEX ? 1 : 0;
     }
   }
 
   return sOnLionOrLater > 0 ? true : false;
 }
 
+static bool sCssmInitialized = false;
+static CSSM_VERSION sCssmVersion = {2, 0};
+static const CSSM_GUID sMozCssmGuid =
+  { 0x9243121f, 0x5820, 0x4b41,
+    { 0xa6, 0x52, 0xba, 0xb6, 0x3f, 0x9d, 0x3d, 0x7f }};
+static CSSM_CSP_HANDLE sCspHandle = NULL;
+
+void* cssmMalloc (CSSM_SIZE aSize, void* aAllocRef) {
+  (void)aAllocRef;
+  return malloc(aSize);
+}
+
+void cssmFree (void* aPtr, void* aAllocRef) {
+  (void)aAllocRef;
+  free(aPtr);
+  return;
+}
+
+void* cssmRealloc (void* aPtr, CSSM_SIZE aSize, void* aAllocRef) {
+  (void)aAllocRef;
+  return realloc(aPtr, aSize);
+}
+
+void* cssmCalloc (uint32 aNum, CSSM_SIZE aSize, void* aAllocRef) {
+  (void)aAllocRef;
+  return calloc(aNum, aSize);
+}
+
+static CSSM_API_MEMORY_FUNCS cssmMemFuncs = {
+    &cssmMalloc,
+    &cssmFree,
+    &cssmRealloc,
+    &cssmCalloc,
+    NULL
+ };
+
 CryptoX_Result
 CryptoMac_InitCryptoProvider()
 {
   if (!OnLionOrLater()) {
     return CryptoX_Success;
   }
 
   if (!SecTransformCreateReadTransformWithReadStreamPtr) {
@@ -117,99 +145,183 @@ CryptoMac_InitCryptoProvider()
   if (!SecVerifyTransformCreatePtr) {
     SecVerifyTransformCreatePtr = (SecVerifyTransformCreateFunc)
       dlsym(RTLD_DEFAULT, "SecVerifyTransformCreate");
   }
   if (!SecTransformSetAttributePtr) {
     SecTransformSetAttributePtr = (SecTransformSetAttributeFunc)
       dlsym(RTLD_DEFAULT, "SecTransformSetAttribute");
   }
-  if (!SecCertificateCreateWithDataPtr) {
-    SecCertificateCreateWithDataPtr = (SecCertificateCreateWithDataFunc)
-      dlsym(RTLD_DEFAULT, "SecCertificateCreateWithData");
-  }
-  if (!SecCertificateCopyPublicKeyPtr) {
-    SecCertificateCopyPublicKeyPtr = (SecCertificateCopyPublicKeyFunc)
-      dlsym(RTLD_DEFAULT, "SecCertificateCopyPublicKey");
-  }
   if (!SecTransformCreateReadTransformWithReadStreamPtr ||
       !SecTransformExecutePtr ||
       !SecVerifyTransformCreatePtr ||
-      !SecTransformSetAttributePtr ||
-      !SecCertificateCreateWithDataPtr ||
-      !SecCertificateCopyPublicKeyPtr) {
+      !SecTransformSetAttributePtr) {
     return CryptoX_Error;
   }
   return CryptoX_Success;
 }
 
 CryptoX_Result
-CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData,
-                      CryptoX_PublicKey* aPublicKey)
+CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData)
 {
-  if (!OnLionOrLater()) {
-    return NSS_VerifyBegin((VFYContext**)aInputData,
-                           (SECKEYPublicKey* const*)aPublicKey);
-  }
-
-  (void)aPublicKey;
   if (!aInputData) {
     return CryptoX_Error;
   }
 
-  CryptoX_Result result = CryptoX_Error;
-  *aInputData = CFDataCreateMutable(kCFAllocatorDefault, 0);
-  if (*aInputData) {
-    result = CryptoX_Success;
+  void* inputData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+  if (!inputData) {
+    return CryptoX_Error;
   }
 
-  return result;
+  if (!OnLionOrLater()) {
+    CSSM_DATA_PTR cssmData = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
+    if (!cssmData) {
+      CFRelease(inputData);
+      return CryptoX_Error;
+    }
+    cssmData->Data = (uint8*)inputData;
+    cssmData->Length = 0;
+    *aInputData = cssmData;
+    return CryptoX_Success;
+  }
+
+  *aInputData = inputData;
+  return CryptoX_Success;
 }
 
 CryptoX_Result
 CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData, void* aBuf,
                        unsigned int aLen)
 {
-  if (!OnLionOrLater()) {
-    return VFY_Update((VFYContext*)*aInputData,
-                      (const unsigned char*)aBuf, aLen);
-  }
-
   if (aLen == 0) {
     return CryptoX_Success;
   }
   if (!aInputData || !*aInputData) {
     return CryptoX_Error;
   }
 
-  CryptoX_Result result = CryptoX_Error;
-  CFDataAppendBytes((CFMutableDataRef)*aInputData, (const UInt8 *) aBuf, aLen);
-  if (*aInputData) {
-    result = CryptoX_Success;
+  CFMutableDataRef inputData;
+  if (!OnLionOrLater()) {
+    inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data;
+    ((CSSM_DATA_PTR)*aInputData)->Length += aLen;
+  } else {
+    inputData = (CFMutableDataRef)*aInputData;
   }
 
-  return result;
+  CFDataAppendBytes(inputData, (const uint8*)aBuf, aLen);
+  return CryptoX_Success;
 }
 
 CryptoX_Result
 CryptoMac_LoadPublicKey(const unsigned char* aCertData,
-                        CryptoX_PublicKey* aPublicKey,
-                        const char* aCertName,
-                        CryptoX_Certificate* aCert)
+                        CryptoX_PublicKey* aPublicKey)
 {
-  if (!aPublicKey ||
-      (OnLionOrLater() && !aCertData) ||
-      (!OnLionOrLater() && !aCertName)) {
+  if (!aCertData || !aPublicKey) {
     return CryptoX_Error;
   }
+  *aPublicKey = NULL;
 
   if (!OnLionOrLater()) {
-    return NSS_LoadPublicKey(aCertName,
-                             (SECKEYPublicKey**)aPublicKey,
-                             (CERTCertificate**)aCert);
+    if (!sCspHandle) {
+      CSSM_RETURN rv;
+      if (!sCssmInitialized) {
+        CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
+        rv = CSSM_Init(&sCssmVersion,
+                       CSSM_PRIVILEGE_SCOPE_PROCESS,
+                       &sMozCssmGuid,
+                       CSSM_KEY_HIERARCHY_NONE,
+                       &pvcPolicy,
+                       NULL);
+        if (rv != CSSM_OK) {
+          return CryptoX_Error;
+        }
+        sCssmInitialized = true;
+      }
+
+      rv = CSSM_ModuleLoad(&gGuidAppleCSP,
+                           CSSM_KEY_HIERARCHY_NONE,
+                           NULL,
+                           NULL);
+      if (rv != CSSM_OK) {
+        return CryptoX_Error;
+      }
+
+      CSSM_CSP_HANDLE cspHandle;
+      rv = CSSM_ModuleAttach(&gGuidAppleCSP,
+                             &sCssmVersion,
+                             &cssmMemFuncs,
+                             0,
+                             CSSM_SERVICE_CSP,
+                             0,
+                             CSSM_KEY_HIERARCHY_NONE,
+                             NULL,
+                             0,
+                             NULL,
+                             &cspHandle);
+      if (rv != CSSM_OK) {
+        return CryptoX_Error;
+      }
+      sCspHandle = cspHandle;
+    }
+
+    FILE* certFile = NULL;
+    long certFileSize = 0;
+    uint8* certBuffer = NULL;
+
+    certFile = fopen((char*)aCertData, "rb");
+    if (!certFile) {
+      return CryptoX_Error;
+    }
+    if (fseek(certFile, 0, SEEK_END)) {
+      fclose(certFile);
+      return CryptoX_Error;
+    }
+    certFileSize = ftell(certFile);
+    if (certFileSize < 0) {
+      fclose(certFile);
+      return CryptoX_Error;
+    }
+    certBuffer = (uint8*)malloc(certFileSize);
+    if (fseek(certFile, 0, SEEK_SET)) {
+      free(certBuffer);
+      fclose(certFile);
+      return CryptoX_Error;
+    }
+    uint readResult = fread(certBuffer, sizeof(uint8), certFileSize, certFile);
+    if (readResult != certFileSize) {
+      free(certBuffer);
+      fclose(certFile);
+      return CryptoX_Error;
+    }
+    fclose(certFile);
+
+    CFDataRef certData = CFDataCreate(kCFAllocatorDefault,
+                                      certBuffer,
+                                      certFileSize);
+    free(certBuffer);
+    if (!certData) {
+      return CryptoX_Error;
+    }
+
+    SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault,
+                                                          certData);
+    CFRelease(certData);
+    if (!cert) {
+      return CryptoX_Error;
+    }
+
+    SecKeyRef publicKey;
+    OSStatus status = SecCertificateCopyPublicKey(cert, (SecKeyRef*)&publicKey);
+    CFRelease(cert);
+    if (status) {
+      return CryptoX_Error;
+    }
+
+    *aPublicKey = (void*)publicKey;
+    return CryptoX_Success;
   }
 
   CFURLRef url =
     CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
                                             aCertData,
                                             strlen((char*)aCertData),
                                             false);
   if (!url) {
@@ -235,29 +347,29 @@ CryptoMac_LoadPublicKey(const unsigned c
                                                              &error);
   if (!tempCertData || error) {
     CFRelease(url);
     CFRelease(stream);
     CFRelease(readTransform);
     return CryptoX_Error;
   }
 
-  SecCertificateRef cert = SecCertificateCreateWithDataPtr(kCFAllocatorDefault,
-                                                           tempCertData);
+  SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault,
+                                                        tempCertData);
   if (!cert) {
     CFRelease(url);
     CFRelease(stream);
     CFRelease(readTransform);
     CFRelease(tempCertData);
     return CryptoX_Error;
   }
 
   CryptoX_Result result = CryptoX_Error;
-  OSStatus status = SecCertificateCopyPublicKeyPtr(cert,
-                                                   (SecKeyRef*)aPublicKey);
+  OSStatus status = SecCertificateCopyPublicKey(cert,
+                                                (SecKeyRef*)aPublicKey);
   if (status == 0) {
     result = CryptoX_Success;
   }
 
   CFRelease(url);
   CFRelease(stream);
   CFRelease(readTransform);
   CFRelease(tempCertData);
@@ -267,26 +379,61 @@ CryptoMac_LoadPublicKey(const unsigned c
 }
 
 CryptoX_Result
 CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
                           CryptoX_PublicKey* aPublicKey,
                           const unsigned char* aSignature,
                           unsigned int aSignatureLen)
 {
-  if (!OnLionOrLater()) {
-    return NSS_VerifySignature((VFYContext* const*)aInputData, aSignature,
-                               aSignatureLen);
-  }
-
   if (!aInputData || !*aInputData || !aPublicKey || !*aPublicKey ||
       !aSignature || aSignatureLen == 0) {
     return CryptoX_Error;
   }
 
+  if (!OnLionOrLater()) {
+    if (!sCspHandle) {
+      return CryptoX_Error;
+    }
+
+    CSSM_KEY* publicKey;
+    OSStatus status = SecKeyGetCSSMKey((SecKeyRef)*aPublicKey,
+                                       (const CSSM_KEY**)&publicKey);
+    if (status) {
+      return CryptoX_Error;
+    }
+
+    CSSM_CC_HANDLE ccHandle;
+    if (CSSM_CSP_CreateSignatureContext(sCspHandle,
+                                        CSSM_ALGID_SHA1WithRSA,
+                                        NULL,
+                                        publicKey,
+                                        &ccHandle) != CSSM_OK) {
+      return CryptoX_Error;
+    }
+
+    CryptoX_Result result = CryptoX_Error;
+    CSSM_DATA signatureData;
+    signatureData.Data = (uint8*)aSignature;
+    signatureData.Length = aSignatureLen;
+    CSSM_DATA inputData;
+    inputData.Data =
+      CFDataGetMutableBytePtr((CFMutableDataRef)
+                                (((CSSM_DATA_PTR)*aInputData)->Data));
+    inputData.Length = ((CSSM_DATA_PTR)*aInputData)->Length;
+    if (CSSM_VerifyData(ccHandle,
+                        &inputData,
+                        1,
+                        CSSM_ALGID_NONE,
+                        &signatureData) == CSSM_OK) {
+      result = CryptoX_Success;
+    }
+    return result;
+  }
+
   CFDataRef signatureData = CFDataCreate(kCFAllocatorDefault,
                                          aSignature, aSignatureLen);
   if (!signatureData) {
     return CryptoX_Error;
   }
 
   CFErrorRef error;
   SecTransformRef verifier =
@@ -325,43 +472,37 @@ CryptoMac_VerifySignature(CryptoX_Signat
   CFRelease(verifier);
 
   return result;
 }
 
 void
 CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData)
 {
-  if (!OnLionOrLater()) {
-    return VFY_DestroyContext((VFYContext*)aInputData, PR_TRUE);
-  }
-
   if (!aInputData || !*aInputData) {
     return;
   }
-  CFRelease((CFMutableDataRef)*aInputData);
+
+  CFMutableDataRef inputData = NULL;
+  if (OnLionOrLater()) {
+    inputData = (CFMutableDataRef)*aInputData;
+  } else {
+    inputData = (CFMutableDataRef)((CSSM_DATA_PTR)*aInputData)->Data;
+  }
+
+  CFRelease(inputData);
+  if (!OnLionOrLater()) {
+    free((CSSM_DATA_PTR)*aInputData);
+  }
 }
 
 void
 CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey)
 {
-  if (!OnLionOrLater()) {
-    return SECKEY_DestroyPublicKey((SECKEYPublicKey*)*aPublicKey);
-  }
-
   if (!aPublicKey || !*aPublicKey) {
     return;
   }
+  if (!OnLionOrLater() && sCspHandle) {
+    CSSM_ModuleDetach(sCspHandle);
+    sCspHandle = NULL;
+  }
   CFRelease((SecKeyRef)*aPublicKey);
 }
-
-void
-CryptoMac_FreeCertificate(CryptoX_Certificate* aCertificate)
-{
-  if (!OnLionOrLater()) {
-    return CERT_DestroyCertificate((CERTCertificate*)*aCertificate);
-  }
-
-  if (!aCertificate || !*aCertificate) {
-    return;
-  }
-  CFRelease((SecKeyRef)*aCertificate);
-}
--- a/modules/libmar/verify/cryptox.h
+++ b/modules/libmar/verify/cryptox.h
@@ -14,105 +14,98 @@
 #define CryptoX_Failed(X) ((X) != CryptoX_Success)
 
 #if defined(MAR_NSS)
 
 #include "nss_secutil.h"
 
 #define CryptoX_InvalidHandleValue NULL
 #define CryptoX_ProviderHandle void*
+#define CryptoX_SignatureHandle VFYContext *
+#define CryptoX_PublicKey SECKEYPublicKey *
+#define CryptoX_Certificate CERTCertificate *
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-CryptoX_Result NSS_LoadPublicKey(const char *certNickname, 
-                                 SECKEYPublicKey **publicKey, 
+CryptoX_Result NSS_LoadPublicKey(const char *certNickname,
+                                 SECKEYPublicKey **publicKey,
                                  CERTCertificate **cert);
-CryptoX_Result NSS_VerifyBegin(VFYContext **ctx, 
+CryptoX_Result NSS_VerifyBegin(VFYContext **ctx,
                                SECKEYPublicKey * const *publicKey);
-CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx , 
-                                   const unsigned char *signature, 
+CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
+                                   const unsigned char *signature,
                                    unsigned int signatureLen);
 #ifdef __cplusplus
 } // extern "C"
 #endif
 
-#ifdef XP_MACOSX
-
-#define CryptoX_SignatureHandle void*
-#define CryptoX_PublicKey void*
-#define CryptoX_Certificate void*
-
-// Forward-declare Objective-C functions implemented in MacVerifyCrypto.mm.
-#ifdef __cplusplus
-extern "C" {
-#endif
-CryptoX_Result CryptoMac_InitCryptoProvider();
-CryptoX_Result CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData,
-                                     CryptoX_PublicKey* aPublicKey);
-CryptoX_Result CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData,
-                                      void* aBuf, unsigned int aLen);
-CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData,
-                                       CryptoX_PublicKey* aPublicKey,
-                                       const char* aCertName,
-                                       CryptoX_Certificate* aCert);
-CryptoX_Result CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
-                                         CryptoX_PublicKey* aPublicKey,
-                                         const unsigned char* aSignature,
-                                         unsigned int aSignatureLen);
-void CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData);
-void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
-void CryptoMac_FreeCertificate(CryptoX_Certificate* aCertificate);
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#define CryptoX_InitCryptoProvider(aCryptoHandle) \
-  CryptoMac_InitCryptoProvider()
-#define CryptoX_VerifyBegin(aCryptoHandle, aInputData, aPublicKey) \
-  CryptoMac_VerifyBegin(aInputData, aPublicKey)
-#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
-  CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
-#define CryptoX_LoadPublicKey(aCryptoHandle, aCertData, aDataSize, \
-                              aPublicKey, aCertName, aCert) \
-  CryptoMac_LoadPublicKey(aCertData, aPublicKey, aCertName, aCert)
-#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
-                                aSignatureLen) \
-  CryptoMac_VerifySignature(aInputData, aPublicKey, aSignature, aSignatureLen)
-#define CryptoX_FreeSignatureHandle(aInputData) \
-  CryptoMac_FreeSignatureHandle(aInputData)
-#define CryptoX_FreePublicKey(aPublicKey) \
-  CryptoMac_FreePublicKey(aPublicKey)
-#define CryptoX_FreeCertificate(aCertificate) \
-  CryptoMac_FreeCertificate(aCertificate)
-
-#else
-
-#define CryptoX_SignatureHandle VFYContext *
-#define CryptoX_PublicKey SECKEYPublicKey *
-#define CryptoX_Certificate CERTCertificate *
 #define CryptoX_InitCryptoProvider(CryptoHandle) \
   CryptoX_Success
 #define CryptoX_VerifyBegin(CryptoHandle, SignatureHandle, PublicKey) \
   NSS_VerifyBegin(SignatureHandle, PublicKey)
 #define CryptoX_FreeSignatureHandle(SignatureHandle) \
-  VFY_DestroyContext(SignatureHandle, PR_TRUE)
+  VFY_DestroyContext(*SignatureHandle, PR_TRUE)
 #define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
   VFY_Update(*SignatureHandle, (const unsigned char*)(buf), len)
 #define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
                               publicKey, certName, cert) \
   NSS_LoadPublicKey(certName, publicKey, cert)
 #define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
   NSS_VerifySignature(hash, (const unsigned char *)(signedData), len)
 #define CryptoX_FreePublicKey(key) \
   SECKEY_DestroyPublicKey(*key)
 #define CryptoX_FreeCertificate(cert) \
   CERT_DestroyCertificate(*cert)
 
+#elif XP_MACOSX
+
+#define CryptoX_InvalidHandleValue NULL
+#define CryptoX_ProviderHandle void*
+#define CryptoX_SignatureHandle void*
+#define CryptoX_PublicKey void*
+#define CryptoX_Certificate void*
+
+// Forward-declare Objective-C functions implemented in MacVerifyCrypto.mm.
+#ifdef __cplusplus
+extern "C" {
 #endif
+CryptoX_Result CryptoMac_InitCryptoProvider();
+CryptoX_Result CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData);
+CryptoX_Result CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData,
+                                      void* aBuf, unsigned int aLen);
+CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData,
+                                       CryptoX_PublicKey* aPublicKey);
+CryptoX_Result CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
+                                         CryptoX_PublicKey* aPublicKey,
+                                         const unsigned char* aSignature,
+                                         unsigned int aSignatureLen);
+void CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData);
+void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#define CryptoX_InitCryptoProvider(aProviderHandle) \
+  CryptoMac_InitCryptoProvider()
+#define CryptoX_VerifyBegin(aCryptoHandle, aInputData, aPublicKey) \
+  CryptoMac_VerifyBegin(aInputData)
+#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
+  CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
+#define CryptoX_LoadPublicKey(aProviderHandle, aCertData, aDataSize, \
+                              aPublicKey, aCertName, aCert) \
+  CryptoMac_LoadPublicKey(aCertData, aPublicKey)
+#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
+                                aSignatureLen) \
+  CryptoMac_VerifySignature(aInputData, aPublicKey, aSignature, aSignatureLen)
+#define CryptoX_FreeSignatureHandle(aInputData) \
+  CryptoMac_FreeSignatureHandle(aInputData)
+#define CryptoX_FreePublicKey(aPublicKey) \
+  CryptoMac_FreePublicKey(aPublicKey)
+#define CryptoX_FreeCertificate(aCertificate)
 
 #elif defined(XP_WIN) 
 
 #include <windows.h>
 #include <wincrypt.h>
 
 CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV *provider);
 CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV hProv, 
--- a/modules/libmar/verify/mar_verify.c
+++ b/modules/libmar/verify/mar_verify.c
@@ -503,13 +503,13 @@ mar_verify_signatures_for_fp(FILE *fp,
       goto failure;
     }
     ++*numVerified;
   }
 
   rv = CryptoX_Success;
 failure:
   for (i = 0; i < signatureCount; i++) {
-    CryptoX_FreeSignatureHandle(signatureHandles[i]);
+    CryptoX_FreeSignatureHandle(&signatureHandles[i]);
   }
 
   return rv;
 }
--- a/modules/libmar/verify/moz.build
+++ b/modules/libmar/verify/moz.build
@@ -10,21 +10,23 @@ UNIFIED_SOURCES += [
     'cryptox.c',
     'mar_verify.c',
 ]
 
 FORCE_STATIC_LIB = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     USE_STATIC_LIBS = True
+elif CONFIG['OS_ARCH'] == 'Darwin':
+    UNIFIED_SOURCES += [
+      'MacVerifyCrypto.cpp',
+    ]
+    LDFLAGS += [
+      '-framework Security',
+    ]
 else:
     DEFINES['MAR_NSS'] = True
     LOCAL_INCLUDES += ['../sign']
 
-if CONFIG['OS_ARCH'] == 'Darwin':
-    UNIFIED_SOURCES += [
-      'MacVerifyCrypto.cpp',
-    ]
-
 LOCAL_INCLUDES += [
     '../src',
 ]
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -780,16 +780,21 @@ pref("javascript.options.strict",       
 #ifdef DEBUG
 pref("javascript.options.strict.debug",     true);
 #endif
 pref("javascript.options.baselinejit",      true);
 pref("javascript.options.ion",              true);
 pref("javascript.options.asmjs",            true);
 pref("javascript.options.parallel_parsing", true);
 pref("javascript.options.ion.parallel_compilation", true);
+// This preference instructs the JS engine to discard the
+// source of any privileged JS after compilation. This saves
+// memory, but makes things like Function.prototype.toSource()
+// fail.
+pref("javascript.options.discardSystemSource", false);
 // This preference limits the memory usage of javascript.
 // If you want to change these values for your device,
 // please find Bug 417052 comment 17 and Bug 456721
 // Comment 32 and Bug 613551.
 pref("javascript.options.mem.high_water_mark", 128);
 pref("javascript.options.mem.max", -1);
 pref("javascript.options.mem.gc_per_compartment", true);
 pref("javascript.options.mem.gc_incremental", true);
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -2428,21 +2428,21 @@ nsSocketTransport::OnKeepaliveEnabledPre
                         aEnabled ? "enable" : "disable", rv));
         }
     }
 }
 
 nsresult
 nsSocketTransport::SetKeepaliveEnabledInternal(bool aEnable)
 {
-    MOZ_ASSERT(mKeepaliveIdleTimeS > 0 ||
+    MOZ_ASSERT(mKeepaliveIdleTimeS > 0 &&
                mKeepaliveIdleTimeS <= kMaxTCPKeepIdle);
-    MOZ_ASSERT(mKeepaliveRetryIntervalS > 0 ||
+    MOZ_ASSERT(mKeepaliveRetryIntervalS > 0 &&
                mKeepaliveRetryIntervalS <= kMaxTCPKeepIntvl);
-    MOZ_ASSERT(mKeepaliveProbeCount > 0 ||
+    MOZ_ASSERT(mKeepaliveProbeCount > 0 &&
                mKeepaliveProbeCount <= kMaxTCPKeepCount);
 
     PRFileDescAutoLock fd(this);
     if (NS_WARN_IF(!fd.IsInitialized())) {
         return NS_ERROR_NOT_INITIALIZED;
     }
 
     // Only enable if keepalives are globally enabled, but ensure other
--- a/netwerk/test/mochitests/test_user_agent_overrides.html
+++ b/netwerk/test/mochitests/test_user_agent_overrides.html
@@ -38,27 +38,21 @@ function getUA(host) {
   xhr.send();
   is(xhr.status, 200, 'request failed');
   is(typeof xhr.response, 'string', 'invalid response');
   return xhr.response;
 }
 
 function testUA(options, callback) {
 
-  var [domain, override, test_hosts, skip, expected] =
-    [options.domain, options.override, options.test_hosts, options.skip, options.expected];
+  var [domain, override, test_hosts, expected] =
+    [options.domain, options.override, options.test_hosts, options.expected];
 
   info('Overriding ' + domain + ' with ' + override);
 
-  if (skip) {
-    todo(false, 'Skipping');
-    callback();
-    return;
-  }
-
   function is_subdomain(host) {
     var [test_domain] = host.slice(host.lastIndexOf('/') + 1).split(':', 1);
     return test_domain === domain || test_domain.endsWith('.' + domain);
   }
 
   var localhost = location.origin;
   var overrideNavigator = is_subdomain(localhost);
   var navigator_ua, test_ua = [];
@@ -99,22 +93,16 @@ function testUA(options, callback) {
         is(getUA(test_host), test_ua[i],
           'Header UA not restored at step ' + (++step));
       });
       callback();
     });
   });
 }
 
-// mochitests on Android appear to have trouble with https
-// but when it eventually works, we should re-enable the test
-var skipHttps = /android/i.test(DEFAULT_UA);
-if (skipHttps) {
-  SimpleTest.doesThrow(function () getUA('https://example.com'), 'Re-enable https test');
-}
 
 var step = 0; // for logging
 var tests = [
   // should override both header and navigator.userAgent
   {
     domain: location.hostname,
     override: UA_WHOLE_OVERRIDE,
     test_hosts: [location.origin],
@@ -145,17 +133,16 @@ var tests = [
     override: UA_WHOLE_OVERRIDE,
     test_hosts: ['http://example.org',
                  'http://test1.example.org'],
     expected: DEFAULT_UA
   },
 
   // should work with https
   {
-    skip: skipHttps,
     domain: 'example.com',
     override: UA_WHOLE_OVERRIDE,
     test_hosts: ['https://example.com',
                  'https://test1.example.com',
                  'https://sub1.test1.example.com'],
     expected: UA_WHOLE_EXPECTED
   },
 ];
@@ -238,9 +225,8 @@ testOverrides(function ()
     testPriority(SimpleTest.finish)
   )
 );
 
 </script>
 </pre>
 </body>
 </html>
-
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -404,16 +404,23 @@ class MochitestOptions(optparse.OptionPa
            "help": "Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots."
         }],
         [["--quiet"],
          { "action": "store_true",
            "default": False,
            "dest": "quiet",
            "help": "Do not print test log lines unless a failure occurs."
          }],
+        [["--pidfile"],
+        { "action": "store",
+          "type": "string",
+          "dest": "pidFile",
+          "help": "name of the pidfile to generate",
+          "default": "",
+        }],
     ]
 
     def __init__(self, **kwargs):
 
         optparse.OptionParser.__init__(self, **kwargs)
         for option, value in self.mochitest_options:
             self.add_option(*option, **value)
         addCommonOptions(self)
@@ -664,23 +671,16 @@ class B2GOptions(MochitestOptions):
         }],
         [["--ssl-port"],
         { "action": "store",
           "type": "string",
           "dest": "sslPort",
           "help": "ip address where the remote web server is hosted at",
           "default": None,
         }],
-        [["--pidfile"],
-        { "action": "store",
-          "type": "string",
-          "dest": "pidFile",
-          "help": "name of the pidfile to generate",
-          "default": "",
-        }],
         [["--gecko-path"],
         { "action": "store",
           "type": "string",
           "dest": "geckoPath",
           "help": "the path to a gecko distribution that should \
                    be installed on the emulator prior to test",
           "default": None,
         }],
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -257,16 +257,20 @@ class MochitestUtilsMixin(object):
 
   # Path to the test script on the server
   TEST_PATH = "tests"
   CHROME_PATH = "redirect.html"
   urlOpts = []
 
   def __init__(self):
     self.update_mozinfo()
+    self.server = None
+    self.wsserver = None
+    self.sslTunnel = None
+    self._locations = None
 
   def update_mozinfo(self):
     """walk up directories to find mozinfo.json update the info"""
     # TODO: This should go in a more generic place, e.g. mozinfo
 
     path = SCRIPT_DIR
     dirs = set()
     while path != os.path.expanduser('~'):
@@ -282,16 +286,24 @@ class MochitestUtilsMixin(object):
     return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
 
   def getLogFilePath(self, logFile):
     """ return the log file path relative to the device we are testing on, in most cases
         it will be the full path on the local system
     """
     return self.getFullPath(logFile)
 
+  @property
+  def locations(self):
+    if self._locations is not None:
+      return self._locations
+    locations_file = os.path.join(SCRIPT_DIR, 'server-locations.txt')
+    self._locations = ServerLocations(locations_file)
+    return self._locations
+
   def buildURLOptions(self, options, env):
     """ Add test control options from the command line to the url
 
         URL parameters to test URL:
 
         autorun -- kick off tests automatically
         closeWhenDone -- closes the browser after the tests
         hideResultsTable -- hides the table of individual test results
@@ -502,53 +514,81 @@ class MochitestUtilsMixin(object):
       with open(os.path.join(testdir, 'tests.json'), 'w') as manifestFile:
         manifestFile.write(json.dumps({'tests': paths}))
       options.manifestFile = 'tests.json'
 
     return self.buildTestURL(options)
 
   def startWebSocketServer(self, options, debuggerInfo):
     """ Launch the websocket server """
-    if options.webServer != '127.0.0.1':
-      return
-
     self.wsserver = WebSocketServer(options, SCRIPT_DIR, debuggerInfo)
     self.wsserver.start()
 
-  def stopWebSocketServer(self, options):
-    if options.webServer != '127.0.0.1':
-      return
-
-    log.info('Stopping web socket server')
-    self.wsserver.stop()
-
   def startWebServer(self, options):
     """Create the webserver and start it up"""
 
-    if options.webServer != '127.0.0.1':
-      return
-
     self.server = MochitestServer(options)
     self.server.start()
 
+    if options.pidFile != "":
+      with open(options.pidFile + ".xpcshell.pid", 'w') as f:
+        f.write("%s" % self.server._process.pid)
+
+  def startServers(self, options, debuggerInfo):
+    # start servers and set ports
+    # TODO: pass these values, don't set on `self`
+    self.webServer = options.webServer
+    self.httpPort = options.httpPort
+    self.sslPort = options.sslPort
+    self.webSocketPort = options.webSocketPort
+
+    # httpd-path is specified by standard makefile targets and may be specified
+    # on the command line to select a particular version of httpd.js. If not
+    # specified, try to select the one from hostutils.zip, as required in bug 882932.
+    if not options.httpdPath:
+      options.httpdPath = os.path.join(options.utilityPath, "components")
+
+    self.startWebServer(options)
+    self.startWebSocketServer(options, debuggerInfo)
+
+    # start SSL pipe
+    self.sslTunnel = SSLTunnel(options)
+    self.sslTunnel.buildConfig(self.locations)
+    self.sslTunnel.start()
+
     # If we're lucky, the server has fully started by now, and all paths are
     # ready, etc.  However, xpcshell cold start times suck, at least for debug
     # builds.  We'll try to connect to the server for awhile, and if we fail,
     # we'll try to kill the server and exit with an error.
-    self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
+    if self.server is not None:
+      self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
+
+  def stopServers(self):
+    """Servers are no longer needed, and perhaps more importantly, anything they
+        might spew to console might confuse things."""
+    if self.server is not None:
+      try:
+        log.info('Stopping web server')
+        self.server.stop()
+      except Exception:
+        log.exception('Exception when stopping web server')
 
-  def stopWebServer(self, options):
-    """ Server's no longer needed, and perhaps more importantly, anything it might
-        spew to console shouldn't disrupt the leak information table we print next.
-    """
-    if options.webServer != '127.0.0.1':
-      return
+    if self.wsserver is not None:
+      try:
+        log.info('Stopping web socket server')
+        self.wsserver.stop()
+      except Exception:
+        log.exception('Exception when stopping web socket server');
 
-    log.info('Stopping web server')
-    self.server.stop()
+    if self.sslTunnel is not None:
+      try:
+        log.info('Stopping ssltunnel')
+        self.sslTunnel.stop()
+      except Exception:
+        log.exception('Exception stopping ssltunnel');
 
   def copyExtraFilesToProfile(self, options):
     "Copy extra files or dirs specified on the command line to the testing profile."
     for f in options.extraProfileFiles:
       abspath = self.getFullPath(f)
       if os.path.isfile(abspath):
         shutil.copy2(abspath, options.profilePath)
       elif os.path.isdir(abspath):
@@ -637,19 +677,91 @@ overlay chrome://webapprt/content/webapp
             path = os.path.join(extensionDir, dirEntry)
             if os.path.isdir(path) or (os.path.isfile(path) and path.endswith(".xpi")):
               extensions.append(path)
 
     # append mochikit
     extensions.append(os.path.join(SCRIPT_DIR, self.jarDir))
     return extensions
 
+class SSLTunnel:
+  def __init__(self, options):
+    self.process = None
+    self.utilityPath = options.utilityPath
+    self.xrePath = options.xrePath
+    self.certPath = options.certPath
+    self.sslPort = options.sslPort
+    self.httpPort = options.httpPort
+    self.webServer = options.webServer
+    self.webSocketPort = options.webSocketPort
+
+    self.customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
+    self.clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
+    self.redirRE      = re.compile("^redir=(?P<redirhost>[0-9a-zA-Z_ .]+)")
+
+  def writeLocation(self, config, loc):
+    for option in loc.options:
+      match = self.customCertRE.match(option)
+      if match:
+        customcert = match.group("nickname");
+        config.write("listen:%s:%s:%s:%s\n" %
+                     (loc.host, loc.port, self.sslPort, customcert))
+
+      match = self.clientAuthRE.match(option)
+      if match:
+        clientauth = match.group("clientauth");
+        config.write("clientauth:%s:%s:%s:%s\n" %
+                     (loc.host, loc.port, self.sslPort, clientauth))
+
+      match = self.redirRE.match(option)
+      if match:
+        redirhost = match.group("redirhost")
+        config.write("redirhost:%s:%s:%s:%s\n" %
+                     (loc.host, loc.port, self.sslPort, redirhost))
+
+  def buildConfig(self, locations):
+    """Create the ssltunnel configuration file"""
+    configFd, self.configFile = tempfile.mkstemp(prefix="ssltunnel", suffix=".cfg")
+    with os.fdopen(configFd, "w") as config:
+      config.write("httpproxy:1\n")
+      config.write("certdbdir:%s\n" % self.certPath)
+      config.write("forward:127.0.0.1:%s\n" % self.httpPort)
+      config.write("websocketserver:%s:%s\n" % (self.webServer, self.webSocketPort))
+      config.write("listen:*:%s:pgo server certificate\n" % self.sslPort)
+
+      for loc in locations:
+        if loc.scheme == "https" and "nocert" not in loc.options:
+          self.writeLocation(config, loc)
+
+  def start(self):
+    """ Starts the SSL Tunnel """
+
+    # start ssltunnel to provide https:// URLs capability
+    bin_suffix = mozinfo.info.get('bin_suffix', '')
+    ssltunnel = os.path.join(self.utilityPath, "ssltunnel" + bin_suffix)
+    if not os.path.exists(ssltunnel):
+      log.error("INFO | runtests.py | expected to find ssltunnel at %s", ssltunnel)
+      exit(1)
+
+    env = environment(xrePath=self.xrePath)
+    self.process = mozprocess.ProcessHandler([ssltunnel, self.configFile],
+                                               env=env)
+    self.process.run()
+    log.info("INFO | runtests.py | SSL tunnel pid: %d", self.process.pid)
+
+  def stop(self):
+    """ Stops the SSL Tunnel and cleans up """
+    if self.process is not None:
+      self.process.kill()
+    if os.path.exists(self.configFile):
+      os.remove(self.configFile)
 
 class Mochitest(MochitestUtilsMixin):
-  runSSLTunnel = True
+  certdbNew = False
+  sslTunnel = None
   vmwareHelper = None
   DEFAULT_TIMEOUT = 60.0
 
   # XXX use automation.py for test name to avoid breaking legacy
   # TODO: replace this with 'runtests.py' or 'mochitest' or the like
   test_name = 'automation.py'
 
   def __init__(self):
@@ -661,30 +773,72 @@ class Mochitest(MochitestUtilsMixin):
     # Max time in seconds to wait for server startup before tests will fail -- if
     # this seems big, it's mostly for debug machines where cold startup
     # (particularly after a build) takes forever.
     self.SERVER_STARTUP_TIMEOUT = 180 if mozinfo.info.get('debug') else 90
 
     # metro browser sub process id
     self.browserProcessId = None
 
-    # cached server locations
-    self._locations = {}
 
     self.haveDumpedScreen = False
 
   def extraPrefs(self, extraPrefs):
     """interpolate extra preferences from option strings"""
 
     try:
       return dict(parseKeyValue(extraPrefs, context='--setpref='))
     except KeyValueParseError, e:
       print str(e)
       sys.exit(1)
 
+  def fillCertificateDB(self, options):
+    # TODO: move -> mozprofile:
+    # https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c35
+
+    pwfilePath = os.path.join(options.profilePath, ".crtdbpw")
+    with open(pwfilePath, "w") as pwfile:
+      pwfile.write("\n")
+
+    # Pre-create the certification database for the profile
+    env = self.environment(xrePath=options.xrePath)
+    bin_suffix = mozinfo.info.get('bin_suffix', '')
+    certutil = os.path.join(options.utilityPath, "certutil" + bin_suffix)
+    pk12util = os.path.join(options.utilityPath, "pk12util" + bin_suffix)
+
+    if self.certdbNew:
+      # android and b2g use the new DB formats exclusively
+      certdbPath = "sql:" + options.profilePath
+    else:
+      # desktop seems to use the old
+      certdbPath = options.profilePath
+
+    status = call([certutil, "-N", "-d", certdbPath, "-f", pwfilePath], env=env)
+    if status:
+      return status
+
+    # Walk the cert directory and add custom CAs and client certs
+    files = os.listdir(options.certPath)
+    for item in files:
+      root, ext = os.path.splitext(item)
+      if ext == ".ca":
+        trustBits = "CT,,"
+        if root.endswith("-object"):
+          trustBits = "CT,,CT"
+        call([certutil, "-A", "-i", os.path.join(options.certPath, item),
+              "-d", certdbPath, "-f", pwfilePath, "-n", root, "-t", trustBits],
+              env=env)
+      elif ext == ".client":
+        call([pk12util, "-i", os.path.join(options.certPath, item),
+              "-w", pwfilePath, "-d", certdbPath],
+              env=env)
+
+    os.unlink(pwfilePath)
+    return 0
+
   def buildProfile(self, options):
     """ create the profile and add optional chrome bits and files if requested """
     if options.browserChrome and options.timeout:
       options.extraPrefs.append("testing.browserTestHarness.timeout=%d" % options.timeout)
     options.extraPrefs.append("browser.tabs.remote=%s" % ('true' if options.e10s else 'false'))
     options.extraPrefs.append("browser.tabs.remote.autostart=%s" % ('true' if options.e10s else 'false'))
 
     # get extensions to install
@@ -693,20 +847,16 @@ class Mochitest(MochitestUtilsMixin):
     # web apps
     appsPath = os.path.join(SCRIPT_DIR, 'profile_data', 'webapps_mochitest.json')
     if os.path.exists(appsPath):
       with open(appsPath) as apps_file:
         apps = json.load(apps_file)
     else:
       apps = None
 
-    # locations
-    locations_file = os.path.join(SCRIPT_DIR, 'server-locations.txt')
-    locations = ServerLocations(locations_file)
-
     # preferences
     prefsPath = os.path.join(SCRIPT_DIR, 'profile_data', 'prefs_general.js')
     prefs = dict(Preferences.read_prefs(prefsPath))
     prefs.update(self.extraPrefs(options.extraPrefs))
 
     # interpolate preferences
     interpolation = {"server": "%s:%s" % (options.webServer, options.httpPort)}
     prefs = json.loads(json.dumps(prefs) % interpolation)
@@ -722,30 +872,39 @@ class Mochitest(MochitestUtilsMixin):
     # use SSL port for legacy compatibility; see
     # - https://bugzilla.mozilla.org/show_bug.cgi?id=688667#c66
     # - https://bugzilla.mozilla.org/show_bug.cgi?id=899221
     # - https://github.com/mozilla/mozbase/commit/43f9510e3d58bfed32790c82a57edac5f928474d
     #             'ws': str(self.webSocketPort)
              'ws': options.sslPort
              }
 
+
     # create a profile
     self.profile = Profile(profile=options.profilePath,
                            addons=extensions,
-                           locations=locations,
+                           locations=self.locations,
                            preferences=prefs,
                            apps=apps,
                            proxy=proxy
                            )
 
     # Fix options.profilePath for legacy consumers.
     options.profilePath = self.profile.profile
 
     manifest = self.addChromeToProfile(options)
     self.copyExtraFilesToProfile(options)
+
+    # create certificate database for the profile
+    # TODO: this should really be upstreamed somewhere, maybe mozprofile
+    certificateStatus = self.fillCertificateDB(options)
+    if certificateStatus:
+      log.info("TEST-UNEXPECTED-FAIL | runtests.py | Certificate integration failed")
+      return None
+
     return manifest
 
   def buildBrowserEnv(self, options, debugger=False):
     """build the environment variables for the specific test and operating system"""
     browserEnv = self.environment(xrePath=options.xrePath, debugger=debugger,
                                   dmdPath=options.dmdPath)
 
     # These variables are necessary for correct application startup; change
@@ -777,16 +936,23 @@ class Mochitest(MochitestUtilsMixin):
       browserEnv["JS_DISABLE_SLOW_SCRIPT_SIGNALS"] = "1"
 
     return browserEnv
 
   def cleanup(self, manifest, options):
     """ remove temporary files and profile """
     os.remove(manifest)
     del self.profile
+    if options.pidFile != "":
+      try:
+        os.remove(options.pidFile)
+        if os.path.exists(options.pidFile + ".xpcshell.pid"):
+          os.remove(options.pidFile + ".xpcshell.pid")
+      except:
+        log.warn("cleaning up pidfile '%s' was unsuccessful from the test harness", options.pidFile)
 
   def dumpScreen(self, utilityPath):
     if self.haveDumpedScreen:
       log.info("Not taking screenshot here: see the one that was previously logged")
       return
     self.haveDumpedScreen = True
     dumpScreen(utilityPath)
 
@@ -863,35 +1029,35 @@ class Mochitest(MochitestUtilsMixin):
       self.vmwareHelper.StartRecording()
     except Exception, e:
       log.warning("runtests.py | Failed to start "
                   "VMware recording: (%s)" % str(e))
       self.vmwareHelper = None
 
   def stopVMwareRecording(self):
     """ stops recording inside VMware VM using the recording helper dll """
-    assert mozinfo.isWin
-    if self.vmwareHelper is not None:
-      log.info("runtests.py | Stopping VMware recording.")
-      try:
+    try:
+      assert mozinfo.isWin
+      if self.vmwareHelper is not None:
+        log.info("runtests.py | Stopping VMware recording.")
         self.vmwareHelper.StopRecording()
-      except Exception, e:
-        log.warning("runtests.py | Failed to stop "
-                    "VMware recording: (%s)" % str(e))
-      self.vmwareHelper = None
+    except Exception, e:
+      log.warning("runtests.py | Failed to stop "
+                  "VMware recording: (%s)" % str(e))
+      log.exception('Error stopping VMWare recording')
+
+    self.vmwareHelper = None
 
   def runApp(self,
              testUrl,
              env,
              app,
              profile,
              extraArgs,
              utilityPath,
-             xrePath,
-             certPath,
              debuggerInfo=None,
              symbolsPath=None,
              timeout=-1,
              onLaunch=None,
              webapprtChrome=False,
              hide_subtests=False,
              screenshotOnFail=False):
     """
@@ -901,26 +1067,16 @@ class Mochitest(MochitestUtilsMixin):
 
     # debugger information
     interactive = False
     debug_args = None
     if debuggerInfo:
         interactive = debuggerInfo['interactive']
         debug_args = [debuggerInfo['path']] + debuggerInfo['args']
 
-    # ensure existence of required paths
-    required_paths = ('utilityPath', 'xrePath', 'certPath')
-    missing = [(path, locals()[path])
-               for path in required_paths
-               if not os.path.exists(locals()[path])]
-    if missing:
-      log.error("runtests.py | runApp called with missing paths: %s" % (
-        ', '.join([("%s->%s" % (key, value)) for key, value in missing])))
-      return 1
-
     # fix default timeout
     if timeout == -1:
       timeout = self.DEFAULT_TIMEOUT
 
     # build parameters
     is_test_build = mozinfo.info.get('tests_enabled', True)
     bin_suffix = mozinfo.info.get('bin_suffix', '')
 
@@ -929,38 +1085,16 @@ class Mochitest(MochitestUtilsMixin):
 
     # make sure we clean up after ourselves.
     try:
       # set process log environment variable
       tmpfd, processLog = tempfile.mkstemp(suffix='pidlog')
       os.close(tmpfd)
       env["MOZ_PROCESS_LOG"] = processLog
 
-      if self.runSSLTunnel:
-
-        # create certificate database for the profile
-        # TODO: this should really be upstreamed somewhere, maybe mozprofile
-        certificateStatus = self.fillCertificateDB(self.profile.profile,
-                                                   certPath,
-                                                   utilityPath,
-                                                   xrePath)
-        if certificateStatus:
-          log.info("TEST-UNEXPECTED-FAIL | runtests.py | Certificate integration failed")
-          return certificateStatus
-
-        # start ssltunnel to provide https:// URLs capability
-        ssltunnel = os.path.join(utilityPath, "ssltunnel" + bin_suffix)
-        ssltunnel_cfg = os.path.join(self.profile.profile, "ssltunnel.cfg")
-        ssltunnelProcess = mozprocess.ProcessHandler([ssltunnel, ssltunnel_cfg], cwd=SCRIPT_DIR,
-                                                      env=environment(xrePath=xrePath))
-        ssltunnelProcess.run()
-        log.info("INFO | runtests.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
-      else:
-        ssltunnelProcess = None
-
       if interactive:
         # If an interactive debugger is attached,
         # don't use timeouts, and don't capture ctrl-c.
         timeout = None
         signal.signal(signal.SIGINT, lambda sigid, frame: None)
 
       # build command line
       cmd = os.path.abspath(app)
@@ -1069,18 +1203,16 @@ class Mochitest(MochitestUtilsMixin):
 
       if crashed or zombieProcesses:
         status = 1
 
     finally:
       # cleanup
       if os.path.exists(processLog):
         os.remove(processLog)
-      if ssltunnelProcess:
-        ssltunnelProcess.kill()
 
     return status
 
   def runTests(self, options, onLaunch=None):
     """ Prepare, configure, run tests and cleanup """
 
     # get debugger info, a dict of:
     # {'path': path to the debugger (string),
@@ -1101,114 +1233,92 @@ class Mochitest(MochitestUtilsMixin):
 
     # buildProfile sets self.profile .
     # This relies on sideeffects and isn't very stateful:
     # https://bugzilla.mozilla.org/show_bug.cgi?id=919300
     manifest = self.buildProfile(options)
     if manifest is None:
       return 1
 
-    # start servers and set ports
-    # TODO: pass these values, don't set on `self`
-    self.webServer = options.webServer
-    self.httpPort = options.httpPort
-    self.sslPort = options.sslPort
-    self.webSocketPort = options.webSocketPort
+    try:
+      self.startServers(options, debuggerInfo)
 
-    try:
-        self.startWebServer(options)
-        self.startWebSocketServer(options, debuggerInfo)
+      testURL = self.buildTestPath(options)
+      self.buildURLOptions(options, browserEnv)
+      if self.urlOpts:
+        testURL += "?" + "&".join(self.urlOpts)
 
-        testURL = self.buildTestPath(options)
-        self.buildURLOptions(options, browserEnv)
-        if self.urlOpts:
-          testURL += "?" + "&".join(self.urlOpts)
+      if options.webapprtContent:
+        options.browserArgs.extend(('-test-mode', testURL))
+        testURL = None
 
-        if options.webapprtContent:
-          options.browserArgs.extend(('-test-mode', testURL))
-          testURL = None
-
-        if options.immersiveMode:
-          options.browserArgs.extend(('-firefoxpath', options.app))
-          options.app = self.immersiveHelperPath
+      if options.immersiveMode:
+        options.browserArgs.extend(('-firefoxpath', options.app))
+        options.app = self.immersiveHelperPath
 
-        if options.jsdebugger:
-          options.browserArgs.extend(['-jsdebugger'])
+      if options.jsdebugger:
+        options.browserArgs.extend(['-jsdebugger'])
 
-        # Remove the leak detection file so it can't "leak" to the tests run.
-        # The file is not there if leak logging was not enabled in the application build.
-        if os.path.exists(self.leak_report_file):
-          os.remove(self.leak_report_file)
+      # Remove the leak detection file so it can't "leak" to the tests run.
+      # The file is not there if leak logging was not enabled in the application build.
+      if os.path.exists(self.leak_report_file):
+        os.remove(self.leak_report_file)
 
-        # then again to actually run mochitest
-        if options.timeout:
-          timeout = options.timeout + 30
-        elif options.debugger or not options.autorun:
-          timeout = None
-        else:
-          timeout = 330.0 # default JS harness timeout is 300 seconds
+      # then again to actually run mochitest
+      if options.timeout:
+        timeout = options.timeout + 30
+      elif options.debugger or not options.autorun:
+        timeout = None
+      else:
+        timeout = 330.0 # default JS harness timeout is 300 seconds
 
-        if options.vmwareRecording:
-          self.startVMwareRecording(options);
+      if options.vmwareRecording:
+        self.startVMwareRecording(options);
 
-        log.info("runtests.py | Running tests: start.\n")
-        try:
-          status = self.runApp(testURL,
-                               browserEnv,
-                               options.app,
-                               profile=self.profile,
-                               extraArgs=options.browserArgs,
-                               utilityPath=options.utilityPath,
-                               xrePath=options.xrePath,
-                               certPath=options.certPath,
-                               debuggerInfo=debuggerInfo,
-                               symbolsPath=options.symbolsPath,
-                               timeout=timeout,
-                               onLaunch=onLaunch,
-                               webapprtChrome=options.webapprtChrome,
-                               hide_subtests=options.hide_subtests,
-                               screenshotOnFail=options.screenshotOnFail
-                               )
-        except KeyboardInterrupt:
-          log.info("runtests.py | Received keyboard interrupt.\n");
-          status = -1
-        except:
-          traceback.print_exc()
-          log.error("Automation Error: Received unexpected exception while running application\n")
-          status = 1
+      log.info("runtests.py | Running tests: start.\n")
+      try:
+        status = self.runApp(testURL,
+                             browserEnv,
+                             options.app,
+                             profile=self.profile,
+                             extraArgs=options.browserArgs,
+                             utilityPath=options.utilityPath,
+                             debuggerInfo=debuggerInfo,
+                             symbolsPath=options.symbolsPath,
+                             timeout=timeout,
+                             onLaunch=onLaunch,
+                             webapprtChrome=options.webapprtChrome,
+                             hide_subtests=options.hide_subtests,
+                             screenshotOnFail=options.screenshotOnFail
+        )
+      except KeyboardInterrupt:
+        log.info("runtests.py | Received keyboard interrupt.\n");
+        status = -1
+      except:
+        traceback.print_exc()
+        log.error("Automation Error: Received unexpected exception while running application\n")
+        status = 1
 
     finally:
-        if options.vmwareRecording:
-            try:
-              self.stopVMwareRecording();
-            except Exception:
-                log.exception('Error stopping VMWare recording')
+      if options.vmwareRecording:
+        self.stopVMwareRecording();
+      self.stopServers()
 
-        try:
-            self.stopWebServer(options)
-        except Exception:
-            log.exception('Exception when stopping web server')
+    processLeakLog(self.leak_report_file, options.leakThreshold)
 
-        try:
-            self.stopWebSocketServer(options)
-        except Exception:
-            log.exception('Exception when stopping websocket server')
-
-        processLeakLog(self.leak_report_file, options.leakThreshold)
+    if self.nsprLogs:
+      with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
+        for logfile in glob.glob("%s/nspr*.log*" % tempfile.gettempdir()):
+          logzip.write(logfile)
+          os.remove(logfile)
 
-        if self.nsprLogs:
-            with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
-                for logfile in glob.glob("%s/nspr*.log*" % tempfile.gettempdir()):
-                    logzip.write(logfile)
-                    os.remove(logfile)
+    log.info("runtests.py | Running tests: end.")
 
-        log.info("runtests.py | Running tests: end.")
-
-        if manifest is not None:
-            self.cleanup(manifest, options)
+    if manifest is not None:
+      self.cleanup(manifest, options)
 
     return status
 
   def handleTimeout(self, timeout, proc, utilityPath, debuggerInfo, browserProcessId):
     """handle process output timeout"""
     # TODO: bug 913975 : _processOutput should call self.processOutputLine one more time one timeout (I think)
     log.info("TEST-UNEXPECTED-FAIL | %s | application timed out after %d seconds with no output", self.lastTestSeen, int(timeout))
     browserProcessId = browserProcessId or proc.pid
@@ -1423,103 +1533,16 @@ class Mochitest(MochitestUtilsMixin):
 
     addons.install_from_path(path)
 
   def installExtensionsToProfile(self, options):
     "Install special testing extensions, application distributed extensions, and specified on the command line ones to testing profile."
     for path in self.getExtensionsToInstall(options):
       self.installExtensionFromPath(options, path)
 
-  def readLocations(self, locations_file):
-    """
-    Reads the locations at which the Mochitest HTTP server is available from
-    `locations_file`.
-    """
-    path = os.path.realpath(locations_file)
-    return self._locations.setdefault(path, ServerLocations(path))
-
-  def fillCertificateDB(self, profileDir, certPath, utilityPath, xrePath):
-    # TODO: move -> mozprofile:
-    # https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c35
-
-    pwfilePath = os.path.join(profileDir, ".crtdbpw")
-    with open(pwfilePath, "w") as pwfile:
-      pwfile.write("\n")
-
-    # Create head of the ssltunnel configuration file
-    sslTunnelConfigPath = os.path.join(profileDir, "ssltunnel.cfg")
-    sslTunnelConfig = open(sslTunnelConfigPath, "w")
-    sslTunnelConfig.write("httpproxy:1\n")
-    sslTunnelConfig.write("certdbdir:%s\n" % certPath)
-    sslTunnelConfig.write("forward:127.0.0.1:%s\n" % self.httpPort)
-    sslTunnelConfig.write("websocketserver:%s:%s\n" % (self.webServer, self.webSocketPort))
-    sslTunnelConfig.write("listen:*:%s:pgo server certificate\n" % self.sslPort)
-
-    # Configure automatic certificate and bind custom certificates, client authentication
-    locations = self.readLocations(os.path.join(SCRIPT_DIR, 'server-locations.txt'))
-
-    for loc in locations:
-
-      if loc.scheme == "https" and "nocert" not in loc.options:
-        customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
-        clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
-        redirRE      = re.compile("^redir=(?P<redirhost>[0-9a-zA-Z_ .]+)")
-        for option in loc.options:
-          match = customCertRE.match(option)
-          if match:
-            customcert = match.group("nickname");
-            sslTunnelConfig.write("listen:%s:%s:%s:%s\n" %
-                      (loc.host, loc.port, self.sslPort, customcert))
-
-          match = clientAuthRE.match(option)
-          if match:
-            clientauth = match.group("clientauth");
-            sslTunnelConfig.write("clientauth:%s:%s:%s:%s\n" %
-                      (loc.host, loc.port, self.sslPort, clientauth))
-
-          match = redirRE.match(option)
-          if match:
-            redirhost = match.group("redirhost")
-            sslTunnelConfig.write("redirhost:%s:%s:%s:%s\n" %
-                      (loc.host, loc.port, self.sslPort, redirhost))
-
-    sslTunnelConfig.close()
-
-    # Pre-create the certification database for the profile
-    env = self.environment(xrePath=xrePath)
-    bin_suffix = mozinfo.info.get('bin_suffix', '')
-    certutil = os.path.join(utilityPath, "certutil" + bin_suffix)
-    pk12util = os.path.join(utilityPath, "pk12util" + bin_suffix)
-
-    status = call([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env=env)
-    printstatus(status, "certutil")
-    if status:
-      return status
-
-    # Walk the cert directory and add custom CAs and client certs
-    files = os.listdir(certPath)
-    for item in files:
-      root, ext = os.path.splitext(item)
-      if ext == ".ca":
-        trustBits = "CT,,"
-        if root.endswith("-object"):
-          trustBits = "CT,,CT"
-        status = call([certutil, "-A", "-i", os.path.join(certPath, item),
-              "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
-              env=env)
-        printstatus(status, "certutil")
-      elif ext == ".client":
-        status = call([pk12util, "-i", os.path.join(certPath, item), "-w",
-              pwfilePath, "-d", profileDir],
-              env=env)
-        printstatus(status, "pk2util")
-
-    os.unlink(pwfilePath)
-    return 0
-
 
 def main():
 
   # parse command line options
   mochitest = Mochitest()
   parser = MochitestOptions()
   options, args = parser.parse_args()
   options = parser.verifyOptions(options, mochitest)
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -35,17 +35,17 @@ log = mozlog.getLogger('Mochitest')
 class B2GMochitest(MochitestUtilsMixin):
     def __init__(self, marionette,
                        out_of_process=True,
                        profile_data_dir=None,
                        locations=os.path.join(here, 'server-locations.txt')):
         super(B2GMochitest, self).__init__()
         self.marionette = marionette
         self.out_of_process = out_of_process
-        self.locations = locations
+        self.locations_file = locations
         self.preferences = []
         self.webapps = None
         self.test_script = os.path.join(here, 'b2g_start_script.js')
         self.test_script_args = [self.out_of_process]
         self.product = 'b2g'
 
         if profile_data_dir:
             self.preferences = [os.path.join(profile_data_dir, f)
@@ -87,17 +87,17 @@ class B2GMochitest(MochitestUtilsMixin):
                           "OOP": "true" if self.out_of_process else "false" }
         prefs = json.loads(json.dumps(prefs) % interpolation)
         for pref in prefs:
             prefs[pref] = Preferences.cast(prefs[pref])
 
         kwargs = {
             'addons': self.getExtensionsToInstall(options),
             'apps': self.webapps,
-            'locations': self.locations,
+            'locations': self.locations_file,
             'preferences': prefs,
             'proxy': {"remote": options.webServer}
         }
 
         if options.profile:
             self.profile = Profile.clone(options.profile, **kwargs)
         else:
             self.profile = Profile(**kwargs)
@@ -109,18 +109,17 @@ class B2GMochitest(MochitestUtilsMixin):
         return manifest
 
     def run_tests(self, options):
         """ Prepare, configure, run tests and cleanup """
 
         self.leak_report_file = os.path.join(options.profilePath, "runtests_leaks.log")
         manifest = self.build_profile(options)
 
-        self.startWebServer(options)
-        self.startWebSocketServer(options, None)
+        self.startServers(options, None)
         self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'})
         self.test_script_args.append(not options.emulator)
         self.test_script_args.append(options.wifi)
 
         if options.debugger or not options.autorun:
             timeout = None
         else:
             if not options.timeout:
@@ -150,18 +149,17 @@ class B2GMochitest(MochitestUtilsMixin):
             log.info("runtests.py | Received keyboard interrupt.\n");
             status = -1
         except:
             traceback.print_exc()
             log.error("Automation Error: Received unexpected exception while running application\n")
             self.runner.check_for_crashes()
             status = 1
 
-        self.stopWebServer(options)
-        self.stopWebSocketServer(options)
+        self.stopServers()
 
         log.info("runtestsb2g.py | Running tests: end.")
 
         if manifest is not None:
             self.cleanup(manifest, options)
         return status
 
 
@@ -194,36 +192,30 @@ class B2GDeviceMochitest(B2GMochitest):
             except:
                 print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile
 
         # stop and clean up the runner
         if getattr(self, 'runner', False):
             self.runner.cleanup()
             self.runner = None
 
-    def startWebServer(self, options):
-        """ Create the webserver on the host and start it up """
-        d = vars(options).copy()
-        d['xrePath'] = self.local_binary_dir
-        d['utilityPath'] = self.local_binary_dir
-        d['profilePath'] = tempfile.mkdtemp()
-        if d.get('httpdPath') is None:
-            d['httpdPath'] = os.path.abspath(os.path.join(self.local_binary_dir, 'components'))
-        self.server = MochitestServer(d)
-        self.server.start()
+    def startServers(self, options, debuggerInfo):
+        """ Create the servers on the host and start them up """
+        savedXre = options.xrePath
+        savedUtility = options.utilityPath
+        savedProfie = options.profilePath
+        options.xrePath = self.local_binary_dir
+        options.utilityPath = self.local_binary_dir
+        options.profilePath = tempfile.mkdtemp()
 
-        if (options.pidFile != ""):
-            f = open(options.pidFile + ".xpcshell.pid", 'w')
-            f.write("%s" % self.server._process.pid)
-            f.close()
-        self.server.ensureReady(90)
+        MochitestUtilsMixin.startServers(self, options, debuggerInfo)
 
-    def stopWebServer(self, options):
-        if hasattr(self, 'server'):
-            self.server.stop()
+        options.xrePath = savedXre
+        options.utilityPath = savedUtility
+        options.profilePath = savedProfie
 
     def buildURLOptions(self, options, env):
         self.local_log = options.logFile
         options.logFile = self.remote_log
         options.profilePath = self.profile.profile
         retVal = super(B2GDeviceMochitest, self).buildURLOptions(options, env)
 
         self.setup_common_options(options)
@@ -233,16 +225,17 @@ class B2GDeviceMochitest(B2GMochitest):
         return retVal
 
 
 class B2GDesktopMochitest(B2GMochitest, Mochitest):
 
     def __init__(self, marionette, profile_data_dir):
         B2GMochitest.__init__(self, marionette, out_of_process=False, profile_data_dir=profile_data_dir)
         Mochitest.__init__(self)
+        self.certdbNew = True
 
     def runMarionetteScript(self, marionette, test_script, test_script_args):
         assert(marionette.wait_for_port())
         marionette.start_session()
         marionette.set_context(marionette.CONTEXT_CHROME)
 
         if os.path.isfile(test_script):
             f = open(test_script, 'r')
@@ -335,18 +328,17 @@ def run_remote_mochitests(parser, option
 
     retVal = 1
     try:
         mochitest.cleanup(None, options)
         retVal = mochitest.run_tests(options)
     except:
         print "Automation Error: Exception caught while running tests"
         traceback.print_exc()
-        mochitest.stopWebServer(options)
-        mochitest.stopWebSocketServer(options)
+        mochitest.stopServers()
         try:
             mochitest.cleanup(None, options)
         except:
             pass
         retVal = 1
 
     sys.exit(retVal)
 
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -77,21 +77,16 @@ class RemoteOptions(MochitestOptions):
                     help = "http port of the remote web server")
         defaults["httpPort"] = automation.DEFAULT_HTTP_PORT
 
         self.add_option("--ssl-port", action = "store",
                     type = "string", dest = "sslPort",
                     help = "ssl port of the remote web server")
         defaults["sslPort"] = automation.DEFAULT_SSL_PORT
 
-        self.add_option("--pidfile", action = "store",
-                    type = "string", dest = "pidFile",
-                    help = "name of the pidfile to generate")
-        defaults["pidFile"] = ""
-
         self.add_option("--robocop-ini", action = "store",
                     type = "string", dest = "robocopIni",
                     help = "name of the .ini file containing the list of tests to run")
         defaults["robocopIni"] = ""
 
         self.add_option("--robocop", action = "store",
                     type = "string", dest = "robocop",
                     help = "name of the .ini file containing the list of tests to run. [DEPRECATED- please use --robocop-ini")
@@ -218,134 +213,137 @@ class RemoteOptions(MochitestOptions):
         # like it's not set for verification purposes.
         options.dumpOutputDirectory = None
         options = MochitestOptions.verifyOptions(self, options, mochitest)
         options.webServer = tempIP
         options.app = temp
         options.sslPort = tempSSL
         options.httpPort = tempPort
 
-        return options 
+        return options
 
 class MochiRemote(Mochitest):
 
     _automation = None
     _dm = None
     localProfile = None
     logLines = []
 
     def __init__(self, automation, devmgr, options):
         self._automation = automation
         Mochitest.__init__(self)
         self._dm = devmgr
-        self.runSSLTunnel = False
         self.environment = self._automation.environment
         self.remoteProfile = options.remoteTestRoot + "/profile"
         self._automation.setRemoteProfile(self.remoteProfile)
         self.remoteLog = options.remoteLogFile
         self.localLog = options.logFile
         self._automation.deleteANRs()
+        self.certdbNew = True
 
     def cleanup(self, manifest, options):
         if self._dm.fileExists(self.remoteLog):
             self._dm.getFile(self.remoteLog, self.localLog)
             self._dm.removeFile(self.remoteLog)
         else:
             log.warn("Unable to retrieve log file (%s) from remote device",
                 self.remoteLog)
         self._dm.removeDir(self.remoteProfile)
-
-        if (options.pidFile != ""):
-            try:
-                os.remove(options.pidFile)
-                os.remove(options.pidFile + ".xpcshell.pid")
-            except:
-                log.warn("cleaning up pidfile '%s' was unsuccessful from the test harness", options.pidFile)
+        Mochitest.cleanup(self, manifest, options)
 
     def findPath(self, paths, filename = None):
         for path in paths:
             p = path
             if filename:
                 p = os.path.join(p, filename)
             if os.path.exists(self.getFullPath(p)):
                 return path
         return None
 
-    def startWebServer(self, options):
-        """ Create the webserver on the host and start it up """
-        remoteXrePath = options.xrePath
-        remoteProfilePath = options.profilePath
-        remoteUtilityPath = options.utilityPath
+    def makeLocalAutomation(self):
         localAutomation = Automation()
         localAutomation.IS_WIN32 = False
         localAutomation.IS_LINUX = False
         localAutomation.IS_MAC = False
         localAutomation.UNIXISH = False
         hostos = sys.platform
         if (hostos == 'mac' or  hostos == 'darwin'):
-          localAutomation.IS_MAC = True
+            localAutomation.IS_MAC = True
         elif (hostos == 'linux' or hostos == 'linux2'):
-          localAutomation.IS_LINUX = True
-          localAutomation.UNIXISH = True
+            localAutomation.IS_LINUX = True
+            localAutomation.UNIXISH = True
         elif (hostos == 'win32' or hostos == 'win64'):
-          localAutomation.BIN_SUFFIX = ".exe"
-          localAutomation.IS_WIN32 = True
+            localAutomation.BIN_SUFFIX = ".exe"
+            localAutomation.IS_WIN32 = True
+        return localAutomation
 
-        paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)]
+    # This seems kludgy, but this class uses paths from the remote host in the
+    # options, except when calling up to the base class, which doesn't
+    # understand the distinction.  This switches out the remote values for local
+    # ones that the base class understands.  This is necessary for the web
+    # server, SSL tunnel and profile building functions.
+    def switchToLocalPaths(self, options):
+        """ Set local paths in the options, return a function that will restore remote values """
+        remoteXrePath = options.xrePath
+        remoteProfilePath = options.profilePath
+        remoteUtilityPath = options.utilityPath
+
+        localAutomation = self.makeLocalAutomation()
+        paths = [
+            options.xrePath,
+            localAutomation.DIST_BIN,
+            self._automation._product,
+            os.path.join('..', self._automation._product)
+        ]
         options.xrePath = self.findPath(paths)
         if options.xrePath == None:
             log.error("unable to find xulrunner path for %s, please specify with --xre-path", os.name)
             sys.exit(1)
 
         xpcshell = "xpcshell"
         if (os.name == "nt"):
             xpcshell += ".exe"
-      
+
         if options.utilityPath:
             paths = [options.utilityPath, options.xrePath]
         else:
             paths = [options.xrePath]
         options.utilityPath = self.findPath(paths, xpcshell)
+
         if options.utilityPath == None:
             log.error("unable to find utility path for %s, please specify with --utility-path", os.name)
             sys.exit(1)
-        # httpd-path is specified by standard makefile targets and may be specified
-        # on the command line to select a particular version of httpd.js. If not
-        # specified, try to select the one from hostutils.zip, as required in bug 882932.
-        if not options.httpdPath:
-            options.httpdPath = os.path.join(options.utilityPath, "components")
 
         xpcshell_path = os.path.join(options.utilityPath, xpcshell)
         if localAutomation.elf_arm(xpcshell_path):
             log.error('xpcshell at %s is an ARM binary; please use '
                       'the --utility-path argument to specify the path '
                       'to a desktop version.' % xpcshell_path)
             sys.exit(1)
 
-        options.profilePath = tempfile.mkdtemp()
-        self.server = MochitestServer(options)
-        self.server.start()
-
-        if (options.pidFile != ""):
-            f = open(options.pidFile + ".xpcshell.pid", 'w')
-            f.write("%s" % self.server._process.pid)
-            f.close()
-        self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
-
-        options.xrePath = remoteXrePath
-        options.utilityPath = remoteUtilityPath
-        options.profilePath = remoteProfilePath
-         
-    def stopWebServer(self, options):
-        if hasattr(self, 'server'):
-            self.server.stop()
-        
-    def buildProfile(self, options):
         if self.localProfile:
             options.profilePath = self.localProfile
+        else:
+            options.profilePath = tempfile.mkdtemp()
+
+        def fixup():
+            options.xrePath = remoteXrePath
+            options.utilityPath = remoteUtilityPath
+            options.profilePath = remoteProfilePath
+
+        return fixup
+
+    def startServers(self, options, debuggerInfo):
+        """ Create the servers on the host and start them up """
+        restoreRemotePaths = self.switchToLocalPaths(options)
+        Mochitest.startServers(self, options, debuggerInfo)
+        restoreRemotePaths()
+
+    def buildProfile(self, options):
+        restoreRemotePaths = self.switchToLocalPaths(options)
         manifest = Mochitest.buildProfile(self, options)
         self.localProfile = options.profilePath
         self._dm.removeDir(self.remoteProfile)
 
         # we do not need this for robotium based tests, lets save a LOT of time
         if options.robocopIni:
             shutil.rmtree(os.path.join(options.profilePath, 'webapps'))
             shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', 'mochikit@mozilla.org'))
@@ -354,19 +352,20 @@ class MochiRemote(Mochitest):
             os.remove(os.path.join(options.profilePath, 'userChrome.css'))
 
         try:
             self._dm.pushDir(options.profilePath, self.remoteProfile)
         except devicemanager.DMError:
             log.error("Automation Error: Unable to copy profile to device.")
             raise
 
+        restoreRemotePaths()
         options.profilePath = self.remoteProfile
         return manifest
-    
+
     def buildURLOptions(self, options, env):
         self.localLog = options.logFile
         options.logFile = self.remoteLog
         options.profilePath = self.localProfile
         env["MOZ_HIDE_RESULTS_TABLE"] = "1"
         retVal = Mochitest.buildURLOptions(self, options, env)
 
         if not options.robocopIni:
@@ -398,17 +397,17 @@ class MochiRemote(Mochitest):
         try:
             self._dm.pushFile(filename, manifest)
         except devicemanager.DMError:
             log.error("Automation Error: Unable to install Chrome files on device.")
             raise
 
         return manifest
 
-    def getLogFilePath(self, logFile):             
+    def getLogFilePath(self, logFile):
         return logFile
 
     # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/
     def addLogData(self):
         with open(self.localLog) as currentLog:
             data = currentLog.readlines()
 
         restart = re.compile('0 INFO SimpleTest START.*')
@@ -439,17 +438,17 @@ class MochiRemote(Mochitest):
             result = 1
         return result
 
     def printLog(self):
         passed = 0
         failed = 0
         todo = 0
         incr = 1
-        logFile = [] 
+        logFile = []
         logFile.append("0 INFO SimpleTest START")
         for line in self.logLines:
             if line.startswith("INFO TEST-PASS"):
                 passed += 1
             elif line.startswith("INFO TEST-UNEXPECTED"):
                 failed += 1
             elif line.startswith("INFO TEST-KNOWN"):
                 todo += 1
@@ -543,16 +542,20 @@ class MochiRemote(Mochitest):
     def runApp(self, *args, **kwargs):
         """front-end automation.py's `runApp` functionality until FennecRunner is written"""
 
         # automation.py/remoteautomation `runApp` takes the profile path,
         # whereas runtest.py's `runApp` takes a mozprofile object.
         if 'profileDir' not in kwargs and 'profile' in kwargs:
             kwargs['profileDir'] = kwargs.pop('profile').profile
 
+        # We're handling ssltunnel, so we should lie to automation.py to avoid
+        # it trying to set up ssltunnel as well
+        kwargs['runSSLTunnel'] = False
+
         return self._automation.runApp(*args, **kwargs)
 
 def main():
     auto = RemoteAutomation(None, "fennec")
     parser = RemoteOptions(auto)
     options, args = parser.parse_args()
 
     if (options.dm_trans == "adb"):
@@ -575,17 +578,17 @@ def main():
         auto.setProduct(options.remoteProductName)
     auto.setAppName(options.remoteappname)
 
     mochitest = MochiRemote(auto, dm, options)
 
     options = parser.verifyOptions(options, mochitest)
     if (options == None):
         sys.exit(1)
-    
+
     logParent = os.path.dirname(options.remoteLogFile)
     dm.mkDir(logParent);
     auto.setRemoteLog(options.remoteLogFile)
     auto.setServerInfo(options.webServer, options.httpPort, options.sslPort)
 
     mochitest.printDeviceInfo()
 
     # Add Android version (SDK level) to mozinfo so that manifest entries
@@ -663,17 +666,17 @@ def main():
 
             options.app = "am"
             options.browserArgs = ["instrument", "-w", "-e", "deviceroot", deviceRoot, "-e", "class"]
             options.browserArgs.append("org.mozilla.gecko.tests.%s" % test['name'])
             options.browserArgs.append("org.mozilla.roboexample.test/org.mozilla.gecko.FennecInstrumentationTestRunner")
 
             # If the test is for checking the import from bookmarks then make sure there is data to import
             if test['name'] == "testImportFromAndroid":
-                
+
                 # Get the OS so we can run the insert in the apropriate database and following the correct table schema
                 osInfo = dm.getInfo("os")
                 devOS = " ".join(osInfo['os'])
 
                 if ("pandaboard" in devOS):
                     delete = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"]
                 else:
                     delete = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"]
@@ -701,18 +704,17 @@ def main():
                     mochitest.printDeviceInfo(printLogcat=True)
                     mochitest.printScreenshots(screenShotDir)
                 # Ensure earlier failures aren't overwritten by success on this run
                 if retVal is None or retVal == 0:
                     retVal = result
             except:
                 log.error("Automation Error: Exception caught while running tests")
                 traceback.print_exc()
-                mochitest.stopWebServer(options)
-                mochitest.stopWebSocketServer(options)
+                mochitest.stopServers()
                 try:
                     mochitest.cleanup(None, options)
                 except devicemanager.DMError:
                     # device error cleaning up... oh well!
                     pass
                 retVal = 1
                 break
             finally:
@@ -737,18 +739,17 @@ def main():
                 retVal = overallResult
     else:
         try:
             dm.recordLogcat()
             retVal = mochitest.runTests(options)
         except:
             log.error("Automation Error: Exception caught while running tests")
             traceback.print_exc()
-            mochitest.stopWebServer(options)
-            mochitest.stopWebSocketServer(options)
+            mochitest.stopServers()
             try:
                 mochitest.cleanup(None, options)
             except devicemanager.DMError:
                 # device error cleaning up... oh well!
                 pass
             retVal = 1
 
     mochitest.printDeviceInfo(printLogcat=True)
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -25,16 +25,17 @@
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMStrings.h"
 #include "nsProxyRelease.h"
+#include "nsString.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #include "prlog.h"
 #include "prprf.h"
@@ -64,16 +65,17 @@ PRLogModuleInfo *gUrlClassifierDbService
 #define CHECK_MALWARE_DEFAULT   false
 
 #define CHECK_PHISHING_PREF     "browser.safebrowsing.enabled"
 #define CHECK_PHISHING_DEFAULT  false
 
 #define GETHASH_NOISE_PREF      "urlclassifier.gethashnoise"
 #define GETHASH_NOISE_DEFAULT   4
 
+// Comma-separated lists
 #define MALWARE_TABLE_PREF      "urlclassifier.malware_table"
 #define PHISH_TABLE_PREF        "urlclassifier.phish_table"
 #define DOWNLOAD_BLOCK_TABLE_PREF "urlclassifier.downloadBlockTable"
 #define DOWNLOAD_ALLOW_TABLE_PREF "urlclassifier.downloadAllowTable"
 #define DISALLOW_COMPLETION_TABLE_PREF "urlclassifier.disallow_completions"
 
 #define CONFIRM_AGE_PREF        "urlclassifier.max-complete-age"
 #define CONFIRM_AGE_DEFAULT_SEC (45 * 60)
@@ -1066,41 +1068,66 @@ nsUrlClassifierDBService::nsUrlClassifie
 }
 
 nsUrlClassifierDBService::~nsUrlClassifierDBService()
 {
   sUrlClassifierDBService = nullptr;
 }
 
 nsresult
+nsUrlClassifierDBService::ReadTablesFromPrefs()
+{
+  nsCString allTables;
+  nsCString tables;
+  Preferences::GetCString(PHISH_TABLE_PREF, &allTables);
+
+  Preferences::GetCString(MALWARE_TABLE_PREF, &tables);
+  if (!tables.IsEmpty()) {
+    allTables.Append(',');
+    allTables.Append(tables);
+  }
+
+  Preferences::GetCString(DOWNLOAD_BLOCK_TABLE_PREF, &tables);
+  if (!tables.IsEmpty()) {
+    allTables.Append(',');
+    allTables.Append(tables);
+  }
+
+  Preferences::GetCString(DOWNLOAD_ALLOW_TABLE_PREF, &tables);
+  if (!tables.IsEmpty()) {
+    allTables.Append(',');
+    allTables.Append(tables);
+  }
+
+  Classifier::SplitTables(allTables, mGethashTables);
+
+  Preferences::GetCString(DISALLOW_COMPLETION_TABLE_PREF, &tables);
+  Classifier::SplitTables(tables, mDisallowCompletionsTables);
+
+  return NS_OK;
+}
+
+nsresult
 nsUrlClassifierDBService::Init()
 {
 #if defined(PR_LOGGING)
   if (!gUrlClassifierDbServiceLog)
     gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService");
 #endif
 
   // Retrieve all the preferences.
   mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF,
     CHECK_MALWARE_DEFAULT);
   mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF,
     CHECK_PHISHING_DEFAULT);
   uint32_t gethashNoise = Preferences::GetUint(GETHASH_NOISE_PREF,
     GETHASH_NOISE_DEFAULT);
   gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF,
     CONFIRM_AGE_DEFAULT_SEC);
-  mGethashTables.AppendElement(Preferences::GetCString(PHISH_TABLE_PREF));
-  mGethashTables.AppendElement(Preferences::GetCString(MALWARE_TABLE_PREF));
-  mGethashTables.AppendElement(Preferences::GetCString(
-    DOWNLOAD_BLOCK_TABLE_PREF));
-  mGethashTables.AppendElement(Preferences::GetCString(
-    DOWNLOAD_ALLOW_TABLE_PREF));
-  nsCString tables;
-  Preferences::GetCString(DISALLOW_COMPLETION_TABLE_PREF, &tables);
-  Classifier::SplitTables(tables, mDisallowCompletionsTables);
+  ReadTablesFromPrefs();
 
   // Do we *really* need to be able to change all of these at runtime?
   Preferences::AddStrongObserver(this, CHECK_MALWARE_PREF);
   Preferences::AddStrongObserver(this, CHECK_PHISHING_PREF);
   Preferences::AddStrongObserver(this, GETHASH_NOISE_PREF);
   Preferences::AddStrongObserver(this, CONFIRM_AGE_PREF);
   Preferences::AddStrongObserver(this, PHISH_TABLE_PREF);
   Preferences::AddStrongObserver(this, MALWARE_TABLE_PREF);
@@ -1167,16 +1194,17 @@ nsUrlClassifierDBService::Classify(nsIPr
   }
 
   nsRefPtr<nsUrlClassifierClassifyCallback> callback =
     new nsUrlClassifierClassifyCallback(c, mCheckMalware, mCheckPhishing);
   if (!callback) return NS_ERROR_OUT_OF_MEMORY;
 
   nsAutoCString tables;
   nsAutoCString malware;
+  // LookupURI takes a comma-separated list already.
   Preferences::GetCString(MALWARE_TABLE_PREF, &malware);
   if (!malware.IsEmpty()) {
     tables.Append(malware);
   }
   nsAutoCString phishing;
   Preferences::GetCString(PHISH_TABLE_PREF, &phishing);
   if (!phishing.IsEmpty()) {
     tables.Append(",");
@@ -1405,16 +1433,19 @@ nsUrlClassifierDBService::GetCompleter(c
 
   // If we don't know about this table at all, or are disallowing completions
   // for it, skip completion checks.
   if (!mGethashTables.Contains(tableName) ||
       mDisallowCompletionsTables.Contains(tableName)) {
     return false;
   }
 
+  MOZ_ASSERT(!StringBeginsWith(tableName, NS_LITERAL_CSTRING("test-")),
+             "We should never fetch hash completions for test tables");
+
   // Otherwise, call gethash to find the hash completions.
   return NS_SUCCEEDED(CallGetService(NS_URLCLASSIFIERHASHCOMPLETER_CONTRACTID,
                                      completer));
 }
 
 NS_IMETHODIMP
 nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic,
                                   const char16_t *aData)
@@ -1424,33 +1455,24 @@ nsUrlClassifierDBService::Observe(nsISup
     nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
     if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) {
       mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF,
         CHECK_MALWARE_DEFAULT);
     } else if (NS_LITERAL_STRING(CHECK_PHISHING_PREF).Equals(aData)) {
       mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF,
         CHECK_PHISHING_DEFAULT);
-    } else if (NS_LITERAL_STRING(PHISH_TABLE_PREF).Equals(aData) ||
-               NS_LITERAL_STRING(MALWARE_TABLE_PREF).Equals(aData) ||
-               NS_LITERAL_STRING(DOWNLOAD_BLOCK_TABLE_PREF).Equals(aData) ||
-               NS_LITERAL_STRING(DOWNLOAD_ALLOW_TABLE_PREF).Equals(aData)) {
+    } else if (
+      NS_LITERAL_STRING(PHISH_TABLE_PREF).Equals(aData) ||
+      NS_LITERAL_STRING(MALWARE_TABLE_PREF).Equals(aData) ||
+      NS_LITERAL_STRING(DOWNLOAD_BLOCK_TABLE_PREF).Equals(aData) ||
+      NS_LITERAL_STRING(DOWNLOAD_ALLOW_TABLE_PREF).Equals(aData) ||
+      NS_LITERAL_STRING(DISALLOW_COMPLETION_TABLE_PREF).Equals(aData)) {
       // Just read everything again.
-      mGethashTables.Clear();
-      mGethashTables.AppendElement(Preferences::GetCString(PHISH_TABLE_PREF));
-      mGethashTables.AppendElement(Preferences::GetCString(MALWARE_TABLE_PREF));
-      mGethashTables.AppendElement(Preferences::GetCString(
-        DOWNLOAD_BLOCK_TABLE_PREF));
-      mGethashTables.AppendElement(Preferences::GetCString(
-        DOWNLOAD_ALLOW_TABLE_PREF));
-    } else if (NS_LITERAL_STRING(DISALLOW_COMPLETION_TABLE_PREF).Equals(aData)) {
-      mDisallowCompletionsTables.Clear();
-      nsCString tables;
-      Preferences::GetCString(DISALLOW_COMPLETION_TABLE_PREF, &tables);
-      Classifier::SplitTables(tables, mDisallowCompletionsTables);
+      ReadTablesFromPrefs();
     } else if (NS_LITERAL_STRING(CONFIRM_AGE_PREF).Equals(aData)) {
       gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF,
         CONFIRM_AGE_DEFAULT_SEC);
     }
   } else if (!strcmp(aTopic, "profile-before-change") ||
              !strcmp(aTopic, "xpcom-shutdown-threads")) {
     Shutdown();
   } else {
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h
@@ -77,16 +77,19 @@ private:
 
   // Close db connection and join the background thread if it exists.
   nsresult Shutdown();
 
   // Check if the key is on a known-clean host.
   nsresult CheckClean(const nsACString &lookupKey,
                       bool *clean);
 
+  // Read everything into mGethashTables and mDisallowCompletionTables
+  nsresult ReadTablesFromPrefs();
+
   nsRefPtr<nsUrlClassifierDBServiceWorker> mWorker;
   nsCOMPtr<nsIUrlClassifierDBServiceWorker> mWorkerProxy;
 
   nsInterfaceHashtable<nsCStringHashKey, nsIUrlClassifierHashCompleter> mCompleters;
 
   // TRUE if the nsURIClassifier implementation should check for malware
   // uris on document loads.
   bool mCheckMalware;
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -1,18 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
-Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/Troubleshoot.jsm");
-Components.utils.import("resource://gre/modules/PluralForm.jsm");
-Components.utils.import("resource://gre/modules/ResetProfile.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Troubleshoot.jsm");
+Cu.import("resource://gre/modules/ResetProfile.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
 
 window.addEventListener("load", function onload(event) {
   window.removeEventListener("load", onload, false);
   Troubleshoot.snapshot(function (snapshot) {
     for (let prop in snapshotFormatters)
       snapshotFormatters[prop](snapshot[prop]);
   });
   populateResetBox();
--- a/toolkit/mozapps/downloads/DownloadUtils.jsm
+++ b/toolkit/mozapps/downloads/DownloadUtils.jsm
@@ -34,21 +34,20 @@ this.EXPORTED_SYMBOLS = [ "DownloadUtils
  * [int time, string units, int subTime, string subUnits]
  * convertTimeUnits(double aSecs)
  */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-this.__defineGetter__("PluralForm", function() {
-  delete this.PluralForm;
-  Cu.import("resource://gre/modules/PluralForm.jsm");
-  return PluralForm;
-});
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
 
 this.__defineGetter__("gDecimalSymbol", function() {
   delete this.gDecimalSymbol;
   return this.gDecimalSymbol = Number(5.4).toLocaleString().match(/\D/);
 });
 
 const kDownloadProperties =
   "chrome://mozapps/locale/downloads/downloads.properties";
--- a/toolkit/mozapps/downloads/content/downloads.js
+++ b/toolkit/mozapps/downloads/content/downloads.js
@@ -13,19 +13,21 @@ const PREF_BDM_SCANWHENDONE = "browser.d
 const nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
                                            "nsILocalFile", "initWithPath");
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 let Cu = Components.utils;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
 const nsIDM = Ci.nsIDownloadManager;
 
 let gDownloadManager = Cc["@mozilla.org/download-manager;1"].getService(nsIDM);
 let gDownloadManagerUI = Cc["@mozilla.org/download-manager-ui;1"].
                          getService(Ci.nsIDownloadManagerUI);
 
 let gDownloadListener = null;
 let gDownloadsView = null;
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -4,23 +4,25 @@
 
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
-
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/addons/AddonRepository.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
 XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () {
   return Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", {}).
          BrowserToolboxProcess;
 });
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
   "resource:///modules/experiments/Experiments.jsm");
 
 const PREF_DISCOVERURL = "extensions.webservice.discoverURL";
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -355,20 +355,20 @@ GfxInfo::GetGfxDriverInfo()
       nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_NO_INFO,
       DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions );
   }
 
   return *mDriverInfo;
 }
 
 nsresult
-GfxInfo::GetFeatureStatusImpl(int32_t aFeature, 
-                              int32_t *aStatus, 
+GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
+                              int32_t *aStatus,
                               nsAString & aSuggestedDriverVersion,
-                              const nsTArray<GfxDriverInfo>& aDriverInfo, 
+                              const nsTArray<GfxDriverInfo>& aDriverInfo,
                               OperatingSystem* aOS /* = nullptr */)
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   aSuggestedDriverVersion.SetIsVoid(true);
   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
   OperatingSystem os = mOS;
   if (aOS)
     *aOS = os;
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -7,17 +7,17 @@
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #endif
 #include "prlog.h"
 
 #include <unistd.h>
 #include <math.h>
- 
+
 #include "nsChildView.h"
 #include "nsCocoaWindow.h"
 
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 
@@ -462,32 +462,32 @@ nsresult nsChildView::Create(nsIWidget *
 
   mBounds = aRect;
 
   // Ensure that the toolkit is created.
   nsToolkit::GetToolkit();
 
   BaseCreate(aParent, aRect, aContext, aInitData);
 
-  // inherit things from the parent view and create our parallel 
+  // inherit things from the parent view and create our parallel
   // NSView in the Cocoa display system
   mParentView = nil;
   if (aParent) {
     // inherit the top-level window. NS_NATIVE_WIDGET is always a NSView
     // regardless of if we're asking a window or a view (for compatibility
     // with windows).
-    mParentView = (NSView<mozView>*)aParent->GetNativeData(NS_NATIVE_WIDGET); 
-    mParentWidget = aParent;   
+    mParentView = (NSView<mozView>*)aParent->GetNativeData(NS_NATIVE_WIDGET);
+    mParentWidget = aParent;
   } else {
     // This is the normal case. When we're the root widget of the view hiararchy,
     // aNativeParent will be the contentView of our window, since that's what
     // nsCocoaWindow returns when asked for an NS_NATIVE_VIEW.
     mParentView = reinterpret_cast<NSView<mozView>*>(aNativeParent);
   }
-  
+
   // create our parallel NSView and hook it up to our parent. Recall
   // that NS_NATIVE_WIDGET is the NSView.
   CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView);
   NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor);
   mView = [(NSView<mozView>*)CreateCocoaView(r) retain];
   if (!mView) {
     return NS_ERROR_FAILURE;
   }
@@ -622,17 +622,17 @@ static void PrintViewHierarchy(NSView *v
 
 // Return native data according to aDataType
 void* nsChildView::GetNativeData(uint32_t aDataType)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
 
   void* retVal = nullptr;
 
-  switch (aDataType) 
+  switch (aDataType)
   {
     case NS_NATIVE_WIDGET:
     case NS_NATIVE_DISPLAY:
       retVal = (void*)mView;
       break;
 
     case NS_NATIVE_WINDOW:
       retVal = [mView window];
@@ -807,17 +807,17 @@ NS_IMETHODIMP
 nsChildView::SetParent(nsIWidget* aNewParent)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (mOnDestroyCalled)
     return NS_OK;
 
   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
-  
+
   if (mParentWidget) {
     mParentWidget->RemoveChild(this);
   }
 
   if (aNewParent) {
     ReparentNativeWidget(aNewParent);
   } else {
     [mView removeFromSuperview];
@@ -841,17 +841,17 @@ nsChildView::ReparentNativeWidget(nsIWid
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   NS_PRECONDITION(aNewParent, "");
 
   if (mOnDestroyCalled)
     return NS_OK;
 
   NSView<mozView>* newParentView =
-   (NSView<mozView>*)aNewParent->GetNativeData(NS_NATIVE_WIDGET); 
+   (NSView<mozView>*)aNewParent->GetNativeData(NS_NATIVE_WIDGET);
   NS_ENSURE_TRUE(newParentView, NS_ERROR_FAILURE);
 
   // we hold a ref to mView, so this is safe
   [mView removeFromSuperview];
   mParentView = newParentView;
   [mParentView addSubview:mView];
   return NS_OK;
 
@@ -1167,31 +1167,31 @@ bool nsChildView::ShowsResizeIndicator(n
 // outClipRect and outOrigin are in display pixels, not device pixels.
 NS_IMETHODIMP nsChildView::GetPluginClipRect(nsIntRect& outClipRect, nsIntPoint& outOrigin, bool& outWidgetVisible)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   NS_ASSERTION(mWindowType == eWindowType_plugin,
                "GetPluginClipRect must only be called on a plugin widget");
   if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE;
-  
+
   NSWindow* window = [mView window];
   if (!window) return NS_ERROR_FAILURE;
-  
+
   NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
   NSRect frame = [[window contentView] frame];
   viewOrigin.y = frame.size.height - viewOrigin.y;
-  
+
   // set up the clipping region for plugins.
   NSRect visibleBounds = [mView visibleRect];
   NSPoint clipOrigin   = [mView convertPoint:visibleBounds.origin toView:nil];
-  
+
   // Convert from cocoa to QuickDraw coordinates
   clipOrigin.y = frame.size.height - clipOrigin.y;
-  
+
   outClipRect.x = NSToIntRound(clipOrigin.x);
   outClipRect.y = NSToIntRound(clipOrigin.y);
 
   // need to convert view's origin to window coordinates.
   // then, encode as "SetOrigin" ready values.
   outOrigin.x = -NSToIntRound(viewOrigin.x);
   outOrigin.y = -NSToIntRound(viewOrigin.y);
 
@@ -1789,17 +1789,17 @@ NS_IMETHODIMP nsChildView::GetAttention(
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 /* static */
 bool nsChildView::DoHasPendingInputEvent()
 {
-  return sLastInputEventCount != GetCurrentInputEventCount(); 
+  return sLastInputEventCount != GetCurrentInputEventCount();
 }
 
 /* static */
 uint32_t nsChildView::GetCurrentInputEventCount()
 {
   // Can't use kCGAnyInputEventType because that updates too rarely for us (and
   // always in increments of 30+!) and because apparently it's sort of broken
   // on Tiger.  So just go ahead and query the counters we care about.
@@ -2465,17 +2465,17 @@ FindUnifiedToolbarBottom(const nsTArray<
         g.mRect.X() <= 0 &&
         g.mRect.XMost() >= aWindowWidth &&
         g.mRect.Y() <= aTitlebarBottom) {
       unifiedToolbarBottom = std::max(unifiedToolbarBottom, g.mRect.YMost());
     }
   }
   return unifiedToolbarBottom;
 }
- 
+
 static nsIntRect
 FindFirstRectOfType(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
                     uint8_t aWidgetType)
 {
   for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) {
     const nsIWidget::ThemeGeometry& g = aThemeGeometries[i];
     if (g.mWidgetType == aWidgetType) {
       return g.mRect;
@@ -2881,17 +2881,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   static BOOL initialized = NO;
 
   if (!initialized) {
     // Inform the OS about the types of services (from the "Services" menu)
     // that we can handle.
 
     NSArray *sendTypes = [[NSArray alloc] initWithObjects:NSStringPboardType,NSHTMLPboardType,nil];
     NSArray *returnTypes = [[NSArray alloc] initWithObjects:NSStringPboardType,NSHTMLPboardType,nil];
-    
+
     [NSApp registerServicesMenuSendTypes:sendTypes returnTypes:returnTypes];
 
     [sendTypes release];
     [returnTypes release];
 
     initialized = YES;
   }
 }
@@ -2983,17 +2983,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(scrollbarSystemMetricChanged)
                                                name:@"NSPreferredScrollerStyleDidChangeNotification"
                                              object:nil];
   [[NSDistributedNotificationCenter defaultCenter] addObserver:self
                                                       selector:@selector(systemMetricsChanged)
                                                           name:@"AppleAquaScrollBarVariantChanged"
                                                         object:nil
-                                            suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 
+                                            suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(_surfaceNeedsUpdate:)
                                                name:NSViewGlobalFrameDidChangeNotification
                                              object:self];
 
   return self;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
@@ -4070,17 +4070,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   geckoEvent.delta = deltaZ;
   [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
 
   // Send the event.
   mGeckoChild->DispatchWindowEvent(geckoEvent);
 
   // Keep track of the cumulative magnification for the final "magnify" event.
   mCumulativeMagnification += deltaZ;
-  
+
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (void)smartMagnifyWithEvent:(NSEvent *)anEvent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (!anEvent || !mGeckoChild) {
@@ -4595,17 +4595,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (!mGeckoChild || mBlockedLastMouseDown)
     return;
 
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
 
   NPCocoaEvent cocoaEvent;
-	
+
   WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild,
                               WidgetMouseEvent::eReal);
   [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
   if ([theEvent modifierFlags] & NSControlKeyMask)
     geckoEvent.button = WidgetMouseEvent::eRightButton;
   else
     geckoEvent.button = WidgetMouseEvent::eLeftButton;
 
@@ -4967,17 +4967,17 @@ static int32_t RoundUp(double aDouble)
   [self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
 
   wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
   wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
 
   if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
     // Some scrolling devices supports pixel scrolling, e.g. a Macbook
     // touchpad or a Mighty Mouse. On those devices, [theEvent deviceDeltaX/Y]
-    // contains the amount of pixels to scroll. Since Lion this has changed 
+    // contains the amount of pixels to scroll. Since Lion this has changed
     // to [theEvent scrollingDeltaX/Y].
     double scale = mGeckoChild->BackingScaleFactor();
     if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
       wheelEvent.deltaX = -[theEvent scrollingDeltaX] * scale;
       wheelEvent.deltaY = -[theEvent scrollingDeltaY] * scale;
     } else {
       wheelEvent.deltaX = -[theEvent deviceDeltaX] * scale;
       wheelEvent.deltaY = -[theEvent deviceDeltaY] * scale;
@@ -5754,17 +5754,17 @@ static int32_t RoundUp(double aDouble)
         nsCOMPtr<nsIDOMNode> sourceNode;
         dragSession->GetSourceNode(getter_AddRefs(sourceNode));
         if (!sourceNode) {
           mDragService->EndDragSession(false);
         }
         return NSDragOperationNone;
       }
     }
-    
+
     unsigned int modifierFlags = [[NSApp currentEvent] modifierFlags];
     uint32_t action = nsIDragService::DRAGDROP_ACTION_MOVE;
     // force copy = option, alias = cmd-option, default is move
     if (modifierFlags & NSAlternateKeyMask) {
       if (modifierFlags & NSCommandKeyMask)
         action = nsIDragService::DRAGDROP_ACTION_LINK;
       else
         action = nsIDragService::DRAGDROP_ACTION_COPY;
@@ -5814,17 +5814,17 @@ static int32_t RoundUp(double aDouble)
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSDragOperationNone);
 }
 
 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingEntered: entered\n"));
-  
+
   // there should never be a globalDragPboard when "draggingEntered:" is
   // called, but just in case we'll take care of it here.
   [globalDragPboard release];
 
   // Set the global drag pasteboard that will be used for this drag session.
   // This will be set back to nil when the drag session ends (mouse exits
   // the view or a drop happens within the view).
   globalDragPboard = [[sender draggingPasteboard] retain];
@@ -5893,22 +5893,22 @@ static int32_t RoundUp(double aDouble)
 
   if (mDragService) {
     // set the dragend point from the current mouse location
     nsDragService* dragService = static_cast<nsDragService *>(mDragService);
     NSPoint pnt = [NSEvent mouseLocation];
     FlipCocoaScreenCoordinate(pnt);
     dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y)));
 
-    // XXX: dropEffect should be updated per |operation|. 
+    // XXX: dropEffect should be updated per |operation|.
     // As things stand though, |operation| isn't well handled within "our"
     // events, that is, when the drop happens within the window: it is set
     // either to NSDragOperationGeneric or to NSDragOperationNone.
     // For that reason, it's not yet possible to override dropEffect per the
-    // given OS value, and it's also unclear what's the correct dropEffect 
+    // given OS value, and it's also unclear what's the correct dropEffect
     // value for NSDragOperationGeneric that is passed by other applications.
     // All that said, NSDragOperationNone is still reliable.
     if (operation == NSDragOperationNone) {
       nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
       dragService->GetDataTransfer(getter_AddRefs(dataTransfer));
       if (dataTransfer)
         dataTransfer->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
     }
@@ -5970,24 +5970,24 @@ static int32_t RoundUp(double aDouble)
     gDraggedTransferables->GetElementAt(i, getter_AddRefs(genericItem));
     nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
     if (!item) {
       NS_ERROR("no transferable");
       return nil;
     }
 
     item->SetTransferData(kFilePromiseDirectoryMime, macLocalFile, sizeof(nsIFile*));
-    
+
     // now request the kFilePromiseMime data, which will invoke the data provider
     // If successful, the returned data is a reference to the resulting file.
     nsCOMPtr<nsISupports> fileDataPrimitive;
     uint32_t dataSize = 0;
     item->GetTransferData(kFilePromiseMime, getter_AddRefs(fileDataPrimitive), &dataSize);
   }
-  
+
   NSPasteboard* generalPboard = [NSPasteboard pasteboardWithName:NSDragPboard];
   NSData* data = [generalPboard dataForType:@"application/x-moz-file-promise-dest-filename"];
   NSString* name = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
   NSArray* rslt = [NSArray arrayWithObject:name];
 
   [name release];
 
   return rslt;
@@ -6024,17 +6024,17 @@ static int32_t RoundUp(double aDouble)
   if ((!sendType || IsSupportedType(sendType)) &&
       (!returnType || IsSupportedType(returnType))) {
     if (mGeckoChild) {
       // Assume that this object will be able to handle this request.
       result = self;
 
       // Keep the ChildView alive during this operation.
       nsAutoRetainCocoaObject kungFuDeathGrip(self);
-      
+
       // Determine if there is a selection (if sending to the service).
       if (sendType) {
         WidgetQueryContentEvent event(true, NS_QUERY_CONTENT_STATE,
                                       mGeckoChild);
         // This might destroy our widget (and null out mGeckoChild).
         mGeckoChild->DispatchWindowEvent(event);
         if (!mGeckoChild || !event.mSucceeded || !event.mReply.mHasSelection)
           result = nil;
@@ -6109,17 +6109,17 @@ static int32_t RoundUp(double aDouble)
         currentKey == kCorePboardType_urld ||
         currentKey == kCorePboardType_urln) {
       [pboard setString:currentValue forType:currentKey];
     } else if (currentKey == NSHTMLPboardType) {
       [pboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) forType:currentKey];
     } else if (currentKey == NSTIFFPboardType) {
       [pboard setData:currentValue forType:currentKey];
     } else if (currentKey == NSFilesPromisePboardType) {
-      [pboard setPropertyList:currentValue forType:currentKey];        
+      [pboard setPropertyList:currentValue forType:currentKey];
     }
   }
 
   return YES;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
@@ -6141,17 +6141,17 @@ static int32_t RoundUp(double aDouble)
 
   NS_ENSURE_TRUE(mGeckoChild, false);
 
   WidgetContentCommandEvent command(true,
                                     NS_CONTENT_COMMAND_PASTE_TRANSFERABLE,
                                     mGeckoChild);
   command.mTransferable = trans;
   mGeckoChild->DispatchWindowEvent(command);
-  
+
   return command.mSucceeded && command.mIsEnabled;
 }
 
 #pragma mark -
 
 #ifdef ACCESSIBILITY
 
 /* Every ChildView has a corresponding mozDocAccessible object that is doing all
--- a/widget/cocoa/nsMenuGroupOwnerX.mm
+++ b/widget/cocoa/nsMenuGroupOwnerX.mm
@@ -9,17 +9,16 @@
 #include "nsMenuItemX.h"
 #include "nsMenuUtilsX.h"
 #include "nsCocoaUtils.h"
 #include "nsCocoaWindow.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsObjCExceptions.h"
-#include "nsHashtable.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/Element.h"
 #include "nsIWidget.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 
--- a/widget/gtk/gtk3drawing.c
+++ b/widget/gtk/gtk3drawing.c
@@ -2802,30 +2802,34 @@ moz_gtk_get_widget_border(GtkThemeWidget
 
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_MENUPOPUP:
         ensure_menu_popup_widget();
         w = gMenuPopupWidget;
         break;
     case MOZ_GTK_MENUITEM:
+    case MOZ_GTK_CHECKMENUITEM:
+    case MOZ_GTK_RADIOMENUITEM:
         {
-            ensure_menu_item_widget();
-            ensure_menu_bar_item_widget();
-            
-            *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gMenuItemWidget));
-            moz_gtk_add_style_padding(gtk_widget_get_style_context(gMenuItemWidget), 
+            if (widget == MOZ_GTK_MENUITEM) {
+                ensure_menu_item_widget();
+                ensure_menu_bar_item_widget();
+                w = gMenuItemWidget;
+            }
+            else {
+                ensure_check_menu_item_widget();
+                w = gCheckMenuItemWidget;
+            }
+
+            *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
+            moz_gtk_add_style_padding(gtk_widget_get_style_context(w),
                                       left, top, right, bottom);
             return MOZ_GTK_SUCCESS;
         }
-    case MOZ_GTK_CHECKMENUITEM:
-    case MOZ_GTK_RADIOMENUITEM:
-        ensure_check_menu_item_widget();
-        w = gCheckMenuItemWidget;
-        break;
     case MOZ_GTK_TAB:
         ensure_tab_widget();
         w = gTabWidget;
         break;
     /* These widgets have no borders, since they are not containers. */
     case MOZ_GTK_SPLITTER_HORIZONTAL:
     case MOZ_GTK_SPLITTER_VERTICAL:
     case MOZ_GTK_CHECKBUTTON:
--- a/widget/gtk/nsClipboard.cpp
+++ b/widget/gtk/nsClipboard.cpp
@@ -871,27 +871,28 @@ static gchar* CopyRetrievedData(const gc
 
 static GtkSelectionData* CopyRetrievedData(GtkSelectionData *aData)
 {
     // A negative length indicates that retrieving the data failed.
     return gtk_selection_data_get_length(aData) >= 0 ?
         gtk_selection_data_copy(aData) : nullptr;
 }
 
-class RetrievalContext : public RefCounted<RetrievalContext> {
-public:
-    MOZ_DECLARE_REFCOUNTED_TYPENAME(RetrievalContext)
-    enum State { INITIAL, COMPLETED, TIMED_OUT };
-
-    RetrievalContext() : mState(INITIAL), mData(nullptr) {}
+class RetrievalContext {
     ~RetrievalContext()
     {
         MOZ_ASSERT(!mData, "Wait() wasn't called");
     }
 
+public:
+    NS_INLINE_DECL_REFCOUNTING(RetrievalContext)
+    enum State { INITIAL, COMPLETED, TIMED_OUT };
+
+    RetrievalContext() : mState(INITIAL), mData(nullptr) {}
+
     /**
      * Call this when data has been retrieved.
      */
     template <class T> void Complete(T *aData)
     {
         if (mState == INITIAL) {
             mState = COMPLETED;
             mData = CopyRetrievedData(aData);