Merge latest green fx-team changeset and mozilla-central; a=merge
authorEd Morley <emorley@mozilla.com>
Fri, 03 Oct 2014 14:51:14 +0100
changeset 208649 84204f7936028d2e78b670b001aa79d8eda922f0
parent 208648 250cb4595afb4256a3199bd9ade06010f620d03d (current diff)
parent 208621 46f41cc9392d5da2183a1514426800e01addb4b6 (diff)
child 208650 c0f5f5f80e66c384020356de6d64c70d72fb1587
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone35.0a1
Merge latest green fx-team changeset and mozilla-central; a=merge
content/html/content/src/HTMLMediaElement.cpp
js/src/tests/ecma_7/Array/browser.js
js/src/tests/ecma_7/Array/contains.js
js/src/tests/ecma_7/Array/shell.js
js/src/tests/ecma_7/browser.js
js/src/tests/ecma_7/shell.js
media/libvpx/vp8/common/arm/neon/bilinearpredict_neon.c
media/libvpx/vp8/common/arm/neon/copymem_neon.c
media/libvpx/vp8/common/arm/neon/dc_only_idct_add_neon.c
media/libvpx/vp8/common/arm/neon/dequant_idct_neon.c
media/libvpx/vp8/common/arm/neon/dequantizeb_neon.c
media/libvpx/vp8/common/arm/neon/idct_dequant_0_2x_neon.c
media/libvpx/vp8/common/arm/neon/idct_dequant_full_2x_neon.c
media/libvpx/vp8/common/arm/neon/iwalsh_neon.c
media/libvpx/vp8/common/arm/neon/loopfilter_neon.c
media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.c
media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.c
media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.c
media/libvpx/vp8/common/arm/neon/reconintra_neon.c
media/libvpx/vp8/common/arm/neon/sad_neon.c
media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.c
media/libvpx/vp8/common/arm/neon/sixtappredict_neon.c
media/libvpx/vp8/common/arm/neon/variance_neon.c
media/libvpx/vp8/common/arm/neon/vp8_subpixelvariance_neon.c
media/libvpx/vp8/common/x86/loopfilter_block_sse2_x86_64.asm
media/libvpx/vp8/decoder/decodeframe.c
media/libvpx/vp8/encoder/arm/neon/denoising_neon.c
media/libvpx/vp8/encoder/arm/neon/shortfdct_neon.c
media/libvpx/vp8/encoder/arm/neon/subtract_neon.c
media/libvpx/vp8/encoder/arm/neon/vp8_mse16x16_neon.c
media/libvpx/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.c
media/libvpx/vp8/encoder/x86/quantize_sse4.c
media/libvpx/vp8/encoder/x86/quantize_ssse3.c
media/libvpx/vp8/encoder/x86/ssim_opt_x86_64.asm
media/libvpx/vp9/common/arm/neon/vp9_idct16x16_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct16x16_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct32x32_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct32x32_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct4x4_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct4x4_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct8x8_1_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_idct8x8_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_iht4x4_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_iht8x8_add_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_loopfilter_16_neon.asm
media/libvpx/vp9/common/arm/neon/vp9_loopfilter_16_neon.c
media/libvpx/vp9/common/arm/neon/vp9_reconintra_neon.asm
media/libvpx/vp9/common/vp9_blockd.c
media/libvpx/vp9/common/vp9_frame_buffers.c
media/libvpx/vp9/common/vp9_frame_buffers.h
media/libvpx/vp9/common/vp9_prob.c
media/libvpx/vp9/common/vp9_prob.h
media/libvpx/vp9/common/vp9_thread.c
media/libvpx/vp9/common/vp9_thread.h
media/libvpx/vp9/common/x86/vp9_high_intrapred_sse2.asm
media/libvpx/vp9/common/x86/vp9_high_loopfilter_intrin_sse2.c
media/libvpx/vp9/common/x86/vp9_high_subpixel_8t_sse2.asm
media/libvpx/vp9/common/x86/vp9_high_subpixel_bilinear_sse2.asm
media/libvpx/vp9/common/x86/vp9_idct_intrin_sse2.h
media/libvpx/vp9/common/x86/vp9_idct_intrin_ssse3.c
media/libvpx/vp9/common/x86/vp9_idct_ssse3_x86_64.asm
media/libvpx/vp9/common/x86/vp9_subpixel_8t_intrin_avx2.c
media/libvpx/vp9/common/x86/vp9_subpixel_8t_intrin_ssse3.c
media/libvpx/vp9/common/x86/vp9_subpixel_bilinear_sse2.asm
media/libvpx/vp9/common/x86/vp9_subpixel_bilinear_ssse3.asm
media/libvpx/vp9/decoder/vp9_decodeframe.c
media/libvpx/vp9/decoder/vp9_decodeframe.h
media/libvpx/vp9/decoder/vp9_decoder.c
media/libvpx/vp9/decoder/vp9_decoder.h
media/libvpx/vp9/decoder/vp9_dthread.c
media/libvpx/vp9/decoder/vp9_dthread.h
media/libvpx/vp9/decoder/vp9_read_bit_buffer.c
media/libvpx/vp9/decoder/vp9_reader.c
media/libvpx/vp9/decoder/vp9_reader.h
media/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_quantize_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_sad_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_subtract_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_variance_neon.c
media/libvpx/vp9/encoder/vp9_aq_complexity.c
media/libvpx/vp9/encoder/vp9_aq_complexity.h
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.c
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.h
media/libvpx/vp9/encoder/vp9_aq_variance.c
media/libvpx/vp9/encoder/vp9_aq_variance.h
media/libvpx/vp9/encoder/vp9_context_tree.c
media/libvpx/vp9/encoder/vp9_context_tree.h
media/libvpx/vp9/encoder/vp9_cost.c
media/libvpx/vp9/encoder/vp9_cost.h
media/libvpx/vp9/encoder/vp9_denoiser.c
media/libvpx/vp9/encoder/vp9_denoiser.h
media/libvpx/vp9/encoder/vp9_encoder.c
media/libvpx/vp9/encoder/vp9_encoder.h
media/libvpx/vp9/encoder/vp9_extend.c
media/libvpx/vp9/encoder/vp9_extend.h
media/libvpx/vp9/encoder/vp9_pickmode.c
media/libvpx/vp9/encoder/vp9_pickmode.h
media/libvpx/vp9/encoder/vp9_rd.c
media/libvpx/vp9/encoder/vp9_rd.h
media/libvpx/vp9/encoder/vp9_resize.c
media/libvpx/vp9/encoder/vp9_resize.h
media/libvpx/vp9/encoder/vp9_sad.c
media/libvpx/vp9/encoder/vp9_speed_features.c
media/libvpx/vp9/encoder/vp9_speed_features.h
media/libvpx/vp9/encoder/vp9_ssim.h
media/libvpx/vp9/encoder/vp9_svc_layercontext.c
media/libvpx/vp9/encoder/vp9_svc_layercontext.h
media/libvpx/vp9/encoder/vp9_variance.c
media/libvpx/vp9/encoder/vp9_write_bit_buffer.c
media/libvpx/vp9/encoder/vp9_writer.c
media/libvpx/vp9/encoder/vp9_writer.h
media/libvpx/vp9/encoder/x86/vp9_dct32x32_avx2.c
media/libvpx/vp9/encoder/x86/vp9_dct_avx2.c
media/libvpx/vp9/encoder/x86/vp9_dct_mmx.asm
media/libvpx/vp9/encoder/x86/vp9_dct_ssse3_x86_64.asm
media/libvpx/vp9/encoder/x86/vp9_error_intrin_avx2.c
media/libvpx/vp9/encoder/x86/vp9_quantize_ssse3_x86_64.asm
media/libvpx/vp9/encoder/x86/vp9_sad4d_intrin_avx2.c
media/libvpx/vp9/encoder/x86/vp9_ssim_opt_x86_64.asm
media/libvpx/vp9/encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c
media/libvpx/vp9/encoder/x86/vp9_variance_avx2.c
media/libvpx/vp9/encoder/x86/vp9_variance_impl_intrin_avx2.c
media/libvpx/vpx/internal/vpx_psnr.h
media/libvpx/vpx/src/vpx_psnr.c
media/libvpx/vpx/vpx_frame_buffer.h
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -486,17 +486,16 @@ let settingsToObserve = {
     resetToPref: true
   },
   'dom.mozApps.use_reviewer_certs': false,
   'dom.mozApps.signed_apps_installable_from': 'https://marketplace.firefox.com',
   'layers.draw-borders': false,
   'layers.draw-tile-borders': false,
   'layers.dump': false,
   'layers.enable-tiles': true,
-  'layers.simple-tiles': false,
   'layers.effect.invert': false,
   'layers.effect.grayscale': false,
   'layers.effect.contrast': "0.0",
   'privacy.donottrackheader.enabled': false,
   'ril.radio.disabled': false,
   'ril.mms.requestReadReport.enabled': {
     prefName: 'dom.mms.requestReadReport',
     defaultValue: true
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -128,17 +128,17 @@
   <remove-project name="platform/external/bluetooth/bluedroid"/>
   <!--original fetch url was git://github.com/t2m-foxfone/-->
   <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
   <default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
   <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="52c909e821d107d414f851e267dedcd7aae2cebf"/>
-  <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="893238eb1215f8fd4f3747169170cc5e1cc33969"/>
+  <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="1072f7d31dc0bf3a2adc64177b1104da9f4ce4b6"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
   <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="ea2f399b3ca0a23524d2828f85f69902caefc22e"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="6b58ab45e3e56c1fc20708cc39fa2264c52558df"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "3e43be9b8c24802b40fdfbcf17895c4355e6d238", 
+    "revision": "736a08de0dd46c283137a289a484a6b404cb0dd1", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- 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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8a6eed2ba9d66239aac789b9ee4900f911c73cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4bc3cfde42118081268690217172d7b577867c65"/>
   <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="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
new file mode 100644
--- /dev/null
+++ b/b2g/dev/config/mozconfigs/macosx64/mulet
@@ -0,0 +1,25 @@
+MOZ_AUTOMATION_TALOS_SENDCHANGE=0
+. $topsrcdir/build/macosx/mozconfig.common
+
+ac_add_options --enable-application=b2g/dev
+ac_add_options --disable-install-strip
+ac_add_options --enable-signmar
+ac_add_options --enable-profiling
+ac_add_options --enable-instruments
+ac_add_options --enable-dtrace
+
+# Nightlies only since this has a cost in performance
+ac_add_options --enable-js-diagnostics
+
+# Needed to enable breakpad in application.ini
+export MOZILLA_OFFICIAL=1
+
+ac_add_options --with-macbundlename-prefix=Firefox
+
+# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
+ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/b2g/installer/removed-files.in
+++ b/b2g/installer/removed-files.in
@@ -1,18 +1,18 @@
 # Due to Apple Mac OS X packaging requirements files that are in the same
 # directory on other platforms must be located in different directories on
 # Mac OS X. The following defines allow specifying the Mac OS X bundle
 # location which also work on other platforms.
 #
 # @DIR_MACOS@
-# Equals Contents/MacOS/ on Mac OX X and is an empty string on other platforms.
+# Equals Contents/MacOS/ on Mac OS X and is an empty string on other platforms.
 #
 # @DIR_RESOURCES@
-# Equals Contents/Resources/ on Mac OX X and is an empty string on other
+# Equals Contents/Resources/ on Mac OS X and is an empty string on other
 # platforms.
 
 # Mac OS X v2 signing removals
 #ifdef XP_MACOSX
   @DIR_MACOS@active-update.xml
   @DIR_MACOS@update-settings.ini
   @DIR_MACOS@updates.xml
   @DIR_MACOS@defaults/*
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -41,17 +41,17 @@ const gXPInstallObserver = {
                               .getInterface(Components.interfaces.nsIWebNavigation)
                               .QueryInterface(Components.interfaces.nsIDocShell);
       browser = this._getBrowser(shell);
     } catch (e) {
       browser = winOrBrowser;
     }
     // Note that the above try/catch will pass through dead object proxies and
     // other degenerate objects. Make sure the browser is bonafide.
-    if (!browser || !gBrowser.browsers.contains(browser))
+    if (!browser || gBrowser.browsers.indexOf(browser) == -1)
       return;
 
     const anchorID = "addons-notification-icon";
     var messageString, action;
     var brandShortName = brandBundle.getString("brandShortName");
 
     var notificationID = aTopic;
     // Make notifications persist a minimum of 30 seconds
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1366,17 +1366,17 @@ let BookmarkingUI = {
         Components.utils.reportError("BookmarkingUI did not receive current URI");
         return;
       }
 
       // It's possible that onItemAdded gets called before the async statement
       // calls back.  For such an edge case, retain all unique entries from both
       // arrays.
       this._itemIds = this._itemIds.filter(
-        function (id) !aItemIds.contains(id)
+        function (id) aItemIds.indexOf(id) == -1
       ).concat(aItemIds);
 
       this._updateStar();
 
       // Start observing bookmarks if needed.
       if (!this._hasBookmarksObserver) {
         try {
           PlacesUtils.addLazyBookmarkObserver(this);
@@ -1587,17 +1587,17 @@ let BookmarkingUI = {
     PanelUI.hide();
   },
 
   // nsINavBookmarkObserver
   onItemAdded: function BUI_onItemAdded(aItemId, aParentId, aIndex, aItemType,
                                         aURI) {
     if (aURI && aURI.equals(this._uri)) {
       // If a new bookmark has been added to the tracked uri, register it.
-      if (!this._itemIds.contains(aItemId)) {
+      if (this._itemIds.indexOf(aItemId) == -1) {
         this._itemIds.push(aItemId);
         // Only need to update the UI if it wasn't marked as starred before:
         if (this._itemIds.length == 1) {
           this._updateStar();
         }
       }
     }
   },
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2228,17 +2228,17 @@ function URLBarSetURI(aURI) {
     // Strip off "wyciwyg://" and passwords for the location bar
     try {
       uri = Services.uriFixup.createExposableURI(uri);
     } catch (e) {}
 
     // Replace initial page URIs with an empty string
     // only if there's no opener (bug 370555).
     // Bug 863515 - Make content.opener checks work in electrolysis.
-    if (gInitialPages.contains(uri.spec))
+    if (gInitialPages.indexOf(uri.spec) != -1)
       value = !gMultiProcessBrowser && content.opener ? uri.spec : "";
     else
       value = losslessDecodeURI(uri);
 
     valid = !isBlankPageURL(uri.spec);
   }
 
   gURLBar.value = value;
--- a/browser/base/content/newtab/updater.js
+++ b/browser/base/content/newtab/updater.js
@@ -124,17 +124,17 @@ let gUpdater = {
    * @param aCallback The callback to call when finished.
    */
   _removeLegacySites: function Updater_removeLegacySites(aSites, aCallback) {
     let batch = [];
 
     // Delete sites that were removed from the grid.
     gGrid.sites.forEach(function (aSite) {
       // The site must be valid and not in the current grid.
-      if (!aSite || aSites.contains(aSite))
+      if (!aSite || aSites.indexOf(aSite) != -1)
         return;
 
       batch.push(new Promise(resolve => {
         // Fade out the to-be-removed site.
         gTransformation.hideSite(aSite, function () {
           let node = aSite.node;
 
           // Remove the site from the DOM.
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -13,17 +13,17 @@ var gPermissions = SitePermissions.listP
 gPermissions.push("plugins");
 
 var permissionObserver = {
   observe: function (aSubject, aTopic, aData)
   {
     if (aTopic == "perm-changed") {
       var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
       if (permission.host == gPermURI.host) {
-        if (gPermissions.contains(permission.type))
+        if (gPermissions.indexOf(permission.type) > -1)
           initRow(permission.type);
         else if (permission.type.startsWith("plugin"))
           setPluginsRadioState();
       }
     }
   }
 };
 
--- a/browser/base/content/sync/setup.js
+++ b/browser/base/content/sync/setup.js
@@ -147,19 +147,19 @@ var gSyncSetup = {
 
     // Generate a new passphrase so that Weave.Service.login() will
     // actually do something.
     let passphrase = Weave.Utils.generatePassphrase();
     Weave.Service.identity.syncKey = passphrase;
 
     // Only open the dialog if username + password are actually correct.
     Weave.Service.login();
-    if (![Weave.LOGIN_FAILED_INVALID_PASSPHRASE,
-          Weave.LOGIN_FAILED_NO_PASSPHRASE,
-          Weave.LOGIN_SUCCEEDED].contains(Weave.Status.login)) {
+    if ([Weave.LOGIN_FAILED_INVALID_PASSPHRASE,
+         Weave.LOGIN_FAILED_NO_PASSPHRASE,
+         Weave.LOGIN_SUCCEEDED].indexOf(Weave.Status.login) == -1) {
       return;
     }
 
     // Hide any errors about the passphrase, we know it's not right.
     let feedback = document.getElementById("existingPassphraseFeedbackRow");
     feedback.hidden = true;
     let el = document.getElementById("existingPassphrase");
     el.value = Weave.Utils.hyphenatePassphrase(passphrase);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1663,17 +1663,17 @@
             evt.initEvent("TabOpen", true, false);
             t.dispatchEvent(evt);
 
             // If we didn't swap docShells with a preloaded browser
             // then let's just continue loading the page normally.
             if (!docShellsSwapped && !uriIsAboutBlank) {
               // pretend the user typed this so it'll be available till
               // the document successfully loads
-              if (aURI && !gInitialPages.contains(aURI))
+              if (aURI && gInitialPages.indexOf(aURI) == -1)
                 b.userTypedValue = aURI;
 
               let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
               if (aAllowThirdPartyFixup) {
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
               }
               if (aFromExternal)
@@ -2162,24 +2162,24 @@
                 return !tab.closing;
               }, this);
             }
 
             // Try to find a remaining tab that comes after the given tab
             var tab = aTab;
             do {
               tab = tab.nextSibling;
-            } while (tab && !remainingTabs.contains(tab));
+            } while (tab && remainingTabs.indexOf(tab) == -1);
 
             if (!tab) {
               tab = aTab;
 
               do {
                 tab = tab.previousSibling;
-              } while (tab && !remainingTabs.contains(tab));
+              } while (tab && remainingTabs.indexOf(tab) == -1);
             }
 
             this.selectedTab = tab;
           ]]>
         </body>
       </method>
 
       <method name="swapNewTabWithBrowser">
@@ -2417,20 +2417,20 @@
         </body>
       </method>
 
       <method name="showOnlyTheseTabs">
         <parameter name="aTabs"/>
         <body>
         <![CDATA[
           Array.forEach(this.tabs, function(tab) {
-            if (aTabs.contains(tab))
+            if (aTabs.indexOf(tab) == -1)
+              this.hideTab(tab);
+            else
               this.showTab(tab);
-            else
-              this.hideTab(tab);
           }, this);
 
           this.tabContainer._handleTabSelect(false);
         ]]>
         </body>
       </method>
 
       <method name="showTab">
--- a/browser/base/content/test/general/browser_blockHPKP.js
+++ b/browser/base/content/test/general/browser_blockHPKP.js
@@ -64,33 +64,27 @@ let successfulPinningPageListener = {
     gBrowser.addProgressListener(certErrorProgressListener);
     gBrowser.selectedBrowser.loadURI("https://" + kBadPinningDomain);
   }
 };
 
 // The browser should load about:neterror, when this happens, proceed
 // to load the pinning domain again, this time removing the pinning information
 let certErrorProgressListener = {
-  buttonClicked: false,
   onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
-      let self = this;
-      // Can't directly call button.click() in onStateChange
-      executeSoon(function() {
-        let button =   content.document.getElementById("errorTryAgain");
-        // If about:neterror hasn't fully loaded, the button won't be present.
-        // It will eventually be there, however.
-        if (button && !self.buttonClicked) {
-          gBrowser.removeProgressListener(self);
-          gBrowser.selectedBrowser.addEventListener("load",
-                                                    successfulPinningRemovalPageListener,
-                                                    true);
-          gBrowser.selectedBrowser.loadURI("https://" + kPinningDomain + kURLPath + "zeromaxagevalid");
-        }
-      });
+      let textElement = content.document.getElementById("errorShortDescText");
+      let text = textElement.innerHTML;
+      ok(text.indexOf("mozilla_pkix_error_key_pinning_failure") > 0,
+         "Got a pinning error page");
+      gBrowser.removeProgressListener(this);
+      gBrowser.selectedBrowser.addEventListener("load",
+                                                successfulPinningRemovalPageListener,
+                                                true);
+      gBrowser.selectedBrowser.loadURI("https://" + kPinningDomain + kURLPath + "zeromaxagevalid");
     }
   }
 };
 
 // After the pinning information has been removed (successful load) proceed
 // to load again with the invalid pin domain.
 let successfulPinningRemovalPageListener = {
   handleEvent: function() {
--- a/browser/base/content/test/general/browser_bug521216.js
+++ b/browser/base/content/test/general/browser_bug521216.js
@@ -8,17 +8,17 @@ function test() {
   tabIndex = gBrowser.tabs.length;
   gBrowser.addTabsProgressListener(progressListener);
   gBrowser.tabContainer.addEventListener("TabOpen", TabOpen, false);
   gBrowser.addTab("data:text/html,<html><head><link href='about:logo' rel='shortcut icon'>");
 }
 
 function record(aName) {
   info("got " + aName);
-  if (!actual.contains(aName))
+  if (actual.indexOf(aName) == -1)
     actual.push(aName);
   if (actual.length == expected.length) {
     is(actual.toString(), expected.toString(),
        "got events and progress notifications in expected order");
     gBrowser.removeTab(tab);
     gBrowser.removeTabsProgressListener(progressListener);
     gBrowser.tabContainer.removeEventListener("TabOpen", TabOpen, false);
     finish();
--- a/browser/base/content/test/general/browser_contentAreaClick.js
+++ b/browser/base/content/test/general/browser_contentAreaClick.js
@@ -207,18 +207,18 @@ let gClickHandler = {
     let isPanelClick = linkId == "panellink";
     gTestWin.contentAreaClick(event, isPanelClick);
     let prevent = event.defaultPrevented;
     is(prevent, gCurrentTest.preventDefault,
        gCurrentTest.desc + ": event.defaultPrevented is correct (" + prevent + ")")
 
     // Check that all required methods have been called.
     gCurrentTest.expectedInvokedMethods.forEach(function(aExpectedMethodName) {
-      ok(gInvokedMethods.contains(aExpectedMethodName),
-         gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
+      isnot(gInvokedMethods.indexOf(aExpectedMethodName), -1,
+            gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
     });
     
     if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {
       ok(false, "Wrong number of invoked methods");
       gInvokedMethods.forEach(function (method) info(method + " was invoked"));
     }
 
     event.preventDefault();
--- a/browser/base/content/test/general/browser_devices_get_user_media.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media.js
@@ -28,17 +28,17 @@ function observer(aSubject, aTopic, aDat
 
 function promiseObserverCalled(aTopic, aAction) {
   let deferred = Promise.defer();
 
   Services.obs.addObserver(function observer() {
     ok(true, "got " + aTopic + " notification");
     Services.obs.removeObserver(observer, aTopic);
 
-    if (kObservedTopics.contains(aTopic)) {
+    if (kObservedTopics.indexOf(aTopic) != -1) {
       if (!(aTopic in gObservedTopics))
         gObservedTopics[aTopic] = -1;
       else
         --gObservedTopics[aTopic];
     }
 
     deferred.resolve();
   }, aTopic, false);
@@ -822,17 +822,17 @@ let gTests = [
     let alwaysLabel = gNavigatorBundle.getString("getUserMedia.always.label");
     ok(!!alwaysLabel, "found the 'Always Allow' localized label");
     let labels = [];
     let notification = PopupNotifications.panel.firstChild;
     for (let node of notification.childNodes) {
       if (node.localName == "menuitem")
         labels.push(node.getAttribute("label"));
     }
-    ok(!labels.contains(alwaysLabel), "The 'Always Allow' item isn't shown");
+    is(labels.indexOf(alwaysLabel), -1, "The 'Always Allow' item isn't shown");
 
     // Cleanup.
     yield closeStream(true);
     Perms.remove(uri.host, "camera");
     Perms.remove(uri.host, "microphone");
   }
 }
 
--- a/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
@@ -33,17 +33,17 @@ function promiseObserverCalled(aTopic, a
   let deferred = Promise.defer();
   info("Waiting for " + aTopic);
 
   Services.obs.addObserver(function observer(aSubject, topic, aData) {
     ok(true, "got " + aTopic + " notification");
     info("Message: " + aData);
     Services.obs.removeObserver(observer, aTopic);
 
-    if (kObservedTopics.contains(aTopic)) {
+    if (kObservedTopics.indexOf(aTopic) != -1) {
       if (!(aTopic in gObservedTopics))
         gObservedTopics[aTopic] = -1;
       else
         --gObservedTopics[aTopic];
     }
 
     deferred.resolve();
   }, aTopic, false);
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -686,17 +686,17 @@ function makeActionURI(action, params) {
 
 function is_hidden(element) {
   var style = element.ownerDocument.defaultView.getComputedStyle(element, "");
   if (style.display == "none")
     return true;
   if (style.visibility != "visible")
     return true;
   if (style.display == "-moz-popup")
-    return ["hiding","closed"].contains(element.state);
+    return ["hiding","closed"].indexOf(element.state) != -1;
 
   // Hiding a parent element will hide all its children
   if (element.parentNode != element.ownerDocument)
     return is_hidden(element.parentNode);
 
   return false;
 }
 
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -886,17 +886,17 @@ function waitForEvents(event)
     loaded = true;
   if (painted && loaded) {
     subwindow.removeEventListener("MozAfterPaint", waitForEvents, false);
     subwindow.onload = null;
     startTest();
   }
 }
 
-const isOSXMtnLion = navigator.userAgent.contains("Mac OS X 10.8");
+const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
 
 if (isOSXMtnLion) {
   todo(false, "Mountain Lion doesn't like this test (bug 792304)");
 } else {
   SpecialPowers.setBoolPref("plugins.click_to_play", true);
   setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
 
   var subwindow = window.open("./subtst_contextmenu.html", "contextmenu-subtext", "width=600,height=800");
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -194,17 +194,17 @@
           let selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
           selection.removeAllRanges();
 
           let textNode = this.editor.rootElement.firstChild;
           let value = textNode.textContent;
 
           let protocol = value.match(/^[a-z\d.+\-]+:(?=[^\d])/);
           if (protocol &&
-              !["http:", "https:", "ftp:"].contains(protocol[0]))
+              ["http:", "https:", "ftp:"].indexOf(protocol[0]) == -1)
             return;
           let matchedURL = value.match(/^((?:[a-z]+:\/\/)?(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/);
           if (!matchedURL)
             return;
 
           let [, preDomain, domain] = matchedURL;
           let baseDomain = domain;
           let subDomain = "";
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -53,20 +53,20 @@
 # Example: path/to/dir/*
 
 # Due to Apple Mac OS X packaging requirements files that are in the same
 # directory on other platforms must be located in different directories on
 # Mac OS X. The following defines allow specifying the Mac OS X bundle
 # location which also work on other platforms.
 #
 # @DIR_MACOS@
-# Equals Contents/MacOS/ on Mac OX X and is an empty string on other platforms.
+# Equals Contents/MacOS/ on Mac OS X and is an empty string on other platforms.
 #
 # @DIR_RESOURCES@
-# Equals Contents/Resources/ on Mac OX X and is an empty string on other
+# Equals Contents/Resources/ on Mac OS X and is an empty string on other
 # platforms.
 
 # Common File Removals
 # This is located under the "distribution/" directory and it was added before
 # Firefox 27
 @DIR_MACOS@distribution/extensions/testpilot@labs.mozilla.com.xpi
 
 # Some users are ending up with unpacked chrome instead of omni.ja. This
--- a/content/media/AudioBufferUtils.h
+++ b/content/media/AudioBufferUtils.h
@@ -72,19 +72,28 @@ public:
 
   /**
    * Check that the buffer is completly filled, and reset internal state so this
    * instance can be reused.
    */
   void BufferFilled() {
     // It's okay to have exactly zero samples here, it can happen we have an
     // audio callback driver because of a hint on MSG creation, but the
-    // AudioOutputStream has not been created yet.
+    // AudioOutputStream has not been created yet, or if all the streams have finished
+    // but we're still running.
+    // Note: it's also ok if we had data in the scratch buffer - and we usually do - and
+    // all the streams were ended (no mixer callback occured).
+    // XXX Remove this warning, or find a way to avoid it if the mixer callback
+    // isn't called.
     NS_WARN_IF_FALSE(Available() == 0 || mSampleWriteOffset == 0,
             "Audio Buffer is not full by the end of the callback.");
+    // Make sure the data returned is always set and not random!
+    if (Available()) {
+      PodZero(mBuffer + mSampleWriteOffset, FramesToSamples(CHANNELS, Available()));
+    }
     MOZ_ASSERT(mSamples, "Buffer not set.");
     mSamples = 0;
     mSampleWriteOffset = 0;
     mBuffer = nullptr;
   }
 
 private:
   /* This is not an owned pointer, but the pointer passed to use via the audio
--- a/content/svg/content/src/SVGCircleElement.cpp
+++ b/content/svg/content/src/SVGCircleElement.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGCircleElement.h"
 #include "mozilla/gfx/2D.h"
 #include "nsGkAtoms.h"
-#include "gfxContext.h"
 #include "mozilla/dom/SVGCircleElementBinding.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Circle)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
@@ -77,27 +76,16 @@ SVGCircleElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
-void
-SVGCircleElement::ConstructPath(gfxContext *aCtx)
-{
-  float x, y, r;
-
-  GetAnimatedLengthValues(&x, &y, &r, nullptr);
-
-  if (r > 0.0f)
-    aCtx->Arc(gfxPoint(x, y), r, 0, 2*M_PI);
-}
-
 TemporaryRef<Path>
 SVGCircleElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, r;
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r <= 0.0f) {
     return nullptr;
--- a/content/svg/content/src/SVGCircleElement.h
+++ b/content/svg/content/src/SVGCircleElement.h
@@ -25,17 +25,16 @@ protected:
   friend nsresult (::NS_NewSVGCircleElement(nsIContent **aResult,
                                             already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> R();
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -154,44 +154,47 @@ GetStrokeDashData(SVGContentUtils::AutoS
 
   return eDashedStroke;
 }
 
 void
 SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
                                   nsSVGElement* aElement,
                                   nsStyleContext* aStyleContext,
-                                  gfxTextContextPaint *aContextPaint)
+                                  gfxTextContextPaint *aContextPaint,
+                                  StrokeOptionFlags aFlags)
 {
   nsRefPtr<nsStyleContext> styleContext;
   if (aStyleContext) {
     styleContext = aStyleContext;
   } else {
     styleContext =
       nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
                                                            nullptr);
   }
 
   if (!styleContext) {
     return;
   }
 
   const nsStyleSVG* styleSVG = styleContext->StyleSVG();
 
-  DashState dashState =
-    GetStrokeDashData(aStrokeOptions, aElement, styleSVG, aContextPaint);
+  if (aFlags != eIgnoreStrokeDashing) {
+    DashState dashState =
+      GetStrokeDashData(aStrokeOptions, aElement, styleSVG, aContextPaint);
 
-  if (dashState == eNoStroke) {
-    // Hopefully this will shortcircuit any stroke operations:
-    aStrokeOptions->mLineWidth = 0;
-    return;
-  }
-  if (dashState == eContinuousStroke && aStrokeOptions->mDashPattern) {
-    // Prevent our caller from wasting time looking at a pattern without gaps:
-    aStrokeOptions->DiscardDashPattern();
+    if (dashState == eNoStroke) {
+      // Hopefully this will shortcircuit any stroke operations:
+      aStrokeOptions->mLineWidth = 0;
+      return;
+    }
+    if (dashState == eContinuousStroke && aStrokeOptions->mDashPattern) {
+      // Prevent our caller from wasting time looking at a pattern without gaps:
+      aStrokeOptions->DiscardDashPattern();
+    }
   }
 
   aStrokeOptions->mLineWidth =
     GetStrokeWidth(aElement, styleContext, aContextPaint);
 
   aStrokeOptions->mMiterLimit = Float(styleSVG->mStrokeMiterlimit);
 
   switch (styleSVG->mStrokeLinejoin) {
--- a/content/svg/content/src/SVGContentUtils.h
+++ b/content/svg/content/src/SVGContentUtils.h
@@ -123,20 +123,25 @@ public:
       mDashLength = 0;
       mDashPattern = nullptr;
     }
   private:
     // Most dasharrays will fit in this and save us allocating
     Float mSmallArray[16];
   };
 
+  enum StrokeOptionFlags {
+    eAllStrokeOptions,
+    eIgnoreStrokeDashing
+  };
   static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
                                nsSVGElement* aElement,
                                nsStyleContext* aStyleContext,
-                               gfxTextContextPaint *aContextPaint);
+                               gfxTextContextPaint *aContextPaint,
+                               StrokeOptionFlags aFlags = eAllStrokeOptions);
 
   /**
    * Returns the current computed value of the CSS property 'stroke-width' for
    * the given element. aStyleContext may be provided as an optimization. 
    * aContextPaint is also optional.
    *
    * Note that this function does NOT take account of the value of the 'stroke'
    * and 'stroke-opacity' properties to, say, return zero if they are "none" or
--- a/content/svg/content/src/SVGEllipseElement.cpp
+++ b/content/svg/content/src/SVGEllipseElement.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGEllipseElement.h"
 #include "mozilla/dom/SVGEllipseElementBinding.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/RefPtr.h"
-#include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 
@@ -88,27 +87,16 @@ SVGEllipseElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
-void
-SVGEllipseElement::ConstructPath(gfxContext *aCtx)
-{
-  RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
-  RefPtr<PathBuilder> builder = dt->CreatePathBuilder(aCtx->CurrentFillRule());
-  RefPtr<Path> path = BuildPath(builder);
-  if (path) {
-    aCtx->SetPath(path);
-  }
-}
-
 TemporaryRef<Path>
 SVGEllipseElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, rx, ry;
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx <= 0.0f || ry <= 0.0f) {
     return nullptr;
--- a/content/svg/content/src/SVGEllipseElement.h
+++ b/content/svg/content/src/SVGEllipseElement.h
@@ -25,17 +25,16 @@ protected:
   friend nsresult (::NS_NewSVGEllipseElement(nsIContent **aResult,
                                              already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> Rx();
--- a/content/svg/content/src/SVGImageElement.cpp
+++ b/content/svg/content/src/SVGImageElement.cpp
@@ -7,17 +7,16 @@
 #include "mozilla/EventStates.h"
 
 #include "mozilla/dom/SVGImageElement.h"
 #include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "imgINotificationObserver.h"
-#include "gfxContext.h"
 #include "mozilla/dom/SVGImageElementBinding.h"
 #include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Image)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
@@ -222,29 +221,16 @@ SVGImageElement::IsAttributeMapped(const
     SVGImageElementBase::IsAttributeMapped(name);
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 /* For the purposes of the update/invalidation logic pretend to
    be a rectangle. */
-void
-SVGImageElement::ConstructPath(gfxContext *aCtx)
-{
-  float x, y, width, height;
-
-  GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
-
-  if (width <= 0 || height <= 0)
-    return;
-
-  aCtx->Rectangle(gfxRect(x, y, width, height));
-}
-
 TemporaryRef<Path>
 SVGImageElement::BuildPath(PathBuilder* aBuilder)
 {
   // We get called in order to get bounds for this element, and for
   // hit-testing against it. For that we just pretend to be a rectangle.
 
   float x, y, width, height;
   GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
--- a/content/svg/content/src/SVGImageElement.h
+++ b/content/svg/content/src/SVGImageElement.h
@@ -48,17 +48,16 @@ public:
                               bool aCompileEventHandlers) MOZ_OVERRIDE;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) MOZ_OVERRIDE;
 
   virtual EventStates IntrinsicState() const MOZ_OVERRIDE;
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   nsresult CopyInnerTo(mozilla::dom::Element* aDest);
--- a/content/svg/content/src/SVGLineElement.cpp
+++ b/content/svg/content/src/SVGLineElement.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGLineElement.h"
 #include "mozilla/dom/SVGLineElementBinding.h"
 #include "mozilla/gfx/2D.h"
-#include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Line)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 
@@ -102,27 +101,16 @@ SVGLineElement::GetMarkPoints(nsTArray<n
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
 
   float angle = atan2(y2 - y1, x2 - x1);
 
   aMarks->AppendElement(nsSVGMark(x1, y1, angle, nsSVGMark::eStart));
   aMarks->AppendElement(nsSVGMark(x2, y2, angle, nsSVGMark::eEnd));
 }
 
-void
-SVGLineElement::ConstructPath(gfxContext *aCtx)
-{
-  float x1, y1, x2, y2;
-
-  GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
-
-  aCtx->MoveTo(gfxPoint(x1, y1));
-  aCtx->LineTo(gfxPoint(x2, y2));
-}
-
 TemporaryRef<Path>
 SVGLineElement::BuildPath(PathBuilder* aBuilder)
 {
   RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   float x1, y1, x2, y2;
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
 
--- a/content/svg/content/src/SVGLineElement.h
+++ b/content/svg/content/src/SVGLineElement.h
@@ -27,17 +27,16 @@ protected:
 
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X1();
   already_AddRefed<SVGAnimatedLength> Y1();
   already_AddRefed<SVGAnimatedLength> X2();
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -14,17 +14,16 @@
 #include "nsError.h"
 #include "nsString.h"
 #include "nsSVGPathDataParser.h"
 #include "nsSVGPathGeometryElement.h" // for nsSVGMark
 #include <stdarg.h>
 #include "nsStyleConsts.h"
 #include "SVGContentUtils.h"
 #include "SVGPathSegUtils.h"
-#include "gfxContext.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 static bool IsMoveto(uint16_t aSegType)
 {
   return aSegType == PATHSEG_MOVETO_ABS ||
@@ -255,69 +254,44 @@ ApproximateZeroLengthSubpathSquareCaps(P
   // not to.
   MOZ_ASSERT(aStrokeWidth > 0.0f,
              "Make the caller check for this, or check it here");
 
   // The fraction of the stroke width that we choose for the length of the
   // line is rather arbitrary, other than being chosen to meet the requirements
   // described in the comment above.
 
-  Float tinyLength = aStrokeWidth / 32;
+  Float tinyLength = aStrokeWidth / 512;
 
-  aPB->MoveTo(aPoint);
   aPB->LineTo(aPoint + Point(tinyLength, 0));
   aPB->MoveTo(aPoint);
 }
 
-static void
-ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
-{
-  // Cairo's fixed point fractional part is 8 bits wide, so its device space
-  // coordinate granularity is 1/256 pixels. However, to prevent user space
-  // |aPoint| and |aPoint + tinyAdvance| being rounded to the same device
-  // coordinates, we double this for |tinyAdvance|:
-
-  const gfxSize tinyAdvance = aCtx->DeviceToUser(gfxSize(2.0/256.0, 0.0));
-
-  aCtx->MoveTo(aPoint);
-  aCtx->LineTo(aPoint + gfxPoint(tinyAdvance.width, tinyAdvance.height));
-  aCtx->MoveTo(aPoint);
-}
-
 #define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT               \
   do {                                                                        \
-    if (capsAreSquare && !subpathHasLength && aStrokeWidth > 0 &&             \
-        subpathContainsNonArc && SVGPathSegUtils::IsValidType(prevSegType) && \
+    if (!subpathHasLength && hasLineCaps && aStrokeWidth > 0 &&               \
+        subpathContainsNonMoveTo &&                                           \
+        SVGPathSegUtils::IsValidType(prevSegType) &&                          \
         (!IsMoveto(prevSegType) || segType == PATHSEG_CLOSEPATH)) {           \
       ApproximateZeroLengthSubpathSquareCaps(builder, segStart, aStrokeWidth);\
     }                                                                         \
   } while(0)
 
-#define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS                     \
-  do {                                                                        \
-    if (capsAreSquare && !subpathHasLength && subpathContainsNonArc &&        \
-        SVGPathSegUtils::IsValidType(prevSegType) &&                          \
-        (!IsMoveto(prevSegType) ||                                            \
-         segType == PATHSEG_CLOSEPATH)) {                                     \
-      ApproximateZeroLengthSubpathSquareCaps(segStart, aCtx);                 \
-    }                                                                         \
-  } while(0)
-
 TemporaryRef<Path>
 SVGPathData::BuildPath(PathBuilder* builder,
                        uint8_t aStrokeLineCap,
                        Float aStrokeWidth) const
 {
   if (mData.IsEmpty() || !IsMoveto(SVGPathSegUtils::DecodeType(mData[0]))) {
     return nullptr; // paths without an initial moveto are invalid
   }
 
-  bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
+  bool hasLineCaps = aStrokeLineCap != NS_STYLE_STROKE_LINECAP_BUTT;
   bool subpathHasLength = false;  // visual length
-  bool subpathContainsNonArc = false;
+  bool subpathContainsNonMoveTo = false;
 
   uint32_t segType     = PATHSEG_UNKNOWN;
   uint32_t prevSegType = PATHSEG_UNKNOWN;
   Point pathStart(0.0, 0.0); // start point of [sub]path
   Point segStart(0.0, 0.0);
   Point segEnd;
   Point cp1, cp2;            // previous bezier's control points
   Point tcp1, tcp2;          // temporaries
@@ -330,483 +304,216 @@ SVGPathData::BuildPath(PathBuilder* buil
   while (i < mData.Length()) {
     segType = SVGPathSegUtils::DecodeType(mData[i++]);
     uint32_t argCount = SVGPathSegUtils::ArgCountForType(segType);
 
     switch (segType)
     {
     case PATHSEG_CLOSEPATH:
       // set this early to allow drawing of square caps for "M{x},{y} Z":
-      subpathContainsNonArc = true;
+      subpathContainsNonMoveTo = true;
       MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT;
       segEnd = pathStart;
       builder->Close();
       break;
 
     case PATHSEG_MOVETO_ABS:
       MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT;
       pathStart = segEnd = Point(mData[i], mData[i+1]);
       builder->MoveTo(segEnd);
       subpathHasLength = false;
-      subpathContainsNonArc = false;
       break;
 
     case PATHSEG_MOVETO_REL:
       MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT;
       pathStart = segEnd = segStart + Point(mData[i], mData[i+1]);
       builder->MoveTo(segEnd);
       subpathHasLength = false;
-      subpathContainsNonArc = false;
       break;
 
     case PATHSEG_LINETO_ABS:
       segEnd = Point(mData[i], mData[i+1]);
-      builder->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
+      if (segEnd != segStart) {
+        subpathHasLength = true;
+        builder->LineTo(segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_LINETO_REL:
       segEnd = segStart + Point(mData[i], mData[i+1]);
-      builder->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
+      if (segEnd != segStart) {
+        subpathHasLength = true;
+        builder->LineTo(segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_CUBIC_ABS:
       cp1 = Point(mData[i], mData[i+1]);
       cp2 = Point(mData[i+2], mData[i+3]);
       segEnd = Point(mData[i+4], mData[i+5]);
-      builder->BezierTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
+      if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
+        subpathHasLength = true;
+        builder->BezierTo(cp1, cp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_CUBIC_REL:
       cp1 = segStart + Point(mData[i], mData[i+1]);
       cp2 = segStart + Point(mData[i+2], mData[i+3]);
       segEnd = segStart + Point(mData[i+4], mData[i+5]);
-      builder->BezierTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
+      if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
+        subpathHasLength = true;
+        builder->BezierTo(cp1, cp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_QUADRATIC_ABS:
       cp1 = Point(mData[i], mData[i+1]);
       // Convert quadratic curve to cubic curve:
       tcp1 = segStart + (cp1 - segStart) * 2 / 3;
       segEnd = Point(mData[i+2], mData[i+3]); // set before setting tcp2!
       tcp2 = cp1 + (segEnd - cp1) / 3;
-      builder->BezierTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
+      if (segEnd != segStart || segEnd != cp1) {
+        subpathHasLength = true;
+        builder->BezierTo(tcp1, tcp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_QUADRATIC_REL:
       cp1 = segStart + Point(mData[i], mData[i+1]);
       // Convert quadratic curve to cubic curve:
       tcp1 = segStart + (cp1 - segStart) * 2 / 3;
       segEnd = segStart + Point(mData[i+2], mData[i+3]); // set before setting tcp2!
       tcp2 = cp1 + (segEnd - cp1) / 3;
-      builder->BezierTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
+      if (segEnd != segStart || segEnd != cp1) {
+        subpathHasLength = true;
+        builder->BezierTo(tcp1, tcp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_ARC_ABS:
     case PATHSEG_ARC_REL:
     {
       Point radii(mData[i], mData[i+1]);
       segEnd = Point(mData[i+5], mData[i+6]);
       if (segType == PATHSEG_ARC_REL) {
         segEnd += segStart;
       }
       if (segEnd != segStart) {
+        subpathHasLength = true;
         if (radii.x == 0.0f || radii.y == 0.0f) {
           builder->LineTo(segEnd);
         } else {
           nsSVGArcConverter converter(segStart, segEnd, radii, mData[i+2],
                                       mData[i+3] != 0, mData[i+4] != 0);
           while (converter.GetNextSegment(&cp1, &cp2, &segEnd)) {
             builder->BezierTo(cp1, cp2, segEnd);
           }
         }
       }
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
       break;
     }
 
     case PATHSEG_LINETO_HORIZONTAL_ABS:
       segEnd = Point(mData[i], segStart.y);
-      builder->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
+      if (segEnd != segStart) {
+        subpathHasLength = true;
+        builder->LineTo(segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_LINETO_HORIZONTAL_REL:
       segEnd = segStart + Point(mData[i], 0.0f);
-      builder->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
+      if (segEnd != segStart) {
+        subpathHasLength = true;
+        builder->LineTo(segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_LINETO_VERTICAL_ABS:
       segEnd = Point(segStart.x, mData[i]);
-      builder->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
+      if (segEnd != segStart) {
+        subpathHasLength = true;
+        builder->LineTo(segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_LINETO_VERTICAL_REL:
       segEnd = segStart + Point(0.0f, mData[i]);
-      builder->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
+      if (segEnd != segStart) {
+        subpathHasLength = true;
+        builder->LineTo(segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
       cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - cp2 : segStart;
       cp2 = Point(mData[i],   mData[i+1]);
       segEnd = Point(mData[i+2], mData[i+3]);
-      builder->BezierTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
+      if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
+        subpathHasLength = true;
+        builder->BezierTo(cp1, cp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
       cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - cp2 : segStart;
       cp2 = segStart + Point(mData[i], mData[i+1]);
       segEnd = segStart + Point(mData[i+2], mData[i+3]);
-      builder->BezierTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
+      if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
+        subpathHasLength = true;
+        builder->BezierTo(cp1, cp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
       cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - cp1 : segStart;
       // Convert quadratic curve to cubic curve:
       tcp1 = segStart + (cp1 - segStart) * 2 / 3;
       segEnd = Point(mData[i], mData[i+1]); // set before setting tcp2!
       tcp2 = cp1 + (segEnd - cp1) / 3;
-      builder->BezierTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
+      if (segEnd != segStart || segEnd != cp1) {
+        subpathHasLength = true;
+        builder->BezierTo(tcp1, tcp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
       cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - cp1 : segStart;
       // Convert quadratic curve to cubic curve:
       tcp1 = segStart + (cp1 - segStart) * 2 / 3;
       segEnd = segStart + Point(mData[i], mData[i+1]); // changed before setting tcp2!
       tcp2 = cp1 + (segEnd - cp1) / 3;
-      builder->BezierTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
+      if (segEnd != segStart || segEnd != cp1) {
+        subpathHasLength = true;
+        builder->BezierTo(tcp1, tcp2, segEnd);
       }
-      subpathContainsNonArc = true;
       break;
 
     default:
       NS_NOTREACHED("Bad path segment type");
       return nullptr; // according to spec we'd use everything up to the bad seg anyway
     }
+
+    subpathContainsNonMoveTo = segType != PATHSEG_MOVETO_ABS &&
+                               segType != PATHSEG_MOVETO_REL;
     i += argCount;
     prevSegType = segType;
     segStart = segEnd;
   }
 
   NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
   NS_ABORT_IF_FALSE(prevSegType == segType,
                     "prevSegType should be left at the final segType");
 
   MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT;
 
   return builder->Finish();
 }
 
-void
-SVGPathData::ConstructPath(gfxContext *aCtx) const
-{
-  if (mData.IsEmpty() || !IsMoveto(SVGPathSegUtils::DecodeType(mData[0]))) {
-    return; // paths without an initial moveto are invalid
-  }
-
-  bool capsAreSquare = aCtx->CurrentLineCap() == gfxContext::LINE_CAP_SQUARE;
-  bool subpathHasLength = false;  // visual length
-  bool subpathContainsNonArc = false;
-
-  uint32_t segType     = PATHSEG_UNKNOWN;
-  uint32_t prevSegType = PATHSEG_UNKNOWN;
-  gfxPoint pathStart(0.0, 0.0); // start point of [sub]path
-  gfxPoint segStart(0.0, 0.0);
-  gfxPoint segEnd;
-  gfxPoint cp1, cp2;            // previous bezier's control points
-  gfxPoint tcp1, tcp2;          // temporaries
-
-  // Regarding cp1 and cp2: If the previous segment was a cubic bezier curve,
-  // then cp2 is its second control point. If the previous segment was a
-  // quadratic curve, then cp1 is its (only) control point.
-
-  uint32_t i = 0;
-  while (i < mData.Length()) {
-    segType = SVGPathSegUtils::DecodeType(mData[i++]);
-    uint32_t argCount = SVGPathSegUtils::ArgCountForType(segType);
-
-    switch (segType)
-    {
-    case PATHSEG_CLOSEPATH:
-      // set this early to allow drawing of square caps for "M{x},{y} Z":
-      subpathContainsNonArc = true;
-      MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
-      segEnd = pathStart;
-      aCtx->ClosePath();
-      break;
-
-    case PATHSEG_MOVETO_ABS:
-      MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
-      pathStart = segEnd = gfxPoint(mData[i], mData[i+1]);
-      aCtx->MoveTo(segEnd);
-      subpathHasLength = false;
-      subpathContainsNonArc = false;
-      break;
-
-    case PATHSEG_MOVETO_REL:
-      MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
-      pathStart = segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
-      aCtx->MoveTo(segEnd);
-      subpathHasLength = false;
-      subpathContainsNonArc = false;
-      break;
-
-    case PATHSEG_LINETO_ABS:
-      segEnd = gfxPoint(mData[i], mData[i+1]);
-      aCtx->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_LINETO_REL:
-      segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
-      aCtx->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_CUBIC_ABS:
-      cp1 = gfxPoint(mData[i], mData[i+1]);
-      cp2 = gfxPoint(mData[i+2], mData[i+3]);
-      segEnd = gfxPoint(mData[i+4], mData[i+5]);
-      aCtx->CurveTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_CUBIC_REL:
-      cp1 = segStart + gfxPoint(mData[i], mData[i+1]);
-      cp2 = segStart + gfxPoint(mData[i+2], mData[i+3]);
-      segEnd = segStart + gfxPoint(mData[i+4], mData[i+5]);
-      aCtx->CurveTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_QUADRATIC_ABS:
-      cp1 = gfxPoint(mData[i], mData[i+1]);
-      // Convert quadratic curve to cubic curve:
-      tcp1 = segStart + (cp1 - segStart) * 2 / 3;
-      segEnd = gfxPoint(mData[i+2], mData[i+3]); // set before setting tcp2!
-      tcp2 = cp1 + (segEnd - cp1) / 3;
-      aCtx->CurveTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_QUADRATIC_REL:
-      cp1 = segStart + gfxPoint(mData[i], mData[i+1]);
-      // Convert quadratic curve to cubic curve:
-      tcp1 = segStart + (cp1 - segStart) * 2 / 3;
-      segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]); // set before setting tcp2!
-      tcp2 = cp1 + (segEnd - cp1) / 3;
-      aCtx->CurveTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_ARC_ABS:
-    case PATHSEG_ARC_REL:
-    {
-      gfxPoint radii(mData[i], mData[i+1]);
-      segEnd = gfxPoint(mData[i+5], mData[i+6]);
-      if (segType == PATHSEG_ARC_REL) {
-        segEnd += segStart;
-      }
-      if (segEnd != segStart) {
-        if (radii.x == 0.0f || radii.y == 0.0f) {
-          aCtx->LineTo(segEnd);
-        } else {
-          nsSVGArcConverter converter(ToPoint(segStart), ToPoint(segEnd),
-                                      ToPoint(radii), mData[i+2],
-                                      mData[i+3] != 0, mData[i+4] != 0);
-          Point cp1, cp2, segEnd_;
-          while (converter.GetNextSegment(&cp1, &cp2, &segEnd_)) {
-            aCtx->CurveTo(ThebesPoint(cp1), ThebesPoint(cp2), ThebesPoint(segEnd_));
-          }
-          segEnd = ThebesPoint(segEnd_);
-        }
-      }
-      if (!subpathHasLength) {
-        // Round to make sure the current comparison doesn't fail due to
-        // precision issues:
-        // XXX kill after all code is converted to float precision
-        segStart = ThebesPoint(ToPoint(segStart));
-        subpathHasLength = (segEnd != segStart);
-      }
-      break;
-    }
-
-    case PATHSEG_LINETO_HORIZONTAL_ABS:
-      segEnd = gfxPoint(mData[i], segStart.y);
-      aCtx->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_LINETO_HORIZONTAL_REL:
-      segEnd = segStart + gfxPoint(mData[i], 0.0f);
-      aCtx->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_LINETO_VERTICAL_ABS:
-      segEnd = gfxPoint(segStart.x, mData[i]);
-      aCtx->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_LINETO_VERTICAL_REL:
-      segEnd = segStart + gfxPoint(0.0f, mData[i]);
-      aCtx->LineTo(segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
-      cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - cp2 : segStart;
-      cp2 = gfxPoint(mData[i],   mData[i+1]);
-      segEnd = gfxPoint(mData[i+2], mData[i+3]);
-      aCtx->CurveTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
-      cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - cp2 : segStart;
-      cp2 = segStart + gfxPoint(mData[i], mData[i+1]);
-      segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
-      aCtx->CurveTo(cp1, cp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
-      cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - cp1 : segStart;
-      // Convert quadratic curve to cubic curve:
-      tcp1 = segStart + (cp1 - segStart) * 2 / 3;
-      segEnd = gfxPoint(mData[i], mData[i+1]); // set before setting tcp2!
-      tcp2 = cp1 + (segEnd - cp1) / 3;
-      aCtx->CurveTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
-      cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - cp1 : segStart;
-      // Convert quadratic curve to cubic curve:
-      tcp1 = segStart + (cp1 - segStart) * 2 / 3;
-      segEnd = segStart + gfxPoint(mData[i], mData[i+1]); // changed before setting tcp2!
-      tcp2 = cp1 + (segEnd - cp1) / 3;
-      aCtx->CurveTo(tcp1, tcp2, segEnd);
-      if (!subpathHasLength) {
-        subpathHasLength = (segEnd != segStart || segEnd != cp1);
-      }
-      subpathContainsNonArc = true;
-      break;
-
-    default:
-      NS_NOTREACHED("Bad path segment type");
-      return; // according to spec we'd use everything up to the bad seg anyway
-    }
-    i += argCount;
-    prevSegType = segType;
-    segStart = segEnd;
-  }
-
-  NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
-  NS_ABORT_IF_FALSE(prevSegType == segType,
-                    "prevSegType should be left at the final segType");
-
-  MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
-}
-
 TemporaryRef<Path>
 SVGPathData::ToPathForLengthOrPositionMeasuring() const
 {
   // Since the path that we return will not be used for painting it doesn't
   // matter what we pass to CreatePathBuilder as aFillRule. Hawever, we do want
   // to pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as
   // aStrokeLineCap to avoid the insertion of extra little lines (by
   // ApproximateZeroLengthSubpathSquareCaps), in which case the value that we
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -15,17 +15,16 @@
 #include "mozilla/gfx/Types.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/RefPtr.h"
 #include "nsSVGElement.h"
 #include "nsTArray.h"
 
 #include <string.h>
 
-class gfxContext;
 class nsSVGPathDataParser; // IWYU pragma: keep
 
 struct nsSVGMark;
 
 namespace mozilla {
 
 /**
  * ATTENTION! WARNING! WATCH OUT!!
@@ -161,17 +160,16 @@ public:
 
   /**
    * This returns a path without the extra little line segments that
    * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
    * See the comment for that function for more info on that.
    */
   TemporaryRef<Path> ToPathForLengthOrPositionMeasuring() const;
 
-  void ConstructPath(gfxContext *aCtx) const;
   TemporaryRef<Path> BuildPath(PathBuilder* aBuilder,
                                uint8_t aCapStyle,
                                Float aStrokeWidth) const;
 
   const_iterator begin() const { return mData.Elements(); }
   const_iterator end() const { return mData.Elements() + mData.Length(); }
 
   // memory reporting methods
--- a/content/svg/content/src/SVGPathElement.cpp
+++ b/content/svg/content/src/SVGPathElement.cpp
@@ -17,18 +17,16 @@
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsStyleStruct.h"
 #include "SVGContentUtils.h"
 
-class gfxContext;
-
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Path)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
@@ -329,22 +327,16 @@ SVGPathElement::IsMarkable()
 }
 
 void
 SVGPathElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
 {
   mD.GetAnimValue().GetMarkerPositioningData(aMarks);
 }
 
-void
-SVGPathElement::ConstructPath(gfxContext *aCtx)
-{
-  mD.GetAnimValue().ConstructPath(aCtx);
-}
-
 float
 SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
 {
   NS_ABORT_IF_FALSE(aFor == eForTextPath || aFor == eForStroking,
                     "Unknown enum");
   if (mPathLength.IsExplicitlySet()) {
     float authorsPathLengthEstimate = mPathLength.GetAnimValue();
     if (authorsPathLengthEstimate > 0) {
@@ -387,17 +379,17 @@ SVGPathElement::BuildPath(PathBuilder* a
   nsRefPtr<nsStyleContext> styleContext =
     nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, nullptr);
   if (styleContext) {
     const nsStyleSVG* style = styleContext->StyleSVG();
     // Note: the path that we return may be used for hit-testing, and SVG
     // exposes hit-testing of strokes that are not actually painted. For that
     // reason we do not check for eStyleSVGPaintType_None or check the stroke
     // opacity here.
-    if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
+    if (style->mStrokeLinecap != NS_STYLE_STROKE_LINECAP_BUTT) {
       strokeLineCap = style->mStrokeLinecap;
       strokeWidth = SVGContentUtils::GetStrokeWidth(this, styleContext, nullptr);
     }
   }
 
   RefPtr<PathBuilder> builder;
   if (aBuilder) {
     builder = aBuilder;
--- a/content/svg/content/src/SVGPathElement.h
+++ b/content/svg/content/src/SVGPathElement.h
@@ -11,18 +11,16 @@
 #include "nsSVGNumber2.h"
 #include "nsSVGPathGeometryElement.h"
 #include "SVGAnimatedPathSegList.h"
 #include "DOMSVGPathSeg.h"
 
 nsresult NS_NewSVGPathElement(nsIContent **aResult,
                               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
-class gfxContext;
-
 typedef nsSVGPathGeometryElement SVGPathElementBase;
 
 namespace mozilla {
 
 class nsISVGPoint;
 
 namespace dom {
 
@@ -47,17 +45,16 @@ public:
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE;
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   /**
    * This returns a path without the extra little line segments that
    * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
    * See the comment for that function for more info on that.
    */
   virtual TemporaryRef<Path>
--- a/content/svg/content/src/SVGPathSegUtils.cpp
+++ b/content/svg/content/src/SVGPathSegUtils.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h" // MOZ_ARRAY_LENGTH
 
 #include "SVGPathSegUtils.h"
 
 #include "gfx2DGlue.h"
-#include "gfxPoint.h"
 #include "nsSVGPathDataParser.h"
 #include "nsTextFormatter.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 static const float PATH_SEG_LENGTH_TOLERANCE = 0.0000001f;
 static const uint32_t MAX_RECURSION = 10;
--- a/content/svg/content/src/SVGPolygonElement.cpp
+++ b/content/svg/content/src/SVGPolygonElement.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGPolygonElement.h"
 #include "mozilla/dom/SVGPolygonElementBinding.h"
-#include "gfxContext.h"
 #include "SVGContentUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Polygon)
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
@@ -53,19 +52,10 @@ SVGPolygonElement::GetMarkPoints(nsTArra
   startMark->angle = SVGContentUtils::AngleBisect(angle, startMark->angle);
   // for a polygon (as opposed to a polyline) there's an implicit extra point
   // co-located with the start point that nsSVGPolyElement::GetMarkPoints
   // doesn't return
   aMarks->AppendElement(nsSVGMark(startMark->x, startMark->y, startMark->angle,
                                   nsSVGMark::eEnd));
 }
 
-void
-SVGPolygonElement::ConstructPath(gfxContext *aCtx)
-{
-  SVGPolygonElementBase::ConstructPath(aCtx);
-  // the difference between a polyline and a polygon is that the
-  // polygon is closed:
-  aCtx->ClosePath();
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGPolygonElement.h
+++ b/content/svg/content/src/SVGPolygonElement.h
@@ -23,17 +23,16 @@ protected:
   explicit SVGPolygonElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx) MOZ_OVERRIDE;
   friend nsresult (::NS_NewSVGPolygonElement(nsIContent **aResult,
                                              already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGPathGeometryElement methods:
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGPolygonElement_h
--- a/content/svg/content/src/SVGRectElement.cpp
+++ b/content/svg/content/src/SVGRectElement.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGRectElement.h"
 #include "nsGkAtoms.h"
-#include "gfxContext.h"
 #include "mozilla/dom/SVGRectElementBinding.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include <algorithm>
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect)
 
 using namespace mozilla::gfx;
@@ -104,59 +103,16 @@ SVGRectElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
-void
-SVGRectElement::ConstructPath(gfxContext *aCtx)
-{
-  float x, y, width, height, rx, ry;
-
-  GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
-
-  /* In a perfect world, this would be handled by the DOM, and
-     return a DOM exception. */
-  if (width <= 0 || height <= 0)
-    return;
-
-  rx = std::max(rx, 0.0f);
-  ry = std::max(ry, 0.0f);
-
-  /* optimize the no rounded corners case */
-  if (rx == 0 && ry == 0) {
-    aCtx->Rectangle(gfxRect(x, y, width, height));
-    return;
-  }
-
-  /* If either the 'rx' or the 'ry' attribute isn't set, then we
-     have to set it to the value of the other. */
-  bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet();
-  bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet();
-  if (hasRx && !hasRy)
-    ry = rx;
-  else if (hasRy && !hasRx)
-    rx = ry;
-
-  /* Clamp rx and ry to half the rect's width and height respectively. */
-  float halfWidth  = width/2;
-  float halfHeight = height/2;
-  if (rx > halfWidth)
-    rx = halfWidth;
-  if (ry > halfHeight)
-    ry = halfHeight;
-
-  gfxSize corner(rx, ry);
-  aCtx->RoundedRectangle(gfxRect(x, y, width, height),
-                         gfxCornerSizes(corner, corner, corner, corner));
-}
-
 TemporaryRef<Path>
 SVGRectElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, width, height, rx, ry;
   GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
 
   if (width <= 0 || height <= 0) {
     return nullptr;
--- a/content/svg/content/src/SVGRectElement.h
+++ b/content/svg/content/src/SVGRectElement.h
@@ -25,17 +25,16 @@ protected:
   friend nsresult (::NS_NewSVGRectElement(nsIContent **aResult,
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Height();
--- a/content/svg/content/src/moz.build
+++ b/content/svg/content/src/moz.build
@@ -254,14 +254,15 @@ include('/ipc/chromium/chromium-config.m
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/content/html/content/src',
     '/dom',
     '/dom/smil',
     '/dom/xbl',
     '/dom/xml',
+    '/layout/base',
     '/layout/generic',
     '/layout/style',
     '/layout/svg',
     '/layout/xul',
 ]
 
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -46,16 +46,17 @@
 #include "nsIFrame.h"
 #include <stdarg.h>
 #include "nsSMILMappedAttribute.h"
 #include "SVGMotionSMILAttr.h"
 #include "nsAttrValueOrString.h"
 #include "nsSMILAnimationController.h"
 #include "mozilla/dom/SVGElementBinding.h"
 #include "mozilla/unused.h"
+#include "RestyleManager.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // This is needed to ensure correct handling of calls to the
 // vararg-list methods in this file:
 //   nsSVGElement::GetAnimated{Length,Number,Integer}Values
 // See bug 547964 for details:
@@ -911,27 +912,28 @@ nsSVGElement::WalkContentStyleRules(nsRu
 void
 nsSVGElement::WalkAnimatedContentStyleRules(nsRuleWalker* aRuleWalker)
 {
   // Update & walk the animated content style rule, to include style from
   // animated mapped attributes.  But first, get nsPresContext to check
   // whether this is a "no-animation restyle". (This should match the check
   // in nsHTMLCSSStyleSheet::RulesMatching(), where we determine whether to
   // apply the SMILOverrideStyle.)
-  nsIDocument* doc = OwnerDoc();
-  nsIPresShell* shell = doc->GetShell();
-  nsPresContext* context = shell ? shell->GetPresContext() : nullptr;
-  if (context && context->IsProcessingRestyles() &&
-      !context->IsProcessingAnimationStyleChange()) {
-    // Any style changes right now could trigger CSS Transitions. We don't
-    // want that to happen from SMIL-animated value of mapped attrs, so
-    // ignore animated value for now, and request an animation restyle to
-    // get our animated value noticed.
-    shell->RestyleForAnimation(this,
-      eRestyle_SVGAttrAnimations | eRestyle_ChangeAnimationPhase);
+  nsPresContext* context = aRuleWalker->PresContext();
+  nsIPresShell* shell = context->PresShell();
+  RestyleManager* restyleManager = context->RestyleManager();
+  if (restyleManager->SkipAnimationRules()) {
+    if (restyleManager->PostAnimationRestyles()) {
+      // Any style changes right now could trigger CSS Transitions. We don't
+      // want that to happen from SMIL-animated value of mapped attrs, so
+      // ignore animated value for now, and request an animation restyle to
+      // get our animated value noticed.
+      shell->RestyleForAnimation(this,
+        eRestyle_SVGAttrAnimations | eRestyle_ChangeAnimationPhase);
+    }
   } else {
     // Ok, this is an animation restyle -- go ahead and update/walk the
     // animated content style rule.
     css::StyleRule* animContentStyleRule = GetAnimatedContentStyleRule();
     if (!animContentStyleRule) {
       UpdateAnimatedContentStyleRule();
       animContentStyleRule = GetAnimatedContentStyleRule();
     }
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -21,18 +21,16 @@ struct nsSVGMark {
   };
 
   float x, y, angle;
   Type type;
   nsSVGMark(float aX, float aY, float aAngle, Type aType) :
     x(aX), y(aY), angle(aAngle), type(aType) {}
 };
 
-class gfxContext;
-
 typedef mozilla::dom::SVGGraphicsElement nsSVGPathGeometryElementBase;
 
 class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
 {
 protected:
   typedef mozilla::gfx::FillRule FillRule;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Path Path;
@@ -51,17 +49,16 @@ public:
    *
    * This could be moved up to a more general class so it can be used for non-leaf
    * elements, but that would require care and for now there's no need.
    */
   bool GeometryDependsOnCoordCtx();
 
   virtual bool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
-  virtual void ConstructPath(gfxContext *aCtx) = 0;
 
   /**
    * Returns a Path that can be used to paint, hit-test or calculate bounds for
    * this element. May return nullptr if there is no [valid] path.
    */
   virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) = 0;
 
   virtual mozilla::TemporaryRef<Path> GetPathForLengthOrPositionMeasuring();
--- a/content/svg/content/src/nsSVGPolyElement.cpp
+++ b/content/svg/content/src/nsSVGPolyElement.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSVGPolyElement.h"
 #include "DOMSVGPointList.h"
-#include "gfxContext.h"
 #include "mozilla/gfx/2D.h"
 #include "SVGContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 //----------------------------------------------------------------------
 // nsISupports methods
@@ -116,30 +115,16 @@ nsSVGPolyElement::GetMarkPoints(nsTArray
     px = x;
     py = y;
   }
 
   aMarks->LastElement().angle = prevAngle;
   aMarks->LastElement().type = nsSVGMark::eEnd;
 }
 
-void
-nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
-{
-  const SVGPointList &points = mPoints.GetAnimValue();
-
-  if (!points.Length())
-    return;
-
-  aCtx->MoveTo(points[0]);
-  for (uint32_t i = 1; i < points.Length(); ++i) {
-    aCtx->LineTo(points[i]);
-  }
-}
-
 TemporaryRef<Path>
 nsSVGPolyElement::BuildPath(PathBuilder* aBuilder)
 {
   const SVGPointList &points = mPoints.GetAnimValue();
 
   if (points.IsEmpty()) {
     return nullptr;
   }
--- a/content/svg/content/src/nsSVGPolyElement.h
+++ b/content/svg/content/src/nsSVGPolyElement.h
@@ -7,18 +7,16 @@
 #define NS_SVGPOLYELEMENT_H_
 
 #include "mozilla/Attributes.h"
 #include "nsSVGPathGeometryElement.h"
 #include "SVGAnimatedPointList.h"
 
 typedef nsSVGPathGeometryElement nsSVGPolyElementBase;
 
-class gfxContext;
-
 namespace mozilla {
 class DOMSVGPointList;
 }
 
 class nsSVGPolyElement : public nsSVGPolyElementBase
 {
 protected:
   explicit nsSVGPolyElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
@@ -42,17 +40,16 @@ public:
 
   // nsSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
-  virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
   virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<mozilla::DOMSVGPointList> Points();
   already_AddRefed<mozilla::DOMSVGPointList> AnimatedPoints();
 
 protected:
   SVGAnimatedPointList mPoints;
--- a/content/svg/content/src/nsSVGTransform.cpp
+++ b/content/svg/content/src/nsSVGTransform.cpp
@@ -109,19 +109,19 @@ nsSVGTransform::SetScale(float aSx, floa
   mOriginY = 0.f;
 }
 
 void
 nsSVGTransform::SetRotate(float aAngle, float aCx, float aCy)
 {
   mType    = SVG_TRANSFORM_ROTATE;
   mMatrix.Reset();
-  mMatrix.Translate(gfxPoint(aCx, aCy));
+  mMatrix.Translate(aCx, aCy);
   mMatrix.Rotate(aAngle*kRadPerDegree);
-  mMatrix.Translate(gfxPoint(-aCx, -aCy));
+  mMatrix.Translate(-aCx, -aCy);
   mAngle   = aAngle;
   mOriginX = aCx;
   mOriginY = aCy;
 }
 
 nsresult
 nsSVGTransform::SetSkewX(float aAngle)
 {
--- a/dom/apps/Webapps.js
+++ b/dom/apps/Webapps.js
@@ -607,31 +607,31 @@ WebappsApplication.prototype = {
         break;
       case "Webapps:ClearBrowserData:Return":
         this.removeMessageListeners(aMessage.name);
         Services.DOMRequest.fireSuccess(req, null);
         break;
       case "Webapps:Connect:Return:OK":
         this.removeMessageListeners(["Webapps:Connect:Return:OK",
                                      "Webapps:Connect:Return:KO"]);
-        let messagePorts = [];
+        let messagePorts = new this._window.Array();
         msg.messagePortIDs.forEach((aPortID) => {
           let port = new this._window.MozInterAppMessagePort(aPortID);
           messagePorts.push(port);
         });
         req.resolve(messagePorts);
         break;
       case "Webapps:Connect:Return:KO":
         this.removeMessageListeners(["Webapps:Connect:Return:OK",
                                      "Webapps:Connect:Return:KO"]);
         req.reject("No connections registered");
         break;
       case "Webapps:GetConnections:Return:OK":
         this.removeMessageListeners(aMessage.name);
-        let connections = [];
+        let connections = new this._window.Array();
         msg.connections.forEach((aConnection) => {
           let connection =
             new this._window.MozInterAppConnection(aConnection.keyword,
                                                    aConnection.pubAppManifestURL,
                                                    aConnection.subAppManifestURL);
           connections.push(connection);
         });
         req.resolve(connections);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2112,17 +2112,24 @@ nsDOMWindowUtils::SendCompositionEvent(c
   }
 
   uint32_t msg;
   if (aType.EqualsLiteral("compositionstart")) {
     msg = NS_COMPOSITION_START;
   } else if (aType.EqualsLiteral("compositionend")) {
     msg = NS_COMPOSITION_END;
   } else if (aType.EqualsLiteral("compositionupdate")) {
-    msg = NS_COMPOSITION_UPDATE;
+    // Now we don't support manually dispatching composition update with this
+    // API.  compositionupdate is dispatched when text event modifies
+    // composition string automatically.  For backward compatibility, this
+    // shouldn't return error in this case.
+    NS_WARNING("Don't call nsIDOMWindowUtils.sendCompositionEvent() for "
+               "compositionupdate since it's ignored and the event is "
+               "fired automatically when it's necessary");
+    return NS_OK;
   } else {
     return NS_ERROR_FAILURE;
   }
 
   WidgetCompositionEvent compositionEvent(true, msg, widget);
   InitEvent(compositionEvent);
   if (msg != NS_COMPOSITION_START) {
     compositionEvent.data = aData;
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -118,18 +118,20 @@ public:
   /**
    * Update the wrapper if the object it contains is moved.
    *
    * This method must be called from the objectMovedOp class extension hook for
    * any wrapper cached object.
    */
   void UpdateWrapper(JSObject* aNewObject, const JSObject* aOldObject)
   {
-    MOZ_ASSERT(mWrapper == aOldObject);
-    mWrapper = aNewObject;
+    if (mWrapper) {
+      MOZ_ASSERT(mWrapper == aOldObject);
+      mWrapper = aNewObject;
+    }
   }
 
   bool PreservingWrapper()
   {
     return HasWrapperFlag(WRAPPER_BIT_PRESERVED);
   }
 
   void SetIsDOMBinding()
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1590,27 +1590,20 @@ GetPropertyOnPrototype(JSContext* cx, JS
   *vp = value;
   return true;
 }
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id)
 {
-  JS::Rooted<JSObject*> obj(cx, proxy);
-  Maybe<JSAutoCompartment> ac;
-  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
-    obj = js::UncheckedUnwrap(obj);
-    ac.emplace(cx, obj);
-  }
-
   bool found;
   // We ignore an error from GetPropertyOnPrototype.  We pass nullptr
   // for vp so that GetPropertyOnPrototype won't actually do a get.
-  return !GetPropertyOnPrototype(cx, obj, id, &found, nullptr) || found;
+  return !GetPropertyOnPrototype(cx, proxy, id, &found, nullptr) || found;
 }
 
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                        nsTArray<nsString>& names,
                        bool shadowPrototypeProperties,
                        JS::AutoIdVector& props)
 {
--- a/dom/bluetooth/tests/marionette/head.js
+++ b/dom/bluetooth/tests/marionette/head.js
@@ -38,18 +38,25 @@ const REMOTE_DEVICE_NAME = "Remote_BT_De
 
 // A system message signature of pairing request event
 const BT_PAIRING_REQ = "bluetooth-pairing-request";
 
 // Passkey and pincode used to reply pairing requst
 const BT_PAIRING_PASSKEY = 123456;
 const BT_PAIRING_PINCODE = "ABCDEFG";
 
-let Promise =
-  SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 let bluetoothManager;
 
 let pendingEmulatorCmdCount = 0;
 
 /**
  * Send emulator command with safe guard.
  *
--- a/dom/bluetooth2/tests/marionette/head.js
+++ b/dom/bluetooth2/tests/marionette/head.js
@@ -31,18 +31,25 @@ const EMULATOR_CLASS = 0x58020c;
 // which were defined at external/qemu/hw/bt.h:
 const BDADDR_ANY   = "00:00:00:00:00:00";
 const BDADDR_ALL   = "ff:ff:ff:ff:ff:ff";
 const BDADDR_LOCAL = "ff:ff:ff:00:00:00";
 
 // A user friendly name for remote BT device.
 const REMOTE_DEVICE_NAME = "Remote_BT_Device";
 
-let Promise =
-  SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 let bluetoothManager;
 
 let pendingEmulatorCmdCount = 0;
 
 /**
  * Push required permissions and test if |navigator.mozBluetooth| exists.
  * Resolve if it does, reject otherwise.
--- a/dom/cellbroadcast/tests/marionette/head.js
+++ b/dom/cellbroadcast/tests/marionette/head.js
@@ -1,14 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
 
-let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 const PDU_DCS_CODING_GROUP_BITS          = 0xF0;
 const PDU_DCS_MSG_CODING_7BITS_ALPHABET  = 0x00;
 const PDU_DCS_MSG_CODING_8BITS_ALPHABET  = 0x04;
 const PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08;
 
 const PDU_DCS_MSG_CLASS_BITS             = 0x03;
 const PDU_DCS_MSG_CLASS_NORMAL           = 0xFF;
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -815,17 +815,16 @@ EventStateManager::PreHandleEvent(nsPres
       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
       WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT,
                                            compositionEvent->widget);
       DoQuerySelectedText(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compositionEvent->data = selectedText.mReply.mString;
     }
     // through to compositionend handling
-  case NS_COMPOSITION_UPDATE:
   case NS_COMPOSITION_END:
     {
       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
       if (IsTargetCrossProcess(compositionEvent)) {
         // Will not be handled locally, remote the event
         if (GetCrossProcessTarget()->SendCompositionEvent(*compositionEvent)) {
           // Cancel local dispatching
           aEvent->mFlags.mPropagationStopped = true;
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -903,16 +903,19 @@ IMEStateManager::DispatchCompositionEven
      GetBoolName(aIsSynthesized)));
 
   MOZ_ASSERT(aEvent->mClass == eCompositionEventClass ||
              aEvent->mClass == eTextEventClass);
   if (!aEvent->mFlags.mIsTrusted || aEvent->mFlags.mPropagationStopped) {
     return;
   }
 
+  MOZ_ASSERT(aEvent->message != NS_COMPOSITION_UPDATE,
+             "compositionupdate event shouldn't be dispatched manually");
+
   EnsureTextCompositionArray();
 
   WidgetGUIEvent* GUIEvent = aEvent->AsGUIEvent();
 
   nsRefPtr<TextComposition> composition =
     sTextCompositions->GetCompositionFor(GUIEvent->widget);
   if (!composition) {
     // If synthesized event comes after delayed native composition events
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -76,26 +76,19 @@ TextComposition::MaybeDispatchCompositio
                                            aEvent->widget);
   compositionUpdate.time = aEvent->time;
   compositionUpdate.timeStamp = aEvent->timeStamp;
   compositionUpdate.data = aEvent->theText;
   compositionUpdate.mFlags.mIsSynthesizedForTests =
     aEvent->mFlags.mIsSynthesizedForTests;
 
   nsEventStatus status = nsEventStatus_eConsumeNoDefault;
-  if (aEvent->mFlags.mIsSynthesizedForTests &&
-      (mIsRequestingCommit || mIsRequestingCancel)) {
-    // At emulating commit/cancel request, compositionupdate should be
-    // dispatched via widget since it's more similar path to native event.
-    aEvent->widget->DispatchEvent(&compositionUpdate, status);
-  } else {
-    mLastData = compositionUpdate.data;
-    EventDispatcher::Dispatch(mNode, mPresContext,
-                              &compositionUpdate, nullptr, &status, nullptr);
-  }
+  mLastData = compositionUpdate.data;
+  EventDispatcher::Dispatch(mNode, mPresContext,
+                            &compositionUpdate, nullptr, &status, nullptr);
   return !Destroyed();
 }
 
 void
 TextComposition::OnCompositionEventDiscarded(const WidgetGUIEvent* aEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
@@ -147,17 +140,16 @@ TextComposition::DispatchEvent(WidgetGUI
   // They typically tell us an IDEOGRAPHIC SPACE or empty string as composition
   // string.  Therefore, we should hack it only when:
   // 1. committing string is empty string at requesting commit but the last
   //    data isn't IDEOGRAPHIC SPACE.
   // 2. non-empty string is committed at requesting cancel.
   if (!aIsSynthesized && (mIsRequestingCommit || mIsRequestingCancel)) {
     nsString* committingData = nullptr;
     switch (aEvent->message) {
-      case NS_COMPOSITION_UPDATE:
       case NS_COMPOSITION_END:
         committingData = &aEvent->AsCompositionEvent()->data;
         break;
       case NS_TEXT_TEXT:
         committingData = &aEvent->AsTextEvent()->theText;
         break;
       default:
         NS_WARNING("Unexpected event comes during committing or "
@@ -166,36 +158,23 @@ TextComposition::DispatchEvent(WidgetGUI
     }
     if (committingData) {
       if (mIsRequestingCommit && committingData->IsEmpty() &&
           mLastData != IDEOGRAPHIC_SPACE) {
         committingData->Assign(mLastData);
       } else if (mIsRequestingCancel && !committingData->IsEmpty()) {
         committingData->Truncate();
       }
-
-      if (aEvent->message == NS_COMPOSITION_UPDATE) {
-        // If committing string is not different from the last data,
-        // we don't need to dispatch this.
-        if (committingData->Equals(mLastData)) {
-          return;
-        }
-      } else if (aEvent->message == NS_TEXT_TEXT) {
-        // If committing string is different from the last data,
-        // we need to dispatch compositionupdate before dispatching text event.
-        if (!MaybeDispatchCompositionUpdate(aEvent->AsTextEvent())) {
-          NS_WARNING("Dispatching compositionupdate caused destroying");
-          return;
-        }
-      }
     }
   }
 
-  if (aEvent->message == NS_COMPOSITION_UPDATE) {
-    mLastData = aEvent->AsCompositionEvent()->data;
+  if (aEvent->message == NS_TEXT_TEXT) {
+    if (!MaybeDispatchCompositionUpdate(aEvent->AsTextEvent())) {
+      return;
+    }
   }
 
   EventDispatcher::Dispatch(mNode, mPresContext,
                             aEvent, nullptr, aStatus, aCallBack);
 
   if (NS_WARN_IF(Destroyed())) {
     return;
   }
@@ -336,25 +315,21 @@ TextComposition::RequestToCommit(nsIWidg
 
   // If the request is performed synchronously, this must be already destroyed.
   if (Destroyed()) {
     return NS_OK;
   }
 
   // Otherwise, synthesize the commit in content.
   nsAutoString data(aDiscard ? EmptyString() : lastData);
-  bool changingData = lastData != data;
-  if (changingData) {
-    DispatchCompositionEventRunnable(NS_COMPOSITION_UPDATE, data, true);
-  }
   // If the last composition string and new data are different, we need to
   // dispatch text event for removing IME selection.  However, if the commit
   // string is empty string and it's not changed from the last data, we don't
   // need to dispatch text event.
-  if (changingData || !data.IsEmpty()) {
+  if (lastData != data || !data.IsEmpty()) {
     DispatchCompositionEventRunnable(NS_TEXT_TEXT, data, true);
   }
   DispatchCompositionEventRunnable(NS_COMPOSITION_END, data, true);
 
   return NS_OK;
 }
 
 nsresult
@@ -463,17 +438,16 @@ TextComposition::CompositionEventDispatc
       compStart.data = selectedText.mReply.mString;
       compStart.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compStart, &status, nullptr,
                                                 mIsSynthesizedEvent);
       break;
     }
-    case NS_COMPOSITION_UPDATE:
     case NS_COMPOSITION_END: {
       WidgetCompositionEvent compEvent(true, mEventMessage, widget);
       compEvent.data = mData;
       compEvent.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compEvent, &status, nullptr,
                                                 mIsSynthesizedEvent);
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -309,17 +309,17 @@ private:
    * DispatchCompositionEventRunnable() dispatches a composition or text event
    * to the content.  Be aware, if you use this method, nsPresShellEventCB
    * isn't used.  That means that nsIFrame::HandleEvent() is never called.
    * WARNING: The instance which is managed by IMEStateManager may be
    *          destroyed by this method call.
    *
    * @param aEventMessage       Must be one of composition event or text event.
    * @param aData               Used for data value if aEventMessage is
-   *                            NS_COMPOSITION_UPDATE or NS_COMPOSITION_END.
+   *                            NS_COMPOSITION_END.
    *                            Used for theText value if aEventMessage is
    *                            NS_TEXT_TEXT.
    * @param aIsSynthesizingCommit   true if this is called for synthesizing
    *                                commit or cancel composition.  Otherwise,
    *                                false.
    */
   void DispatchCompositionEventRunnable(uint32_t aEventMessage,
                                         const nsAString& aData,
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -1175,17 +1175,16 @@ function replaceSurroundingText(element,
     // Insert the text to be replaced with.
     editor.insertText(text);
   }
   return true;
 }
 
 let CompositionManager =  {
   _isStarted: false,
-  _text: '',
   _clauseAttrMap: {
     'raw-input':
       Ci.nsICompositionStringSynthesizer.ATTR_RAWINPUT,
     'selected-raw-text':
       Ci.nsICompositionStringSynthesizer.ATTR_SELECTEDRAWTEXT,
     'converted-text':
       Ci.nsICompositionStringSynthesizer.ATTR_CONVERTEDTEXT,
     'selected-converted-text':
@@ -1228,56 +1227,46 @@ let CompositionManager =  {
       clauseLens.push(len);
       clauseAttrs.push(Ci.nsICompositionStringSynthesizer.ATTR_RAWINPUT);
     }
 
     // Start composition if need to.
     if (!this._isStarted) {
       this._isStarted = true;
       domWindowUtils.sendCompositionEvent('compositionstart', '', '');
-      this._text = '';
     }
 
     // Update the composing text.
-    if (this._text !== text) {
-      this._text = text;
-      domWindowUtils.sendCompositionEvent('compositionupdate', text, '');
-    }
     let compositionString = domWindowUtils.createCompositionStringSynthesizer();
     compositionString.setString(text);
     for (var i = 0; i < clauseLens.length; i++) {
       compositionString.appendClause(clauseLens[i], clauseAttrs[i]);
     }
     if (cursor >= 0) {
       compositionString.setCaret(cursor, 0);
     }
     compositionString.dispatchEvent();
   },
 
   endComposition: function cm_endComposition(text) {
     if (!this._isStarted) {
       return;
     }
     // Update the composing text.
-    if (this._text !== text) {
-      domWindowUtils.sendCompositionEvent('compositionupdate', text, '');
-    }
     let compositionString = domWindowUtils.createCompositionStringSynthesizer();
     compositionString.setString(text);
     // Set the cursor position to |text.length| so that the text will be
     // committed before the cursor position.
     compositionString.setCaret(text.length, 0);
     compositionString.dispatchEvent();
     domWindowUtils.sendCompositionEvent('compositionend', text, '');
-    this._text = '';
     this._isStarted = false;
   },
 
   // Composition ends due to external actions.
   onCompositionEnd: function cm_onCompositionEnd() {
     if (!this._isStarted) {
       return;
     }
 
-    this._text = '';
     this._isStarted = false;
   }
 };
--- a/dom/ipc/tests/test_CrashService_crash.html
+++ b/dom/ipc/tests/test_CrashService_crash.html
@@ -50,37 +50,37 @@ SpecialPowers.pushPrefEnv({'set':[
       };
       privateNoteIntentionalCrash();
       crash();
     }, false);
 
     // Finally, poll for the new crash record.
     function tryGetCrash() {
       info("Waiting for getCrashes");
-      crashMan.getCrashes().then(function (crashes) {
+      crashMan.getCrashes().then(SpecialPowers.wrapCallback(function (crashes) {
         if (crashes.length) {
           is(crashes.length, 1, "There should be only one record");
-          var crash = SpecialPowers.wrap(crashes[0]);
+          var crash = crashes[0];
           ok(crash.isOfType(crashMan.PROCESS_TYPE_CONTENT,
                             crashMan.CRASH_TYPE_CRASH),
              "Record should be a content crash");
           ok(!!crash.id, "Record should have an ID");
           ok(!!crash.crashDate, "Record should have a crash date");
           var dateMS = crash.crashDate.valueOf();
           var twoMin = 1000 * 60 * 2;
           ok(crashDateMS - twoMin <= dateMS &&
              dateMS <= crashDateMS + twoMin,
              "Record's crash date should be nowish: " +
              "now=" + crashDateMS + " recordDate=" + dateMS);
           SimpleTest.finish();
         }
         else {
           setTimeout(tryGetCrash, 1000);
         }
-      }, function (err) {
+      }), function (err) {
         ok(false, "Error getting crashes: " + err);
         SimpleTest.finish();
       });
     }
     setTimeout(tryGetCrash, 1000);
 
   }, function () {
     ok(false, "pruneOldCrashes error");
--- a/dom/mobilemessage/tests/marionette/head.js
+++ b/dom/mobilemessage/tests/marionette/head.js
@@ -1,14 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
 
-let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 /**
  * Push a list of preference settings. Never reject.
  *
  * Fulfill params: (none)
  *
  * @param aPrefs
  *        An JS object.  For example:
--- a/dom/permission/tests/file_framework.js
+++ b/dom/permission/tests/file_framework.js
@@ -163,21 +163,19 @@ function addPermissions(aPerms, aDoc, aC
   });
   SpecialPowers.pushPermissions(permList, aCallback);
 }
 
 function expandPermissions(aPerms) {
   var perms = [];
   aPerms.forEach(function(el) {
     var access = permTable[el].access ? "readwrite" : null;
-    var expanded = SpecialPowers.unwrap(expand(el, access));
-    // COW arrays don't behave array-like enough, to allow
-    // using expanded.slice(0) here.
+    var expanded = expand(el, access);
     for (let i = 0; i < expanded.length; i++) {
-      perms.push(expanded[i]);
+      perms.push(SpecialPowers.unwrap(expanded[i]));
     }
   });
 
   return perms;
 }
 
 function msgHandler(evt) {
   var data = evt.data;
--- a/dom/plugins/test/mochitest/utils.js
+++ b/dom/plugins/test/mochitest/utils.js
@@ -64,34 +64,34 @@ function crashAndGetCrashServiceRecord(c
     catch (e) {
       ok(true, "p." + crashMethodName + "() should throw an exception");
     }
 
     // The crash record store is written and read back asyncly, so poll for
     // the new record.
     function tryGetCrash() {
       info("Waiting for getCrashes");
-      crashMan.getCrashes().then(function (crashes) {
+      crashMan.getCrashes().then(SpecialPowers.wrapCallback(function (crashes) {
         if (crashes.length) {
           is(crashes.length, 1, "There should be only one record");
           var crash = SpecialPowers.wrap(crashes[0]);
           ok(!!crash.id, "Record should have an ID");
           ok(!!crash.crashDate, "Record should have a crash date");
           var dateMS = crash.crashDate.valueOf();
           var twoMin = 1000 * 60 * 2;
           ok(crashDateMS - twoMin <= dateMS &&
              dateMS <= crashDateMS + twoMin,
              "Record's crash date should be nowish: " +
              "now=" + crashDateMS + " recordDate=" + dateMS);
           callback(crashMan, crash);
         }
         else {
           setTimeout(tryGetCrash, 1000);
         }
-      }, function (err) {
+      }), function (err) {
         ok(false, "Error getting crashes: " + err);
         SimpleTest.finish();
       });
     }
     setTimeout(tryGetCrash, 1000);
 
   }, function () {
     ok(false, "pruneOldCrashes error");
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -410,31 +410,45 @@ WifiGeoPositionProvider.prototype = {
     LOG("getMobileInfo called");
     try {
       let radioService = Cc["@mozilla.org/ril;1"]
                     .getService(Ci.nsIRadioInterfaceLayer);
       let service = Cc["@mozilla.org/mobileconnection/mobileconnectionservice;1"]
                     .getService(Ci.nsIMobileConnectionService);
 
       let result = [];
-      for (let i = 0; i < service.length; i++) {
-        LOG("Looking for SIM in slot:" + i + " of " + service.length);
+      for (let i = 0; i < service.numItems; i++) {
+        LOG("Looking for SIM in slot:" + i + " of " + service.numItems);
         let connection = service.getItemByServiceId(i);
         let voice = connection && connection.voice;
         let cell = voice && voice.cell;
         let type = voice && voice.type;
         let network = voice && voice.network;
 
         if (network && cell && type) {
-          if (type === "gsm" || type === "gprs" || type === "edge") {
-            type = "gsm";
-          } else {
-            type = "wcdma";
-          }
-          result.push({ radio: type,
+          let radioTechFamily;
+          switch (type) {
+            case "gsm":
+            case "gprs":
+            case "edge":
+              radioTechFamily = "gsm";
+              break;
+            case "umts":
+            case "hsdpa":
+            case "hsupa":
+            case "hspa":
+            case "hspa+":
+              radioTechFamily = "wcdma";
+              break;
+            case "lte":
+              radioTechFamily = "lte";
+              break;
+            // CDMA cases to be handled in bug 1010282
+          };
+          result.push({ radio: radioTechFamily,
                       mobileCountryCode: voice.network.mcc,
                       mobileNetworkCode: voice.network.mnc,
                       locationAreaCode: cell.gsmLocationAreaCode,
                       cellId: cell.gsmCellId });
         }
       }
       return result;
     } catch (e) {
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -794,32 +794,33 @@ RILContentHelper.prototype = {
     if (message.errorMsg) {
       this.fireRequestError(message.requestId, message.errorMsg);
       return;
     }
 
     let window = this._windowsMap[message.requestId];
     delete this._windowsMap[message.requestId];
     let contacts = message.contacts;
-    let result = contacts.map(function(c) {
+    let result = new window.Array();
+    contacts.forEach(function(c) {
       let prop = {name: [c.alphaId], tel: [{value: c.number}]};
 
       if (c.email) {
         prop.email = [{value: c.email}];
       }
 
       // ANR - Additional Number
       let anrLen = c.anr ? c.anr.length : 0;
       for (let i = 0; i < anrLen; i++) {
         prop.tel.push({value: c.anr[i]});
       }
 
       let contact = new window.mozContact(prop);
       contact.id = c.contactId;
-      return contact;
+      result.push(contact);
     });
 
     this.fireRequestSuccess(message.requestId, result);
   },
 
   handleUpdateIccContact: function(message) {
     if (message.errorMsg) {
       this.fireRequestError(message.requestId, message.errorMsg);
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -1,12 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let Promise = SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
+
 let telephony;
 let conference;
 
 const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
 
 /**
  * Emulator helper.
  */
--- a/dom/tethering/tests/marionette/head.js
+++ b/dom/tethering/tests/marionette/head.js
@@ -20,18 +20,25 @@ const TETHERING_SETTING_DNS2 = "8.8.4.4"
  * Wifi tethering setting.
  */
 const TETHERING_SETTING_SSID = "FirefoxHotSpot";
 const TETHERING_SETTING_SECURITY = "open";
 const TETHERING_SETTING_KEY = "1234567890";
 
 const SETTINGS_RIL_DATA_ENABLED = 'ril.data.enabled';
 
-let Promise =
-  SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 let gTestSuite = (function() {
   let suite = {};
 
   let tetheringManager;
   let pendingEmulatorShellCount = 0;
 
   /**
--- a/dom/voicemail/test/marionette/head.js
+++ b/dom/voicemail/test/marionette/head.js
@@ -1,19 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
 
-let RIL = {};
-Cu.import("resource://gre/modules/ril_consts.js", RIL);
+let RIL = SpecialPowers.wrap(SpecialPowers.createBlankObject());
+SpecialPowers.Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
-let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 const MWI_PDU_PREFIX = "0000";
 const MWI_PDU_UDH_PREFIX = "0040";
 const MWI_PID_DEFAULT = "00";
 const MWI_DCS_DISCARD_INACTIVE = "C0";
 const MWI_DCS_DISCARD_ACTIVE = "C8";
 const MWI_TIMESTAMP = "00000000000000";
 
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -155,17 +155,17 @@ DOMWifiManager.prototype = {
   },
 
   _convertWifiNetwork: function(aNetwork) {
     let network = aNetwork ? new this._window.MozWifiNetwork(aNetwork) : null;
     return network;
   },
 
   _convertWifiNetworks: function(aNetworks) {
-    let networks = [];
+    let networks = new this._window.Array();
     for (let i in aNetworks) {
       networks.push(this._convertWifiNetwork(aNetworks[i]));
     }
     return networks;
   },
 
   _convertConnection: function(aConn) {
     let conn = aConn ? new MozWifiConnection(aConn) : null;
--- a/dom/wifi/test/marionette/head.js
+++ b/dom/wifi/test/marionette/head.js
@@ -1,12 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let Promise = SpecialPowers.Cu.import('resource://gre/modules/Promise.jsm').Promise;
+// Emulate Promise.jsm semantics.
+Promise.defer = function() { return new Deferred(); }
+function Deferred()  {
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+  Object.freeze(this);
+}
 
 const STOCK_HOSTAPD_NAME = 'goldfish-hostapd';
 const HOSTAPD_CONFIG_PATH = '/data/misc/wifi/remote-hostapd/';
 
 const SETTINGS_RIL_DATA_ENABLED = 'ril.data.enabled';
 const SETTINGS_TETHERING_WIFI_ENABLED = 'tethering.wifi.enabled';
 const SETTINGS_TETHERING_WIFI_IP = 'tethering.wifi.ip';
 const SETTINGS_TETHERING_WIFI_SECURITY = 'tethering.wifi.security.type';
--- a/editor/libeditor/tests/test_bug1026397.html
+++ b/editor/libeditor/tests/test_bug1026397.html
@@ -42,17 +42,16 @@ function runTests()
     input.selectionStart = input.selectionEnd = aCaretOffset;
     if (aAdditionalExplanation) {
       aAdditionalExplanation = " " + aAdditionalExplanation;
     } else {
       aAdditionalExplanation = "";
     }
 
     synthesizeComposition({ type: "compositionstart" });
-    synthesizeComposition({ type: "compositionupdate", data: aInsertString });
     synthesizeText(
       { "composition":
         { "string": aInsertString,
           "clauses":
           [
             { "length": aInsertString.length, "attr": COMPOSITION_ATTR_RAWINPUT }
           ]
         },
--- a/editor/libeditor/tests/test_bug697842.html
+++ b/editor/libeditor/tests/test_bug697842.html
@@ -48,31 +48,29 @@ function runTests()
     editor.addEventListener("compositionupdate", handler, true);
     editor.addEventListener("text", handler, true);
 
     // start composition
     synthesizeComposition({ type: "compositionstart" });
 
     // input first character
     composingString = "\u306B";
-    synthesizeComposition({ type: "compositionupdate", data: composingString });
     synthesizeText(
       { "composition":
         { "string": composingString,
           "clauses":
           [
             { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
           ]
         },
         "caret": { "start": 1, "length": 0 }
       });
 
     // input second character
     composingString = "\u306B\u3085";
-    synthesizeComposition({ type: "compositionupdate", data: composingString });
     synthesizeText(
       { "composition":
         { "string": composingString,
           "clauses":
           [
             { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
           ]
         },
--- a/editor/libeditor/tests/test_bug795785.html
+++ b/editor/libeditor/tests/test_bug795785.html
@@ -117,30 +117,28 @@ function doCompositionTest(aElement, aEl
     var str = "Web \u958b\u767a\u8005\u306e\u7686\u3055\u3093\u306f\u3001" +
               "Firefox \u306b\u5b9f\u88c5\u3055\u308c\u3066\u3044\u308b HTML5" +
               " \u3084 CSS \u306e\u65b0\u6a5f\u80fd\u3092\u6d3b\u7528\u3059" +
               "\u308b\u3053\u3068\u3067\u3001\u9b45\u529b\u3042\u308b Web " +
               "\u30b5\u30a4\u30c8\u3084\u9769\u65b0\u7684\u306a Web \u30a2" +
               "\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u3088\u308a" +
               "\u77ed\u6642\u9593\u3067\u7c21\u5358\u306b\u4f5c\u6210\u3067" +
               "\u304d\u307e\u3059\u3002";
-    synthesizeComposition({ type: "compositionupdate", data: str });
     synthesizeText({
         composition: {
           string: str,
           clauses: [
             { length: str.length, attr: COMPOSITION_ATTR_RAWINPUT }
           ]
         },
         caret: { start: str.length, length: 0 }
       });
     hitEventLoop(function () {
       isnot(aElement.scrollTop, 0,
             aElementDescription + " was not scrolled by composition");
-      synthesizeComposition({ type: "compositionupdate", data: "" });
       synthesizeText({
         composition: { string: "", clauses: [ { length: 0, attr: 0 } ] },
         caret: { start: 0, length: 0 }
       });
       synthesizeComposition({ type: "compositionend", data: "" });
       hitEventLoop(function () {
         is(aElement.scrollTop, 0,
            aElementDescription + " was not scrolled back to the top by canceling composition");
--- a/editor/libeditor/tests/test_contenteditable_text_input_handling.html
+++ b/editor/libeditor/tests/test_contenteditable_text_input_handling.html
@@ -217,17 +217,16 @@ function runTests()
     if (!aFocus._isEditable) {
       return;
     }
 
     // IME
     // start composition
     synthesizeComposition({ type: "compositionstart" });
     // input first character
-    synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
     synthesizeText(
       { "composition":
         { "string": "\u3089",
           "clauses":
           [
             { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
           ]
         },
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -2362,17 +2362,19 @@ DrawTargetD2D::CreateBrushForPattern(con
     }
 
     RefPtr<ID2D1Bitmap> bitmap;
 
     Matrix mat = pat->mMatrix;
 
     RefPtr<SourceSurface> source = pat->mSurface;
 
-    if (!pat->mSamplingRect.IsEmpty()) {
+    if (!pat->mSamplingRect.IsEmpty() &&
+        (source->GetType() == SurfaceType::D2D1_BITMAP ||
+         source->GetType() == SurfaceType::D2D1_DRAWTARGET)) {
       IntRect samplingRect = pat->mSamplingRect;
 
       RefPtr<DrawTargetD2D> dt = new DrawTargetD2D();
       if (!dt->Init(samplingRect.Size(),
                     source->GetFormat())) {
         MOZ_ASSERT("Invalid sampling rect size!");
         return nullptr;
       }
@@ -2406,17 +2408,22 @@ DrawTargetD2D::CreateBrushForPattern(con
     default:
       {
         RefPtr<DataSourceSurface> dataSurf = source->GetDataSurface();
         if (!dataSurf) {
           gfxWarning() << "Invalid surface type.";
           return nullptr;
         }
 
-        bitmap = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, pat->mExtendMode, mat, mRT); 
+        IntRect sourceRect = pat->mSamplingRect;
+        if (sourceRect.IsEmpty()) {
+          sourceRect = IntRect(0, 0, source->GetSize().width, source->GetSize().height);
+        }
+
+        bitmap = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, pat->mExtendMode, mat, mRT, &sourceRect);
         if (!bitmap) {
           return nullptr;
         }
       }
       break;
     }
     
     mRT->CreateBitmapBrush(bitmap,
--- a/gfx/2d/HelpersD2D.h
+++ b/gfx/2d/HelpersD2D.h
@@ -508,17 +508,18 @@ CreateStrokeStyleForOptions(const Stroke
 }
 
 // This creates a (partially) uploaded bitmap for a DataSourceSurface. It
 // uploads the minimum requirement and possibly downscales. It adjusts the
 // input Matrix to compensate.
 static TemporaryRef<ID2D1Bitmap>
 CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestinationTransform,
                               const IntSize &aDestinationSize, ExtendMode aExtendMode,
-                              Matrix &aSourceTransform, ID2D1RenderTarget *aRT)
+                              Matrix &aSourceTransform, ID2D1RenderTarget *aRT,
+                              const IntRect* aSourceRect = nullptr)
 {
   RefPtr<ID2D1Bitmap> bitmap;
 
   // This is where things get complicated. The source surface was
   // created for a surface that was too large to fit in a texture.
   // We'll need to figure out if we can work with a partial upload
   // or downsample in software.
 
@@ -533,16 +534,19 @@ CreatePartialBitmapForSurface(DataSource
 
   // Calculate the rectangle of the source mapped to our surface.
   rect = invTransform.TransformBounds(rect);
   rect.RoundOut();
 
   IntSize size = aSurface->GetSize();
 
   Rect uploadRect(0, 0, Float(size.width), Float(size.height));
+  if (aSourceRect) {
+    uploadRect = Rect(aSourceRect->x, aSourceRect->y, aSourceRect->width, aSourceRect->height);
+  }
 
   // Limit the uploadRect as much as possible without supporting discontiguous uploads 
   //
   //                               region we will paint from
   //   uploadRect
   //   .---------------.              .---------------.         resulting uploadRect
   //   |               |rect          |               |
   //   |          .---------.         .----.     .----.          .---------------.
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -109,17 +109,17 @@ struct LayerPropertiesBase : public Laye
   {
     MOZ_COUNT_CTOR(LayerPropertiesBase);
     if (aLayer->GetMaskLayer()) {
       mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer());
     }
     if (mUseClipRect) {
       mClipRect = *aLayer->GetClipRect();
     }
-    mTransform = aLayer->GetTransform();
+    mTransform = aLayer->GetLocalTransform();
   }
   LayerPropertiesBase()
     : mLayer(nullptr)
     , mMaskLayer(nullptr)
   {
     MOZ_COUNT_CTOR(LayerPropertiesBase);
   }
   ~LayerPropertiesBase()
@@ -131,17 +131,17 @@ struct LayerPropertiesBase : public Laye
                                          NotifySubDocInvalidationFunc aCallback,
                                          bool* aGeometryChanged);
 
   virtual void MoveBy(const nsIntPoint& aOffset);
 
   nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback,
                             bool& aGeometryChanged)
   {
-    bool transformChanged = !mTransform.FuzzyEqual(mLayer->GetTransform()) ||
+    bool transformChanged = !mTransform.FuzzyEqual(mLayer->GetLocalTransform()) ||
                             mLayer->GetPostXScale() != mPostXScale ||
                             mLayer->GetPostYScale() != mPostYScale;
     Layer* otherMask = mLayer->GetMaskLayer();
     const nsIntRect* otherClip = mLayer->GetClipRect();
     nsIntRegion result;
     if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
         (mUseClipRect != !!otherClip) ||
         mLayer->GetLocalOpacity() != mOpacity ||
@@ -178,17 +178,17 @@ struct LayerPropertiesBase : public Laye
     }
 
     mLayer->ClearInvalidRect();
     return result;
   }
 
   nsIntRect NewTransformedBounds()
   {
-    return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetTransform());
+    return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetLocalTransform());
   }
 
   nsIntRect OldTransformedBounds()
   {
     return TransformRect(mVisibleRegion.GetBounds(), mTransform);
   }
 
   virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
@@ -285,17 +285,17 @@ struct ContainerLayerProperties : public
           invalidateChildsCurrentArea = true;
         }
       } else {
         // |child| is new, or was reordered to a higher index
         invalidateChildsCurrentArea = true;
       }
       if (invalidateChildsCurrentArea) {
         aGeometryChanged = true;
-        AddTransformedRegion(result, child->GetVisibleRegion(), child->GetTransform());
+        AddTransformedRegion(result, child->GetVisibleRegion(), child->GetLocalTransform());
         if (aCallback) {
           NotifySubdocumentInvalidationRecursive(child, aCallback);
         } else {
           ClearInvalidations(child);
         }
       }
     }
 
@@ -304,17 +304,17 @@ struct ContainerLayerProperties : public
       AddRegion(result, mChildren[i]->OldTransformedBounds());
       i++;
     }
 
     if (aCallback) {
       aCallback(container, result);
     }
 
-    result.Transform(gfx::To3DMatrix(mLayer->GetTransform()));
+    result.Transform(gfx::To3DMatrix(mLayer->GetLocalTransform()));
     return result;
   }
 
   // The old list of children:
   nsAutoTArray<UniquePtr<LayerPropertiesBase>,1> mChildren;
   float mPreXScale;
   float mPreYScale;
 };
@@ -443,17 +443,17 @@ LayerPropertiesBase::ComputeDifferences(
   NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
   if (mLayer != aRoot) {
     if (aCallback) {
       NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
     } else {
       ClearInvalidations(aRoot);
     }
     nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(),
-                                     aRoot->GetTransform());
+                                     aRoot->GetLocalTransform());
     result = result.Union(OldTransformedBounds());
     if (aGeometryChanged != nullptr) {
       *aGeometryChanged = true;
     }
     return result;
   } else {
     bool geometryChanged = (aGeometryChanged != nullptr) ? *aGeometryChanged : false;
     nsIntRegion invalid = ComputeChange(aCallback, geometryChanged);
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
@@ -87,20 +87,21 @@ CompositingRenderTargetOGL::InitializeIm
   GLenum result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
   if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
     nsAutoCString msg;
     msg.AppendPrintf("Framebuffer not complete -- error 0x%x, aFBOTextureTarget 0x%x, mFBO %d, mTextureHandle %d, aRect.width %d, aRect.height %d",
                       result, mInitParams.mFBOTextureTarget, mFBO, mTextureHandle, mInitParams.mSize.width, mInitParams.mSize.height);
     NS_ERROR(msg.get());
   }
 
+  mInitParams.mStatus = InitParams::INITIALIZED;
+
   mCompositor->PrepareViewport(mInitParams.mSize);
   mGL->fScissor(0, 0, mInitParams.mSize.width, mInitParams.mSize.height);
   if (mInitParams.mInit == INIT_MODE_CLEAR) {
     mGL->fClearColor(0.0, 0.0, 0.0, 0.0);
     mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
   }
 
-  mInitParams.mStatus = InitParams::INITIALIZED;
 }
 
 }
 }
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.h
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.h
@@ -79,17 +79,17 @@ public:
    * Create a render target around the default FBO, for rendering straight to
    * the window.
    */
   static TemporaryRef<CompositingRenderTargetOGL>
   RenderTargetForWindow(CompositorOGL* aCompositor,
                         const gfx::IntSize& aSize)
   {
     RefPtr<CompositingRenderTargetOGL> result
-      = new CompositingRenderTargetOGL(aCompositor, gfx::IntPoint(0, 0), 0, 0);
+      = new CompositingRenderTargetOGL(aCompositor, gfx::IntPoint(), 0, 0);
     result->mInitParams = InitParams(aSize, 0, INIT_MODE_NONE);
     result->mInitParams.mStatus = InitParams::INITIALIZED;
     return result.forget();
   }
 
   /**
    * Some initialisation work on the backing FBO and texture.
    * We do this lazily so that when we first set this render target on the
@@ -107,16 +107,18 @@ public:
 
   void BindTexture(GLenum aTextureUnit, GLenum aTextureTarget);
 
   /**
    * Call when we want to draw into our FBO
    */
   void BindRenderTarget();
 
+  bool IsWindow() { return GetFBO() == 0; }
+
   GLuint GetFBO() const
   {
     MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
     return mFBO;
   }
 
   GLuint GetTextureHandle() const
   {
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -588,17 +588,20 @@ CompositorOGL::PrepareViewport(const gfx
     viewMatrix.PreTranslate(-1.0, -1.0);
     viewMatrix.PreScale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
   } else {
     viewMatrix.PreTranslate(-1.0, 1.0);
     viewMatrix.PreScale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
     viewMatrix.PreScale(1.0f, -1.0f);
   }
 
-  if (!mTarget) {
+  MOZ_ASSERT(mCurrentRenderTarget, "No destination");
+  // If we're drawing directly to the window then we want to offset
+  // drawing by the render offset.
+  if (!mTarget && mCurrentRenderTarget->IsWindow()) {
     viewMatrix.PreTranslate(mRenderOffset.x, mRenderOffset.y);
   }
 
   Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
   matrix3d._33 = 0.0f;
 
   mProjMatrix = matrix3d;
 }
@@ -655,18 +658,18 @@ CompositorOGL::CreateRenderTargetFromSou
 
 void
 CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
 {
   MOZ_ASSERT(aSurface);
   CompositingRenderTargetOGL* surface
     = static_cast<CompositingRenderTargetOGL*>(aSurface);
   if (mCurrentRenderTarget != surface) {
+    mCurrentRenderTarget = surface;
     surface->BindRenderTarget();
-    mCurrentRenderTarget = surface;
   }
 }
 
 CompositingRenderTarget*
 CompositorOGL::GetCurrentRenderTarget() const
 {
   return mCurrentRenderTarget;
 }
@@ -1014,19 +1017,24 @@ CompositorOGL::DrawQuad(const Rect& aRec
                         const EffectChain &aEffectChain,
                         Float aOpacity,
                         const gfx::Matrix4x4 &aTransform)
 {
   PROFILER_LABEL("CompositorOGL", "DrawQuad",
     js::ProfileEntry::Category::GRAPHICS);
 
   MOZ_ASSERT(mFrameInProgress, "frame not started");
+  MOZ_ASSERT(mCurrentRenderTarget, "No destination");
 
   Rect clipRect = aClipRect;
-  if (!mTarget) {
+  // aClipRect is in destination coordinate space (after all
+  // transforms and offsets have been applied) so if our
+  // drawing is going to be shifted by mRenderOffset then we need
+  // to shift the clip rect by the same amount.
+  if (!mTarget && mCurrentRenderTarget->IsWindow()) {
     clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
   }
   IntRect intClipRect;
   clipRect.ToIntRect(&intClipRect);
 
   gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
                  intClipRect.width, intClipRect.height);
 
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -851,30 +851,17 @@ gfxContext::ClipContainsRect(const gfxRe
 // rendering sources
 
 void
 gfxContext::SetColor(const gfxRGBA& c)
 {
   CurrentState().pattern = nullptr;
   CurrentState().sourceSurfCairo = nullptr;
   CurrentState().sourceSurface = nullptr;
-
-  if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
-
-      gfxRGBA cms;
-      qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-      if (transform)
-        gfxPlatform::TransformPixel(c, cms, transform);
-
-      // Use the original alpha to avoid unnecessary float->byte->float
-      // conversion errors
-      CurrentState().color = ToColor(cms);
-  }
-  else
-      CurrentState().color = ToColor(c);
+  CurrentState().color = gfxPlatform::MaybeTransformColor(c);
 }
 
 void
 gfxContext::SetDeviceColor(const gfxRGBA& c)
 {
   CurrentState().pattern = nullptr;
   CurrentState().sourceSurfCairo = nullptr;
   CurrentState().sourceSurface = nullptr;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1626,16 +1626,36 @@ gfxPlatform::TransformPixel(const gfxRGB
         new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
 #endif
     }
 
     else if (&out != &in)
         out = in;
 }
 
+Color
+gfxPlatform::MaybeTransformColor(const gfxRGBA& aColor)
+{
+    // We only return this object to get some return value optimization goodness:
+    Color color;
+    if (GetCMSMode() == eCMSMode_All) {
+        gfxRGBA cms;
+        qcms_transform *transform = GetCMSRGBTransform();
+        if (transform) {
+            TransformPixel(aColor, cms, transform);
+            // Use the original alpha to avoid unnecessary float->byte->float
+            // conversion errors
+            color = ToColor(cms);
+            return color;
+        }
+    }
+    color = ToColor(aColor);
+    return color;
+}
+
 void
 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
 {
     mem = nullptr;
     size = 0;
 }
 
 void
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_PLATFORM_H
 #define GFX_PLATFORM_H
 
 #include "prlog.h"
+#include "mozilla/gfx/Types.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 
 #include "gfxPrefs.h"
 #include "gfxTypes.h"
 #include "gfxFontFamilyList.h"
@@ -153,16 +154,17 @@ GetBackendName(mozilla::gfx::BackendType
       case mozilla::gfx::BackendType::NONE:
         return "none";
   }
   MOZ_CRASH("Incomplete switch");
 }
 
 class gfxPlatform {
 public:
+    typedef mozilla::gfx::Color Color;
     typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::gfx::IntSize IntSize;
     typedef mozilla::gfx::SourceSurface SourceSurface;
 
     /**
      * Return a pointer to the current active platform.
      * This is a singleton; it contains mostly convenience
@@ -489,16 +491,22 @@ public:
     /**
      * Convert a pixel using a cms transform in an endian-aware manner.
      *
      * Sets 'out' to 'in' if transform is nullptr.
      */
     static void TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform);
 
     /**
+     * Converts the color using the GetCMSRGBTransform() transform if the
+     * CMS mode is eCMSMode_All, else just returns the color.
+     */
+    static Color MaybeTransformColor(const gfxRGBA& aColor);
+
+    /**
      * Return the output device ICC profile.
      */
     static qcms_profile* GetCMSOutputProfile();
 
     /**
      * Return the sRGB ICC profile.
      */
     static qcms_profile* GetCMSsRGBProfile();
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -588,47 +588,46 @@ gfxUtils::DrawPixelSnapped(gfxContext*  
         return;
 
     nsRefPtr<gfxDrawable> drawable = aDrawable;
 
     aFilter = ReduceResamplingFilter(aFilter,
                                      imageRect.Width(), imageRect.Height(),
                                      region.Width(), region.Height());
 
-    if (aRegion.IsRestricted() &&
-        aContext->CurrentMatrix().HasNonIntegerTranslation() &&
-        drawable->DrawWithSamplingRect(aContext, aRegion.Rect(), aRegion.Restriction(),
-                                       doTile, aFilter, aOpacity)) {
-      return;
-    }
-
-    // On Mobile, we don't ever want to do this; it has the potential for
-    // allocating very large temporary surfaces, especially since we'll
-    // do full-page snapshots often (see bug 749426).
-#ifndef MOZ_GFX_OPTIMIZE_MOBILE
     // OK now, the hard part left is to account for the subimage sampling
     // restriction. If all the transforms involved are just integer
     // translations, then we assume no resampling will occur so there's
     // nothing to do.
     // XXX if only we had source-clipping in cairo!
     if (aContext->CurrentMatrix().HasNonIntegerTranslation()) {
         if (doTile || !aRegion.RestrictionContains(imageRect)) {
+            if (drawable->DrawWithSamplingRect(aContext, aRegion.Rect(), aRegion.Restriction(),
+                                               doTile, aFilter, aOpacity)) {
+              return;
+            }
+
+            // On Mobile, we don't ever want to do this; it has the potential for
+            // allocating very large temporary surfaces, especially since we'll
+            // do full-page snapshots often (see bug 749426).
+#ifndef MOZ_GFX_OPTIMIZE_MOBILE
             nsRefPtr<gfxDrawable> restrictedDrawable =
               CreateSamplingRestrictedDrawable(aDrawable, aContext,
                                                aRegion, aFormat);
             if (restrictedDrawable) {
                 drawable.swap(restrictedDrawable);
             }
+
+            // We no longer need to tile: Either we never needed to, or we already
+            // filled a surface with the tiled pattern; this surface can now be
+            // drawn without tiling.
+            doTile = false;
+#endif
         }
-        // We no longer need to tile: Either we never needed to, or we already
-        // filled a surface with the tiled pattern; this surface can now be
-        // drawn without tiling.
-        doTile = false;
     }
-#endif
 
     drawable->Draw(aContext, aRegion.Rect(), doTile, aFilter, aOpacity);
 }
 
 /* static */ int
 gfxUtils::ImageFormatToDepth(gfxImageFormat aFormat)
 {
     switch (aFormat) {
--- a/ipc/glue/ScopedXREEmbed.cpp
+++ b/ipc/glue/ScopedXREEmbed.cpp
@@ -85,16 +85,21 @@ ScopedXREEmbed::Start()
     NS_ENSURE_TRUE_VOID(localFile);
 
     rv = localFile->GetParent(getter_AddRefs(parent));
     if (NS_FAILED(rv))
       return;
 
     localFile = do_QueryInterface(parent);
     NS_ENSURE_TRUE_VOID(localFile);
+
+    rv = localFile->SetNativeLeafName(NS_LITERAL_CSTRING("Resources"));
+    if (NS_FAILED(rv)) {
+      return;
+    }
   }
 #endif
 
   if (mAppDir)
     rv = XRE_InitEmbedding2(localFile, mAppDir, nullptr);
   else
     rv = XRE_InitEmbedding2(localFile, localFile, nullptr);
   if (NS_FAILED(rv))
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -880,16 +880,34 @@ namespace js {
 template <>
 class RootedBase<JSObject*>
 {
   public:
     template <class U>
     JS::Handle<U*> as() const;
 };
 
+/*
+ * Augment the generic Handle<T> interface when T = JSObject* with
+ * downcasting operations.
+ *
+ * Given a Handle<JSObject*> obj, one can view
+ *   Handle<StringObject*> h = obj.as<StringObject*>();
+ * as an optimization of
+ *   Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
+ *   Handle<StringObject*> h = rooted;
+ */
+template <>
+class HandleBase<JSObject*>
+{
+  public:
+    template <class U>
+    JS::Handle<U*> as() const;
+};
+
 /* Interface substitute for Rooted<T> which does not root the variable's memory. */
 template <typename T>
 class FakeRooted : public RootedBase<T>
 {
   public:
     template <typename CX>
     FakeRooted(CX *cx
                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -998,32 +1016,42 @@ template <typename T> class MaybeRooted<
 
     static inline JS::Handle<T> toHandle(HandleType v) {
         return v;
     }
 
     static inline JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
         return v;
     }
+
+    template <typename T2>
+    static inline JS::Handle<T2*> downcastHandle(HandleType v) {
+        return v.template as<T2>();
+    }
 };
 
 template <typename T> class MaybeRooted<T, NoGC>
 {
   public:
     typedef T HandleType;
     typedef FakeRooted<T> RootType;
     typedef FakeMutableHandle<T> MutableHandleType;
 
     static JS::Handle<T> toHandle(HandleType v) {
         MOZ_CRASH("Bad conversion");
     }
 
     static JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
         MOZ_CRASH("Bad conversion");
     }
+
+    template <typename T2>
+    static inline T2* downcastHandle(HandleType v) {
+        return &v->template as<T2>();
+    }
 };
 
 } /* namespace js */
 
 namespace JS {
 
 template <typename T> template <typename S>
 inline
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -39,16 +39,17 @@
 #endif
 #include "vm/ArrayBufferObject.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/ArrayBufferObject-inl.h"
+#include "vm/ObjectImpl-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsNaN;
 using mozilla::PodZero;
 
 static bool
@@ -112,17 +113,17 @@ HasPureCoercion(JSContext *cx, HandleVal
     // breaking all the code that contains this bug, we make an exception for
     // functions that don't have user-defined valueOf or toString, for their
     // coercions are not observable and coercion via ToNumber/ToInt32
     // definitely produces NaN/0. We should remove this special case later once
     // most apps have been built with newer Emscripten.
     jsid toString = NameToId(cx->names().toString);
     if (v.toObject().is<JSFunction>() &&
         HasObjectValueOf(&v.toObject(), cx) &&
-        ClassMethodIsNative(cx, &v.toObject(), &JSFunction::class_, toString, fun_toString))
+        ClassMethodIsNative(cx, &v.toObject().as<JSFunction>(), &JSFunction::class_, toString, fun_toString))
     {
         return true;
     }
 
     return false;
 }
 
 static bool
@@ -892,17 +893,17 @@ CreateExportObject(JSContext *cx, Handle
 
     if (module.numExportedFunctions() == 1) {
         const AsmJSModule::ExportedFunction &func = module.exportedFunction(0);
         if (!func.maybeFieldName())
             return NewExportedFunction(cx, func, moduleObj, 0);
     }
 
     gc::AllocKind allocKind = gc::GetGCObjectKind(module.numExportedFunctions());
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_, allocKind));
+    RootedNativeObject obj(cx, NewNativeBuiltinClassInstance(cx, &JSObject::class_, allocKind));
     if (!obj)
         return nullptr;
 
     for (unsigned i = 0; i < module.numExportedFunctions(); i++) {
         const AsmJSModule::ExportedFunction &func = module.exportedFunction(i);
 
         RootedFunction fun(cx, NewExportedFunction(cx, func, moduleObj, i));
         if (!fun)
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -863,19 +863,20 @@ const Class AsmJSModuleObject::class_ = 
 };
 
 AsmJSModuleObject *
 AsmJSModuleObject::create(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *module)
 {
     JSObject *obj = NewObjectWithGivenProto(cx, &AsmJSModuleObject::class_, nullptr, nullptr);
     if (!obj)
         return nullptr;
+    AsmJSModuleObject *nobj = &obj->as<AsmJSModuleObject>();
 
-    obj->setReservedSlot(MODULE_SLOT, PrivateValue(module->forget()));
-    return &obj->as<AsmJSModuleObject>();
+    nobj->setReservedSlot(MODULE_SLOT, PrivateValue(module->forget()));
+    return nobj;
 }
 
 AsmJSModule &
 AsmJSModuleObject::module() const
 {
     MOZ_ASSERT(is<AsmJSModuleObject>());
     return *(AsmJSModule *)getReservedSlot(MODULE_SLOT).toPrivate();
 }
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -1432,17 +1432,17 @@ LookupAsmJSModuleInCache(ExclusiveContex
                          AsmJSParser &parser,
                          ScopedJSDeletePtr<AsmJSModule> *module,
                          ScopedJSFreePtr<char> *compilationTimeReport);
 
 // An AsmJSModuleObject is an internal implementation object (i.e., not exposed
 // directly to user script) which manages the lifetime of an AsmJSModule. A
 // JSObject is necessary since we want LinkAsmJS/CallAsmJS JSFunctions to be
 // able to point to their module via their extended slots.
-class AsmJSModuleObject : public JSObject
+class AsmJSModuleObject : public NativeObject
 {
     static const unsigned MODULE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     // On success, return an AsmJSModuleClass JSObject that has taken ownership
     // (and release()ed) the given module.
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -576,64 +576,16 @@ function ArrayFill(value, start = 0, end
     for (; k < final; k++) {
         O[k] = value;
     }
 
     // Step 13.
     return O;
 }
 
-// Proposed for ES7:
-// https://github.com/domenic/Array.prototype.contains/blob/master/spec.md
-function ArrayContains(searchElement, fromIndex = 0) {
-    // Steps 1-2.
-    var O = ToObject(this);
-
-    // Steps 3-4.
-    var len = ToLength(O.length);
-
-    // Step 5.
-    if (len === 0)
-        return false;
-
-    // Steps 6-7.
-    var n = ToInteger(fromIndex);
-
-    // Step 8.
-    if (n >= len)
-        return false;
-
-    // Step 9.
-    var k;
-    if (n >= 0) {
-        k = n;
-    }
-    // Step 10.
-    else {
-        // Step a.
-        k = len + n;
-        // Step b.
-        if (k < 0)
-            k = 0;
-    }
-
-    // Step 11.
-    while (k < len) {
-        // Steps a-c.
-        if (SameValueZero(searchElement, O[k]))
-            return true;
-
-        // Step d.
-        k++;
-    }
-
-    // Step 12.
-    return false;
-}
-
 #define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
 #define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
 #define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
 
 #define ITEM_KIND_VALUE 0
 #define ITEM_KIND_KEY_AND_VALUE 1
 #define ITEM_KIND_KEY 2
 
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -628,17 +628,17 @@ Collator(JSContext *cx, CallArgs args, b
         // 10.1.3.1 paragraph 2
         RootedObject proto(cx, cx->global()->getOrCreateCollatorPrototype(cx));
         if (!proto)
             return false;
         obj = NewObjectWithGivenProto(cx, &CollatorClass, proto, cx->global());
         if (!obj)
             return false;
 
-        obj->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
+        obj->as<NativeObject>().setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
     }
 
     // 10.1.2.1 steps 1 and 2; 10.1.3.1 steps 1 and 2
     RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
     RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
 
     // 10.1.2.1 step 6; 10.1.3.1 step 3
     if (!IntlInitialize(cx, obj, cx->names().InitializeCollator, locales, options))
@@ -664,17 +664,17 @@ js::intl_Collator(JSContext *cx, unsigne
     // intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
     // be used with "new", but it still has to be treated as a constructor.
     return Collator(cx, args, true);
 }
 
 static void
 collator_finalize(FreeOp *fop, JSObject *obj)
 {
-    UCollator *coll = static_cast<UCollator*>(obj->getReservedSlot(UCOLLATOR_SLOT).toPrivate());
+    UCollator *coll = static_cast<UCollator*>(obj->as<NativeObject>().getReservedSlot(UCOLLATOR_SLOT).toPrivate());
     if (coll)
         ucol_close(coll);
 }
 
 static JSObject *
 InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0));
@@ -727,17 +727,17 @@ InitCollatorClass(JSContext *cx, HandleO
     }
 
     return ctor;
 }
 
 bool
 GlobalObject::initCollatorProto(JSContext *cx, Handle<GlobalObject*> global)
 {
-    RootedObject proto(cx, global->createBlankPrototype(cx, &CollatorClass));
+    RootedNativeObject proto(cx, global->createBlankPrototype(cx, &CollatorClass));
     if (!proto)
         return false;
     proto->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
     global->setReservedSlot(COLLATOR_PROTO, ObjectValue(*proto));
     return true;
 }
 
 bool
@@ -1001,22 +1001,22 @@ js::intl_CompareStrings(JSContext *cx, u
 
     RootedObject collator(cx, &args[0].toObject());
 
     // Obtain a UCollator object, cached if possible.
     // XXX Does this handle Collator instances from other globals correctly?
     bool isCollatorInstance = collator->getClass() == &CollatorClass;
     UCollator *coll;
     if (isCollatorInstance) {
-        coll = static_cast<UCollator *>(collator->getReservedSlot(UCOLLATOR_SLOT).toPrivate());
+        coll = static_cast<UCollator *>(collator->as<NativeObject>().getReservedSlot(UCOLLATOR_SLOT).toPrivate());
         if (!coll) {
             coll = NewUCollator(cx, collator);
             if (!coll)
                 return false;
-            collator->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(coll));
+            collator->as<NativeObject>().setReservedSlot(UCOLLATOR_SLOT, PrivateValue(coll));
         }
     } else {
         // There's no good place to cache the ICU collator for an object
         // that has been initialized as a Collator but is not a Collator
         // instance. One possibility might be to add a Collator instance as an
         // internal property to each such object.
         coll = NewUCollator(cx, collator);
         if (!coll)
@@ -1117,17 +1117,17 @@ NumberFormat(JSContext *cx, CallArgs arg
         // 11.1.3.1 paragraph 2
         RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
         if (!proto)
             return false;
         obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto, cx->global());
         if (!obj)
             return false;
 
-        obj->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
+        obj->as<NativeObject>().setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
     }
 
     // 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
     RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
     RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
 
     // 11.1.2.1 step 6; 11.1.3.1 step 3
     if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
@@ -1155,17 +1155,17 @@ js::intl_NumberFormat(JSContext *cx, uns
     // constructor.
     return NumberFormat(cx, args, true);
 }
 
 static void
 numberFormat_finalize(FreeOp *fop, JSObject *obj)
 {
     UNumberFormat *nf =
-        static_cast<UNumberFormat*>(obj->getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
+        static_cast<UNumberFormat*>(obj->as<NativeObject>().getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
     if (nf)
         unum_close(nf);
 }
 
 static JSObject *
 InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0));
@@ -1218,17 +1218,17 @@ InitNumberFormatClass(JSContext *cx, Han
     }
 
     return ctor;
 }
 
 bool
 GlobalObject::initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global)
 {
-    RootedObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass));
+    RootedNativeObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass));
     if (!proto)
         return false;
     proto->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
     global->setReservedSlot(NUMBER_FORMAT_PROTO, ObjectValue(*proto));
     return true;
 }
 
 bool
@@ -1460,22 +1460,22 @@ js::intl_FormatNumber(JSContext *cx, uns
     MOZ_ASSERT(args[1].isNumber());
 
     RootedObject numberFormat(cx, &args[0].toObject());
 
     // Obtain a UNumberFormat object, cached if possible.
     bool isNumberFormatInstance = numberFormat->getClass() == &NumberFormatClass;
     UNumberFormat *nf;
     if (isNumberFormatInstance) {
-        nf = static_cast<UNumberFormat*>(numberFormat->getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
+        nf = static_cast<UNumberFormat*>(numberFormat->as<NativeObject>().getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
         if (!nf) {
             nf = NewUNumberFormat(cx, numberFormat);
             if (!nf)
                 return false;
-            numberFormat->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nf));
+            numberFormat->as<NativeObject>().setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nf));
         }
     } else {
         // There's no good place to cache the ICU number format for an object
         // that has been initialized as a NumberFormat but is not a
         // NumberFormat instance. One possibility might be to add a
         // NumberFormat instance as an internal property to each such object.
         nf = NewUNumberFormat(cx, numberFormat);
         if (!nf)
@@ -1574,17 +1574,17 @@ DateTimeFormat(JSContext *cx, CallArgs a
         // 12.1.3.1 paragraph 2
         RootedObject proto(cx, cx->global()->getOrCreateDateTimeFormatPrototype(cx));
         if (!proto)
             return false;
         obj = NewObjectWithGivenProto(cx, &DateTimeFormatClass, proto, cx->global());
         if (!obj)
             return false;
 
-        obj->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
+        obj->as<NativeObject>().setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
     }
 
     // 12.1.2.1 steps 1 and 2; 12.1.3.1 steps 1 and 2
     RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
     RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
 
     // 12.1.2.1 step 6; 12.1.3.1 step 3
     if (!IntlInitialize(cx, obj, cx->names().InitializeDateTimeFormat, locales, options))
@@ -1611,17 +1611,17 @@ js::intl_DateTimeFormat(JSContext *cx, u
     // cannot be used with "new", but it still has to be treated as a
     // constructor.
     return DateTimeFormat(cx, args, true);
 }
 
 static void
 dateTimeFormat_finalize(FreeOp *fop, JSObject *obj)
 {
-    UDateFormat *df = static_cast<UDateFormat*>(obj->getReservedSlot(UDATE_FORMAT_SLOT).toPrivate());
+    UDateFormat *df = static_cast<UDateFormat*>(obj->as<NativeObject>().getReservedSlot(UDATE_FORMAT_SLOT).toPrivate());
     if (df)
         udat_close(df);
 }
 
 static JSObject *
 InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0));
@@ -1674,17 +1674,17 @@ InitDateTimeFormatClass(JSContext *cx, H
     }
 
     return ctor;
 }
 
 bool
 GlobalObject::initDateTimeFormatProto(JSContext *cx, Handle<GlobalObject*> global)
 {
-    RootedObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass));
+    RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass));
     if (!proto)
         return false;
     proto->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
     global->setReservedSlot(DATE_TIME_FORMAT_PROTO, ObjectValue(*proto));
     return true;
 }
 
 bool
@@ -1961,22 +1961,22 @@ js::intl_FormatDateTime(JSContext *cx, u
     MOZ_ASSERT(args[1].isNumber());
 
     RootedObject dateTimeFormat(cx, &args[0].toObject());
 
     // Obtain a UDateFormat object, cached if possible.
     bool isDateTimeFormatInstance = dateTimeFormat->getClass() == &DateTimeFormatClass;
     UDateFormat *df;
     if (isDateTimeFormatInstance) {
-        df = static_cast<UDateFormat*>(dateTimeFormat->getReservedSlot(UDATE_FORMAT_SLOT).toPrivate());
+        df = static_cast<UDateFormat*>(dateTimeFormat->as<NativeObject>().getReservedSlot(UDATE_FORMAT_SLOT).toPrivate());
         if (!df) {
             df = NewUDateFormat(cx, dateTimeFormat);
             if (!df)
                 return false;
-            dateTimeFormat->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(df));
+            dateTimeFormat->as<NativeObject>().setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(df));
         }
     } else {
         // There's no good place to cache the ICU date-time format for an object
         // that has been initialized as a DateTimeFormat but is not a
         // DateTimeFormat instance. One possibility might be to add a
         // DateTimeFormat instance as an internal property to each such object.
         df = NewUDateFormat(cx, dateTimeFormat);
         if (!df)
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -14,16 +14,18 @@
 
 #include "gc/Marking.h"
 #include "js/Utility.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 
 #include "jsobjinlines.h"
 
+#include "vm/ObjectImpl-inl.h"
+
 using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::Forward;
 using mozilla::IsNaN;
 using mozilla::Move;
 using mozilla::NumberEqualsInt32;
 
@@ -835,17 +837,17 @@ HashableValue::mark(JSTracer *trc) const
     return hv;
 }
 
 
 /*** MapIterator *********************************************************************************/
 
 namespace {
 
-class MapIteratorObject : public JSObject
+class MapIteratorObject : public NativeObject
 {
   public:
     static const Class class_;
 
     enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
     static const JSFunctionSpec methods[];
     static MapIteratorObject *create(JSContext *cx, HandleObject mapobj, ValueMap *data,
                                      MapObject::IteratorKind kind);
@@ -896,18 +898,18 @@ MapIteratorObject::kind() const
 }
 
 bool
 GlobalObject::initMapIteratorProto(JSContext *cx, Handle<GlobalObject *> global)
 {
     JSObject *base = GlobalObject::getOrCreateIteratorPrototype(cx, global);
     if (!base)
         return false;
-    Rooted<JSObject*> proto(cx,
-        NewObjectWithGivenProto(cx, &MapIteratorObject::class_, base, global));
+    RootedNativeObject proto(cx,
+        NewNativeObjectWithGivenProto(cx, &MapIteratorObject::class_, base, global));
     if (!proto)
         return false;
     proto->setSlot(MapIteratorObject::RangeSlot, PrivateValue(nullptr));
     if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods))
         return false;
     global->setReservedSlot(MAP_ITERATOR_PROTO, ObjectValue(*proto));
     return true;
 }
@@ -920,17 +922,17 @@ MapIteratorObject::create(JSContext *cx,
     Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateMapIteratorPrototype(cx, global));
     if (!proto)
         return nullptr;
 
     ValueMap::Range *range = cx->new_<ValueMap::Range>(data->all());
     if (!range)
         return nullptr;
 
-    JSObject *iterobj = NewObjectWithGivenProto(cx, &class_, proto, global);
+    NativeObject *iterobj = NewNativeObjectWithGivenProto(cx, &class_, proto, global);
     if (!iterobj) {
         js_delete(range);
         return nullptr;
     }
     iterobj->setSlot(TargetSlot, ObjectValue(*mapobj));
     iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
     iterobj->setSlot(RangeSlot, PrivateValue(range));
     return static_cast<MapIteratorObject *>(iterobj);
@@ -1039,17 +1041,17 @@ const JSFunctionSpec MapObject::methods[
     JS_SELF_HOSTED_FN("forEach", "MapForEach", 2, 0),
     JS_FS_END
 };
 
 static JSObject *
 InitClass(JSContext *cx, Handle<GlobalObject*> global, const Class *clasp, JSProtoKey key, Native construct,
           const JSPropertySpec *properties, const JSFunctionSpec *methods)
 {
-    Rooted<JSObject*> proto(cx, global->createBlankPrototype(cx, clasp));
+    RootedNativeObject proto(cx, global->createBlankPrototype(cx, clasp));
     if (!proto)
         return nullptr;
     proto->setPrivate(nullptr);
 
     Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 1));
     if (!ctor ||
         !LinkConstructorAndPrototype(cx, ctor, proto) ||
         !DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
@@ -1193,17 +1195,17 @@ MapObject::set(JSContext *cx, HandleObje
     }
     WriteBarrierPost(cx->runtime(), map, key.get());
     return true;
 }
 
 MapObject*
 MapObject::create(JSContext *cx)
 {
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
+    RootedNativeObject obj(cx, NewNativeBuiltinClassInstance(cx, &class_));
     if (!obj)
         return nullptr;
 
     ValueMap *map = cx->new_<ValueMap>(cx->runtime());
     if (!map || !map->init()) {
         js_delete(map);
         js_ReportOutOfMemory(cx);
         return nullptr;
@@ -1273,17 +1275,17 @@ MapObject::construct(JSContext *cx, unsi
 
     args.rval().setObject(*obj);
     return true;
 }
 
 bool
 MapObject::is(HandleValue v)
 {
-    return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().getPrivate();
+    return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().as<MapObject>().getPrivate();
 }
 
 #define ARG0_KEY(cx, args, key)                                               \
     AutoHashableValueRooter key(cx);                                          \
     if (args.length() > 0 && !key.setValue(cx, args[0]))                      \
         return false
 
 ValueMap &
@@ -1484,17 +1486,17 @@ js_InitMapClass(JSContext *cx, HandleObj
     return MapObject::initClass(cx, obj);
 }
 
 
 /*** SetIterator *********************************************************************************/
 
 namespace {
 
-class SetIteratorObject : public JSObject
+class SetIteratorObject : public NativeObject
 {
   public:
     static const Class class_;
 
     enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
     static const JSFunctionSpec methods[];
     static SetIteratorObject *create(JSContext *cx, HandleObject setobj, ValueSet *data,
                                      SetObject::IteratorKind kind);
@@ -1545,17 +1547,18 @@ SetIteratorObject::kind() const
 }
 
 bool
 GlobalObject::initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global)
 {
     JSObject *base = GlobalObject::getOrCreateIteratorPrototype(cx, global);
     if (!base)
         return false;
-    RootedObject proto(cx, NewObjectWithGivenProto(cx, &SetIteratorObject::class_, base, global));
+    RootedNativeObject proto(cx, NewNativeObjectWithGivenProto(cx, &SetIteratorObject::class_,
+                                                               base, global));
     if (!proto)
         return false;
     proto->setSlot(SetIteratorObject::RangeSlot, PrivateValue(nullptr));
     if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods))
         return false;
     global->setReservedSlot(SET_ITERATOR_PROTO, ObjectValue(*proto));
     return true;
 }
@@ -1568,17 +1571,17 @@ SetIteratorObject::create(JSContext *cx,
     Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateSetIteratorPrototype(cx, global));
     if (!proto)
         return nullptr;
 
     ValueSet::Range *range = cx->new_<ValueSet::Range>(data->all());
     if (!range)
         return nullptr;
 
-    JSObject *iterobj = NewObjectWithGivenProto(cx, &class_, proto, global);
+    NativeObject *iterobj = NewNativeObjectWithGivenProto(cx, &class_, proto, global);
     if (!iterobj) {
         js_delete(range);
         return nullptr;
     }
     iterobj->setSlot(TargetSlot, ObjectValue(*setobj));
     iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
     iterobj->setSlot(RangeSlot, PrivateValue(range));
     return static_cast<SetIteratorObject *>(iterobj);
@@ -1737,17 +1740,17 @@ SetObject::add(JSContext *cx, HandleObje
     }
     WriteBarrierPost(cx->runtime(), set, key.get());
     return true;
 }
 
 SetObject*
 SetObject::create(JSContext *cx)
 {
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
+    RootedNativeObject obj(cx, NewNativeBuiltinClassInstance(cx, &class_));
     if (!obj)
         return nullptr;
 
     ValueSet *set = cx->new_<ValueSet>(cx->runtime());
     if (!set || !set->init()) {
         js_delete(set);
         js_ReportOutOfMemory(cx);
         return nullptr;
@@ -1807,17 +1810,17 @@ SetObject::construct(JSContext *cx, unsi
 
     args.rval().setObject(*obj);
     return true;
 }
 
 bool
 SetObject::is(HandleValue v)
 {
-    return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().getPrivate();
+    return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().as<SetObject>().getPrivate();
 }
 
 ValueSet &
 SetObject::extract(CallReceiver call)
 {
     MOZ_ASSERT(call.thisv().isObject());
     MOZ_ASSERT(call.thisv().toObject().hasClass(&SetObject::class_));
     return *static_cast<SetObject&>(call.thisv().toObject()).getData();
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -80,17 +80,17 @@ typedef OrderedHashMap<HashableValue,
                        RelocatableValue,
                        HashableValue::Hasher,
                        RuntimeAllocPolicy> ValueMap;
 
 typedef OrderedHashSet<HashableValue,
                        HashableValue::Hasher,
                        RuntimeAllocPolicy> ValueSet;
 
-class MapObject : public JSObject {
+class MapObject : public NativeObject {
   public:
     enum IteratorKind { Keys, Values, Entries };
 
     static JSObject *initClass(JSContext *cx, JSObject *obj);
     static const Class class_;
 
     static bool getKeysAndValuesInterleaved(JSContext *cx, HandleObject obj,
                                             JS::AutoValueVector *entries);
@@ -125,17 +125,17 @@ class MapObject : public JSObject {
     static bool keys(JSContext *cx, unsigned argc, Value *vp);
     static bool values_impl(JSContext *cx, CallArgs args);
     static bool values(JSContext *cx, unsigned argc, Value *vp);
     static bool entries_impl(JSContext *cx, CallArgs args);
     static bool clear_impl(JSContext *cx, CallArgs args);
     static bool clear(JSContext *cx, unsigned argc, Value *vp);
 };
 
-class SetObject : public JSObject {
+class SetObject : public NativeObject {
   public:
     enum IteratorKind { Values, Entries };
     static JSObject *initClass(JSContext *cx, JSObject *obj);
     static const Class class_;
 
     static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys);
     static bool values(JSContext *cx, unsigned argc, Value *vp);
     static bool add(JSContext *cx, HandleObject obj, HandleValue key);
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -11,16 +11,18 @@
 #include "jscntxt.h"
 
 #include "irregexp/RegExpParser.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
+#include "vm/ObjectImpl-inl.h"
+
 using namespace js;
 using namespace js::types;
 
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 
 bool
 js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs &matches,
@@ -41,17 +43,17 @@ js::CreateRegExpMatchResult(JSContext *c
     /* Get the templateObject that defines the shape and type of the output object */
     JSObject *templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
     if (!templateObject)
         return false;
 
     size_t numPairs = matches.length();
     MOZ_ASSERT(numPairs > 0);
 
-    RootedObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
+    RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
     if (!arr)
         return false;
 
     /* Store a Value for each pair. */
     for (size_t i = 0; i < numPairs; i++) {
         const MatchPair &pair = matches[i];
 
         if (pair.isUndefined()) {
@@ -66,31 +68,31 @@ js::CreateRegExpMatchResult(JSContext *c
 
             // We don't have to update type information here, since the match
             // result template is already known to have string elements.
             arr->initDenseElement(i, StringValue(str));
         }
     }
 
     /* Set the |index| property. (TemplateObject positions it in slot 0) */
-    arr->nativeSetSlot(0, Int32Value(matches[0].start));
+    arr->setSlot(0, Int32Value(matches[0].start));
 
     /* Set the |input| property. (TemplateObject positions it in slot 1) */
-    arr->nativeSetSlot(1, StringValue(input));
+    arr->setSlot(1, StringValue(input));
 
 #ifdef DEBUG
     RootedValue test(cx);
     RootedId id(cx, NameToId(cx->names().index));
     if (!baseops::GetProperty(cx, arr, id, &test))
         return false;
-    MOZ_ASSERT(test == arr->nativeGetSlot(0));
+    MOZ_ASSERT(test == arr->getSlot(0));
     id = NameToId(cx->names().input);
     if (!baseops::GetProperty(cx, arr, id, &test))
         return false;
-    MOZ_ASSERT(test == arr->nativeGetSlot(1));
+    MOZ_ASSERT(test == arr->getSlot(1));
 #endif
 
     rval.setObject(*arr);
     return true;
 }
 
 static RegExpRunStatus
 ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, HandleLinearString input,
@@ -503,17 +505,17 @@ static const JSPropertySpec regexp_stati
 
 JSObject *
 js_InitRegExpClass(JSContext *cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->isNative());
 
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
 
-    RootedObject proto(cx, global->createBlankPrototype(cx, &RegExpObject::class_));
+    RootedNativeObject proto(cx, global->createBlankPrototype(cx, &RegExpObject::class_));
     if (!proto)
         return nullptr;
     proto->setPrivate(nullptr);
 
     HandlePropertyName empty = cx->names().empty;
     RegExpObjectBuilder builder(cx, &proto->as<RegExpObject>());
     if (!builder.build(empty, RegExpFlag(0)))
         return nullptr;
--- a/js/src/builtin/SymbolObject.h
+++ b/js/src/builtin/SymbolObject.h
@@ -2,23 +2,22 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_SymbolObject_h
 #define builtin_SymbolObject_h
 
-#include "jsobj.h"
-
+#include "vm/ObjectImpl.h"
 #include "vm/Symbol.h"
 
 namespace js {
 
-class SymbolObject : public JSObject
+class SymbolObject : public NativeObject
 {
     /* Stores this Symbol object's [[PrimitiveValue]]. */
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -31,16 +31,18 @@
 #include "vm/Interpreter.h"
 #include "vm/ProxyObject.h"
 #include "vm/SavedStacks.h"
 #include "vm/TraceLogging.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/ObjectImpl-inl.h"
+
 using namespace js;
 using namespace JS;
 
 using mozilla::ArrayLength;
 using mozilla::Move;
 using mozilla::UniquePtr;
 
 // If fuzzingSafe is set, remove functionality that could cause problems with
@@ -1364,31 +1366,31 @@ static bool
 SetIonCheckGraphCoherency(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     jit::js_JitOptions.checkGraphConsistency = ToBoolean(args.get(0));
     args.rval().setUndefined();
     return true;
 }
 
-class CloneBufferObject : public JSObject {
+class CloneBufferObject : public NativeObject {
     static const JSPropertySpec props_[2];
     static const size_t DATA_SLOT   = 0;
     static const size_t LENGTH_SLOT = 1;
     static const size_t NUM_SLOTS   = 2;
 
   public:
     static const Class class_;
 
     static CloneBufferObject *Create(JSContext *cx) {
         RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_), JS::NullPtr(), JS::NullPtr()));
         if (!obj)
             return nullptr;
-        obj->setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
-        obj->setReservedSlot(LENGTH_SLOT, Int32Value(0));
+        obj->as<CloneBufferObject>().setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
+        obj->as<CloneBufferObject>().setReservedSlot(LENGTH_SLOT, Int32Value(0));
 
         if (!JS_DefineProperties(cx, obj, props_))
             return nullptr;
 
         return &obj->as<CloneBufferObject>();
     }
 
     static CloneBufferObject *Create(JSContext *cx, JSAutoStructuredCloneBuffer *buffer) {
@@ -1971,17 +1973,17 @@ FindPath(JSContext *cx, unsigned argc, j
     //     edge: <string describing outgoing edge from node>
     //   }
     //
     // or, if the node is some internal thing that isn't a proper JavaScript
     // value:
     //
     //   { node: undefined, edge: <string> }
     size_t length = nodes.length();
-    RootedObject result(cx, NewDenseFullyAllocatedArray(cx, length));
+    RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length));
     if (!result)
         return false;
     result->ensureDenseInitializedLength(cx, 0, length);
 
     // Walk |nodes| and |edges| in the stored order, and construct the result
     // array in start-to-target order.
     for (size_t i = 0; i < length; i++) {
         // Build an object describing the node and edge.
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -20,16 +20,17 @@
 #include "vm/ObjectImpl.h"
 #include "vm/String.h"
 #include "vm/StringBuffer.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/ObjectImpl-inl.h"
 #include "vm/Shape-inl.h"
 
 using mozilla::AssertedCast;
 using mozilla::CheckedInt32;
 using mozilla::DebugOnly;
 
 using namespace js;
 
@@ -1118,81 +1119,74 @@ StructMetaTypeDescr::construct(JSContext
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                          JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS);
     return false;
 }
 
 size_t
 StructTypeDescr::fieldCount() const
 {
-    return getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).toObject().getDenseInitializedLength();
+    return fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).getDenseInitializedLength();
 }
 
 size_t
 StructTypeDescr::maybeForwardedFieldCount() const
 {
-    JSObject *fieldNames =
-        MaybeForwarded(&getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).toObject());
-    return fieldNames->getDenseInitializedLength();
+    return maybeForwardedFieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).getDenseInitializedLength();
 }
 
 bool
 StructTypeDescr::fieldIndex(jsid id, size_t *out) const
 {
-    JSObject &fieldNames = getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).toObject();
+    NativeObject &fieldNames = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES);
     size_t l = fieldNames.getDenseInitializedLength();
     for (size_t i = 0; i < l; i++) {
         JSAtom &a = fieldNames.getDenseElement(i).toString()->asAtom();
         if (JSID_IS_ATOM(id, &a)) {
             *out = i;
             return true;
         }
     }
     return false;
 }
 
 JSAtom &
 StructTypeDescr::fieldName(size_t index) const
 {
-    JSObject &fieldNames = getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).toObject();
-    return fieldNames.getDenseElement(index).toString()->asAtom();
+    return fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).getDenseElement(index).toString()->asAtom();
 }
 
 size_t
 StructTypeDescr::fieldOffset(size_t index) const
 {
-    JSObject &fieldOffsets =
-        getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS).toObject();
+    NativeObject &fieldOffsets = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS);
     MOZ_ASSERT(index < fieldOffsets.getDenseInitializedLength());
     return AssertedCast<size_t>(fieldOffsets.getDenseElement(index).toInt32());
 }
 
 size_t
 StructTypeDescr::maybeForwardedFieldOffset(size_t index) const
 {
-    JSObject &fieldOffsets =
-        *MaybeForwarded(&getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS).toObject());
+    NativeObject &fieldOffsets = maybeForwardedFieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS);
     MOZ_ASSERT(index < fieldOffsets.getDenseInitializedLength());
     return AssertedCast<size_t>(fieldOffsets.getDenseElement(index).toInt32());
 }
 
 SizedTypeDescr&
 StructTypeDescr::fieldDescr(size_t index) const
 {
-    JSObject &fieldDescrs =
-        getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject();
+    NativeObject &fieldDescrs = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
     MOZ_ASSERT(index < fieldDescrs.getDenseInitializedLength());
     return fieldDescrs.getDenseElement(index).toObject().as<SizedTypeDescr>();
 }
 
 SizedTypeDescr&
 StructTypeDescr::maybeForwardedFieldDescr(size_t index) const
 {
-    JSObject &fieldDescrs =
-        *MaybeForwarded(&getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject());
+    NativeObject &fieldDescrs = maybeForwardedFieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
     MOZ_ASSERT(index < fieldDescrs.getDenseInitializedLength());
     JSObject &descr =
         *MaybeForwarded(&fieldDescrs.getDenseElement(index).toObject());
     return descr.as<SizedTypeDescr>();
 }
 
 /******************************************************************************
  * Creating the TypedObject "module"
@@ -1296,17 +1290,17 @@ DefineSimpleTypeDescr(JSContext *cx,
 }
 
 ///////////////////////////////////////////////////////////////////////////
 
 template<typename T>
 static JSObject *
 DefineMetaTypeDescr(JSContext *cx,
                     Handle<GlobalObject*> global,
-                    HandleObject module,
+                    HandleNativeObject module,
                     TypedObjectModuleObject::Slot protoSlot)
 {
     RootedAtom className(cx, Atomize(cx, T::class_.name,
                                      strlen(T::class_.name)));
     if (!className)
         return nullptr;
 
     RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
@@ -1465,17 +1459,17 @@ js_InitTypedObjectDummy(JSContext *cx, H
  * Typed objects
  */
 
 int32_t
 TypedObject::offset() const
 {
     if (is<InlineOpaqueTypedObject>())
         return 0;
-    return getReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET).toInt32();
+    return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET).toInt32();
 }
 
 int32_t
 TypedObject::length() const
 {
     MOZ_ASSERT(typeDescr().kind() == type::SizedArray ||
                typeDescr().kind() == type::UnsizedArray);
 
@@ -1581,36 +1575,36 @@ OutlineTypedObject::createUnattachedWith
     RootedObject proto(cx, PrototypeForTypeDescr(cx, type));
     if (!proto)
         return nullptr;
 
     RootedObject obj(cx, NewObjectWithClassProto(cx, clasp, proto, nullptr));
     if (!obj)
         return nullptr;
 
-    obj->initPrivate(nullptr);
-    obj->initReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
-    obj->initReservedSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(length));
-    obj->initReservedSlot(JS_BUFVIEW_SLOT_OWNER, NullValue());
+    obj->fakeNativeInitPrivate(nullptr);
+    obj->fakeNativeInitReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
+    obj->fakeNativeInitReservedSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(length));
+    obj->fakeNativeInitReservedSlot(JS_BUFVIEW_SLOT_OWNER, NullValue());
 
     return &obj->as<OutlineTypedObject>();
 }
 
 void
 OutlineTypedObject::attach(JSContext *cx, ArrayBufferObject &buffer, int32_t offset)
 {
     MOZ_ASSERT(offset >= 0);
     MOZ_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
 
     if (!buffer.addView(cx, this))
         CrashAtUnhandlableOOM("TypedObject::attach");
 
-    InitArrayBufferViewDataPointer(this, &buffer, offset);
-    setReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
-    setReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(buffer));
+    fakeNativeInitPrivate(buffer.dataPointer() + offset);
+    fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
+    fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(buffer));
 }
 
 void
 OutlineTypedObject::attach(JSContext *cx, TypedObject &typedObj, int32_t offset)
 {
     MOZ_ASSERT(typedObj.isAttached());
 
     JSObject *owner = &typedObj;
@@ -1618,21 +1612,21 @@ OutlineTypedObject::attach(JSContext *cx
         owner = &typedObj.as<OutlineTypedObject>().owner();
         offset += typedObj.offset();
     }
 
     if (owner->is<ArrayBufferObject>()) {
         attach(cx, owner->as<ArrayBufferObject>(), offset);
     } else {
         MOZ_ASSERT(owner->is<InlineOpaqueTypedObject>());
-        initPrivate(owner->as<InlineOpaqueTypedObject>().inlineTypedMem() + offset);
+        fakeNativeInitPrivate(owner->as<InlineOpaqueTypedObject>().inlineTypedMem() + offset);
         PostBarrierTypedArrayObject(this);
 
-        setReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
-        setReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(*owner));
+        fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
+        fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(*owner));
     }
 }
 
 // Returns a suitable JS_TYPEDOBJ_SLOT_LENGTH value for an instance of
 // the type `type`. `type` must not be an unsized array.
 static int32_t
 TypedObjLengthFromType(TypeDescr &descr)
 {
@@ -1762,29 +1756,29 @@ OutlineTypedObject::obj_trace(JSTracer *
     // When this is called for compacting GC, the related objects we touch here
     // may not have had their slots updated yet. Note that this does not apply
     // to generational GC because these objects (type descriptors and
     // prototypes) are never allocated in the nursery.
     TypeDescr &descr = typedObj.maybeForwardedTypeDescr();
 
     // Mark the owner, watching in case it is moved by the tracer.
     JSObject *oldOwner = typedObj.maybeOwner();
-    gc::MarkSlot(trc, &typedObj.getFixedSlotRef(JS_BUFVIEW_SLOT_OWNER), "typed object owner");
+    gc::MarkSlot(trc, &typedObj.fakeNativeGetSlotRef(JS_BUFVIEW_SLOT_OWNER), "typed object owner");
     JSObject *owner = typedObj.maybeOwner();
 
     uint8_t *mem = typedObj.outOfLineTypedMem();
 
     // Update the data pointer if the owner moved and the owner's data is
     // inline with it.
     if (owner != oldOwner &&
         (owner->is<InlineOpaqueTypedObject>() ||
          owner->as<ArrayBufferObject>().hasInlineData()))
     {
         mem += reinterpret_cast<uint8_t *>(owner) - reinterpret_cast<uint8_t *>(oldOwner);
-        typedObj.setPrivate(mem);
+        typedObj.fakeNativeSetPrivate(mem);
     }
 
     if (!descr.opaque() || !typedObj.maybeForwardedIsAttached())
         return;
 
     switch (descr.kind()) {
       case type::Scalar:
       case type::Reference:
@@ -2323,46 +2317,46 @@ TypedObject::obj_enumerate(JSContext *cx
     }
 
     return true;
 }
 
 /* static */ size_t
 OutlineTypedObject::offsetOfOwnerSlot()
 {
-    return JSObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_OWNER);
+    return NativeObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_OWNER);
 }
 
 /* static */ size_t
 OutlineTypedObject::offsetOfDataSlot()
 {
 #ifdef DEBUG
     // Compute offset of private data based on TransparentTypedObject;
     // both OpaqueOutlineTypedObject and TransparentTypedObject have the same
     // number of slots, so no problem there.
     gc::AllocKind allocKind = gc::GetGCObjectKind(&TransparentTypedObject::class_);
     size_t nfixed = gc::GetGCKindSlots(allocKind);
     MOZ_ASSERT(DATA_SLOT == nfixed - 1);
 #endif
 
-    return JSObject::getPrivateDataOffset(DATA_SLOT);
+    return NativeObject::getPrivateDataOffset(DATA_SLOT);
 }
 
 /* static */ size_t
 OutlineTypedObject::offsetOfByteOffsetSlot()
 {
-    return JSObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_BYTEOFFSET);
+    return NativeObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_BYTEOFFSET);
 }
 
 void
 OutlineTypedObject::neuter(void *newData)
 {
-    setSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(0));
-    setSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
-    setPrivate(newData);
+    fakeNativeSetSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(0));
+    fakeNativeSetSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
+    fakeNativeSetPrivate(newData);
 }
 
 /******************************************************************************
  * Inline typed objects
  */
 
 /* static */ InlineOpaqueTypedObject *
 InlineOpaqueTypedObject::create(JSContext *cx, HandleTypeDescr descr)
@@ -2378,24 +2372,24 @@ InlineOpaqueTypedObject::create(JSContex
         return nullptr;
 
     return &obj->as<InlineOpaqueTypedObject>();
 }
 
 uint8_t *
 InlineOpaqueTypedObject::inlineTypedMem() const
 {
-    return fixedData(0);
+    return fakeNativeFixedData(0);
 }
 
 /* static */
 size_t
 InlineOpaqueTypedObject::offsetOfDataStart()
 {
-    return getFixedSlotOffset(0);
+    return NativeObject::getFixedSlotOffset(0);
 }
 
 /* static */ void
 InlineOpaqueTypedObject::obj_trace(JSTracer *trc, JSObject *object)
 {
     InlineOpaqueTypedObject &typedObj = object->as<InlineOpaqueTypedObject>();
 
     // When this is called for compacting GC, the related objects we touch here
@@ -2838,18 +2832,18 @@ js::SetTypedObjectOffset(ThreadSafeConte
     MOZ_ASSERT(args[1].isInt32());
 
     OutlineTypedObject &typedObj = args[0].toObject().as<OutlineTypedObject>();
     int32_t offset = args[1].toInt32();
 
     MOZ_ASSERT(typedObj.isAttached());
     int32_t oldOffset = typedObj.offset();
 
-    typedObj.setPrivate((typedObj.typedMem() - oldOffset) + offset);
-    typedObj.setReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
+    typedObj.fakeNativeSetPrivate((typedObj.typedMem() - oldOffset) + offset);
+    typedObj.fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
     args.rval().setUndefined();
     return true;
 }
 
 bool
 js::intrinsic_SetTypedObjectOffset(JSContext *cx, unsigned argc, Value *vp)
 {
     // Do not use JSNativeThreadSafeWrapper<> so that ion can reference
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -139,17 +139,17 @@ class SimdTypeDescr;
 class StructTypeDescr;
 class SizedTypedProto;
 
 /*
  * The prototype for a typed object. Currently, carries a link to the
  * type descriptor. Eventually will carry most of the type information
  * we want.
  */
-class TypedProto : public JSObject
+class TypedProto : public NativeObject
 {
   public:
     static const Class class_;
 
     inline void initTypeDescrSlot(TypeDescr &descr);
 
     TypeDescr &typeDescr() const {
         return getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject().as<TypeDescr>();
@@ -157,17 +157,17 @@ class TypedProto : public JSObject
 
     TypeDescr &maybeForwardedTypeDescr() const {
         return MaybeForwarded(&getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject())->as<TypeDescr>();
     }
 
     inline type::Kind kind() const;
 };
 
-class TypeDescr : public JSObject
+class TypeDescr : public NativeObject
 {
   public:
     // This is *intentionally* not defined so as to produce link
     // errors if a is<FooTypeDescr>() etc goes wrong. Otherwise, the
     // default implementation resolves this to a reference to
     // FooTypeDescr::class_ which resolves to
     // JSObject::class_. Debugging the resulting errors leads to much
     // fun and rejoicing.
@@ -504,38 +504,47 @@ class StructTypeDescr : public ComplexTy
 
     // Return the type descr of the field at index `index`.
     SizedTypeDescr &fieldDescr(size_t index) const;
     SizedTypeDescr &maybeForwardedFieldDescr(size_t index) const;
 
     // Return the offset of the field at index `index`.
     size_t fieldOffset(size_t index) const;
     size_t maybeForwardedFieldOffset(size_t index) const;
+
+  private:
+    NativeObject &fieldInfoObject(size_t slot) const {
+        return getReservedSlot(slot).toObject().as<NativeObject>();
+    }
+
+    NativeObject &maybeForwardedFieldInfoObject(size_t slot) const {
+        return *MaybeForwarded(&fieldInfoObject(slot));
+    }
 };
 
 typedef Handle<StructTypeDescr*> HandleStructTypeDescr;
 
 /*
  * This object exists in order to encapsulate the typed object types
  * somewhat, rather than sticking them all into the global object.
  * Eventually it will go away and become a module.
  */
-class TypedObjectModuleObject : public JSObject {
+class TypedObjectModuleObject : public NativeObject {
   public:
     enum Slot {
         ArrayTypePrototype,
         StructTypePrototype,
         SlotCount
     };
 
     static const Class class_;
 };
 
 /* Base type for transparent and opaque typed objects. */
-class TypedObject : public ArrayBufferViewObject
+class TypedObject : public JSObject
 {
   private:
     static const bool IsTypedObjectClass = true;
 
     template<class T>
     static bool obj_getArrayElement(JSContext *cx,
                                     Handle<TypedObject*> typedObj,
                                     Handle<TypeDescr*> typeDescr,
@@ -685,29 +694,29 @@ class OutlineTypedObject : public TypedO
     // where the `void*` pointer can be found. It is intended for use
     // by the JIT.
     static size_t offsetOfDataSlot();
 
     // Offset of the byte offset slot.
     static size_t offsetOfByteOffsetSlot();
 
     JSObject &owner() const {
-        return getReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObject();
+        return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObject();
     }
 
     JSObject *maybeOwner() const {
-        return getReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObjectOrNull();
+        return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObjectOrNull();
     }
 
     uint8_t *outOfLineTypedMem() const {
-        return static_cast<uint8_t *>(getPrivate(DATA_SLOT));
+        return static_cast<uint8_t *>(fakeNativeGetPrivate(DATA_SLOT));
     }
 
     int32_t length() const {
-        return getReservedSlot(JS_BUFVIEW_SLOT_LENGTH).toInt32();
+        return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_LENGTH).toInt32();
     }
 
     // Helper for createUnattached()
     static OutlineTypedObject *createUnattachedWithClass(JSContext *cx,
                                                          const Class *clasp,
                                                          HandleTypeDescr type,
                                                          int32_t length);
 
@@ -758,17 +767,17 @@ class OutlineOpaqueTypedObject : public 
 };
 
 // Class for an opaque typed object whose data is allocated inline.
 class InlineOpaqueTypedObject : public TypedObject
 {
   public:
     static const Class class_;
 
-    static const size_t MaximumSize = JSObject::MAX_FIXED_SLOTS * sizeof(Value);
+    static const size_t MaximumSize = NativeObject::MAX_FIXED_SLOTS * sizeof(Value);
 
     static gc::AllocKind allocKindForTypeDescriptor(TypeDescr *descr) {
         size_t nbytes = descr->as<SizedTypeDescr>().size();
         MOZ_ASSERT(nbytes <= MaximumSize);
 
         size_t dataSlots = AlignBytes(nbytes, sizeof(Value) / sizeof(Value));
         MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
         return gc::GetGCObjectKind(dataSlots);
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -87,32 +87,27 @@ function ToNumber(v) {
 
 
 /* Spec: ECMAScript Language Specification, 5.1 edition, 9.10 */
 function CheckObjectCoercible(v) {
     if (v === undefined || v === null)
         ThrowError(JSMSG_CANT_CONVERT_TO, ToString(v), "object");
 }
 
-// Spec: ECMAScript Draft, 6th edition May 22, 2014, 7.1.15.
+/* Spec: ECMAScript Draft, 6 edition May 22, 2014, 7.1.15 */
 function ToLength(v) {
     v = ToInteger(v);
 
     if (v <= 0)
         return 0;
 
     // Math.pow(2, 53) - 1 = 0x1fffffffffffff
     return v < 0x1fffffffffffff ? v : 0x1fffffffffffff;
 }
 
-// Spec: ECMAScript Draft, 6th edition Aug 24, 2014, 7.2.4.
-function SameValueZero(x, y) {
-    return x === y || (x !== x && y !== y);
-}
-
 /********** Testing code **********/
 
 #ifdef ENABLE_PARALLEL_JS
 
 /**
  * Internal debugging tool: checks that the given `mode` permits
  * sequential execution
  */
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -10,16 +10,18 @@
 #include "jscntxt.h"
 #include "jsiter.h"
 
 #include "builtin/SelfHostingDefines.h"
 #include "vm/GlobalObject.h"
 
 #include "jsobjinlines.h"
 
+#include "vm/ObjectImpl-inl.h"
+
 using namespace js;
 using namespace JS;
 
 const Class WeakSetObject::class_ = {
     "WeakSet",
     JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
     JSCLASS_HAS_RESERVED_SLOTS(WeakSetObject::RESERVED_SLOTS),
     JS_PropertyStub,         // addProperty
@@ -43,17 +45,17 @@ const JSFunctionSpec WeakSetObject::meth
     JS_FS_END
 };
 
 JSObject *
 WeakSetObject::initClass(JSContext *cx, JSObject *obj)
 {
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
     // Todo: WeakSet.prototype should not be a WeakSet!
-    Rooted<JSObject*> proto(cx, global->createBlankPrototype(cx, &class_));
+    RootedNativeObject proto(cx, global->createBlankPrototype(cx, &class_));
     if (!proto)
         return nullptr;
     proto->setReservedSlot(WEAKSET_MAP_SLOT, UndefinedValue());
 
     Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(JSProto_WeakSet, cx), 1));
     if (!ctor ||
         !LinkConstructorAndPrototype(cx, ctor, proto) ||
         !DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
@@ -62,17 +64,17 @@ WeakSetObject::initClass(JSContext *cx, 
         return nullptr;
     }
     return proto;
 }
 
 WeakSetObject*
 WeakSetObject::create(JSContext *cx)
 {
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
+    RootedNativeObject obj(cx, NewNativeBuiltinClassInstance(cx, &class_));
     if (!obj)
         return nullptr;
 
     RootedObject map(cx, NewWeakMapObject(cx));
     if (!map)
         return nullptr;
 
     obj->setReservedSlot(WEAKSET_MAP_SLOT, ObjectValue(*map));
--- a/js/src/builtin/WeakSetObject.h
+++ b/js/src/builtin/WeakSetObject.h
@@ -2,21 +2,21 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_WeakSetObject_h
 #define builtin_WeakSetObject_h
 
-#include "jsobj.h"
+#include "vm/ObjectImpl.h"
 
 namespace js {
 
-class WeakSetObject : public JSObject
+class WeakSetObject : public NativeObject
 {
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     static JSObject *initClass(JSContext *cx, JSObject *obj);
     static const Class class_;
 
   private:
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -197,17 +197,17 @@ if test -n "$gonkdir" ; then
     CXX="$gonk_toolchain_prefix"g++
     CPP="$gonk_toolchain_prefix"cpp
     LD="$gonk_toolchain_prefix"ld
     AR="$gonk_toolchain_prefix"ar
     RANLIB="$gonk_toolchain_prefix"ranlib
     STRIP="$gonk_toolchain_prefix"strip
     OBJCOPY="$gonk_toolchain_prefix"objcopy
 
-    STLPORT_CPPFLAGS="-I$gonkdir/external/stlport/stlport"
+    STLPORT_CPPFLAGS="-I$_topsrcdir/build/stlport/stlport -I$gonkdir/ndk/sources/cxx-stl/system/include"
     STLPORT_LIBS="-lstlport"
 
     case "$target_cpu" in
     arm)
         ARCH_DIR=arch-arm
         ;;
     i?86)
         ARCH_DIR=arch-x86
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -3388,41 +3388,41 @@ CType::Finalize(JSFreeOp *fop, JSObject*
     break;
   }
 }
 
 void
 CType::Trace(JSTracer* trc, JSObject* obj)
 {
   // Make sure our TypeCode slot is legit. If it's not, bail.
-  jsval slot = obj->getSlot(SLOT_TYPECODE);
+  jsval slot = obj->as<NativeObject>().getSlot(SLOT_TYPECODE);
   if (slot.isUndefined())
     return;
 
   // The contents of our slots depends on what kind of type we are.
   switch (TypeCode(slot.toInt32())) {
   case TYPE_struct: {
-    slot = obj->getReservedSlot(SLOT_FIELDINFO);
+    slot = obj->as<NativeObject>().getReservedSlot(SLOT_FIELDINFO);
     if (slot.isUndefined())
       return;
 
     FieldInfoHash* fields = static_cast<FieldInfoHash*>(slot.toPrivate());
     for (FieldInfoHash::Enum e(*fields); !e.empty(); e.popFront()) {
       JSString *key = e.front().key();
       JS_CallUnbarrieredStringTracer(trc, &key, "fieldName");
       if (key != e.front().key())
           e.rekeyFront(JS_ASSERT_STRING_IS_FLAT(key));
       JS_CallObjectTracer(trc, &e.front().value().mType, "fieldType");
     }
 
     break;
   }
   case TYPE_function: {
     // Check if we have a FunctionInfo.
-    slot = obj->getReservedSlot(SLOT_FNINFO);
+    slot = obj->as<NativeObject>().getReservedSlot(SLOT_FNINFO);
     if (slot.isUndefined())
       return;
 
     FunctionInfo* fninfo = static_cast<FunctionInfo*>(slot.toPrivate());
     MOZ_ASSERT(fninfo);
 
     // Identify our objects to the tracer.
     JS_CallObjectTracer(trc, &fninfo->mABI, "abi");
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -34,16 +34,17 @@
 #include "vm/Stack.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/ParseMaps-inl.h"
 #include "frontend/ParseNode-inl.h"
+#include "vm/ObjectImpl-inl.h"
 #include "vm/ScopeObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::DebugOnly;
 using mozilla::NumberIsInt32;
@@ -2161,19 +2162,19 @@ EmitNewInit(ExclusiveContext *cx, Byteco
     return true;
 }
 
 static bool
 IteratorResultShape(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned *shape)
 {
     MOZ_ASSERT(bce->script->compileAndGo());
 
-    RootedObject obj(cx);
+    RootedNativeObject obj(cx);
     gc::AllocKind kind = GuessObjectGCKind(2);
-    obj = NewBuiltinClassInstance(cx, &JSObject::class_, kind);
+    obj = NewNativeBuiltinClassInstance(cx, &JSObject::class_, kind);
     if (!obj)
         return false;
 
     Rooted<jsid> value_id(cx, AtomToId(cx->names().value));
     Rooted<jsid> done_id(cx, AtomToId(cx->names().done));
     if (!DefineNativeProperty(cx, obj, value_id, UndefinedHandleValue, nullptr, nullptr,
                               JSPROP_ENUMERATE))
         return false;
@@ -4060,17 +4061,17 @@ ParseNode::getConstantValue(ExclusiveCon
             count = pn_count - 1;
             pn = pn_head->pn_next;
         } else {
             MOZ_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
             count = pn_count;
             pn = pn_head;
         }
 
-        RootedObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, MaybeSingletonObject));
+        RootedArrayObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, MaybeSingletonObject));
         if (!obj)
             return false;
 
         unsigned idx = 0;
         RootedId id(cx);
         for (; pn; idx++, pn = pn->pn_next) {
             if (!pn->getConstantValue(cx, allowObjects, &value))
                 return false;
@@ -4089,17 +4090,18 @@ ParseNode::getConstantValue(ExclusiveCon
         MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
 
         if (allowObjects == DontAllowObjects)
             return false;
         if (allowObjects == DontAllowNestedObjects)
             allowObjects = DontAllowObjects;
 
         gc::AllocKind kind = GuessObjectGCKind(pn_count);
-        RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_, kind, MaybeSingletonObject));
+        RootedNativeObject obj(cx, NewNativeBuiltinClassInstance(cx, &JSObject::class_,
+                                                                 kind, MaybeSingletonObject));
         if (!obj)
             return false;
 
         RootedValue value(cx), idvalue(cx);
         for (ParseNode *pn = pn_head; pn; pn = pn->pn_next) {
             if (!pn->pn_right->getConstantValue(cx, allowObjects, &value))
                 return false;
 
@@ -4152,17 +4154,17 @@ ParseNode::getConstantValue(ExclusiveCon
 
 static bool
 EmitSingletonInitialiser(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     RootedValue value(cx);
     if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value))
         return false;
 
-    RootedObject obj(cx, &value.toObject());
+    RootedNativeObject obj(cx, &value.toObject().as<NativeObject>());
     if (!obj->is<ArrayObject>() && !JSObject::setSingletonType(cx, obj))
         return false;
 
     ObjectBox *objbox = bce->parser->newObjectBox(obj);
     if (!objbox)
         return false;
 
     return EmitObjectOp(cx, objbox, JSOP_OBJECT, bce);
@@ -4172,26 +4174,26 @@ static bool
 EmitCallSiteObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     RootedValue value(cx);
     if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value))
         return false;
 
     MOZ_ASSERT(value.isObject());
 
-    ObjectBox *objbox1 = bce->parser->newObjectBox(&value.toObject());
+    ObjectBox *objbox1 = bce->parser->newObjectBox(&value.toObject().as<NativeObject>());
     if (!objbox1)
         return false;
 
     if (!pn->as<CallSiteNode>().getRawArrayValue(cx, &value))
         return false;
 
     MOZ_ASSERT(value.isObject());
 
-    ObjectBox *objbox2 = bce->parser->newObjectBox(&value.toObject());
+    ObjectBox *objbox2 = bce->parser->newObjectBox(&value.toObject().as<NativeObject>());
     if (!objbox2)
         return false;
 
     return EmitObjectPairOp(cx, objbox1, objbox2, JSOP_CALLSITEOBJ, bce);
 }
 
 /* See the SRC_FOR source note offsetBias comments later in this file. */
 JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
@@ -6214,20 +6216,20 @@ EmitObject(ExclusiveContext *cx, Bytecod
     ptrdiff_t offset = bce->offset();
     if (!EmitNewInit(cx, bce, JSProto_Object))
         return false;
 
     /*
      * Try to construct the shape of the object as we go, so we can emit a
      * JSOP_NEWOBJECT with the final shape instead.
      */
-    RootedObject obj(cx);
+    RootedNativeObject obj(cx);
     if (bce->script->compileAndGo()) {
         gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
-        obj = NewBuiltinClassInstance(cx, &JSObject::class_, kind, TenuredObject);
+        obj = NewNativeBuiltinClassInstance(cx, &JSObject::class_, kind, TenuredObject);
         if (!obj)
             return false;
     }
 
     for (ParseNode *propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
         if (!UpdateSourceCoordNotes(cx, bce, propdef->pn_pos.begin))
             return false;
 
@@ -6899,17 +6901,17 @@ frontend::EmitTree(ExclusiveContext *cx,
             {
                 // Note: the type of the template object might not yet reflect
                 // that the object has copy on write elements. When the
                 // interpreter or JIT compiler fetches the template, it should
                 // use types::GetOrFixupCopyOnWriteObject to make sure the type
                 // for the template is accurate. We don't do this here as we
                 // want to use types::InitObject, which requires a finished
                 // script.
-                JSObject *obj = &value.toObject();
+                NativeObject *obj = &value.toObject().as<NativeObject>();
                 if (!ObjectElements::MakeElementsCopyOnWrite(cx, obj))
                     return false;
 
                 ObjectBox *objbox = bce->parser->newObjectBox(obj);
                 if (!objbox)
                     return false;
 
                 ok = EmitObjectOp(cx, objbox, JSOP_NEWARRAY_COPYONWRITE, bce);
@@ -7273,17 +7275,17 @@ CGObjectList::indexOf(JSObject *obj)
 }
 
 void
 CGObjectList::finish(ObjectArray *array)
 {
     MOZ_ASSERT(length <= INDEX_LIMIT);
     MOZ_ASSERT(length == array->length);
 
-    js::HeapPtrObject *cursor = array->vector + array->length;
+    js::HeapPtrNativeObject *cursor = array->vector + array->length;
     ObjectBox *objbox = lastbox;
     do {
         --cursor;
         MOZ_ASSERT(!*cursor);
         *cursor = objbox->object;
     } while ((objbox = objbox->emitLink) != nullptr);
     MOZ_ASSERT(cursor == array->vector);
 }
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -167,17 +167,17 @@ class FullParseHandler
     ParseNode *newNullLiteral(const TokenPos &pos) {
         return new_<NullLiteral>(pos);
     }
 
     // The Boxer object here is any object that can allocate ObjectBoxes.
     // Specifically, a Boxer has a .newObjectBox(T) method that accepts a
     // Rooted<RegExpObject*> argument and returns an ObjectBox*.
     template <class Boxer>
-    ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) {
+    ParseNode *newRegExp(RegExpObject *reobj, const TokenPos &pos, Boxer &boxer) {
         ObjectBox *objbox = boxer.newObjectBox(reobj);
         if (!objbox)
             return null();
         return new_<RegExpLiteral>(objbox, pos);
     }
 
     ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) {
         return new_<ConditionalExpression>(cond, thenExpr, elseExpr);
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -749,17 +749,17 @@ NameNode::dump(int indent)
         fprintf(stderr, "(%s ", name);
         indent += strlen(name) + 2;
         DumpParseTree(expr(), indent);
         fprintf(stderr, ")");
     }
 }
 #endif
 
-ObjectBox::ObjectBox(JSObject *object, ObjectBox* traceLink)
+ObjectBox::ObjectBox(NativeObject *object, ObjectBox* traceLink)
   : object(object),
     traceLink(traceLink),
     emitLink(nullptr)
 {
     MOZ_ASSERT(!object->is<JSFunction>());
 }
 
 ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink)
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1493,19 +1493,19 @@ ParseNode::isConstant()
       default:
         return false;
     }
 }
 
 class ObjectBox
 {
   public:
-    JSObject *object;
+    NativeObject *object;
 
-    ObjectBox(JSObject *object, ObjectBox *traceLink);
+    ObjectBox(NativeObject *object, ObjectBox *traceLink);
     bool isFunctionBox() { return object->is<JSFunction>(); }
     FunctionBox *asFunctionBox();
     void trace(JSTracer *trc);
 
   protected:
     friend struct CGObjectList;
 
     ObjectBox *traceLink;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -532,17 +532,17 @@ Parser<ParseHandler>::~Parser()
     {
         AutoLockForExclusiveAccess lock(context);
         context->perThreadData->removeActiveCompilation();
     }
 }
 
 template <typename ParseHandler>
 ObjectBox *
-Parser<ParseHandler>::newObjectBox(JSObject *obj)
+Parser<ParseHandler>::newObjectBox(NativeObject *obj)
 {
     MOZ_ASSERT(obj && !IsPoisonedPtr(obj));
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
@@ -2956,17 +2956,17 @@ LexicalLookup(ContextT *ct, HandleAtom a
         if (stmt->type == STMT_WITH)
             break;
 
         // Skip statements that do not introduce a new scope
         if (!stmt->isBlockScope)
             continue;
 
         StaticBlockObject &blockObj = stmt->staticBlock();
-        Shape *shape = blockObj.nativeLookup(ct->sc->context, id);
+        Shape *shape = blockObj.lookup(ct->sc->context, id);
         if (shape) {
             if (slotp)
                 *slotp = blockObj.shapeToIndex(*shape);
             return stmt;
         }
     }
 
     if (slotp)
@@ -7214,17 +7214,17 @@ Parser<ParseHandler>::arrayInitializer()
         handler.setListFlag(literal, PNX_NONCONST);
     } else if (tokenStream.matchToken(TOK_FOR, TokenStream::Operand)) {
         // ES6 array comprehension.
         return arrayComprehension(begin);
     } else {
         bool spread = false, missingTrailingComma = false;
         uint32_t index = 0;
         for (; ; index++) {
-            if (index == JSObject::NELEMENTS_LIMIT) {
+            if (index == NativeObject::NELEMENTS_LIMIT) {
                 report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
                 return null();
             }
 
             TokenKind tt = tokenStream.peekToken(TokenStream::Operand);
             if (tt == TOK_RB)
                 break;
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -424,17 +424,17 @@ class Parser : private JS::AutoGCRooter,
      * Parse a top-level JS script.
      */
     Node parse(JSObject *chain);
 
     /*
      * Allocate a new parsed object or function container from
      * cx->tempLifoAlloc.
      */
-    ObjectBox *newObjectBox(JSObject *obj);
+    ObjectBox *newObjectBox(NativeObject *obj);
     FunctionBox *newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *pc,
                                 Directives directives, GeneratorKind generatorKind);
 
     /*
      * Create a new function object given parse context (pc) and a name (which
      * is optional if this is a function expression).
      */
     JSFunction *newFunction(GenericParseContext *pc, HandleAtom atom, FunctionSyntaxKind kind,
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -90,17 +90,17 @@ class SyntaxParseHandler
     bool addToCallSiteObject(Node callSiteObj, Node rawNode, Node cookedNode) {
         return true;
     }
 
     Node newThisLiteral(const TokenPos &pos) { return NodeGeneric; }
     Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; }
 
     template <class Boxer>
-    Node newRegExp(JSObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; }
+    Node newRegExp(RegExpObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; }
 
     Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; }
 
     Node newElision() { return NodeGeneric; }
 
     Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; }
 
     Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) {
--- a/js/src/gc/Barrier.cpp
+++ b/js/src/gc/Barrier.cpp
@@ -29,35 +29,35 @@ ValueReadBarrier(const Value &value)
         MOZ_ASSERT(!value.isMarkable());
 }
 
 #ifdef DEBUG
 bool
 HeapSlot::preconditionForSet(JSObject *owner, Kind kind, uint32_t slot)
 {
     return kind == Slot
-         ? &owner->getSlotRef(slot) == this
-         : &owner->getDenseElement(slot) == (const Value *)this;
+         ? &owner->fakeNativeGetSlotRef(slot) == this
+         : &owner->fakeNativeGetDenseElement(slot) == (const Value *)this;
 }
 
 bool
 HeapSlot::preconditionForSet(Zone *zone, JSObject *owner, Kind kind, uint32_t slot)
 {
     bool ok = kind == Slot
-            ? &owner->getSlotRef(slot) == this
-            : &owner->getDenseElement(slot) == (const Value *)this;
+            ? &owner->fakeNativeGetSlotRef(slot) == this
+            : &owner->fakeNativeGetDenseElement(slot) == (const Value *)this;
     return ok && owner->zone() == zone;
 }
 
 bool
 HeapSlot::preconditionForWriteBarrierPost(JSObject *obj, Kind kind, uint32_t slot, Value target) const
 {
     return kind == Slot
-         ? obj->getSlotAddressUnchecked(slot)->get() == target
-         : static_cast<HeapSlot *>(obj->getDenseElements() + slot)->get() == target;
+         ? obj->fakeNativeGetSlotAddressUnchecked(slot)->get() == target
+         : static_cast<HeapSlot *>(obj->fakeNativeGetDenseElements() + slot)->get() == target;
 }
 
 bool
 RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone *shadowZone)
 {
     return shadowZone->runtimeFromMainThread()->isHeapMajorCollecting();
 }
 
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -156,29 +156,30 @@ class JSFlatString;
 class JSLinearString;
 
 namespace JS {
 class Symbol;
 }
 
 namespace js {
 
+class NativeObject;
+class ArrayObject;
 class ArgumentsObject;
 class ArrayBufferObjectMaybeShared;
 class ArrayBufferObject;
 class ArrayBufferViewObject;
 class SharedArrayBufferObject;
 class SharedTypedArrayObject;
 class BaseShape;
 class DebugScopeObject;
 class GlobalObject;
 class LazyScript;
 class NestedScopeObject;
 class Nursery;
-class ObjectImpl;
 class PropertyName;
 class SavedFrame;
 class ScopeObject;
 class ScriptSourceObject;
 class Shape;
 class UnownedBaseShape;
 
 namespace types {
@@ -197,16 +198,18 @@ CurrentThreadIsIonCompiling();
 #endif
 
 bool
 StringIsPermanentAtom(JSString *str);
 
 namespace gc {
 
 template <typename T> struct MapTypeToTraceKind {};
+template <> struct MapTypeToTraceKind<NativeObject>     { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
+template <> struct MapTypeToTraceKind<ArrayObject>      { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArgumentsObject>  { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArrayBufferObjectMaybeShared>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<BaseShape>        { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
 template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<GlobalObject>     { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<JS::Symbol>       { static const JSGCTraceKind kind = JSTRACE_SYMBOL; };
@@ -214,17 +217,16 @@ template <> struct MapTypeToTraceKind<JS
 template <> struct MapTypeToTraceKind<JSFlatString>     { static const JSGCTraceKind kind = JSTRACE_STRING; };
 template <> struct MapTypeToTraceKind<JSFunction>       { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<JSLinearString>   { static const JSGCTraceKind kind = JSTRACE_STRING; };
 template <> struct MapTypeToTraceKind<JSObject>         { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<JSScript>         { static const JSGCTraceKind kind = JSTRACE_SCRIPT; };
 template <> struct MapTypeToTraceKind<JSString>         { static const JSGCTraceKind kind = JSTRACE_STRING; };
 template <> struct MapTypeToTraceKind<LazyScript>       { static const JSGCTraceKind kind = JSTRACE_LAZY_SCRIPT; };
 template <> struct MapTypeToTraceKind<NestedScopeObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
-template <> struct MapTypeToTraceKind<ObjectImpl>       { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<PropertyName>     { static const JSGCTraceKind kind = JSTRACE_STRING; };
 template <> struct MapTypeToTraceKind<SavedFrame>       { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ScopeObject>      { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<Shape>            { static const JSGCTraceKind kind = JSTRACE_SHAPE; };
 template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<SharedTypedArrayObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
 template <> struct MapTypeToTraceKind<jit::JitCode>     { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
@@ -773,16 +775,17 @@ class ReadBarriered
     T operator->() const { return get(); }
 
     T *unsafeGet() { return &value; }
     T const * unsafeGet() const { return &value; }
 
     void set(T v) { value = v; }
 };
 
+class ArrayObject;
 class ArrayBufferObject;
 class NestedScopeObject;
 class DebugScopeObject;
 class GlobalObject;
 class ScriptSourceObject;
 class Shape;
 class BaseShape;
 class UnownedBaseShape;
@@ -796,18 +799,21 @@ class TypeNewScript;
 
 typedef PreBarriered<JSObject*> PreBarrieredObject;
 typedef PreBarriered<JSScript*> PreBarrieredScript;
 typedef PreBarriered<jit::JitCode*> PreBarrieredJitCode;
 typedef PreBarriered<JSAtom*> PreBarrieredAtom;
 
 typedef RelocatablePtr<JSObject*> RelocatablePtrObject;
 typedef RelocatablePtr<JSScript*> RelocatablePtrScript;
+typedef RelocatablePtr<NativeObject*> RelocatablePtrNativeObject;
 typedef RelocatablePtr<NestedScopeObject*> RelocatablePtrNestedScopeObject;
 
+typedef HeapPtr<NativeObject*> HeapPtrNativeObject;
+typedef HeapPtr<ArrayObject*> HeapPtrArrayObject;
 typedef HeapPtr<ArrayBufferObjectMaybeShared*> HeapPtrArrayBufferObjectMaybeShared;
 typedef HeapPtr<ArrayBufferObject*> HeapPtrArrayBufferObject;
 typedef HeapPtr<BaseShape*> HeapPtrBaseShape;
 typedef HeapPtr<JSAtom*> HeapPtrAtom;
 typedef HeapPtr<JSFlatString*> HeapPtrFlatString;
 typedef HeapPtr<JSFunction*> HeapPtrFunction;
 typedef HeapPtr<JSLinearString*> HeapPtrLinearString;
 typedef HeapPtr<JSObject*> HeapPtrObject;
--- a/js/src/gc/ForkJoinNursery.cpp
+++ b/js/src/gc/ForkJoinNursery.cpp
@@ -533,19 +533,19 @@ ForkJoinNursery::allocateObject(size_t b
 
     // Allocate slots contiguously after the object.
     size_t totalSize = baseSize + sizeof(HeapSlot) * numDynamic;
     JSObject *obj = static_cast<JSObject *>(allocate(totalSize));
     if (!obj) {
         tooLarge = false;
         return nullptr;
     }
-    obj->setInitialSlots(numDynamic
-                         ? reinterpret_cast<HeapSlot *>(size_t(obj) + baseSize)
-                         : nullptr);
+    obj->fakeNativeSetInitialSlots(numDynamic
+                                   ? reinterpret_cast<HeapSlot *>(size_t(obj) + baseSize)
+                                   : nullptr);
     return obj;
 }
 
 HeapSlot *
 ForkJoinNursery::allocateSlots(JSObject *obj, uint32_t nslots)
 {
     MOZ_ASSERT(obj);
     MOZ_ASSERT(nslots > 0);
@@ -663,22 +663,23 @@ MOZ_ALWAYS_INLINE void
 ForkJoinNursery::traceObject(ForkJoinNurseryCollectionTracer *trc, JSObject *obj)
 {
     const Class *clasp = obj->getClass();
     if (clasp->trace)
         clasp->trace(trc, obj);
 
     if (!obj->isNative())
         return;
+    NativeObject *nobj = &obj->as<NativeObject>();
 
-    if (!obj->hasEmptyElements())
-        markSlots(obj->getDenseElements(), obj->getDenseInitializedLength());
+    if (!nobj->hasEmptyElements())
+        markSlots(nobj->getDenseElements(), nobj->getDenseInitializedLength());
 
     HeapSlot *fixedStart, *fixedEnd, *dynStart, *dynEnd;
-    obj->getSlotRange(0, obj->slotSpan(), &fixedStart, &fixedEnd, &dynStart, &dynEnd);
+    nobj->getSlotRange(0, nobj->slotSpan(), &fixedStart, &fixedEnd, &dynStart, &dynEnd);
     markSlots(fixedStart, fixedEnd);
     markSlots(dynStart, dynEnd);
 }
 
 MOZ_ALWAYS_INLINE void
 ForkJoinNursery::markSlots(HeapSlot *vp, uint32_t nslots)
 {
     markSlots(vp, vp + nslots);
@@ -709,30 +710,31 @@ ForkJoinNursery::markSlot(HeapSlot *slot
     JSObject *moved = static_cast<JSObject *>(moveObjectToTospace(obj));
     slotp->unsafeGet()->setObject(*moved);
 }
 
 AllocKind
 ForkJoinNursery::getObjectAllocKind(JSObject *obj)
 {
     if (obj->is<ArrayObject>()) {
-        MOZ_ASSERT(obj->numFixedSlots() == 0);
+        ArrayObject *aobj = &obj->as<ArrayObject>();
+        MOZ_ASSERT(aobj->numFixedSlots() == 0);
 
         // Use minimal size object if we are just going to copy the pointer.
-        if (!isInsideFromspace((void *)obj->getElementsHeader()))
+        if (!isInsideFromspace((void *)aobj->getElementsHeader()))
             return FINALIZE_OBJECT0_BACKGROUND;
 
-        size_t nelements = obj->getDenseCapacity();
+        size_t nelements = aobj->getDenseCapacity();
         return GetBackgroundAllocKind(GetGCArrayKind(nelements));
     }
 
     if (obj->is<JSFunction>())
         return obj->as<JSFunction>().getAllocKind();
 
-    AllocKind kind = GetGCObjectFixedSlotsKind(obj->numFixedSlots());
+    AllocKind kind = GetGCObjectFixedSlotsKind(obj->fakeNativeNumFixedSlots());
     MOZ_ASSERT(!IsBackgroundFinalized(kind));
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, obj->getClass()));
     return GetBackgroundAllocKind(kind);
 }
 
 // Nursery allocation will never fail during GC - apart from true OOM - since
 // newspace is at least as large as fromspace, ergo a nullptr return from the
 // allocator means true OOM, which we catch and signal here.
@@ -803,17 +805,17 @@ ForkJoinNursery::copyObjectToTospace(JSO
 {
     size_t srcSize = Arena::thingSize(dstKind);
     size_t movedSize = srcSize;
 
     // Arrays do not necessarily have the same AllocKind between src and dst.
     // We deal with this by copying elements manually, possibly re-inlining
     // them if there is adequate room inline in dst.
     if (src->is<ArrayObject>())
-        srcSize = movedSize = sizeof(ObjectImpl);
+        srcSize = movedSize = sizeof(NativeObject);
 
     js_memcpy(dst, src, srcSize);
     movedSize += copySlotsToTospace(dst, src, dstKind);
     movedSize += copyElementsToTospace(dst, src, dstKind);
 
     // The shape's list head may point into the old object.
     if (&src->shape_ == dst->shape_->listp) {
         MOZ_ASSERT(cx_->isThreadLocal(dst->shape_.get()));
@@ -822,72 +824,72 @@ ForkJoinNursery::copyObjectToTospace(JSO
 
     return movedSize;
 }
 
 size_t
 ForkJoinNursery::copySlotsToTospace(JSObject *dst, JSObject *src, AllocKind dstKind)
 {
     // Fixed slots have already been copied over.
-    if (!src->hasDynamicSlots())
+    if (!src->fakeNativeHasDynamicSlots())
         return 0;
 
-    if (!isInsideFromspace(src->slots)) {
-        hugeSlots[hugeSlotsFrom].remove(src->slots);
+    if (!isInsideFromspace(src->fakeNativeSlots())) {
+        hugeSlots[hugeSlotsFrom].remove(src->fakeNativeSlots());
         if (!isEvacuating_)
-            hugeSlots[hugeSlotsNew].put(src->slots);
+            hugeSlots[hugeSlotsNew].put(src->fakeNativeSlots());
         return 0;
     }
 
-    size_t count = src->numDynamicSlots();
-    dst->slots = allocateInTospace<HeapSlot>(count);
-    if (!dst->slots)
+    size_t count = src->fakeNativeNumDynamicSlots();
+    dst->fakeNativeSlots() = allocateInTospace<HeapSlot>(count);
+    if (!dst->fakeNativeSlots())
         CrashAtUnhandlableOOM("Failed to allocate slots while moving object.");
-    js_memcpy(dst->slots, src->slots, count * sizeof(HeapSlot));
-    setSlotsForwardingPointer(src->slots, dst->slots, count);
+    js_memcpy(dst->fakeNativeSlots(), src->fakeNativeSlots(), count * sizeof(HeapSlot));
+    setSlotsForwardingPointer(src->fakeNativeSlots(), dst->fakeNativeSlots(), count);
     return count * sizeof(HeapSlot);
 }
 
 size_t
 ForkJoinNursery::copyElementsToTospace(JSObject *dst, JSObject *src, AllocKind dstKind)
 {
-    if (src->hasEmptyElements() || src->denseElementsAreCopyOnWrite())
+    if (src->fakeNativeHasEmptyElements() || src->fakeNativeDenseElementsAreCopyOnWrite())
         return 0;
 
-    ObjectElements *srcHeader = src->getElementsHeader();
+    ObjectElements *srcHeader = src->fakeNativeGetElementsHeader();
     ObjectElements *dstHeader;
 
     // TODO Bug 874151: Prefer to put element data inline if we have space.
     // (Note, not a correctness issue.)
     if (!isInsideFromspace(srcHeader)) {
-        MOZ_ASSERT(src->elements == dst->elements);
+        MOZ_ASSERT(src->fakeNativeElements() == dst->fakeNativeElements());
         hugeSlots[hugeSlotsFrom].remove(reinterpret_cast<HeapSlot*>(srcHeader));
         if (!isEvacuating_)
             hugeSlots[hugeSlotsNew].put(reinterpret_cast<HeapSlot*>(srcHeader));
         return 0;
     }
 
     size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity;
 
     // Unlike other objects, Arrays can have fixed elements.
     if (src->is<ArrayObject>() && nslots <= GetGCKindSlots(dstKind)) {
-        dst->setFixedElements();
-        dstHeader = dst->getElementsHeader();
+        dst->as<ArrayObject>().setFixedElements();
+        dstHeader = dst->as<ArrayObject>().getElementsHeader();
         js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
         setElementsForwardingPointer(srcHeader, dstHeader, nslots);
         return nslots * sizeof(HeapSlot);
     }
 
     MOZ_ASSERT(nslots >= 2);
     dstHeader = reinterpret_cast<ObjectElements *>(allocateInTospace<HeapSlot>(nslots));
     if (!dstHeader)
         CrashAtUnhandlableOOM("Failed to allocate elements while moving object.");
     js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
     setElementsForwardingPointer(srcHeader, dstHeader, nslots);
-    dst->elements = dstHeader->elements();
+    dst->fakeNativeElements() = dstHeader->elements();
     return nslots * sizeof(HeapSlot);
 }
 
 void
 ForkJoinNursery::setSlotsForwardingPointer(HeapSlot *oldSlots, HeapSlot *newSlots, uint32_t nslots)
 {
     MOZ_ASSERT(nslots > 0);
     MOZ_ASSERT(isInsideFromspace(oldSlots));
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -136,17 +136,16 @@ void
 CheckHashTablesAfterMovingGC(JSRuntime *rt);
 #endif
 
 #ifdef JSGC_COMPACTING
 struct MovingTracer : JSTracer {
     MovingTracer(JSRuntime *rt) : JSTracer(rt, Visit, TraceWeakMapKeysValues) {}
 
     static void Visit(JSTracer *jstrc, void **thingp, JSGCTraceKind kind);
-    static void Sweep(JSTracer *jstrc);
     static bool IsMovingTracer(JSTracer *trc) {
         return trc->callback == Visit;
     }
 };
 #endif
 
 
 } /* namespace gc */
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -527,16 +527,17 @@ class GCRuntime
     void sweepZones(FreeOp *fop, bool lastGC);
     void decommitArenasFromAvailableList(Chunk **availableListHeadp);
     void decommitArenas();
     void expireChunksAndArenas(bool shouldShrink);
     void sweepBackgroundThings(bool onBackgroundThread);
     void assertBackgroundSweepingFinished();
     bool shouldCompact();
 #ifdef JSGC_COMPACTING
+    void sweepZoneAfterCompacting(Zone *zone);
     void compactPhase();
     ArenaHeader *relocateArenas();
     void updatePointersToRelocatedCells();
     void releaseRelocatedArenas(ArenaHeader *relocatedList);
 #endif
     void finishCollection();
 
     void computeNonIncrementalMarkingForValidation();
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -178,17 +178,17 @@ class TenuredCell : public Cell
     static MOZ_ALWAYS_INLINE const TenuredCell *fromPointer(const void *ptr);
 
     // Mark bit management.
     MOZ_ALWAYS_INLINE bool isMarked(uint32_t color = BLACK) const;
     MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
     MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
     MOZ_ALWAYS_INLINE void copyMarkBitsFrom(const TenuredCell *src);
 
-    // Note: this is in TenuredCell because ObjectImpl subclasses are sometimes
+    // Note: this is in TenuredCell because JSObject subclasses are sometimes
     // used tagged.
     static MOZ_ALWAYS_INLINE bool isNullLike(const Cell *thing) { return !thing; }
 
     // Access to the arena header.
     inline ArenaHeader *arenaHeader() const;
     inline AllocKind getAllocKind() const;
     inline JS::Zone *zone() const;
     inline JS::Zone *zoneFromAnyThread() const;
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/DebugOnly.h"
 
 #include "jsprf.h"
 
 #include "jit/IonCode.h"
 #include "js/SliceBudget.h"
 #include "vm/ArgumentsObject.h"
+#include "vm/ArrayObject.h"
 #include "vm/ScopeObject.h"
 #include "vm/Shape.h"
 #include "vm/Symbol.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jscompartmentinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
@@ -63,17 +64,17 @@ JS_PUBLIC_DATA(void * const) JS::NullPtr
  * call a callback for each object visited. This is a recursive process; the
  * mark stacks are not involved. These callbacks may ask for the outgoing
  * pointers to be visited. Eventually, this leads to the MarkChildren functions
  * being called. These functions duplicate much of the functionality of
  * scanning functions, but they don't push onto an explicit stack.
  */
 
 static inline void
-PushMarkStack(GCMarker *gcmarker, ObjectImpl *thing);
+PushMarkStack(GCMarker *gcmarker, JSObject *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSScript *thing);
 
 static inline void
@@ -251,16 +252,23 @@ template<>
 void
 SetMaybeAliveFlag(JSObject *thing)
 {
     thing->compartment()->maybeAlive = true;
 }
 
 template<>
 void
+SetMaybeAliveFlag(NativeObject *thing)
+{
+    thing->compartment()->maybeAlive = true;
+}
+
+template<>
+void
 SetMaybeAliveFlag(JSScript *thing)
 {
     thing->compartment()->maybeAlive = true;
 }
 
 template<typename T>
 static void
 MarkInternal(JSTracer *trc, T **thingp)
@@ -624,26 +632,27 @@ Update##base##IfRelocated(JSRuntime *rt,
 {                                                                                                 \
     return UpdateIfRelocated<type>(rt, thingp);                                                   \
 }
 
 
 DeclMarkerImpl(BaseShape, BaseShape)
 DeclMarkerImpl(BaseShape, UnownedBaseShape)
 DeclMarkerImpl(JitCode, jit::JitCode)
+DeclMarkerImpl(Object, NativeObject)
+DeclMarkerImpl(Object, ArrayObject)
 DeclMarkerImpl(Object, ArgumentsObject)
 DeclMarkerImpl(Object, ArrayBufferObject)
 DeclMarkerImpl(Object, ArrayBufferObjectMaybeShared)
 DeclMarkerImpl(Object, ArrayBufferViewObject)
 DeclMarkerImpl(Object, DebugScopeObject)
 DeclMarkerImpl(Object, GlobalObject)
 DeclMarkerImpl(Object, JSObject)
 DeclMarkerImpl(Object, JSFunction)
 DeclMarkerImpl(Object, NestedScopeObject)
-DeclMarkerImpl(Object, ObjectImpl)
 DeclMarkerImpl(Object, SavedFrame)
 DeclMarkerImpl(Object, ScopeObject)
 DeclMarkerImpl(Object, SharedArrayBufferObject)
 DeclMarkerImpl(Object, SharedTypedArrayObject)
 DeclMarkerImpl(Script, JSScript)
 DeclMarkerImpl(LazyScript, LazyScript)
 DeclMarkerImpl(Shape, Shape)
 DeclMarkerImpl(String, JSAtom)
@@ -926,17 +935,17 @@ gc::MarkArraySlots(JSTracer *trc, size_t
 }
 
 void
 gc::MarkObjectSlots(JSTracer *trc, JSObject *obj, uint32_t start, uint32_t nslots)
 {
     MOZ_ASSERT(obj->isNative());
     for (uint32_t i = start; i < (start + nslots); ++i) {
         trc->setTracingDetails(js_GetObjectSlotName, obj, i);
-        MarkValueInternal(trc, obj->nativeGetSlotRef(i).unsafeGet());
+        MarkValueInternal(trc, obj->fakeNativeGetSlotRef(i).unsafeGet());
     }
 }
 
 static bool
 ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell)
 {
     if (!IS_GC_MARKING_TRACER(trc))
         return true;
@@ -1031,17 +1040,17 @@ gc::IsCellAboutToBeFinalized(Cell **thin
     MOZ_ASSERT((thing)->zone()->isGCMarking() ||                        \
                (rt)->isAtomsZone((thing)->zone()));
 
 // Symbols can also be in the atoms zone.
 #define JS_COMPARTMENT_ASSERT_SYM(rt, sym)                              \
     JS_COMPARTMENT_ASSERT_STR(rt, sym)
 
 static void
-PushMarkStack(GCMarker *gcmarker, ObjectImpl *thing)
+PushMarkStack(GCMarker *gcmarker, JSObject *thing)
 {
     JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
     MOZ_ASSERT(!IsInsideNursery(thing));
 
     if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
@@ -1536,17 +1545,17 @@ struct SlotArrayLayout
     union {
         HeapSlot *end;
         uintptr_t kind;
     };
     union {
         HeapSlot *start;
         uintptr_t index;
     };
-    JSObject *obj;
+    NativeObject *obj;
 
     static void staticAsserts() {
         /* This should have the same layout as three mark stack items. */
         JS_STATIC_ASSERT(sizeof(SlotArrayLayout) == 3 * sizeof(uintptr_t));
     }
 };
 
 /*
@@ -1561,17 +1570,17 @@ void
 GCMarker::saveValueRanges()
 {
     for (uintptr_t *p = stack.tos_; p > stack.stack_; ) {
         uintptr_t tag = *--p & StackTagMask;
         if (tag == ValueArrayTag) {
             *p &= ~StackTagMask;
             p -= 2;
             SlotArrayLayout *arr = reinterpret_cast<SlotArrayLayout *>(p);
-            JSObject *obj = arr->obj;
+            NativeObject *obj = arr->obj;
             MOZ_ASSERT(obj->isNative());
 
             HeapSlot *vp = obj->getDenseElements();
             if (arr->end == vp + obj->getDenseInitializedLength()) {
                 MOZ_ASSERT(arr->start >= vp);
                 arr->index = arr->start - vp;
                 arr->kind = HeapSlot::Element;
             } else {
@@ -1592,17 +1601,17 @@ GCMarker::saveValueRanges()
             p[2] |= SavedValueArrayTag;
         } else if (tag == SavedValueArrayTag) {
             p -= 2;
         }
     }
 }
 
 bool
-GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp)
+GCMarker::restoreValueArray(NativeObject *obj, void **vpp, void **endp)
 {
     uintptr_t start = stack.pop();
     HeapSlot::Kind kind = (HeapSlot::Kind) stack.pop();
 
     if (kind == HeapSlot::Element) {
         if (!obj->is<ArrayObject>())
             return false;
 
@@ -1640,17 +1649,17 @@ GCMarker::restoreValueArray(JSObject *ob
 
 void
 GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
 {
     if (tag == TypeTag) {
         ScanTypeObject(this, reinterpret_cast<types::TypeObject *>(addr));
     } else if (tag == SavedValueArrayTag) {
         MOZ_ASSERT(!(addr & CellMask));
-        JSObject *obj = reinterpret_cast<JSObject *>(addr);
+        NativeObject *obj = reinterpret_cast<NativeObject *>(addr);
         HeapValue *vp, *end;
         if (restoreValueArray(obj, (void **)&vp, (void **)&end))
             pushValueArray(obj, vp, end);
         else
             pushObject(obj);
     } else if (tag == JitCodeTag) {
         MarkChildren(this, reinterpret_cast<jit::JitCode *>(addr));
     }
@@ -1754,48 +1763,49 @@ GCMarker::processMarkStackTop(SliceBudge
                              !obj->isOwnGlobal())),
                           clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
             clasp->trace(this, obj);
         }
 
         if (!shape->isNative())
             return;
 
-        unsigned nslots = obj->slotSpan();
+        NativeObject *nobj = &obj->as<NativeObject>();
+        unsigned nslots = nobj->slotSpan();
 
         do {
-            if (obj->hasEmptyElements())
+            if (nobj->hasEmptyElements())
                 break;
 
-            if (obj->denseElementsAreCopyOnWrite()) {
-                JSObject *owner = obj->getElementsHeader()->ownerObject();
-                if (owner != obj) {
+            if (nobj->denseElementsAreCopyOnWrite()) {
+                JSObject *owner = nobj->getElementsHeader()->ownerObject();
+                if (owner != nobj) {
                     PushMarkStack(this, owner);
                     break;
                 }
             }
 
-            vp = obj->getDenseElementsAllowCopyOnWrite();
-            end = vp + obj->getDenseInitializedLength();
+            vp = nobj->getDenseElementsAllowCopyOnWrite();
+            end = vp + nobj->getDenseInitializedLength();
             if (!nslots)
                 goto scan_value_array;
-            pushValueArray(obj, vp, end);
+            pushValueArray(nobj, vp, end);
         } while (false);
 
-        vp = obj->fixedSlots();
-        if (obj->slots) {
-            unsigned nfixed = obj->numFixedSlots();
+        vp = nobj->fixedSlots();
+        if (nobj->slots) {
+            unsigned nfixed = nobj->numFixedSlots();
             if (nslots > nfixed) {
-                pushValueArray(obj, vp, vp + nfixed);
-                vp = obj->slots;
+                pushValueArray(nobj, vp, vp + nfixed);
+                vp = nobj->slots;
                 end = vp + (nslots - nfixed);
                 goto scan_value_array;
             }
         }
-        MOZ_ASSERT(nslots <= obj->numFixedSlots());
+        MOZ_ASSERT(nslots <= nobj->numFixedSlots());
         end = vp + nslots;
         goto scan_value_array;
     }
 }
 
 bool
 GCMarker::drainMarkStack(SliceBudget &budget)
 {
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -100,16 +100,18 @@ bool Is##base##Marked(BarrieredBase<type
 bool Is##base##AboutToBeFinalized(type **thingp);                                                 \
 bool Is##base##AboutToBeFinalized(BarrieredBase<type*> *thingp);                                  \
 type *Update##base##IfRelocated(JSRuntime *rt, BarrieredBase<type*> *thingp);                     \
 type *Update##base##IfRelocated(JSRuntime *rt, type **thingp);
 
 DeclMarker(BaseShape, BaseShape)
 DeclMarker(BaseShape, UnownedBaseShape)
 DeclMarker(JitCode, jit::JitCode)
+DeclMarker(Object, NativeObject)
+DeclMarker(Object, ArrayObject)
 DeclMarker(Object, ArgumentsObject)
 DeclMarker(Object, ArrayBufferObject)
 DeclMarker(Object, ArrayBufferObjectMaybeShared)
 DeclMarker(Object, ArrayBufferViewObject)
 DeclMarker(Object, DebugScopeObject)
 DeclMarker(Object, GlobalObject)
 DeclMarker(Object, JSObject)
 DeclMarker(Object, JSFunction)
@@ -300,16 +302,23 @@ Mark(JSTracer *trc, HeapPtrJitCode *code
 
 /* For use by WeakMap's HashKeyRef instantiation. */
 inline void
 Mark(JSTracer *trc, JSObject **objp, const char *name)
 {
     MarkObjectUnbarriered(trc, objp, name);
 }
 
+/* For use by Debugger::WeakMap's missingScopes HashKeyRef instantiation. */
+inline void
+Mark(JSTracer *trc, NativeObject **obj, const char *name)
+{
+    MarkObjectUnbarriered(trc, obj, name);
+}
+
 /* For use by Debugger::WeakMap's proxiedScopes HashKeyRef instantiation. */
 inline void
 Mark(JSTracer *trc, ScopeObject **obj, const char *name)
 {
     MarkObjectUnbarriered(trc, obj, name);
 }
 
 bool
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -166,34 +166,34 @@ js::Nursery::allocateObject(JSContext *c
     /* Ensure there's enough space to replace the contents with a RelocationOverlay. */
     MOZ_ASSERT(size >= sizeof(RelocationOverlay));
 
     /* Attempt to allocate slots contiguously after object, if possible. */
     if (numDynamic && numDynamic <= MaxNurserySlots) {
         size_t totalSize = size + sizeof(HeapSlot) * numDynamic;
         JSObject *obj = static_cast<JSObject *>(allocate(totalSize));
         if (obj) {
-            obj->setInitialSlots(reinterpret_cast<HeapSlot *>(size_t(obj) + size));
+            obj->fakeNativeSetInitialSlots(reinterpret_cast<HeapSlot *>(size_t(obj) + size));
             TraceNurseryAlloc(obj, size);
             return obj;
         }
         /* If we failed to allocate as a block, retry with out-of-line slots. */
     }
 
     HeapSlot *slots = nullptr;
     if (numDynamic) {
         slots = allocateHugeSlots(cx->zone(), numDynamic);
         if (MOZ_UNLIKELY(!slots))
             return nullptr;
     }
 
     JSObject *obj = static_cast<JSObject *>(allocate(size));
 
     if (obj)
-        obj->setInitialSlots(slots);
+        obj->fakeNativeSetInitialSlots(slots);
     else
         freeSlots(slots);
 
     TraceNurseryAlloc(obj, size);
     return obj;
 }
 
 void *
@@ -362,23 +362,24 @@ class MinorCollectionTracer : public JST
 
 } /* namespace gc */
 } /* namespace js */
 
 static AllocKind
 GetObjectAllocKindForCopy(const Nursery &nursery, JSObject *obj)
 {
     if (obj->is<ArrayObject>()) {
-        MOZ_ASSERT(obj->numFixedSlots() == 0);
+        ArrayObject *aobj = &obj->as<ArrayObject>();
+        MOZ_ASSERT(aobj->numFixedSlots() == 0);
 
         /* Use minimal size object if we are just going to copy the pointer. */
-        if (!nursery.isInside(obj->getElementsHeader()))
+        if (!nursery.isInside(aobj->getElementsHeader()))
             return FINALIZE_OBJECT0_BACKGROUND;
 
-        size_t nelements = obj->getDenseCapacity();
+        size_t nelements = aobj->getDenseCapacity();
         return GetBackgroundAllocKind(GetGCArrayKind(nelements));
     }
 
     if (obj->is<JSFunction>())
         return obj->as<JSFunction>().getAllocKind();
 
     /*
      * Typed arrays in the nursery may have a lazily allocated buffer, make
@@ -394,17 +395,17 @@ GetObjectAllocKindForCopy(const Nursery 
     if (obj->is<InlineOpaqueTypedObject>()) {
         // Figure out the size of this object, from the prototype's TypeDescr.
         // The objects we are traversing here are all tenured, so we don't need
         // to check forwarding pointers.
         TypeDescr *descr = &obj->as<InlineOpaqueTypedObject>().typeDescr();
         return InlineOpaqueTypedObject::allocKindForTypeDescriptor(descr);
     }
 
-    AllocKind kind = GetGCObjectFixedSlotsKind(obj->numFixedSlots());
+    AllocKind kind = GetGCObjectFixedSlotsKind(obj->fakeNativeNumFixedSlots());
     MOZ_ASSERT(!IsBackgroundFinalized(kind));
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, obj->getClass()));
     return GetBackgroundAllocKind(kind);
 }
 
 MOZ_ALWAYS_INLINE void *
 js::Nursery::allocateFromTenured(Zone *zone, AllocKind thingKind)
 {
@@ -513,24 +514,25 @@ js::Nursery::traceObject(MinorCollection
 {
     const Class *clasp = obj->getClass();
     if (clasp->trace)
         clasp->trace(trc, obj);
 
     MOZ_ASSERT(obj->isNative() == clasp->isNative());
     if (!clasp->isNative())
         return;
+    NativeObject *nobj = &obj->as<NativeObject>();
 
     // Note: the contents of copy on write elements pointers are filled in
     // during parsing and cannot contain nursery pointers.
-    if (!obj->hasEmptyElements() && !obj->denseElementsAreCopyOnWrite())
-        markSlots(trc, obj->getDenseElements(), obj->getDenseInitializedLength());
+    if (!nobj->hasEmptyElements() && !nobj->denseElementsAreCopyOnWrite())
+        markSlots(trc, nobj->getDenseElements(), nobj->getDenseInitializedLength());
 
     HeapSlot *fixedStart, *fixedEnd, *dynStart, *dynEnd;
-    obj->getSlotRange(0, obj->slotSpan(), &fixedStart, &fixedEnd, &dynStart, &dynEnd);
+    nobj->getSlotRange(0, nobj->slotSpan(), &fixedStart, &fixedEnd, &dynStart, &dynEnd);
     markSlots(trc, fixedStart, fixedEnd);
     markSlots(trc, dynStart, dynEnd);
 }
 
 MOZ_ALWAYS_INLINE void
 js::Nursery::markSlots(MinorCollectionTracer *trc, HeapSlot *vp, uint32_t nslots)
 {
     markSlots(trc, vp, vp + nslots);
@@ -592,44 +594,44 @@ js::Nursery::moveObjectToTenured(JSObjec
      * We deal with this by copying elements manually, possibly re-inlining
      * them if there is adequate room inline in dst.
      *
      * For Arrays we're reducing tenuredSize to the smaller srcSize
      * because moveElementsToTenured() accounts for all Array elements,
      * even if they are inlined.
      */
     if (src->is<ArrayObject>())
-        tenuredSize = srcSize = sizeof(ObjectImpl);
+        tenuredSize = srcSize = sizeof(NativeObject);
 
     js_memcpy(dst, src, srcSize);
     tenuredSize += moveSlotsToTenured(dst, src, dstKind);
     tenuredSize += moveElementsToTenured(dst, src, dstKind);
 
     if (src->is<TypedArrayObject>())
-        forwardTypedArrayPointers(dst, src);
+        forwardTypedArrayPointers(&dst->as<TypedArrayObject>(), &src->as<TypedArrayObject>());
 
     /* The shape's list head may point into the old object. */
     if (&src->shape_ == dst->shape_->listp)
         dst->shape_->listp = &dst->shape_;
 
     return tenuredSize;
 }
 
 void
-js::Nursery::forwardTypedArrayPointers(JSObject *dst, JSObject *src)
+js::Nursery::forwardTypedArrayPointers(TypedArrayObject *dst, TypedArrayObject *src)
 {
     /*
      * Typed array data may be stored inline inside the object's fixed slots. If
      * so, we need update the private pointer and leave a forwarding pointer at
      * the start of the data.
      */
-    TypedArrayObject &typedArray = src->as<TypedArrayObject>();
-    MOZ_ASSERT_IF(typedArray.buffer(), !isInside(src->getPrivate()));
-    if (typedArray.buffer())
+    if (src->buffer()) {
+        MOZ_ASSERT(!isInside(src->getPrivate()));
         return;
+    }
 
     void *srcData = src->fixedData(TypedArrayObject::FIXED_DATA_START);
     void *dstData = dst->fixedData(TypedArrayObject::FIXED_DATA_START);
     MOZ_ASSERT(src->getPrivate() == srcData);
     dst->setPrivate(dstData);
 
     /*
      * We don't know the number of slots here, but
@@ -641,69 +643,69 @@ js::Nursery::forwardTypedArrayPointers(J
                               reinterpret_cast<HeapSlot*>(dstData),
                               nslots);
 }
 
 MOZ_ALWAYS_INLINE size_t
 js::Nursery::moveSlotsToTenured(JSObject *dst, JSObject *src, AllocKind dstKind)
 {
     /* Fixed slots have already been copied over. */
-    if (!src->hasDynamicSlots())
+    if (!src->fakeNativeHasDynamicSlots())
         return 0;
 
-    if (!isInside(src->slots)) {
-        hugeSlots.remove(src->slots);
+    if (!isInside(src->fakeNativeSlots())) {
+        hugeSlots.remove(src->fakeNativeSlots());
         return 0;
     }
 
     Zone *zone = src->zone();
-    size_t count = src->numDynamicSlots();
-    dst->slots = zone->pod_malloc<HeapSlot>(count);
-    if (!dst->slots)
+    size_t count = src->fakeNativeNumDynamicSlots();
+    dst->fakeNativeSlots() = zone->pod_malloc<HeapSlot>(count);
+    if (!dst->fakeNativeSlots())
         CrashAtUnhandlableOOM("Failed to allocate slots while tenuring.");
-    PodCopy(dst->slots, src->slots, count);
-    setSlotsForwardingPointer(src->slots, dst->slots, count);
+    PodCopy(dst->fakeNativeSlots(), src->fakeNativeSlots(), count);
+    setSlotsForwardingPointer(src->fakeNativeSlots(), dst->fakeNativeSlots(), count);
     return count * sizeof(HeapSlot);
 }
 
 MOZ_ALWAYS_INLINE size_t
 js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKind)
 {
-    if (src->hasEmptyElements() || src->denseElementsAreCopyOnWrite())
+    if (src->fakeNativeHasEmptyElements() || src->fakeNativeDenseElementsAreCopyOnWrite())
         return 0;
 
     Zone *zone = src->zone();
-    ObjectElements *srcHeader = src->getElementsHeader();
+    ObjectElements *srcHeader = src->fakeNativeGetElementsHeader();
     ObjectElements *dstHeader;
 
     /* TODO Bug 874151: Prefer to put element data inline if we have space. */
     if (!isInside(srcHeader)) {
-        MOZ_ASSERT(src->elements == dst->elements);
+        MOZ_ASSERT(src->fakeNativeElements() == dst->fakeNativeElements());
         hugeSlots.remove(reinterpret_cast<HeapSlot*>(srcHeader));
         return 0;
     }
 
     size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity;
 
     /* Unlike other objects, Arrays can have fixed elements. */
     if (src->is<ArrayObject>() && nslots <= GetGCKindSlots(dstKind)) {
-        dst->setFixedElements();
-        dstHeader = dst->getElementsHeader();
+        dst->as<ArrayObject>().setFixedElements();
+        dstHeader = dst->as<ArrayObject>().getElementsHeader();
         js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
         setElementsForwardingPointer(srcHeader, dstHeader, nslots);
         return nslots * sizeof(HeapSlot);
     }
 
     MOZ_ASSERT(nslots >= 2);
     dstHeader = reinterpret_cast<ObjectElements *>(zone->pod_malloc<HeapSlot>(nslots));
     if (!dstHeader)
         CrashAtUnhandlableOOM("Failed to allocate elements while tenuring.");
     js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
     setElementsForwardingPointer(srcHeader, dstHeader, nslots);
-    dst->elements = dstHeader->elements();
+    dst->fakeNativeElements() = dstHeader->elements();
     return nslots * sizeof(HeapSlot);
 }
 
 static bool
 ShouldMoveToTenured(MinorCollectionTracer *trc, void **thingp)
 {
     Cell *cell = static_cast<Cell *>(*thingp);
     Nursery &nursery = *trc->nursery;
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -23,16 +23,17 @@
 #include "js/Vector.h"
 
 namespace JS {
 struct Zone;
 }
 
 namespace js {
 
+class TypedArrayObject;
 class ObjectElements;
 class HeapSlot;
 void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
 
 namespace gc {
 struct Cell;
 class Collector;
 class MinorCollectionTracer;
@@ -281,17 +282,17 @@ class Nursery
     MOZ_ALWAYS_INLINE void traceObject(gc::MinorCollectionTracer *trc, JSObject *src);
     MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer *trc, HeapSlot *vp, uint32_t nslots);
     MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer *trc, HeapSlot *vp, HeapSlot *end);
     MOZ_ALWAYS_INLINE void markSlot(gc::MinorCollectionTracer *trc, HeapSlot *slotp);
     void *moveToTenured(gc::MinorCollectionTracer *trc, JSObject *src);
     size_t moveObjectToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
     size_t moveElementsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
     size_t moveSlotsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
-    void forwardTypedArrayPointers(JSObject *dst, JSObject *src);
+    void forwardTypedArrayPointers(TypedArrayObject *dst, TypedArrayObject *src);
 
     /* Handle relocation of slots/elements pointers stored in Ion frames. */
     void setSlotsForwardingPointer(HeapSlot *oldSlots, HeapSlot *newSlots, uint32_t nslots);
     void setElementsForwardingPointer(ObjectElements *oldHeader, ObjectElements *newHeader,
                                       uint32_t nelems);
 
     /* Free malloced pointers owned by freed things in the nursery. */
     void freeHugeSlots();
--- a/js/src/gc/Rooting.h
+++ b/js/src/gc/Rooting.h
@@ -10,35 +10,42 @@
 #include "js/RootingAPI.h"
 
 class JSAtom;
 class JSLinearString;
 
 namespace js {
 
 class PropertyName;
+class NativeObject;
+class ArrayObject;
 class ScriptSourceObject;
 class Shape;
 
 namespace types { struct TypeObject; }
 
 // These are internal counterparts to the public types such as HandleObject.
 
+typedef JS::Handle<NativeObject*>      HandleNativeObject;
 typedef JS::Handle<Shape*>             HandleShape;
 typedef JS::Handle<types::TypeObject*> HandleTypeObject;
 typedef JS::Handle<JSAtom*>            HandleAtom;
 typedef JS::Handle<JSLinearString*>    HandleLinearString;
 typedef JS::Handle<PropertyName*>      HandlePropertyName;
+typedef JS::Handle<ArrayObject*>       HandleArrayObject;
 typedef JS::Handle<ScriptSourceObject*> HandleScriptSource;
 
 typedef JS::MutableHandle<Shape*>      MutableHandleShape;
 typedef JS::MutableHandle<JSAtom*>     MutableHandleAtom;
+typedef JS::MutableHandle<NativeObject*> MutableHandleNativeObject;
 
+typedef JS::Rooted<NativeObject*>      RootedNativeObject;
 typedef JS::Rooted<Shape*>             RootedShape;
 typedef JS::Rooted<types::TypeObject*> RootedTypeObject;
 typedef JS::Rooted<JSAtom*>            RootedAtom;
 typedef JS::Rooted<JSLinearString*>    RootedLinearString;
 typedef JS::Rooted<PropertyName*>      RootedPropertyName;
+typedef JS::Rooted<ArrayObject*>       RootedArrayObject;
 typedef JS::Rooted<ScriptSourceObject*> RootedScriptSource;
 
 } /* namespace js */
 
 #endif /* gc_Rooting_h */
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -32,24 +32,24 @@ StoreBuffer::SlotsEdge::mark(JSTracer *t
     if (!obj->isNative()) {
         const Class *clasp = obj->getClass();
         if (clasp)
             clasp->trace(trc, obj);
         return;
     }
 
     if (kind() == ElementKind) {
-        int32_t initLen = obj->getDenseInitializedLength();
+        int32_t initLen = obj->fakeNativeGetDenseInitializedLength();
         int32_t clampedStart = Min(start_, initLen);
         int32_t clampedEnd = Min(start_ + count_, initLen);
         gc::MarkArraySlots(trc, clampedEnd - clampedStart,
-                           obj->getDenseElements() + clampedStart, "element");
+                           obj->fakeNativeGetDenseElements() + clampedStart, "element");
     } else {
-        int32_t start = Min(uint32_t(start_), obj->slotSpan());
-        int32_t end = Min(uint32_t(start_) + count_, obj->slotSpan());
+        int32_t start = Min(uint32_t(start_), obj->fakeNativeSlotSpan());
+        int32_t end = Min(uint32_t(start_) + count_, obj->fakeNativeSlotSpan());
         MOZ_ASSERT(end >= start);
         MarkObjectSlots(trc, obj, start, end - start);
     }
 }
 
 void
 StoreBuffer::WholeCellEdges::mark(JSTracer *trc)
 {
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -199,17 +199,17 @@ JS_GetTraceThingInfo(char *buf, size_t b
             if (obj->is<JSFunction>()) {
                 JSFunction *fun = &obj->as<JSFunction>();
                 if (fun->displayAtom()) {
                     *buf++ = ' ';
                     bufsize--;
                     PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
                 }
             } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) {
-                JS_snprintf(buf, bufsize, " %p", obj->getPrivate());
+                JS_snprintf(buf, bufsize, " %p", obj->fakeNativeGetPrivate());
             } else {
                 JS_snprintf(buf, bufsize, " <no private>");
             }
             break;
           }
 
           case JSTRACE_STRING:
           {
--- a/js/src/gc/Tracer.h
+++ b/js/src/gc/Tracer.h
@@ -9,18 +9,18 @@
 
 #include "mozilla/DebugOnly.h"
 
 #include "js/GCAPI.h"
 #include "js/SliceBudget.h"
 #include "js/TracingAPI.h"
 
 namespace js {
+class NativeObject;
 class GCMarker;
-class ObjectImpl;
 namespace gc {
 struct ArenaHeader;
 }
 namespace jit {
 class JitCode;
 }
 namespace types {
 struct TypeObject;
@@ -134,17 +134,17 @@ class GCMarker : public JSTracer
 
     void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
     size_t maxCapacity() const { return stack.maxCapacity(); }
 
     void start();
     void stop();
     void reset();
 
-    void pushObject(ObjectImpl *obj) {
+    void pushObject(JSObject *obj) {
         pushTaggedPtr(ObjectTag, obj);
     }
 
     void pushType(types::TypeObject *type) {
         pushTaggedPtr(TypeTag, type);
     }
 
     void pushJitCode(jit::JitCode *code) {
@@ -265,17 +265,17 @@ class GCMarker : public JSTracer
         if (!stack.push(endAddr, startAddr, tagged))
             delayMarkingChildren(obj);
     }
 
     bool isMarkStackEmpty() {
         return stack.isEmpty();
     }
 
-    bool restoreValueArray(JSObject *obj, void **vpp, void **endp);
+    bool restoreValueArray(NativeObject *obj, void **vpp, void **endp);
     void saveValueRanges();
     inline void processMarkStackTop(SliceBudget &budget);
     void processMarkStackOther(uintptr_t tag, uintptr_t addr);
 
     void appendGrayRoot(void *thing, JSGCTraceKind kind);
 
     /* The color is only applied to objects and functions. */
     uint32_t color;
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -473,17 +473,17 @@ PostVerifierVisitEdge(JSTracer *jstrc, v
     MOZ_ASSERT(!trc->runtime()->gc.nursery.isInside(thingp));
     JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
     if (!IsInsideNursery(dst))
         return;
 
     /*
      * Values will be unpacked to the stack before getting here. However, the
      * only things that enter this callback are marked by the JS_TraceChildren
-     * below. Since ObjectImpl::markChildren handles this, the real trace
+     * below. Since JSObject::markChildren handles this, the real trace
      * location will be set correctly in these cases.
      */
     void **loc = trc->tracingLocation(thingp);
 
     AssertStoreBufferContainsEdge(trc->edges, loc, dst);
 }
 #endif
 
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -150,17 +150,17 @@ Zone::sweepBreakpoints(FreeOp *fop)
         for (unsigned i = 0; i < script->length(); i++) {
             BreakpointSite *site = script->getBreakpointSite(script->offsetToPC(i));
             if (!site)
                 continue;
 
             Breakpoint *nextbp;
             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
                 nextbp = bp->nextInSite();
-                HeapPtrObject &dbgobj = bp->debugger->toJSObjectRef();
+                HeapPtrNativeObject &dbgobj = bp->debugger->toJSObjectRef();
                 MOZ_ASSERT_IF(isGCSweeping() && dbgobj->zone()->isCollecting(),
                               dbgobj->zone()->isGCSweeping());
                 bool dying = scriptGone || IsObjectAboutToBeFinalized(&dbgobj);
                 MOZ_ASSERT_IF(!dying, !IsAboutToBeFinalized(&bp->getHandlerRef()));
                 if (dying)
                     bp->destroy(fop);
             }
         }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1073861.js
@@ -0,0 +1,69 @@
+function a(a, b, c, g) {
+    for (;;) {
+        if (0 > c) return a;
+        a: {
+            for (;;) {
+                var k = a.forward[c];
+                if (t(k))
+                    if (k.key < b) a = k;
+                    else break a;
+                else break a
+            }
+            a = void 0
+        }
+        null !=
+            g && (g[c] = a);
+        c -= 1
+    }
+}
+
+function t(a) {
+    return null != a && !1 !== a
+}
+
+
+var d = {forward: [{},null,{}]}
+for (var i=0; i < 1000; i++) {
+    a(d, 0, 1, null);
+    a(d, 0, 0, null);
+}
+
+
+
+
+function test(a) {
+  var t = a[0]
+  if (t) {
+    return t.test;
+  }
+}
+
+function test2(a) {
+  var t = a[0]
+  if (t) {
+    if (t) {
+      return t.test;
+    }
+  }
+}
+
+function test3(a) {
+  var t = a[0]
+  if (t !== null) {
+    if (t !== undefined) {
+      return t.test;
+    }
+  }
+}
+
+var a = [{test:1}]
+var b = [undefined]
+assertEq(test(b), undefined)
+assertEq(test(a), 1)
+assertEq(test(a), 1)
+assertEq(test2(b), undefined)
+assertEq(test2(a), 1)
+assertEq(test2(a), 1)
+assertEq(test3(b), undefined)
+assertEq(test3(a), 1)
+assertEq(test3(a), 1)
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -18,16 +18,17 @@
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 #include "vm/TraceLogging.h"
 
 #include "jsscriptinlines.h"
 
 #include "vm/Interpreter-inl.h"
+#include "vm/ObjectImpl-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 BaselineCompiler::BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script)
   : BaselineCompilerSpecific(cx, alloc, script),
     modifiesArguments_(false)
 {
@@ -1253,17 +1254,17 @@ BaselineCompiler::emit_JSOP_DOUBLE()
 
 bool
 BaselineCompiler::emit_JSOP_STRING()
 {
     frame.push(StringValue(script->getAtom(pc)));
     return true;
 }
 
-typedef JSObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleObject, NewObjectKind);
+typedef NativeObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleNativeObject, NewObjectKind);
 static const VMFunction DeepCloneObjectLiteralInfo =
     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
 
 bool
 BaselineCompiler::emit_JSOP_OBJECT()
 {
     if (JS::CompartmentOptionsRef(cx).cloneSingletons()) {
         RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc)));
@@ -1641,30 +1642,30 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
         if (!type)
             return false;
     }
 
     // Pass length in R0, type in R1.
     masm.move32(Imm32(length), R0.scratchReg());
     masm.movePtr(ImmGCPtr(type), R1.scratchReg());
 
-    JSObject *templateObject = NewDenseUnallocatedArray(cx, length, nullptr, TenuredObject);
+    ArrayObject *templateObject = NewDenseUnallocatedArray(cx, length, nullptr, TenuredObject);
     if (!templateObject)
         return false;
     templateObject->setType(type);
 
     ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     frame.push(R0);
     return true;
 }
 
-typedef JSObject *(*NewArrayCopyOnWriteFn)(JSContext *, HandleObject, gc::InitialHeap);
+typedef JSObject *(*NewArrayCopyOnWriteFn)(JSContext *, HandleNativeObject, gc::InitialHeap);
 const VMFunction jit::NewArrayCopyOnWriteInfo =
     FunctionInfo<NewArrayCopyOnWriteFn>(js::NewDenseCopyOnWriteArray);
 
 bool
 BaselineCompiler::emit_JSOP_NEWARRAY_COPYONWRITE()
 {
     RootedScript scriptRoot(cx, script);
     JSObject *obj = types::GetOrFixupCopyOnWriteObject(cx, scriptRoot, pc);
@@ -1712,18 +1713,18 @@ BaselineCompiler::emit_JSOP_NEWOBJECT()
 
     RootedTypeObject type(cx);
     if (!types::UseNewTypeForInitializer(script, pc, JSProto_Object)) {
         type = types::TypeScript::InitObject(cx, script, pc, JSProto_Object);
         if (!type)
             return false;
     }
 
-    RootedObject baseObject(cx, script->getObject(pc));
-    RootedObject templateObject(cx, CopyInitializerObject(cx, baseObject, TenuredObject));
+    RootedNativeObject baseObject(cx, script->getObject(pc));
+    RootedNativeObject templateObject(cx, CopyInitializerObject(cx, baseObject, TenuredObject));
     if (!templateObject)
         return false;
 
     if (type) {
         templateObject->setType(type);
     } else {
         if (!JSObject::setSingletonType(cx, templateObject))
             return false;
@@ -1750,29 +1751,29 @@ BaselineCompiler::emit_JSOP_NEWINIT()
             return false;
     }
 
     if (key == JSProto_Array) {
         // Pass length in R0, type in R1.
         masm.move32(Imm32(0), R0.scratchReg());
         masm.movePtr(ImmGCPtr(type), R1.scratchReg());
 
-        JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
+        ArrayObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
         if (!templateObject)
             return false;
         templateObject->setType(type);
 
         ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
             return false;
     } else {
         MOZ_ASSERT(key == JSProto_Object);
 
-        RootedObject templateObject(cx);
-        templateObject = NewBuiltinClassInstance(cx, &JSObject::class_, TenuredObject);
+        RootedNativeObject templateObject(cx);
+        templateObject = NewNativeBuiltinClassInstance(cx, &JSObject::class_, TenuredObject);
         if (!templateObject)
             return false;
 
         if (type) {
             templateObject->setType(type);
         } else {
             if (!JSObject::setSingletonType(cx, templateObject))
                 return false;
@@ -2098,21 +2099,21 @@ BaselineCompiler::getScopeCoordinateObje
 Address
 BaselineCompiler::getScopeCoordinateAddressFromObject(Register objReg, Register reg)
 {
     ScopeCoordinate sc(pc);
     Shape *shape = ScopeCoordinateToStaticScopeShape(script, pc);
 
     Address addr;
     if (shape->numFixedSlots() <= sc.slot()) {
-        masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), reg);
+        masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), reg);
         return Address(reg, (sc.slot() - shape->numFixedSlots()) * sizeof(Value));
     }
 
-    return Address(objReg, JSObject::getFixedSlotOffset(sc.slot()));
+    return Address(objReg, NativeObject::getFixedSlotOffset(sc.slot()));
 }
 
 Address
 BaselineCompiler::getScopeCoordinateAddress(Register reg)
 {
     getScopeCoordinateObject(reg);
     return getScopeCoordinateAddressFromObject(reg, reg);
 }
@@ -3212,17 +3213,17 @@ BaselineCompiler::emit_JSOP_RUNONCE()
     return callVM(RunOnceScriptPrologueInfo);
 }
 
 bool
 BaselineCompiler::emit_JSOP_REST()
 {
     frame.syncStack(0);
 
-    JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
+    ArrayObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
     if (!templateObject)
         return false;
     types::FixRestArgumentsType(cx, templateObject);
 
     // Call IC.
     ICRest_Fallback::Compiler compiler(cx, templateObject);
     if (!emitOpIC(compiler.getStub(&stubSpace_)))
         return false;
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1743,17 +1743,17 @@ ICNewArray_Fallback::Compiler::generateS
 // NewObject_Fallback
 //
 
 static bool
 DoNewObject(JSContext *cx, ICNewObject_Fallback *stub, MutableHandleValue res)
 {
     FallbackICSpew(cx, stub, "NewObject");
 
-    RootedObject templateObject(cx, stub->templateObject());
+    RootedNativeObject templateObject(cx, stub->templateObject());
     JSObject *obj = NewInitObject(cx, templateObject);
     if (!obj)
         return false;
 
     res.setObject(*obj);
     return true;
 }
 
@@ -3184,23 +3184,23 @@ ICUnaryArith_Double::Compiler::generateS
     EmitStubGuardFailure(masm);
     return true;
 }
 
 //
 // GetElem_Fallback
 //
 
-static void GetFixedOrDynamicSlotOffset(HandleObject obj, uint32_t slot,
+static void GetFixedOrDynamicSlotOffset(NativeObject *obj, uint32_t slot,
                                         bool *isFixed, uint32_t *offset)
 {
     MOZ_ASSERT(isFixed);
     MOZ_ASSERT(offset);
     *isFixed = obj->isFixedSlot(slot);
-    *offset = *isFixed ? JSObject::getFixedSlotOffset(slot)
+    *offset = *isFixed ? NativeObject::getFixedSlotOffset(slot)
                        : obj->dynamicSlotIndex(slot) * sizeof(Value);
 }
 
 static JSObject *
 GetDOMProxyProto(JSObject *obj)
 {
     MOZ_ASSERT(IsCacheableDOMProxy(obj));
     return obj->getTaggedProto().toObjectOrNull();
@@ -3216,17 +3216,17 @@ GenerateDOMProxyChecks(JSContext *cx, Ma
                        GeneralRegisterSet &domProxyRegSet,
                        Label *checkFailed)
 {
     // Guard the following:
     //      1. The object is a DOMProxy.
     //      2. The object does not have expando properties, or has an expando
     //          which is known to not have the desired property.
     Address handlerAddr(object, ProxyObject::offsetOfHandler());
-    Address expandoAddr(object, JSObject::getFixedSlotOffset(GetDOMProxyExpandoSlot()));
+    Address expandoAddr(object, NativeObject::getFixedSlotOffset(GetDOMProxyExpandoSlot()));
 
     // Check that object is a DOMProxy.
     masm.loadPtr(checkProxyHandlerAddr, scratch);
     masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, scratch, checkFailed);
 
     // At this point, if not checking for an expando object, just return.
     if (!checkExpandoShapeAddr)
         return;
@@ -3328,17 +3328,17 @@ EffectlesslyLookupProperty(JSContext *cx
     } else if (!obj->isNative()) {
         return true;
     }
 
     if (checkObj->hasIdempotentProtoChain()) {
         if (!JSObject::lookupProperty(cx, checkObj, name, holder, shape))
             return false;
     } else if (checkObj->isNative()) {
-        shape.set(checkObj->nativeLookup(cx, NameToId(name)));
+        shape.set(checkObj->as<NativeObject>().lookup(cx, NameToId(name)));
         if (shape)
             holder.set(checkObj);
     }
     return true;
 }
 
 static bool
 CheckHasNoSuchProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
@@ -3347,17 +3347,17 @@ CheckHasNoSuchProperty(JSContext *cx, Ha
     MOZ_ASSERT(protoChainDepthOut != nullptr);
 
     size_t depth = 0;
     RootedObject curObj(cx, obj);
     while (curObj) {
         if (!curObj->isNative())
             return false;
 
-        Shape *shape = curObj->nativeLookup(cx, NameToId(name));
+        Shape *shape = curObj->as<NativeObject>().lookup(cx, NameToId(name));
         if (shape)
             return false;
 
         JSObject *proto = curObj->getTaggedProto().toObjectOrNull();
         if (!proto)
             break;
 
         curObj = proto;
@@ -3505,30 +3505,30 @@ IsCacheableSetPropAddSlot(JSContext *cx,
     // are native, and that all prototypes have setter defined on the property
     for (JSObject *proto = obj->getProto(); proto; proto = proto->getProto()) {
         chainDepth++;
         // if prototype is non-native, don't optimize
         if (!proto->isNative())
             return false;
 
         // if prototype defines this property in a non-plain way, don't optimize
-        Shape *protoShape = proto->nativeLookup(cx, id);
+        Shape *protoShape = proto->as<NativeObject>().lookup(cx, id);
         if (protoShape && !protoShape->hasDefaultSetter())
             return false;
 
         // Otherise, if there's no such property, watch out for a resolve hook that would need
         // to be invoked and thus prevent inlining of property addition.
         if (proto->getClass()->resolve != JS_ResolveStub)
              return false;
     }
 
     // Only add a IC entry if the dynamic slots didn't change when the shapes
     // changed.  Need to ensure that a shape change for a subsequent object
     // won't involve reallocating the slot array.
-    if (obj->numDynamicSlots() != oldSlots)
+    if (obj->as<NativeObject>().numDynamicSlots() != oldSlots)
         return false;
 
     *protoChainDepth = chainDepth;
     return true;
 }
 
 static bool
 IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted)
@@ -3777,17 +3777,18 @@ static bool TryAttachNativeGetElemStub(J
         if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize))
             return true;
 
         // Remove any existing stubs that may interfere with the new stub being added.
         RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize);
 
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(&holder->as<NativeObject>(),
+                                    shape->slot(), &isFixedSlot, &offset);
 
         ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
         ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlot
                                             : ICStub::GetElem_NativePrototypeSlot;
 
         JitSpew(JitSpew_BaselineIC, "  Generating GetElem(Native %s%s slot) stub "
                                     "(obj=%p, shape=%p, holder=%p, holderShape=%p)",
                     (obj == holder) ? "direct" : "prototype",
@@ -4321,17 +4322,17 @@ ICGetElemNativeCompiler::generateStubCod
     if (acctype_ == ICGetElemNativeStub::DynamicSlot ||
         acctype_ == ICGetElemNativeStub::FixedSlot)
     {
         masm.load32(Address(BaselineStubReg, ICGetElemNativeSlotStub::offsetOfOffset()),
                     scratchReg);
 
         // Load from object.
         if (acctype_ == ICGetElemNativeStub::DynamicSlot)
-            masm.addPtr(Address(holderReg, JSObject::offsetOfSlots()), scratchReg);
+            masm.addPtr(Address(holderReg, NativeObject::offsetOfSlots()), scratchReg);
         else
             masm.addPtr(holderReg, scratchReg);
 
         Address valAddr(scratchReg, 0);
 
         // Check if __noSuchMethod__ needs to be called.
 #if JS_HAS_NO_SUCH_METHOD
         if (isCallElem_) {
@@ -4496,17 +4497,17 @@ ICGetElem_Dense::Compiler::generateStubC
     Register scratchReg = regs.takeAny();
 
     // Unbox R0 and shape guard.
     Register obj = masm.extractObject(R0, ExtractTemp0);
     masm.loadPtr(Address(BaselineStubReg, ICGetElem_Dense::offsetOfShape()), scratchReg);
     masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
 
     // Load obj->elements.
-    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratchReg);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratchReg);
 
     // Unbox key.
     Register key = masm.extractInt32(R1, ExtractTemp1);
 
     // Bounds check.
     Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
     masm.branch32(Assembler::BelowOrEqual, initLength, key, &failure);
 
@@ -4897,31 +4898,31 @@ RemoveExistingTypedArraySetElemStub(JSCo
         MOZ_ASSERT(!iter->toSetElem_TypedArray()->expectOutOfBounds());
         iter.unlink(cx);
         return true;
     }
     return false;
 }
 
 static bool
-CanOptimizeDenseSetElem(JSContext *cx, HandleObject obj, uint32_t index,
-                        HandleShape oldShape, uint32_t oldCapacity, uint32_t oldInitLength,
+CanOptimizeDenseSetElem(NativeObject *obj, uint32_t index,
+                        Shape *oldShape, uint32_t oldCapacity, uint32_t oldInitLength,
                         bool *isAddingCaseOut, size_t *protoDepthOut)
 {
     uint32_t initLength = obj->getDenseInitializedLength();
     uint32_t capacity = obj->getDenseCapacity();
 
     *isAddingCaseOut = false;
     *protoDepthOut = 0;
 
     // Some initial sanity checks.
     if (initLength < oldInitLength || capacity < oldCapacity)
         return false;
 
-    RootedShape shape(cx, obj->lastProperty());
+    Shape *shape = obj->lastProperty();
 
     // Cannot optimize if the shape changed.
     if (oldShape != shape)
         return false;
 
     // Cannot optimize if the capacity changed.
     if (oldCapacity != capacity)
         return false;
@@ -4945,17 +4946,17 @@ CanOptimizeDenseSetElem(JSContext *cx, H
         return false;
     if (index != oldInitLength)
         return false;
 
     // The checks are not complete.  The object may have a setter definition,
     // either directly, or via a prototype, or via the target object for a prototype
     // which is a proxy, that handles a particular integer write.
     // Scan the prototype and shape chain to make sure that this is not the case.
-    RootedObject curObj(cx, obj);
+    JSObject *curObj = obj;
     while (curObj) {
         // Ensure object is native.
         if (!curObj->isNative())
             return false;
 
         // Ensure all indexed properties are stored in dense elements.
         if (curObj->isIndexed())
             return false;
@@ -4995,18 +4996,18 @@ DoSetElemFallback(JSContext *cx, Baselin
         return false;
 
     RootedShape oldShape(cx, obj->lastProperty());
 
     // Check the old capacity
     uint32_t oldCapacity = 0;
     uint32_t oldInitLength = 0;
     if (obj->isNative() && index.isInt32() && index.toInt32() >= 0) {
-        oldCapacity = obj->getDenseCapacity();
-        oldInitLength = obj->getDenseInitializedLength();
+        oldCapacity = obj->as<NativeObject>().getDenseCapacity();
+        oldInitLength = obj->as<NativeObject>().getDenseInitializedLength();
     }
 
     if (op == JSOP_INITELEM) {
         if (!InitElemOperation(cx, obj, index, rhs))
             return false;
     } else if (op == JSOP_INITELEM_ARRAY) {
         MOZ_ASSERT(uint32_t(index.toInt32()) == GET_UINT24(pc));
         if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
@@ -5037,17 +5038,18 @@ DoSetElemFallback(JSContext *cx, Baselin
     if (obj->isNative() &&
         !IsAnyTypedArray(obj.get()) &&
         index.isInt32() && index.toInt32() >= 0 &&
         !rhs.isMagic(JS_ELEMENTS_HOLE))
     {
         bool addingCase;
         size_t protoDepth;
 
-        if (CanOptimizeDenseSetElem(cx, obj, index.toInt32(), oldShape, oldCapacity, oldInitLength,
+        if (CanOptimizeDenseSetElem(&obj->as<NativeObject>(), index.toInt32(),
+                                    oldShape, oldCapacity, oldInitLength,
                                     &addingCase, &protoDepth))
         {
             RootedShape shape(cx, obj->lastProperty());
             RootedTypeObject type(cx, obj->getType(cx));
             if (!type)
                 return false;
 
             if (addingCase && !DenseSetElemStubExists(cx, ICStub::SetElem_DenseAdd, stub, obj)) {
@@ -5224,17 +5226,17 @@ ICSetElem_Dense::Compiler::generateStubC
     regs = availableGeneralRegs(2);
     scratchReg = regs.takeAny();
 
     // Unbox object and key.
     obj = masm.extractObject(R0, ExtractTemp0);
     Register key = masm.extractInt32(R1, ExtractTemp1);
 
     // Load obj->elements in scratchReg.
-    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratchReg);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratchReg);
 
     // Bounds check.
     Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
     masm.branch32(Assembler::BelowOrEqual, initLength, key, &failure);
 
     // Hole check.
     BaseIndex element(scratchReg, key, TimesEight);
     masm.branchTestMagic(Assembler::Equal, element, &failure);
@@ -5407,17 +5409,17 @@ ICSetElemDenseAddCompiler::generateStubC
     regs = availableGeneralRegs(2);
     scratchReg = regs.takeAny();
 
     // Unbox obj and key.
     obj = masm.extractObject(R0, ExtractTemp0);
     Register key = masm.extractInt32(R1, ExtractTemp1);
 
     // Load obj->elements in scratchReg.
-    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratchReg);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratchReg);
 
     // Bounds check (key == initLength)
     Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
     masm.branch32(Assembler::NotEqual, initLength, key, &failure);
 
     // Capacity check.
     Address capacity(scratchReg, ObjectElements::offsetOfCapacity());
     masm.branch32(Assembler::BelowOrEqual, capacity, key, &failure);
@@ -5664,29 +5666,29 @@ ICIn_Fallback::Compiler::generateStubCod
     masm.push(BaselineStubReg);
 
     return tailCallVM(DoInFallbackInfo, masm);
 }
 
 // Attach an optimized stub for a GETGNAME/CALLGNAME op.
 static bool
 TryAttachGlobalNameStub(JSContext *cx, HandleScript script, jsbytecode *pc,
-                        ICGetName_Fallback *stub, HandleObject global,
+                        ICGetName_Fallback *stub, Handle<GlobalObject*> global,
                         HandlePropertyName name)
 {
     MOZ_ASSERT(global->is<GlobalObject>());
 
     RootedId id(cx, NameToId(name));
 
     // Instantiate this global property, for use during Ion compilation.
     if (IsIonEnabled(cx))
         types::EnsureTrackPropertyTypes(cx, global, NameToId(name));
 
     // The property must be found, and it must be found as a normal data property.
-    RootedShape shape(cx, global->nativeLookup(cx, id));
+    RootedShape shape(cx, global->lookup(cx, id));
     if (!shape)
         return true;
 
     if (shape->hasDefaultGetter() && shape->hasSlot()) {
 
         MOZ_ASSERT(shape->slot() >= global->numFixedSlots());
         uint32_t slot = shape->slot() - global->numFixedSlots();
 
@@ -5735,45 +5737,46 @@ TryAttachScopeNameStub(JSContext *cx, Ha
     RootedObject scopeChain(cx, initialScopeChain);
 
     Shape *shape = nullptr;
     while (scopeChain) {
         if (!shapes.append(scopeChain->lastProperty()))
             return false;
 
         if (scopeChain->is<GlobalObject>()) {
-            shape = scopeChain->nativeLookup(cx, id);
+            shape = scopeChain->as<GlobalObject>().lookup(cx, id);
             if (shape)
                 break;
             return true;
         }
 
         if (!scopeChain->is<ScopeObject>() || scopeChain->is<DynamicWithObject>())
             return true;
 
         // Check for an 'own' property on the scope. There is no need to
         // check the prototype as non-with scopes do not inherit properties
         // from any prototype.
-        shape = scopeChain->nativeLookup(cx, id);
+        shape = scopeChain->as<NativeObject>().lookup(cx, id);
         if (shape)
             break;
 
         scopeChain = scopeChain->enclosingScope();
     }
 
     // We don't handle getters here. When this changes, we need to make sure
     // IonBuilder::getPropTryCommonGetter (which requires a Baseline stub to
     // work) handles non-outerized this objects correctly.
 
     if (!IsCacheableGetPropReadSlot(scopeChain, scopeChain, shape))
         return true;
 
     bool isFixedSlot;
     uint32_t offset;
-    GetFixedOrDynamicSlotOffset(scopeChain, shape->slot(), &isFixedSlot, &offset);
+    GetFixedOrDynamicSlotOffset(&scopeChain->as<NativeObject>(),
+                                shape->slot(), &isFixedSlot, &offset);
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
     ICStub *newStub;
 
     switch (shapes.length()) {
       case 1: {
         ICGetName_Scope<0>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
         newStub = compiler.getStub(compiler.getStubSpace(script));
@@ -5856,17 +5859,17 @@ DoGetNameFallback(JSContext *cx, Baselin
 
     // Attach new stub.
     if (stub->numOptimizedStubs() >= ICGetName_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with generic stub.
         return true;
     }
 
     if (js_CodeSpec[*pc].format & JOF_GNAME) {
-        if (!TryAttachGlobalNameStub(cx, script, pc, stub, scopeChain, name))
+        if (!TryAttachGlobalNameStub(cx, script, pc, stub, scopeChain.as<GlobalObject>(), name))
             return false;
     } else {
         if (!TryAttachScopeNameStub(cx, script, stub, scopeChain, name))
             return false;
     }
 
     return true;
 }
@@ -5896,17 +5899,17 @@ ICGetName_Global::Compiler::generateStub
     Register obj = R0.scratchReg();
     Register scratch = R1.scratchReg();
 
     // Shape guard.
     masm.loadPtr(Address(BaselineStubReg, ICGetName_Global::offsetOfShape()), scratch);
     masm.branchTestObjShape(Assembler::NotEqual, obj, scratch, &failure);
 
     // Load dynamic slot.
-    masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), obj);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), obj);
     masm.load32(Address(BaselineStubReg, ICGetName_Global::offsetOfSlot()), scratch);
     masm.loadValue(BaseIndex(obj, scratch, TimesEight), R0);
 
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
@@ -5936,17 +5939,17 @@ ICGetName_Scope<NumHops>::Compiler::gene
 
         if (index < numHops)
             masm.extractObject(Address(scope, ScopeObject::offsetOfEnclosingScope()), walker);
     }
 
     Register scope = NumHops ? walker : obj;
 
     if (!isFixedSlot_) {
-        masm.loadPtr(Address(scope, JSObject::offsetOfSlots()), walker);
+        masm.loadPtr(Address(scope, NativeObject::offsetOfSlots()), walker);
         scope = walker;
     }
 
     masm.load32(Address(BaselineStubReg, ICGetName_Scope::offsetOfOffset()), scratch);
     masm.loadValue(BaseIndex(scope, scratch, TimesOne), R0);
 
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
@@ -6180,17 +6183,17 @@ TryAttachLengthStub(JSContext *cx, JSScr
 
     return true;
 }
 
 static bool
 UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback *stub,
                                        HandleObject obj)
 {
-    Value expandoSlot = obj->getFixedSlot(GetDOMProxyExpandoSlot());
+    Value expandoSlot = obj->fakeNativeGetReservedSlot(GetDOMProxyExpandoSlot());
     MOZ_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
     ExpandoAndGeneration *expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
         if (iter->isGetProp_CallDOMProxyWithGenerationNative()) {
             ICGetProp_CallDOMProxyWithGenerationNative* updateStub =
                 iter->toGetProp_CallDOMProxyWithGenerationNative();
             if (updateStub->expandoAndGeneration() == expandoAndGeneration) {
                 // Update generation
@@ -6267,17 +6270,17 @@ TryAttachNativeGetPropStub(JSContext *cx
         return true;
 
     bool isCallProp = (JSOp(*pc) == JSOP_CALLPROP);
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
     if (!isDOMProxy && IsCacheableGetPropReadSlot(obj, holder, shape)) {
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(&holder->as<NativeObject>(), shape->slot(), &isFixedSlot, &offset);
 
         // Instantiate this property for singleton holders, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, holder, NameToId(name));
 
         ICStub::Kind kind = (obj == holder) ? ICStub::GetProp_Native
                                             : ICStub::GetProp_NativePrototype;
 
@@ -6412,17 +6415,17 @@ TryAttachNativeGetPropStub(JSContext *cx
 static bool
 TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
                               ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
                               HandleValue res, bool *attached)
 {
     MOZ_ASSERT(!*attached);
 
     JSValueType primitiveType;
-    RootedObject proto(cx);
+    RootedNativeObject proto(cx);
     Rooted<GlobalObject*> global(cx, &script->global());
     if (val.isString()) {
         primitiveType = JSVAL_TYPE_STRING;
         proto = GlobalObject::getOrCreateStringPrototype(cx, global);
     } else if (val.isSymbol()) {
         primitiveType = JSVAL_TYPE_SYMBOL;
         proto = GlobalObject::getOrCreateSymbolPrototype(cx, global);
     } else if (val.isNumber()) {
@@ -6437,17 +6440,17 @@ TryAttachPrimitiveGetPropStub(JSContext 
         return false;
 
     // Instantiate this property, for use during Ion compilation.
     RootedId id(cx, NameToId(name));
     if (IsIonEnabled(cx))
         types::EnsureTrackPropertyTypes(cx, proto, id);
 
     // For now, only look for properties directly set on the prototype.
-    RootedShape shape(cx, proto->nativeLookup(cx, id));
+    RootedShape shape(cx, proto->lookup(cx, id));
     if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
         return true;
 
     bool isFixedSlot;
     uint32_t offset;
     GetFixedOrDynamicSlotOffset(proto, shape->slot(), &isFixedSlot, &offset);
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
@@ -6688,17 +6691,17 @@ ICGetProp_ArrayLength::Compiler::generat
 
     Register scratch = R1.scratchReg();
 
     // Unbox R0 and guard it's an array.
     Register obj = masm.extractObject(R0, ExtractTemp0);
     masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, &ArrayObject::class_, &failure);
 
     // Load obj->elements->length.
-    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratch);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
     masm.load32(Address(scratch, ObjectElements::offsetOfLength()), scratch);
 
     // Guard length fits in an int32.
     masm.branchTest32(Assembler::Signed, scratch, scratch, &failure);
 
     masm.tagValue(JSVAL_TYPE_INT32, scratch, R0);
     EmitReturnFromIC(masm);
 
@@ -6755,17 +6758,17 @@ ICGetProp_Primitive::Compiler::generateS
     // Verify the shape of the prototype.
     masm.movePtr(ImmGCPtr(prototype_.get()), holderReg);
 
     Address shapeAddr(BaselineStubReg, ICGetProp_Primitive::offsetOfProtoShape());
     masm.loadPtr(Address(holderReg, JSObject::offsetOfShape()), scratchReg);
     masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
 
     if (!isFixedSlot_)
-        masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg);
+        masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg);
 
     masm.load32(Address(BaselineStubReg, ICGetPropNativeStub::offsetOfOffset()), scratchReg);
     masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
 
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
 
     // Failure case - jump to next stub
@@ -6802,17 +6805,17 @@ ICGetPropNativeCompiler::generateStubCod
                      scratch);
         masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
     }
 
     if (!isFixedSlot_) {
         // Don't overwrite actual holderReg if we need to load a dynamic slots object.
         // May need to preserve object for noSuchMethod check later.
         Register nextHolder = regs.takeAny();
-        masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), nextHolder);
+        masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), nextHolder);
         holderReg = nextHolder;
     }
 
     masm.load32(Address(BaselineStubReg, ICGetPropNativeStub::offsetOfOffset()), scratch);
     BaseIndex result(holderReg, scratch, TimesOne);
 
 #if JS_HAS_NO_SUCH_METHOD
 #ifdef DEBUG
@@ -7236,17 +7239,17 @@ ICGetPropCallDOMProxyNativeCompiler::gen
 }
 
 ICStub *
 ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace *space)
 {
     RootedShape shape(cx, proxy_->lastProperty());
     RootedShape holderShape(cx, holder_->lastProperty());
 
-    Value expandoSlot = proxy_->getFixedSlot(GetDOMProxyExpandoSlot());
+    Value expandoSlot = proxy_->fakeNativeGetReservedSlot(GetDOMProxyExpandoSlot());
     RootedShape expandoShape(cx, nullptr);
     ExpandoAndGeneration *expandoAndGeneration;
     int32_t generation;
     Value expandoVal;
     if (kind == ICStub::GetProp_CallDOMProxyNative) {
         expandoVal = expandoSlot;
     } else {
         MOZ_ASSERT(kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
@@ -7523,17 +7526,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         // a stub, though, so the access is not marked as unoptimizable.
         if (oldType->newScript() && !oldType->newScript()->analyzed()) {
             *attached = true;
             return true;
         }
 
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(obj, shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(&obj->as<NativeObject>(), shape->slot(), &isFixedSlot, &offset);
 
         JitSpew(JitSpew_BaselineIC, "  Generating SetProp(NativeObject.ADD) stub");
         ICSetPropNativeAddCompiler compiler(cx, obj, oldShape, oldType,
                                             chainDepth, isFixedSlot, offset);
         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
@@ -7552,17 +7555,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         types::EnsureTrackPropertyTypes(cx, obj, id);
         if (!types::PropertyHasBeenMarkedNonConstant(obj, id)) {
             *attached = true;
             return true;
         }
 
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(obj, shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(&obj->as<NativeObject>(), shape->slot(), &isFixedSlot, &offset);
 
         JitSpew(JitSpew_BaselineIC, "  Generating SetProp(NativeObject.PROP) stub");
         ICSetProp_Native::Compiler compiler(cx, obj, isFixedSlot, offset);
         ICSetProp_Native *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
             return false;
@@ -7649,22 +7652,25 @@ DoSetPropFallback(JSContext *cx, Baselin
 
     RootedObject obj(cx, ToObjectFromStack(cx, lhs));
     if (!obj)
         return false;
     RootedShape oldShape(cx, obj->lastProperty());
     RootedTypeObject oldType(cx, obj->getType(cx));
     if (!oldType)
         return false;
-    uint32_t oldSlots = obj->numDynamicSlots();
+    uint32_t oldSlots = obj->fakeNativeNumDynamicSlots();
 
     if (op == JSOP_INITPROP) {
         MOZ_ASSERT(obj->is<JSObject>());
-        if (!DefineNativeProperty(cx, obj, id, rhs, nullptr, nullptr, JSPROP_ENUMERATE))
-            return false;
+        if (!DefineNativeProperty(cx, obj.as<NativeObject>(), id, rhs,
+                                  nullptr, nullptr, JSPROP_ENUMERATE))
+        {
+            return false;
+        }
     } else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
         if (!SetNameOperation(cx, script, pc, obj, rhs))
             return false;
     } else if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) {
         obj->as<ScopeObject>().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs);
     } else {
         MOZ_ASSERT(op == JSOP_SETPROP);
         if (script->strict()) {
@@ -7793,17 +7799,17 @@ ICSetProp_Native::Compiler::generateStub
     regs.add(R0);
     regs.takeUnchecked(objReg);
 
     Register holderReg;
     if (isFixedSlot_) {
         holderReg = objReg;
     } else {
         holderReg = regs.takeAny();
-        masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), holderReg);
+        masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg);
     }
 
     // Perform the store.
     masm.load32(Address(BaselineStubReg, ICSetProp_Native::offsetOfOffset()), scratch);
     EmitPreBarrier(masm, BaseIndex(holderReg, scratch, TimesOne), MIRType_Value);
     masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
     if (holderReg != objReg)
         regs.add(holderReg);
@@ -7937,17 +7943,17 @@ ICSetPropNativeAddCompiler::generateStub
 
     Register holderReg;
     regs.add(R0);
     regs.takeUnchecked(objReg);
     if (isFixedSlot_) {
         holderReg = objReg;
     } else {
         holderReg = regs.takeAny();
-        masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), holderReg);
+        masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg);
     }
 
     // Perform the store.  No write barrier required since this is a new
     // initialization.
     masm.load32(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfOffset()), scratch);
     masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
 
     if (holderReg != objReg)
@@ -8251,17 +8257,17 @@ TryAttachFunCallStub(JSContext *cx, ICCa
         return true;
     }
 
     return true;
 }
 
 static bool
 GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
-                           Native native, const CallArgs &args, MutableHandleObject res)
+                           Native native, const CallArgs &args, MutableHandleNativeObject res)
 {
     // Check for natives to which template objects can be attached. This is
     // done to provide templates to Ion for inlining these natives later on.
 
     if (native == js_Array) {
         // Note: the template array won't be used if its length is inaccurately
         // computed here.  (We allocate here because compilation may occur on a
         // separate thread where allocation is impossible.)
@@ -8426,17 +8432,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
 
         // Keep track of the function's |prototype| property in type
         // information, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
 
         // Remember the template object associated with any script being called
         // as a constructor, for later use during Ion compilation.
-        RootedObject templateObject(cx);
+        RootedNativeObject templateObject(cx);
         if (constructing) {
             templateObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
             if (!templateObject)
                 return false;
 
             // If we are calling a constructor for which the new script
             // properties analysis has not been performed yet, don't attach a
             // stub. After the analysis is performed, CreateThisForFunction may
@@ -8491,17 +8497,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
         }
 
         if (stub->nativeStubCount() >= ICCall_Fallback::MAX_NATIVE_STUBS) {
             JitSpew(JitSpew_BaselineIC,
                     "  Too many Call_Native stubs. TODO: add Call_AnyNative!");
             return true;
         }
 
-        RootedObject templateObject(cx);
+        RootedNativeObject templateObject(cx);
         if (MOZ_LIKELY(!isSpread)) {
             CallArgs args = CallArgsFromVp(argc, vp);
             if (!GetTemplateObjectForNative(cx, script, pc, fun->native(), args, &templateObject))
                 return false;
         }
 
         JitSpew(JitSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
                 fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no");
@@ -8515,27 +8521,27 @@ TryAttachCallStub(JSContext *cx, ICCall_
         stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
-CopyArray(JSContext *cx, HandleObject obj, MutableHandleValue result)
+CopyArray(JSContext *cx, HandleArrayObject obj, MutableHandleValue result)
 {
     MOZ_ASSERT(obj->is<ArrayObject>());
     uint32_t length = obj->as<ArrayObject>().length();
     MOZ_ASSERT(obj->getDenseInitializedLength() == length);
 
     RootedTypeObject type(cx, obj->getType(cx));
     if (!type)
         return false;
 
-    RootedObject newObj(cx, NewDenseArray(cx, length, type, NewArray_FullyAllocating));
+    RootedArrayObject newObj(cx, NewDenseArray(cx, length, type, NewArray_FullyAllocating));
     if (!newObj)
         return false;
 
     newObj->setDenseInitializedLength(length);
     newObj->initDenseElements(0, obj->getDenseElements(), length);
     result.setObject(*newObj);
     return true;
 }
@@ -8549,23 +8555,22 @@ TryAttachStringSplit(JSContext *cx, ICCa
 
     RootedValue callee(cx, vp[0]);
     RootedValue thisv(cx, vp[1]);
     Value *args = vp + 2;
 
     if (!IsOptimizableCallStringSplit(callee, thisv, argc, args))
         return true;
 
-    MOZ_ASSERT(res.toObject().is<ArrayObject>());
     MOZ_ASSERT(callee.isObject());
     MOZ_ASSERT(callee.toObject().is<JSFunction>());
 
     RootedString thisString(cx, thisv.toString());
     RootedString argString(cx, args[0].toString());
-    RootedObject obj(cx, &res.toObject());
+    RootedArrayObject obj(cx, &res.toObject().as<ArrayObject>());
     RootedValue arr(cx);
 
     // Copy the array before storing in stub.
     if (!CopyArray(cx, obj, &arr))
         return false;
 
     ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                           script->pcToOffset(pc), thisString, argString,
@@ -8760,17 +8765,17 @@ ICCallStubCompiler::pushCallArguments(Ma
     }
     masm.bind(&done);
 }
 
 void
 ICCallStubCompiler::guardSpreadCall(MacroAssembler &masm, Register argcReg, Label *failure)
 {
     masm.unboxObject(Address(BaselineStackReg, ICStackValueOffset), argcReg);
-    masm.loadPtr(Address(argcReg, JSObject::offsetOfElements()), argcReg);
+    masm.loadPtr(Address(argcReg, NativeObject::offsetOfElements()), argcReg);
     masm.load32(Address(argcReg, ObjectElements::offsetOfLength()), argcReg);
 
     // Limit actual argc to something reasonable (huge number of arguments can
     // blow the stack limit).
     static_assert(ICCall_Scripted::MAX_ARGS_SPREAD_LENGTH <= ARGS_LENGTH_MAX,
                   "maximum arguments length for optimized stub should be <= ARGS_LENGTH_MAX");
     masm.branch32(Assembler::Above, argcReg, Imm32(ICCall_Scripted::MAX_ARGS_SPREAD_LENGTH),
                   failure);
@@ -8779,17 +8784,17 @@ ICCallStubCompiler::guardSpreadCall(Macr
 void
 ICCallStubCompiler::pushSpreadCallArguments(MacroAssembler &masm, GeneralRegisterSet regs,
                                             Register argcReg)
 {
     // Push arguments
     Register startReg = regs.takeAny();
     Register endReg = regs.takeAny();
     masm.unboxObject(Address(BaselineStackReg, STUB_FRAME_SIZE), startReg);
-    masm.loadPtr(Address(startReg, JSObject::offsetOfElements()), startReg);
+    masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg);
     masm.mov(argcReg, endReg);
     static_assert(sizeof(Value) == 8, "Value must be 8 bytes");
     masm.lshiftPtr(Imm32(3), endReg);
     masm.addPtr(startReg, endReg);
 
     // Copying pre-decrements endReg by 8 until startReg is reached
     Label copyDone;
     Label copyStart;
@@ -8842,17 +8847,17 @@ ICCallStubCompiler::guardFunApply(MacroA
 
         regsx.add(secondArgVal);
         regsx.takeUnchecked(secondArgObj);
 
         masm.branchTestObjClass(Assembler::NotEqual, secondArgObj, regsx.getAny(),
                                 &ArrayObject::class_, failure);
 
         // Get the array elements and ensure that initializedLength == length
-        masm.loadPtr(Address(secondArgObj, JSObject::offsetOfElements()), secondArgObj);
+        masm.loadPtr(Address(secondArgObj, NativeObject::offsetOfElements()), secondArgObj);
 
         Register lenReg = regsx.takeAny();
         masm.load32(Address(secondArgObj, ObjectElements::offsetOfLength()), lenReg);
 
         masm.branch32(Assembler::NotEqual,
                       Address(secondArgObj, ObjectElements::offsetOfInitializedLength()),
                       lenReg, failure);
 
@@ -8952,17 +8957,17 @@ ICCallStubCompiler::pushArrayArguments(M
                                        GeneralRegisterSet regs)
 {
     // Load start and end address of values to copy.
     // guardFunApply has already gauranteed that the array is packed and contains
     // no holes.
     Register startReg = regs.takeAny();
     Register endReg = regs.takeAny();
     masm.extractObject(arrayVal, startReg);
-    masm.loadPtr(Address(startReg, JSObject::offsetOfElements()), startReg);
+    masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg);
     masm.load32(Address(startReg, ObjectElements::offsetOfInitializedLength()), endReg);
     JS_STATIC_ASSERT(sizeof(Value) == 8);
     masm.lshiftPtr(Imm32(3), endReg);
     masm.addPtr(startReg, endReg);
 
     // Copying pre-decrements endReg by 8 until startReg is reached
     Label copyDone;
     Label copyStart;
@@ -9350,17 +9355,17 @@ ICCallScriptedCompiler::generateStubCode
     if (argcReg != R0.scratchReg())
         masm.mov(argcReg, R0.scratchReg());
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
-typedef bool (*CopyArrayFn)(JSContext *, HandleObject, MutableHandleValue);
+typedef bool (*CopyArrayFn)(JSContext *, HandleArrayObject, MutableHandleValue);
 static const VMFunction CopyArrayInfo = FunctionInfo<CopyArrayFn>(CopyArray);
 
 bool
 ICCall_StringSplit::Compiler::generateStubCode(MacroAssembler &masm)
 {
     // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, +ICStackValueOffset+ ]
     GeneralRegisterSet regs = availableGeneralRegs(0);
     Label failureRestoreArgc;
@@ -9612,17 +9617,17 @@ ICCall_ScriptedApplyArray::Compiler::gen
 
     // All pushes after this use Push instead of push to make sure ARM can align
     // stack properly for call.
     Register scratch = regs.takeAny();
     EmitCreateStubFrameDescriptor(masm, scratch);
 
     // Reload argc from length of array.
     masm.extractObject(arrayVal, argcReg);
-    masm.loadPtr(Address(argcReg, JSObject::offsetOfElements()), argcReg);
+    masm.loadPtr(Address(argcReg, NativeObject::offsetOfElements()), argcReg);
     masm.load32(Address(argcReg, ObjectElements::offsetOfInitializedLength()), argcReg);
 
     masm.Push(argcReg);
     masm.Push(target);
     masm.Push(scratch);
 
     // Load nargs into scratch for underflow check, and then load jitcode pointer into target.
     masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
@@ -10847,43 +10852,43 @@ ICSetProp_CallNative::Clone(JSContext *c
     RootedShape shape(cx, other.shape_);
     RootedObject holder(cx, other.holder_);
     RootedShape holderShape(cx, other.holderShape_);
     RootedFunction setter(cx, other.setter_);
     return New(space, other.jitCode(), shape, holder, holderShape, setter, other.pcOffset_);
 }
 
 ICCall_Scripted::ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
-                                 HandleScript calleeScript, HandleObject templateObject,
+                                 HandleScript calleeScript, HandleNativeObject templateObject,
                                  uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
     calleeScript_(calleeScript),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 { }
 
 /* static */ ICCall_Scripted *
 ICCall_Scripted::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                        ICCall_Scripted &other)
 {
     RootedScript calleeScript(cx, other.calleeScript_);
-    RootedObject templateObject(cx, other.templateObject_);
+    RootedNativeObject templateObject(cx, other.templateObject_);
     return New(space, other.jitCode(), firstMonitorStub, calleeScript, templateObject,
                other.pcOffset_);
 }
 
 /* static */ ICCall_AnyScripted *
 ICCall_AnyScripted::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
                           ICCall_AnyScripted &other)
 {
     return New(space, other.jitCode(), firstMonitorStub, other.pcOffset_);
 }
 
 ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
-                             HandleFunction callee, HandleObject templateObject,
+                             HandleFunction callee, HandleNativeObject templateObject,
                              uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
     callee_(callee),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 {
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     // The simulator requires VM calls to be redirected to a special swi
@@ -10894,17 +10899,17 @@ ICCall_Native::ICCall_Native(JitCode *st
 #endif
 }
 
 /* static */ ICCall_Native *
 ICCall_Native::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                      ICCall_Native &other)
 {
     RootedFunction callee(cx, other.callee_);
-    RootedObject templateObject(cx, other.templateObject_);
+    RootedNativeObject templateObject(cx, other.templateObject_);
     return New(space, other.jitCode(), firstMonitorStub, callee, templateObject,
                other.pcOffset_);
 }
 
 /* static */ ICCall_ScriptedApplyArray *
 ICCall_ScriptedApplyArray::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
                                  ICCall_ScriptedApplyArray &other)
 {
@@ -11022,17 +11027,17 @@ ICGetProp_DOMProxyShadowed::Clone(JSCont
 static bool DoRestFallback(JSContext *cx, ICRest_Fallback *stub,
                            BaselineFrame *frame, MutableHandleValue res)
 {
     unsigned numFormals = frame->numFormalArgs() - 1;
     unsigned numActuals = frame->numActualArgs();
     unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
     Value *rest = frame->argv() + numFormals;
 
-    JSObject *obj = NewDenseCopiedArray(cx, numRest, rest, nullptr);
+    ArrayObject *obj = NewDenseCopiedArray(cx, numRest, rest, nullptr);
     if (!obj)
         return false;
     types::FixRestArgumentsType(cx, obj);
     res.setObject(*obj);
     return true;
 }
 
 typedef bool (*DoRestFallbackFn)(JSContext *, ICRest_Fallback *, BaselineFrame *,
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -11,16 +11,17 @@
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsgc.h"
 #include "jsopcode.h"
 
 #include "jit/BaselineJIT.h"
 #include "jit/BaselineRegisters.h"
+#include "vm/ArrayObject.h"
 
 namespace js {
 
 class TypedArrayLayout;
 
 namespace jit {
 
 //
@@ -1873,84 +1874,84 @@ class ICThis_Fallback : public ICFallbac
         }
     };
 };
 
 class ICNewArray_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
-    HeapPtrObject templateObject_;
-
-    ICNewArray_Fallback(JitCode *stubCode, JSObject *templateObject)
+    HeapPtrArrayObject templateObject_;
+
+    ICNewArray_Fallback(JitCode *stubCode, ArrayObject *templateObject)
       : ICFallbackStub(ICStub::NewArray_Fallback, stubCode), templateObject_(templateObject)
     {}
 
   public:
     static inline ICNewArray_Fallback *New(ICStubSpace *space, JitCode *code,
-                                           JSObject *templateObject) {
+                                           ArrayObject *templateObject) {
         if (!code)
             return nullptr;
         return space->allocate<ICNewArray_Fallback>(code, templateObject);
     }
 
     class Compiler : public ICStubCompiler {
-        RootedObject templateObject;
+        RootedArrayObject templateObject;
         bool generateStubCode(MacroAssembler &masm);
 
       public:
-        Compiler(JSContext *cx, JSObject *templateObject)
+        Compiler(JSContext *cx, ArrayObject *templateObject)
           : ICStubCompiler(cx, ICStub::NewArray_Fallback),
             templateObject(cx, templateObject)
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICNewArray_Fallback::New(space, getStubCode(), templateObject);
         }
     };
 
-    HeapPtrObject &templateObject() {
+    HeapPtrArrayObject &templateObject() {
         return templateObject_;
     }
 };
 
 class ICNewObject_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
-    HeapPtrObject templateObject_;
-
-    ICNewObject_Fallback(JitCode *stubCode, JSObject *templateObject)
+    HeapPtrNativeObject templateObject_;
+
+    ICNewObject_Fallback(JitCode *stubCode, NativeObject *templateObject)
       : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(templateObject)
     {}
 
   public:
     static inline ICNewObject_Fallback *New(ICStubSpace *space, JitCode *code,
-                                            JSObject *templateObject) {
+                                            NativeObject *templateObject) {
         if (!code)
             return nullptr;
         return space->allocate<ICNewObject_Fallback>(code, templateObject);
     }
 
     class Compiler : public ICStubCompiler {
-        RootedObject templateObject;
+        RootedNativeObject templateObject;
         bool generateStubCode(MacroAssembler &masm);
 
       public:
-        Compiler(JSContext *cx, JSObject *templateObject)
+        Compiler(JSContext *cx, NativeObject *templateObject)
           : ICStubCompiler(cx, ICStub::NewObject_Fallback),
             templateObject(cx, templateObject)
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICNewObject_Fallback::New(space, getStubCode(), templateObject);
         }
     };
 
-    HeapPtrObject &templateObject() {
+    HeapPtrNativeObject &templateObject() {
         return templateObject_;
     }
 };
 
 // Compare
 //      JSOP_LT
 //      JSOP_GT
 
@@ -5674,42 +5675,42 @@ class ICCall_Scripted : public ICMonitor
   public:
     // The maximum number of inlineable spread call arguments. Keep this small
     // to avoid controllable stack overflows by attackers passing large arrays
     // to spread call. This value is shared with ICCall_Native.
     static const uint32_t MAX_ARGS_SPREAD_LENGTH = 16;
 
   protected:
     HeapPtrScript calleeScript_;
-    HeapPtrObject templateObject_;
+    HeapPtrNativeObject templateObject_;
     uint32_t pcOffset_;
 
     ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
-                    HandleScript calleeScript, HandleObject templateObject,
+                    HandleScript calleeScript, HandleNativeObject templateObject,
                     uint32_t pcOffset);
 
   public:
     static inline ICCall_Scripted *New(
             ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
-            HandleScript calleeScript, HandleObject templateObject,
+            HandleScript calleeScript, HandleNativeObject templateObject,
             uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_Scripted>(code, firstMonitorStub,
                                                 calleeScript, templateObject, pcOffset);
     }
 
     static ICCall_Scripted *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                                   ICCall_Scripted &other);
 
     HeapPtrScript &calleeScript() {
         return calleeScript_;
     }
-    HeapPtrObject &templateObject() {
+    HeapPtrNativeObject &templateObject() {
         return templateObject_;
     }
 
     static size_t offsetOfCalleeScript() {
         return offsetof(ICCall_Scripted, calleeScript_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Scripted, pcOffset_);
@@ -5747,28 +5748,28 @@ class ICCall_AnyScripted : public ICMoni
 
 // Compiler for Call_Scripted and Call_AnyScripted stubs.
 class ICCallScriptedCompiler : public ICCallStubCompiler {
   protected:
     ICStub *firstMonitorStub_;
     bool isConstructing_;
     bool isSpread_;
     RootedScript calleeScript_;
-    RootedObject templateObject_;
+    RootedNativeObject templateObject_;
     uint32_t pcOffset_;
     bool generateStubCode(MacroAssembler &masm);
 
     virtual int32_t getKey() const {
         return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16) |
                (static_cast<int32_t>(isSpread_) << 17);
     }
 
   public:
     ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub,
-                           HandleScript calleeScript, HandleObject templateObject,
+                           HandleScript calleeScript, HandleNativeObject templateObject,
                            bool isConstructing, bool isSpread, uint32_t pcOffset)
       : ICCallStubCompiler(cx, ICStub::Call_Scripted),
         firstMonitorStub_(firstMonitorStub),
         isConstructing_(isConstructing),
         isSpread_(isSpread),
         calleeScript_(cx, calleeScript),
         templateObject_(cx, templateObject),
         pcOffset_(pcOffset)
@@ -5796,45 +5797,45 @@ class ICCallScriptedCompiler : public IC
 };
 
 class ICCall_Native : public ICMonitoredStub
 {
     friend class ICStubSpace;
 
   protected:
     HeapPtrFunction callee_;
-    HeapPtrObject templateObject_;
+    HeapPtrNativeObject templateObject_;
     uint32_t pcOffset_;
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     void *native_;
 #endif
 
     ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
-                  HandleFunction callee, HandleObject templateObject,
+                  HandleFunction callee, HandleNativeObject templateObject,
                   uint32_t pcOffset);
 
   public:
     static inline ICCall_Native *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
-                                     HandleFunction callee, HandleObject templateObject,
+                                     HandleFunction callee, HandleNativeObject templateObject,
                                      uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_Native>(code, firstMonitorStub,
                                               callee, templateObject, pcOffset);
     }
 
     static ICCall_Native *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                                 ICCall_Native &other);
 
     HeapPtrFunction &callee() {
         return callee_;
     }
-    HeapPtrObject &templateObject() {
+    HeapPtrNativeObject &templateObject() {
         return templateObject_;
     }
 
     static size_t offsetOfCallee() {
         return offsetof(ICCall_Native, callee_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Native, pcOffset_);
@@ -5848,28 +5849,28 @@ class ICCall_Native : public ICMonitored
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub *firstMonitorStub_;
         bool isConstructing_;
         bool isSpread_;
         RootedFunction callee_;
-        RootedObject templateObject_;
+        RootedNativeObject templateObject_;
         uint32_t pcOffset_;
         bool generateStubCode(MacroAssembler &masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16) |
                    (static_cast<int32_t>(isSpread_) << 17);
         }
 
       public:
         Compiler(JSContext *cx, ICStub *firstMonitorStub,
-                 HandleFunction callee, HandleObject templateObject,
+                 HandleFunction callee, HandleNativeObject templateObject,
                  bool isConstructing, bool isSpread, uint32_t pcOffset)
           : ICCallStubCompiler(cx, ICStub::Call_Native),
             firstMonitorStub_(firstMonitorStub),
             isConstructing_(isConstructing),
             isSpread_(isSpread),
             callee_(cx, callee),
             templateObject_(cx, templateObject),
             pcOffset_(pcOffset)
@@ -6417,43 +6418,43 @@ class ICTypeOf_Typed : public ICFallback
         }
     };
 };
 
 class ICRest_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
-    HeapPtrObject templateObject_;
-
-    ICRest_Fallback(JitCode *stubCode, JSObject *templateObject)
+    HeapPtrArrayObject templateObject_;
+
+    ICRest_Fallback(JitCode *stubCode, ArrayObject *templateObject)
       : ICFallbackStub(ICStub::Rest_Fallback, stubCode), templateObject_(templateObject)
     { }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICRest_Fallback *New(ICStubSpace *space, JitCode *code,
-                                       JSObject *templateObject) {
+                                       ArrayObject *templateObject) {
         if (!code)
             return nullptr;
         return space->allocate<ICRest_Fallback>(code, templateObject);
     }
 
-    HeapPtrObject &templateObject() {
+    HeapPtrArrayObject &templateObject() {
         return templateObject_;
     }
 
     class Compiler : public ICStubCompiler {
       protected:
-        RootedObject templateObject;
+        RootedArrayObject templateObject;
         bool generateStubCode(MacroAssembler &masm);
 
       public:
-        Compiler(JSContext *cx, JSObject *templateObject)
+        Compiler(JSContext *cx, ArrayObject *templateObject)
           : ICStubCompiler(cx, ICStub::Rest_Fallback),
             templateObject(cx, templateObject)
         { }
 
         ICStub *getStub(ICStubSpace *space) {
             return ICRest_Fallback::New(space, getStubCode(), templateObject);
         }
     };
@@ -6548,17 +6549,17 @@ IsCacheableDOMProxy(JSObject *obj)
     if (!obj->is<ProxyObject>())
         return false;
 
     const BaseProxyHandler *handler = obj->as<ProxyObject>().handler();
 
     if (handler->family() != GetDOMProxyHandlerFamily())
         return false;
 
-    if (obj->numFixedSlots() <= GetDOMProxyExpandoSlot())
+    if (obj->fakeNativeNumFixedSlots() <= GetDOMProxyExpandoSlot())
         return false;
 
     return true;
 }
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -408,44 +408,44 @@ BaselineInspector::hasSeenDoubleResult(j
     if (stub->isUnaryArith_Fallback())
         return stub->toUnaryArith_Fallback()->sawDoubleResult();
     else
         return stub->toBinaryArith_Fallback()->sawDoubleResult();
 
     return false;
 }
 
-JSObject *
+NativeObject *
 BaselineInspector::getTemplateObject(jsbytecode *pc)
 {
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         switch (stub->kind()) {
           case ICStub::NewArray_Fallback:
             return stub->toNewArray_Fallback()->templateObject();
           case ICStub::NewObject_Fallback:
             return stub->toNewObject_Fallback()->templateObject();
           case ICStub::Rest_Fallback:
             return stub->toRest_Fallback()->templateObject();
           case ICStub::Call_Scripted:
-            if (JSObject *obj = stub->toCall_Scripted()->templateObject())
+            if (NativeObject *obj = stub->toCall_Scripted()->templateObject())
                 return obj;
             break;
           default:
             break;
         }
     }
 
     return nullptr;
 }
 
-JSObject *
+NativeObject *
 BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
 {
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -104,18 +104,18 @@ class BaselineInspector
     MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
 
     bool hasSeenNonNativeGetElement(jsbytecode *pc);
     bool hasSeenNegativeIndexGetElement(jsbytecode *pc);
     bool hasSeenAccessedGetter(jsbytecode *pc);
     bool hasSeenDoubleResult(jsbytecode *pc);
     bool hasSeenNonStringIterMore(jsbytecode *pc);
 
-    JSObject *getTemplateObject(jsbytecode *pc);
-    JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
+    NativeObject *getTemplateObject(jsbytecode *pc);
+    NativeObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
 
     DeclEnvObject *templateDeclEnvObject();
     CallObject *templateCallObject();
 
     JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter);
     JSObject *commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter);
 };
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1371,17 +1371,17 @@ CodeGenerator::visitTableSwitchV(LTableS
     masm.bind(&unboxInt);
     masm.unboxInt32(value, index);
 
     masm.bind(&isInt);
 
     return emitTableSwitchDispatch(mir, index, ToRegisterOrInvalid(ins->tempPointer()));
 }
 
-typedef JSObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleObject, NewObjectKind);
+typedef NativeObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleNativeObject, NewObjectKind);
 static const VMFunction DeepCloneObjectLiteralInfo =
     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
 
 bool
 CodeGenerator::visitCloneLiteral(LCloneLiteral *lir)
 {
     pushArg(ImmWord(js::MaybeSingletonObject));
     pushArg(ToRegister(lir->getObjectLiteral()));
@@ -1629,17 +1629,17 @@ CodeGenerator::visitPointer(LPointer *li
     else
         masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
     return true;
 }
 
 bool
 CodeGenerator::visitSlots(LSlots *lir)
 {
-    Address slots(ToRegister(lir->object()), JSObject::offsetOfSlots());
+    Address slots(ToRegister(lir->object()), NativeObject::offsetOfSlots());
     masm.loadPtr(slots, ToRegister(lir->output()));
     return true;
 }
 
 bool
 CodeGenerator::visitLoadSlotT(LLoadSlotT *lir)
 {
     Register base = ToRegister(lir->slots());
@@ -1717,22 +1717,22 @@ CodeGenerator::emitGetPropertyPolymorphi
             }
         } else {
             masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
         }
 
         Shape *shape = mir->shape(i);
         if (shape->slot() < shape->numFixedSlots()) {
             // Fixed slot.
-            masm.loadTypedOrValue(Address(obj, JSObject::getFixedSlotOffset(shape->slot())),
+            masm.loadTypedOrValue(Address(obj, NativeObject::getFixedSlotOffset(shape->slot())),
                                   output);
         } else {
             // Dynamic slot.
             uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
-            masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), scratch);
+            masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
             masm.loadTypedOrValue(Address(scratch, offset), output);
         }
 
         if (i != mir->numShapes() - 1)
             masm.jump(&done);
         masm.bind(&next);
     }
 
@@ -1779,23 +1779,23 @@ CodeGenerator::emitSetPropertyPolymorphi
             }
         } else {
             masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
         }
 
         Shape *shape = mir->shape(i);
         if (shape->slot() < shape->numFixedSlots()) {
             // Fixed slot.
-            Address addr(obj, JSObject::getFixedSlotOffset(shape->slot()));
+            Address addr(obj, NativeObject::getFixedSlotOffset(shape->slot()));
             if (mir->needsBarrier())
                 emitPreBarrier(addr);
             masm.storeConstantOrRegister(value, addr);
         } else {
             // Dynamic slot.
-            masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), scratch);
+            masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
             Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
             if (mir->needsBarrier())
                 emitPreBarrier(addr);
             masm.storeConstantOrRegister(value, addr);
         }
 
         if (i != mir->numShapes() - 1)
             masm.jump(&done);
@@ -1828,17 +1828,17 @@ CodeGenerator::visitSetPropertyPolymorph
         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(ins->value()));
 
     return emitSetPropertyPolymorphic(ins, obj, temp, value);
 }
 
 bool
 CodeGenerator::visitElements(LElements *lir)
 {
-    Address elements(ToRegister(lir->object()), JSObject::offsetOfElements());
+    Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
     masm.loadPtr(elements, ToRegister(lir->output()));
     return true;
 }
 
 typedef bool (*ConvertElementsToDoublesFn)(JSContext *, uintptr_t);
 static const VMFunction ConvertElementsToDoublesInfo =
     FunctionInfo<ConvertElementsToDoublesFn>(ObjectElements::ConvertElementsToDoubles);
 
@@ -1882,32 +1882,32 @@ CodeGenerator::visitMaybeToDoubleElement
     masm.bind(&convert);
     masm.convertInt32ToDouble(value, temp);
     masm.boxDouble(temp, out);
 
     masm.bind(&done);
     return true;
 }
 
-typedef bool (*CopyElementsForWriteFn)(ThreadSafeContext *, JSObject *);
+typedef bool (*CopyElementsForWriteFn)(ThreadSafeContext *, NativeObject *);
 static const VMFunction CopyElementsForWriteInfo =
-    FunctionInfo<CopyElementsForWriteFn>(JSObject::CopyElementsForWrite);
+    FunctionInfo<CopyElementsForWriteFn>(NativeObject::CopyElementsForWrite);
 
 bool
 CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite *lir)
 {
     Register object = ToRegister(lir->object());
     Register temp = ToRegister(lir->temp());
 
     OutOfLineCode *ool = oolCallVM(CopyElementsForWriteInfo, lir,
                                    (ArgList(), object), StoreNothing());
     if (!ool)
         return false;
 
-    masm.loadPtr(Address(object, JSObject::offsetOfElements()), temp);
+    masm.loadPtr(Address(object, NativeObject::offsetOfElements()), temp);
     masm.branchTest32(Assembler::NonZero,
                       Address(temp, ObjectElements::offsetOfFlags()),
                       Imm32(ObjectElements::COPY_ON_WRITE),
                       ool->entry());
     masm.bind(ool->rejoin());
     return true;
 }
 
@@ -2273,17 +2273,17 @@ CodeGenerator::visitCallDOMNative(LCallD
     // argv is &vp[2] we just need to add 2*sizeof(Value) to the current
     // StackPointer.
     JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgv == 0);
     JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgc ==
                      IonDOMMethodExitFrameLayoutTraits::offsetOfArgcFromArgv);
     masm.computeEffectiveAddress(Address(StackPointer, 2 * sizeof(Value)), argArgs);
 
     // GetReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate()
-    masm.loadPrivate(Address(obj, JSObject::getFixedSlotOffset(0)), argPrivate);
+    masm.loadPrivate(Address(obj, NativeObject::getFixedSlotOffset(0)), argPrivate);
 
     // Push argc from the call instruction into what will become the IonExitFrame
     masm.Push(Imm32(call->numStackArgs()));
 
     // Push our argv onto the stack
     masm.Push(argArgs);
     // And store our JSJitMethodCallArgs* in argArgs.
     masm.movePtr(StackPointer, argArgs);
@@ -3590,20 +3590,20 @@ bool CodeGenerator::visitHypot(LHypot *l
 }
 
 bool
 CodeGenerator::visitNewArray(LNewArray *lir)
 {
     MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
-    JSObject *templateObject = lir->mir()->templateObject();
+    ArrayObject *templateObject = lir->mir()->templateObject();
     DebugOnly<uint32_t> count = lir->mir()->count();
 
-    MOZ_ASSERT(count < JSObject::NELEMENTS_LIMIT);
+    MOZ_ASSERT(count < NativeObject::NELEMENTS_LIMIT);
 
     if (lir->mir()->shouldUseVM())
         return visitNewArrayCallVM(lir);
 
     OutOfLineNewArray *ool = new(alloc()) OutOfLineNewArray(lir);
     if (!addOutOfLineCode(ool, lir->mir()))
         return false;
 
@@ -3622,17 +3622,17 @@ CodeGenerator::visitOutOfLineNewArray(Ou
     return true;
 }
 
 bool
 CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
-    JSObject *templateObject = lir->mir()->templateObject();
+    ArrayObject *templateObject = lir->mir()->templateObject();
     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
 
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool = oolCallVM(NewArrayCopyOnWriteInfo, lir,
                                    (ArgList(), ImmGCPtr(templateObject), Imm32(initialHeap)),
                                    StoreRegisterTo(objReg));
     if (!ool)
         return false;
@@ -3657,17 +3657,17 @@ class OutOfLineNewObject : public OutOfL
         return codegen->visitOutOfLineNewObject(this);
     }
 
     LNewObject *lir() const {
         return lir_;
     }
 };
 
-typedef JSObject *(*NewInitObjectFn)(JSContext *, HandleObject);
+typedef JSObject *(*NewInitObjectFn)(JSContext *, HandleNativeObject);
 static const VMFunction NewInitObjectInfo = FunctionInfo<NewInitObjectFn>(NewInitObject);
 
 typedef JSObject *(*NewInitObjectWithClassPrototypeFn)(JSContext *, HandleObject);
 static const VMFunction NewInitObjectWithClassPrototypeInfo =
     FunctionInfo<NewInitObjectWithClassPrototypeFn>(NewInitObjectWithClassPrototype);
 
 bool
 CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
@@ -3695,17 +3695,17 @@ CodeGenerator::visitNewObjectVMCall(LNew
     if (ReturnReg != objReg)
         masm.movePtr(ReturnReg, objReg);
 
     restoreLive(lir);
     return true;
 }
 
 static bool
-ShouldInitFixedSlots(LInstruction *lir, JSObject *templateObj)
+ShouldInitFixedSlots(LInstruction *lir, NativeObject *templateObj)
 {
     // Look for StoreFixedSlot instructions following an object allocation
     // that write to this object before a GC is triggered or this object is
     // passed to a VM call. If all fixed slots will be initialized, the
     // allocation code doesn't need to set the slots to |undefined|.
 
     uint32_t nfixed = templateObj->numUsedFixedSlots();
     if (nfixed == 0)
@@ -3716,18 +3716,18 @@ ShouldInitFixedSlots(LInstruction *lir, 
     // comment below.
     for (uint32_t slot = 0; slot < nfixed; slot++) {
         if (!templateObj->getSlot(slot).isUndefined())
             return true;
     }
 
     // Keep track of the fixed slots that are initialized. initializedSlots is
     // a bit mask with a bit for each slot.
-    MOZ_ASSERT(nfixed <= JSObject::MAX_FIXED_SLOTS);
-    static_assert(JSObject::MAX_FIXED_SLOTS <= 32, "Slot bits must fit in 32 bits");
+    MOZ_ASSERT(nfixed <= NativeObject::MAX_FIXED_SLOTS);
+    static_assert(NativeObject::MAX_FIXED_SLOTS <= 32, "Slot bits must fit in 32 bits");
     uint32_t initializedSlots = 0;
     uint32_t numInitialized = 0;
 
     MInstruction *allocMir = lir->mirRaw()->toInstruction();
     MBasicBlock *block = allocMir->block();
 
     // Skip the allocation instruction.
     MInstructionIterator iter = block->begin(allocMir);
@@ -3784,17 +3784,17 @@ ShouldInitFixedSlots(LInstruction *lir, 
 }
 
 bool
 CodeGenerator::visitNewObject(LNewObject *lir)
 {
     MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
-    JSObject *templateObject = lir->mir()->templateObject();
+    NativeObject *templateObject = lir->mir()->templateObject();
 
     if (lir->mir()->shouldUseVM())
         return visitNewObjectVMCall(lir);
 
     OutOfLineNewObject *ool = new(alloc()) OutOfLineNewObject(lir);
     if (!addOutOfLineCode(ool, lir->mir()))
         return false;
 
@@ -3819,17 +3819,17 @@ typedef js::DeclEnvObject *(*NewDeclEnvO
 static const VMFunction NewDeclEnvObjectInfo =
     FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
 
 bool
 CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
-    JSObject *templateObj = lir->mir()->templateObj();
+    NativeObject *templateObj = lir->mir()->templateObj();
     CompileInfo &info = lir->mir()->block()->info();
 
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool = oolCallVM(NewDeclEnvObjectInfo, lir,
                                    (ArgList(), ImmGCPtr(info.funMaybeLazy()),
                                     Imm32(gc::DefaultHeap)),
                                    StoreRegisterTo(objReg));
     if (!ool)
@@ -3848,17 +3848,17 @@ static const VMFunction NewCallObjectInf
     FunctionInfo<NewCallObjectFn>(NewCallObject);
 
 bool
 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
 
-    JSObject *templateObj = lir->mir()->templateObject();
+    NativeObject *templateObj = lir->mir()->templateObject();
 
     OutOfLineCode *ool = oolCallVM(NewCallObjectInfo, lir,
                                    (ArgList(), ImmGCPtr(templateObj->lastProperty()),
                                                ImmGCPtr(templateObj->type())),
                                    StoreRegisterTo(objReg));
     if (!ool)
         return false;
 
@@ -3900,34 +3900,34 @@ CodeGenerator::visitNewSingletonCallObje
 
 bool
 CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
 {
     Register resultReg = ToRegister(lir->output());
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register tempReg1 = ToRegister(lir->getTemp0());
     Register tempReg2 = ToRegister(lir->getTemp1());
-    JSObject *templateObj = lir->mir()->templateObj();
+    NativeObject *templateObj = lir->mir()->templateObj();
 
     return emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
 }
 
-typedef JSObject *(*ExtendArrayParFn)(ForkJoinContext*, JSObject*, uint32_t);
+typedef ArrayObject *(*ExtendArrayParFn)(ForkJoinContext*, ArrayObject*, uint32_t);
 static const VMFunction ExtendArrayParInfo =
     FunctionInfo<ExtendArrayParFn>(ExtendArrayPar);
 
 bool
 CodeGenerator::visitNewDenseArrayPar(LNewDenseArrayPar *lir)
 {
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register lengthReg = ToRegister(lir->length());
     Register tempReg0 = ToRegister(lir->getTemp0());
     Register tempReg1 = ToRegister(lir->getTemp1());
     Register tempReg2 = ToRegister(lir->getTemp2());
-    JSObject *templateObj = lir->mir()->templateObject();
+    ArrayObject *templateObj = lir->mir()->templateObject();
 
     if (!emitAllocateGCThingPar(lir, tempReg2, cxReg, tempReg0, tempReg1, templateObj))
         return false;
 
     // Invoke a C helper to allocate the elements.  The helper returns
     // nullptr on allocation error or the array object.
 
     saveLive(lir);
@@ -3971,17 +3971,17 @@ CodeGenerator::visitNewStringObject(LNew
 
 bool
 CodeGenerator::visitNewPar(LNewPar *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register tempReg1 = ToRegister(lir->getTemp0());
     Register tempReg2 = ToRegister(lir->getTemp1());
-    JSObject *templateObject = lir->mir()->templateObject();
+    NativeObject *templateObject = lir->mir()->templateObject();
     return emitAllocateGCThingPar(lir, objReg, cxReg, tempReg1, tempReg2, templateObject);
 }
 
 #ifndef JSGC_FJGENERATIONAL
 class OutOfLineNewGCThingPar : public OutOfLineCodeBase<CodeGenerator>
 {
 public:
     LInstruction *lir;
@@ -4001,17 +4001,17 @@ public:
 #endif // JSGC_FJGENERATIONAL
 
 typedef JSObject *(*NewGCThingParFn)(ForkJoinContext *, js::gc::AllocKind allocKind);
 static const VMFunction NewGCThingParInfo =
     FunctionInfo<NewGCThingParFn>(NewGCThingPar);
 
 bool
 CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
-                                      Register tempReg1, Register tempReg2, JSObject *templateObj)
+                                      Register tempReg1, Register tempReg2, NativeObject *templateObj)
 {
     MOZ_ASSERT(lir->mirRaw());
     MOZ_ASSERT(lir->mirRaw()->isInstruction());
 
     gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
 #ifdef JSGC_FJGENERATIONAL
     OutOfLineCode *ool = oolCallVM(NewGCThingParInfo, lir,
                                    (ArgList(), Imm32(allocKind)), StoreRegisterTo(objReg));
@@ -4098,17 +4098,17 @@ CodeGenerator::visitMutateProto(LMutateP
     Register objReg = ToRegister(lir->getObject());
 
     pushArg(ToValue(lir, LMutateProto::ValueIndex));
     pushArg(objReg);
 
     return callVM(MutatePrototypeInfo, lir);
 }
 
-typedef bool(*InitPropFn)(JSContext *cx, HandleObject obj,
+typedef bool(*InitPropFn)(JSContext *cx, HandleNativeObject obj,
                           HandlePropertyName name, HandleValue value);
 static const VMFunction InitPropInfo =
     FunctionInfo<InitPropFn>(InitProp);
 
 bool
 CodeGenerator::visitInitProp(LInitProp *lir)
 {
     Register objReg = ToRegister(lir->getObject());
@@ -4187,17 +4187,17 @@ CodeGenerator::visitCreateThisWithProto(
 typedef JSObject *(*NewGCObjectFn)(JSContext *cx, gc::AllocKind allocKind,
                                    gc::InitialHeap initialHeap);
 static const VMFunction NewGCObjectInfo =
     FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
 
 bool
 CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
 {
-    JSObject *templateObject = lir->mir()->templateObject();
+    NativeObject *templateObject = lir->mir()->templateObject();
     gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
 
     OutOfLineCode *ool = oolCallVM(NewGCObjectInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(initialHeap)),
                                    StoreRegisterTo(objReg));
@@ -5942,17 +5942,17 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
     else
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*SetDenseElementFn)(JSContext *, HandleObject, int32_t, HandleValue,
+typedef bool (*SetDenseElementFn)(JSContext *, HandleNativeObject, int32_t, HandleValue,
                                   bool strict);
 typedef bool (*SetDenseElementParFn)(ForkJoinContext *, HandleObject, int32_t, HandleValue, bool);
 static const VMFunctionsModal SetDenseElementInfo = VMFunctionsModal(
     FunctionInfo<SetDenseElementFn>(SetDenseElement),
     FunctionInfo<SetDenseElementParFn>(SetDenseElementPar));
 
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
@@ -6064,17 +6064,17 @@ CodeGenerator::emitArrayPopShift(LInstru
         if (!ool)
             return false;
     }
 
     // VM call if a write barrier is necessary.
     masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
 
     // Load elements and length.
-    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), elementsTemp);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
 
     // VM call if length != initializedLength.
     Int32Key key = Int32Key(lengthTemp);
     Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
     masm.branchKey(Assembler::NotEqual, initLength, key, ool->entry());
 
     // Test for length != 0. On zero length either take a VM call or generate
@@ -6147,30 +6147,30 @@ CodeGenerator::visitArrayPopShiftT(LArra
 {
     Register obj = ToRegister(lir->object());
     Register elements = ToRegister(lir->temp0());
     Register length = ToRegister(lir->temp1());
     TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
     return emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
 }
 
-typedef bool (*ArrayPushDenseFn)(JSContext *, HandleObject, HandleValue, uint32_t *);
+typedef bool (*ArrayPushDenseFn)(JSContext *, HandleArrayObject, HandleValue, uint32_t *);
 static const VMFunction ArrayPushDenseInfo =
     FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense);
 
 bool
 CodeGenerator::emitArrayPush(LInstruction *lir, const MArrayPush *mir, Register obj,
                              ConstantOrRegister value, Register elementsTemp, Register length)
 {
     OutOfLineCode *ool = oolCallVM(ArrayPushDenseInfo, lir, (ArgList(), obj, value), StoreRegisterTo(length));
     if (!ool)
         return false;
 
     // Load elements and length.
-    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), elementsTemp);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
 
     Int32Key key = Int32Key(length);
     Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
     Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
 
     // Guard length == initializedLength.
     masm.branchKey(Assembler::NotEqual, initLength, key, ool->entry());
@@ -6222,21 +6222,21 @@ CodeGenerator::visitArrayConcat(LArrayCo
     Register rhs = ToRegister(lir->rhs());
     Register temp1 = ToRegister(lir->temp1());
     Register temp2 = ToRegister(lir->temp2());
 
     // If 'length == initializedLength' for both arrays we try to allocate an object
     // inline and pass it to the stub. Else, we just pass nullptr and the stub falls
     // back to a slow path.
     Label fail, call;
-    masm.loadPtr(Address(lhs, JSObject::offsetOfElements()), temp1);
+    masm.loadPtr(Address(lhs, NativeObject::offsetOfElements()), temp1);
     masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
     masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
 
-    masm.loadPtr(Address(rhs, JSObject::offsetOfElements()), temp1);
+    masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1);
     masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
     masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
 
     // Try to allocate an object.
     masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
     masm.jump(&call);
     {
         masm.bind(&fail);
@@ -6321,17 +6321,17 @@ CodeGenerator::visitIteratorStart(LItera
     // be a plain ), so we do not need to generate a loop here.
     masm.loadObjProto(obj, temp1);
     masm.loadObjProto(temp1, temp1);
     masm.branchTestPtr(Assembler::NonZero, temp1, temp1, ool->entry());
 
     // Ensure the object does not have any elements. The presence of dense
     // elements is not captured by the shape tests above.
     masm.branchPtr(Assembler::NotEqual,
-                   Address(obj, JSObject::offsetOfElements()),
+                   Address(obj, NativeObject::offsetOfElements()),
                    ImmPtr(js::emptyObjectElements),
                    ool->entry());
 
     // Write barrier for stores to the iterator. We only need to take a write
     // barrier if NativeIterator::obj is actually going to change.
     {
 #ifdef JSGC_GENERATIONAL
         // Bug 867815: When using a nursery, we unconditionally take this out-
@@ -6566,17 +6566,17 @@ CodeGenerator::visitRunOncePrologue(LRun
     pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
     return callVM(RunOnceScriptPrologueInfo, lir);
 }
 
 
 typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
                                          HandleObject);
 typedef JSObject *(*InitRestParameterParFn)(ForkJoinContext *, uint32_t, Value *,
-                                            HandleObject, HandleObject);
+                                            HandleObject, HandleArrayObject);
 static const VMFunctionsModal InitRestParameterInfo = VMFunctionsModal(
     FunctionInfo<InitRestParameterFn>(InitRestParameter),
     FunctionInfo<InitRestParameterParFn>(InitRestParameterPar));
 
 bool
 CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
                         Register temp0, Register temp1, unsigned numFormals,
                         JSObject *templateObject, bool saveAndRestore, Register resultreg)
@@ -6619,17 +6619,17 @@ CodeGenerator::emitRest(LInstruction *li
 bool
 CodeGenerator::visitRest(LRest *lir)
 {
     Register numActuals = ToRegister(lir->numActuals());
     Register temp0 = ToRegister(lir->getTemp(0));
     Register temp1 = ToRegister(lir->getTemp(1));
     Register temp2 = ToRegister(lir->getTemp(2));
     unsigned numFormals = lir->mir()->numFormals();
-    JSObject *templateObject = lir->mir()->templateObject();
+    ArrayObject *templateObject = lir->mir()->templateObject();
 
     Label joinAlloc, failAlloc;
     masm.createGCObject(temp2, temp0, templateObject, gc::DefaultHeap, &failAlloc);
     masm.jump(&joinAlloc);
     {
         masm.bind(&failAlloc);
         masm.movePtr(ImmPtr(nullptr), temp2);
     }
@@ -6645,17 +6645,17 @@ bool
 CodeGenerator::visitRestPar(LRestPar *lir)
 {
     Register numActuals = ToRegister(lir->numActuals());
     Register cx = ToRegister(lir->forkJoinContext());
     Register temp0 = ToRegister(lir->getTemp(0));
     Register temp1 = ToRegister(lir->getTemp(1));
     Register temp2 = ToRegister(lir->getTemp(2));
     unsigned numFormals = lir->mir()->numFormals();
-    JSObject *templateObject = lir->mir()->templateObject();
+    ArrayObject *templateObject = lir->mir()->templateObject();
 
     if (!emitAllocateGCThingPar(lir, temp2, cx, temp0, temp1, templateObject))
         return false;
 
     return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, true, ToRegister(lir->output()));
 }
 
 bool
@@ -7208,42 +7208,42 @@ CodeGenerator::visitCallInitElementArray
 
 bool
 CodeGenerator::visitLoadFixedSlotV(LLoadFixedSlotV *ins)
 {
     const Register obj = ToRegister(ins->getOperand(0));
     size_t slot = ins->mir()->slot();
     ValueOperand result = GetValueOutput(ins);
 
-    masm.loadValue(Address(obj, JSObject::getFixedSlotOffset(slot)), result);
+    masm.loadValue(Address(obj, NativeObject::getFixedSlotOffset(slot)), result);
     return true;
 }
 
 bool
 CodeGenerator::visitLoadFixedSlotT(LLoadFixedSlotT *ins)
 {
     const Register obj = ToRegister(ins->getOperand(0));
     size_t slot = ins->mir()->slot();
     AnyRegister result = ToAnyRegister(ins->getDef(0));
     MIRType type = ins->mir()->type();
 
-    masm.loadUnboxedValue(Address(obj, JSObject::getFixedSlotOffset(slot)), type, result);
+    masm.loadUnboxedValue(Address(obj, NativeObject::getFixedSlotOffset(slot)), type, result);
 
     return true;
 }
 
 bool
 CodeGenerator::visitStoreFixedSlotV(LStoreFixedSlotV *ins)
 {
     const Register obj = ToRegister(ins->getOperand(0));
     size_t slot = ins->mir()->slot();
 
     const ValueOperand value = ToValue(ins, LStoreFixedSlotV::Value);
 
-    Address address(obj, JSObject::getFixedSlotOffset(slot));
+    Address address(obj, NativeObject::getFixedSlotOffset(slot));
     if (ins->mir()->needsBarrier())
         emitPreBarrier(address);
 
     masm.storeValue(value, address);
 
     return true;
 }
 
@@ -7255,17 +7255,17 @@ CodeGenerator::visitStoreFixedSlotT(LSto
 
     const LAllocation *value = ins->value();
     MIRType valueType = ins->mir()->value()->type();
 
     ConstantOrRegister nvalue = value->isConstant()
                               ? ConstantOrRegister(*value->toConstant())
                               : TypedOrValueRegister(valueType, ToAnyRegister(value));
 
-    Address address(obj, JSObject::getFixedSlotOffset(slot));
+    Address address(obj, NativeObject::getFixedSlotOffset(slot));
     if (ins->mir()->needsBarrier())
         emitPreBarrier(address);
 
     masm.storeConstantOrRegister(nvalue, address);
 
     return true;
 }
 
@@ -8590,24 +8590,24 @@ CodeGenerator::visitGetDOMProperty(LGetD
     const Register ValueReg = ToRegister(ins->getValueReg());
 
     Label haveValue;
     if (ins->mir()->valueMayBeInSlot()) {
         size_t slot = ins->mir()->domMemberSlotIndex();
         // It's a bit annoying to redo these slot calculations, which duplcate
         // LSlots and a few other things like that, but I'm not sure there's a
         // way to reuse those here.
-        if (slot < JSObject::MAX_FIXED_SLOTS) {
-            masm.loadValue(Address(ObjectReg, JSObject::getFixedSlotOffset(slot)),
+        if (slot < NativeObject::MAX_FIXED_SLOTS) {
+            masm.loadValue(Address(ObjectReg, NativeObject::getFixedSlotOffset(slot)),
                            JSReturnOperand);
         } else {
             // It's a dynamic slot.
-            slot -= JSObject::MAX_FIXED_SLOTS;
+            slot -= NativeObject::MAX_FIXED_SLOTS;
             // Use PrivateReg as a scratch register for the slots pointer.
-            masm.loadPtr(Address(ObjectReg, JSObject::offsetOfSlots()),
+            masm.loadPtr(Address(ObjectReg, NativeObject::offsetOfSlots()),
                          PrivateReg);
             masm.loadValue(Address(PrivateReg, slot*sizeof(js::Value)),
                            JSReturnOperand);
         }
         masm.branchTestUndefined(Assembler::NotEqual, JSReturnOperand, &haveValue);
     }
 
     DebugOnly<uint32_t> initialStack = masm.framePushed();
@@ -8620,17 +8620,17 @@ CodeGenerator::visitGetDOMProperty(LGetD
     // We pass the pointer to our out param as an instance of
     // JSJitGetterCallArgs, since on the binary level it's the same thing.
     JS_STATIC_ASSERT(sizeof(JSJitGetterCallArgs) == sizeof(Value*));
     masm.movePtr(StackPointer, ValueReg);
 
     masm.Push(ObjectReg);
 
     // GetReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate()
-    masm.loadPrivate(Address(ObjectReg, JSObject::getFixedSlotOffset(0)), PrivateReg);
+    masm.loadPrivate(Address(ObjectReg, NativeObject::getFixedSlotOffset(0)), PrivateReg);
 
     // Rooting will happen at GC time.
     masm.movePtr(StackPointer, ObjectReg);
 
     uint32_t safepointOffset;
     if (!masm.buildFakeExitFrame(JSContextReg, &safepointOffset))
         return false;
     masm.enterFakeExitFrame(IonDOMExitFrameLayout::GetterToken());
@@ -8672,17 +8672,17 @@ CodeGenerator::visitGetDOMMember(LGetDOM
     // use an LLoadFixedSlotV or some subclass of it for this case: that would
     // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
     // we'd have to duplicate a bunch of stuff we now get for free from
     // MGetDOMProperty.
     Register object = ToRegister(ins->object());
     size_t slot = ins->mir()->domMemberSlotIndex();
     ValueOperand result = GetValueOutput(ins);
 
-    masm.loadValue(Address(object, JSObject::getFixedSlotOffset(slot)), result);
+    masm.loadValue(Address(object, NativeObject::getFixedSlotOffset(slot)), result);
     return true;
 }
 
 bool
 CodeGenerator::visitSetDOMProperty(LSetDOMProperty *ins)
 {
     const Register JSContextReg = ToRegister(ins->getJSContextReg());
     const Register ObjectReg = ToRegister(ins->getObjectReg());
@@ -8699,17 +8699,17 @@ CodeGenerator::visitSetDOMProperty(LSetD
     // We pass the pointer to our out param as an instance of
     // JSJitGetterCallArgs, since on the binary level it's the same thing.
     JS_STATIC_ASSERT(sizeof(JSJitSetterCallArgs) == sizeof(Value*));
     masm.movePtr(StackPointer, ValueReg);
 
     masm.Push(ObjectReg);
 
     // GetReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate()
-    masm.loadPrivate(Address(ObjectReg, JSObject::getFixedSlotOffset(0)), PrivateReg);
+    masm.loadPrivate(Address(ObjectReg, NativeObject::getFixedSlotOffset(0)), PrivateReg);
 
     // Rooting will happen at GC time.
     masm.movePtr(StackPointer, ObjectReg);
 
     uint32_t safepointOffset;
     if (!masm.buildFakeExitFrame(JSContextReg, &safepointOffset))
         return false;
     masm.enterFakeExitFrame(IonDOMExitFrameLayout::SetterToken());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -383,17 +383,17 @@ class CodeGenerator : public CodeGenerat
                             FloatRegister tempDouble, FloatRegister tempFloat32,
                             ValueOperand index, ConstantOrRegister value,
                             bool strict, bool guardHoles, jsbytecode *profilerLeavePc);
 
     bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
 
     bool emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
                                 Register tempReg1, Register tempReg2,
-                                JSObject *templateObj);
+                                NativeObject *templateObj);
 
     bool emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg);
 
     void emitLambdaInit(Register resultReg, Register scopeChainReg,
                         const LambdaFunctionInfo &info);
 
     bool emitFilterArgumentsOrEval(LInstruction *lir, Register string, Register temp1,
                                    Register temp2);
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2684,17 +2684,17 @@ jit::ConvertLinearInequality(TempAllocat
     compare->setCompareType(MCompare::Compare_Int32);
 
     return compare;
 }
 
 static bool
 AnalyzePoppedThis(JSContext *cx, types::TypeObject *type,
                   MDefinition *thisValue, MInstruction *ins, bool definitelyExecuted,
-                  HandleObject baseobj,
+                  HandleNativeObject baseobj,
                   Vector<types::TypeNewScript::Initializer> *initializerList,
                   Vector<PropertyName *> *accessedProperties,
                   bool *phandled)
 {
     // Determine the effect that a use of the |this| value when calling |new|
     // on a script has on the properties definitely held by the new object.
 
     if (ins->isCallSetProperty()) {
@@ -2709,17 +2709,17 @@ AnalyzePoppedThis(JSContext *cx, types::
         if (setprop->name() == cx->names().prototype ||
             setprop->name() == cx->names().proto ||
             setprop->name() == cx->names().constructor)
         {
             return true;
         }
 
         // Ignore assignments to properties that were already written to.
-        if (baseobj->nativeLookup(cx, NameToId(setprop->name()))) {
+        if (baseobj->lookup(cx, NameToId(setprop->name()))) {
             *phandled = true;
             return true;
         }
 
         // Don't add definite properties for properties that were already
         // read in the constructor.
         for (size_t i = 0; i < accessedProperties->length(); i++) {
             if ((*accessedProperties)[i] == setprop->name())
@@ -2739,17 +2739,17 @@ AnalyzePoppedThis(JSContext *cx, types::
         if (!types::AddClearDefiniteGetterSetterForPrototypeChain(cx, type, id)) {
             // The prototype chain already contains a getter/setter for this
             // property, or type information is too imprecise.
             return true;
         }
 
         // Add the property to the object, being careful not to update type information.
         DebugOnly<unsigned> slotSpan = baseobj->slotSpan();
-        MOZ_ASSERT(!baseobj->nativeContainsPure(id));
+        MOZ_ASSERT(!baseobj->containsPure(id));
         if (!baseobj->addDataProperty(cx, id, baseobj->slotSpan(), JSPROP_ENUMERATE))
             return false;
         MOZ_ASSERT(baseobj->slotSpan() != slotSpan);
         MOZ_ASSERT(!baseobj->inDictionaryMode());
 
         Vector<MResumePoint *> callerResumePoints(cx);
         for (MResumePoint *rp = ins->block()->callerResumePoint();
              rp;
@@ -2788,17 +2788,17 @@ AnalyzePoppedThis(JSContext *cx, types::
          *   could cause 'this' to escape.
          *
          * - The accessed property is either already a definite property or
          *   is not later added as one. Since the definite properties are
          *   added to the object at the point of its creation, reading a
          *   definite property before it is assigned could incorrectly hit.
          */
         RootedId id(cx, NameToId(get->name()));
-        if (!baseobj->nativeLookup(cx, id) && !accessedProperties->append(get->name()))
+        if (!baseobj->lookup(cx, id) && !accessedProperties->append(get->name()))
             return false;
 
         if (!types::AddClearDefiniteGetterSetterForPrototypeChain(cx, type, id)) {
             // The |this| value can escape if any property reads it does go
             // through a getter.
             return true;
         }
 
@@ -2818,17 +2818,17 @@ static int
 CmpInstructions(const void *a, const void *b)
 {
     return (*static_cast<MInstruction * const *>(a))->id() -
            (*static_cast<MInstruction * const *>(b))->id();
 }
 
 bool
 jit::AnalyzeNewScriptDefiniteProperties(JSContext *cx, JSFunction *fun,
-                                        types::TypeObject *type, HandleObject baseobj,
+                                        types::TypeObject *type, HandleNativeObject baseobj,
                                         Vector<types::TypeNewScript::Initializer> *initializerList)
 {
     MOZ_ASSERT(cx->compartment()->activeAnalysis);
 
     // When invoking 'new' on the specified script, try to find some properties
     // which will definitely be added to the created object before it has a
     // chance to escape and be accessed elsewhere.
 
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -157,17 +157,17 @@ ConvertLinearSum(TempAllocator &alloc, M
 
 // Convert the test 'sum >= 0' to a comparison, adding any necessary
 // instructions to the end of block.
 MCompare *
 ConvertLinearInequality(TempAllocator &alloc, MBasicBlock *block, const LinearSum &sum);
 
 bool
 AnalyzeNewScriptDefiniteProperties(JSContext *cx, JSFunction *fun,
-                                   types::TypeObject *type, HandleObject baseobj,
+                                   types::TypeObject *type, HandleNativeObject baseobj,
                                    Vector<types::TypeNewScript::Initializer> *initializerList);
 
 bool
 AnalyzeArgumentsUsage(JSContext *cx, JSScript *script);
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -24,16 +24,17 @@
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsopcodeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "jit/CompileInfo-inl.h"
 #include "jit/ExecutionMode-inl.h"
+#include "vm/ObjectImpl-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::AssertedCast;
 using mozilla::DebugOnly;
 using mozilla::Maybe;
 
@@ -3139,54 +3140,59 @@ IonBuilder::tableSwitch(JSOp op, jssrcno
 }
 
 bool
 IonBuilder::replaceTypeSet(MDefinition *subject, types::TemporaryTypeSet *type, MTest *test)
 {
     if (type->unknown())
         return true;
 
-    MFilterTypeSet *replace = nullptr;
+    MInstruction *replace = nullptr;
     MDefinition *ins;
 
     for (uint32_t i = 0; i < current->stackDepth(); i++) {
         ins = current->getSlot(i);
 
         // Instead of creating a new MFilterTypeSet, try to update the old one.
         if (ins->isFilterTypeSet() && ins->getOperand(0) == subject &&
             ins->dependency() == test)
         {
             types::TemporaryTypeSet *intersect =
                 types::TypeSet::intersectSets(ins->resultTypeSet(), type, alloc_->lifoAlloc());
             if (!intersect)
                 return false;
 
             ins->toFilterTypeSet()->setResultType(intersect->getKnownMIRType());
             ins->toFilterTypeSet()->setResultTypeSet(intersect);
+
+            if (ins->type() == MIRType_Undefined)
+                current->setSlot(i, constant(UndefinedValue()));
+            if (ins->type() == MIRType_Null)
+                current->setSlot(i, constant(NullValue()));
             continue;
         }
 
         if (ins == subject) {
             if (!replace) {
                 replace = MFilterTypeSet::New(alloc(), subject, type);
-
                 if (!replace)
                     return false;
-                if (replace == subject)
-                    break;
 
                 current->add(replace);
 
-                if (replace != subject) {
-                    // Make sure we don't hoist it above the MTest, we can use the
-                    // 'dependency' of an MInstruction. This is normally used by
-                    // Alias Analysis, but won't get overwritten, since this
-                    // instruction doesn't have an AliasSet.
-                    replace->setDependency(test);
-                }
+                // Make sure we don't hoist it above the MTest, we can use the
+                // 'dependency' of an MInstruction. This is normally used by
+                // Alias Analysis, but won't get overwritten, since this
+                // instruction doesn't have an AliasSet.
+                replace->setDependency(test);
+
+                if (replace->type() == MIRType_Undefined)
+                    replace = constant(UndefinedValue());
+                if (replace->type() == MIRType_Null)