Merge m-c to fx-team, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 08 Jun 2016 17:13:46 -0700
changeset 301241 8a447c89176fb240f78db350e8d65f62d0a6fabb
parent 301240 d03332bc9097bbf3bcf15dce7fb0fde5d10b7eae (current diff)
parent 301187 249d57fa78a0522f63a5b1ed1fdda55f383156e0 (diff)
child 301242 1b4bc4a13f27d22de9b8c7b064ccc7fa1767dac2
push id78263
push usercbook@mozilla.com
push dateThu, 09 Jun 2016 10:13:31 +0000
treeherdermozilla-inbound@3d132a280ca0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team, a=merge
browser/app/profile/firefox.js
dom/base/Console.cpp
dom/base/Console.h
dom/base/ConsoleAPI.manifest
dom/base/ConsoleAPIStorage.js
dom/base/ConsoleReportCollector.cpp
dom/base/ConsoleReportCollector.h
dom/base/nsIConsoleAPIStorage.idl
dom/base/nsIConsoleReportCollector.h
dom/base/test/test_bug659625.html
dom/base/test/test_bug978522.html
dom/base/test/test_bug979109.html
dom/base/test/test_bug989665.html
dom/base/test/test_console.xul
dom/base/test/test_consoleEmptyStack.html
dom/base/test/test_console_binding.html
dom/base/test/test_console_proto.html
modules/libpref/init/all.js
taskcluster/taskgraph/test/test_util.py
taskcluster/taskgraph/util.py
testing/eslint/eslint-plugin-mozilla/LICENSE
testing/eslint/eslint-plugin-mozilla/docs/balanced-listeners.rst
testing/eslint/eslint-plugin-mozilla/docs/import-browserjs-globals.rst
testing/eslint/eslint-plugin-mozilla/docs/import-globals.rst
testing/eslint/eslint-plugin-mozilla/docs/import-headjs-globals.rst
testing/eslint/eslint-plugin-mozilla/docs/index.rst
testing/eslint/eslint-plugin-mozilla/docs/mark-test-function-used.rst
testing/eslint/eslint-plugin-mozilla/docs/no-aArgs.rst
testing/eslint/eslint-plugin-mozilla/docs/no-cpows-in-tests.rst
testing/eslint/eslint-plugin-mozilla/docs/reject-importGlobalProperties.rst
testing/eslint/eslint-plugin-mozilla/docs/var-only-at-top-level.rst
testing/eslint/eslint-plugin-mozilla/lib/globals.js
testing/eslint/eslint-plugin-mozilla/lib/helpers.js
testing/eslint/eslint-plugin-mozilla/lib/index.js
testing/eslint/eslint-plugin-mozilla/lib/processors/xbl-bindings.js
testing/eslint/eslint-plugin-mozilla/lib/rules/.eslintrc
testing/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js
testing/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
testing/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js
testing/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js
testing/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js
testing/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js
testing/eslint/eslint-plugin-mozilla/lib/rules/no-cpows-in-tests.js
testing/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js
testing/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js
testing/eslint/eslint-plugin-mozilla/moz.build
testing/eslint/eslint-plugin-mozilla/package.json
testing/eslint/manifest.tt
testing/eslint/npm-shrinkwrap.json
testing/eslint/package.json
testing/eslint/update
testing/taskcluster/design.md
testing/taskcluster/mach_commands.py
testing/taskcluster/requirements.txt
testing/taskcluster/routes.json
testing/taskcluster/scripts/builder/build-emulator-x86.sh
testing/taskcluster/scripts/builder/build-emulator.sh
testing/taskcluster/scripts/builder/build-haz-linux.sh
testing/taskcluster/scripts/builder/build-linux.sh
testing/taskcluster/scripts/builder/build-mulet-haz-linux.sh
testing/taskcluster/scripts/builder/build-mulet-linux.sh
testing/taskcluster/scripts/builder/build-simulator.sh
testing/taskcluster/scripts/builder/build-sm-package.sh
testing/taskcluster/scripts/builder/build-sm.sh
testing/taskcluster/scripts/builder/desktop-setup.sh
testing/taskcluster/scripts/builder/gaia_props.py
testing/taskcluster/scripts/builder/get-objdir.py
testing/taskcluster/scripts/builder/hazard-analysis.sh
testing/taskcluster/scripts/builder/install-packages.sh
testing/taskcluster/scripts/builder/pull-gaia.sh
testing/taskcluster/scripts/builder/setup-ccache.sh
testing/taskcluster/scripts/builder/sm-tooltool-config.sh
testing/taskcluster/scripts/copy.sh
testing/taskcluster/scripts/misc/build-cctools.sh
testing/taskcluster/scripts/misc/build-clang-linux.sh
testing/taskcluster/scripts/misc/build-gcc-linux.sh
testing/taskcluster/scripts/misc/minidump_stackwalk.sh
testing/taskcluster/scripts/misc/repackage-jdk-centos.sh
testing/taskcluster/scripts/phone-builder/build-dolphin.sh
testing/taskcluster/scripts/phone-builder/build-phone-ota.sh
testing/taskcluster/scripts/phone-builder/build-phone.sh
testing/taskcluster/scripts/phone-builder/post-build.sh
testing/taskcluster/scripts/phone-builder/pre-build.sh
testing/taskcluster/scripts/tester/harness-test-linux.sh
testing/taskcluster/scripts/tester/test-b2g.sh
testing/taskcluster/scripts/tester/test-linux.sh
testing/taskcluster/setup.py
testing/taskcluster/taskcluster_graph/__init__.py
testing/taskcluster/taskcluster_graph/build_task.py
testing/taskcluster/taskcluster_graph/commit_parser.py
testing/taskcluster/taskcluster_graph/dry_run.py
testing/taskcluster/taskcluster_graph/from_now.py
testing/taskcluster/taskcluster_graph/image_builder.py
testing/taskcluster/taskcluster_graph/mach_util.py
testing/taskcluster/taskcluster_graph/slugidjar.py
testing/taskcluster/taskcluster_graph/templates.py
testing/taskcluster/taskcluster_graph/transform/__init__.py
testing/taskcluster/taskcluster_graph/transform/routes.py
testing/taskcluster/taskcluster_graph/transform/treeherder.py
testing/taskcluster/taskcluster_graph/try_test_parser.py
testing/taskcluster/tasks/branches/alder/job_flags.yml
testing/taskcluster/tasks/branches/ash/job_flags.yml
testing/taskcluster/tasks/branches/autoland/job_flags.yml
testing/taskcluster/tasks/branches/b2g-inbound/job_flags.yml
testing/taskcluster/tasks/branches/base_job_flags.yml
testing/taskcluster/tasks/branches/base_jobs.yml
testing/taskcluster/tasks/branches/fx-team/job_flags.yml
testing/taskcluster/tasks/branches/larch/job_flags.yml
testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml
testing/taskcluster/tasks/branches/mozilla-inbound/job_flags.yml
testing/taskcluster/tasks/branches/try/job_flags.yml
testing/taskcluster/tasks/build.yml
testing/taskcluster/tasks/builds/android_api_15.yml
testing/taskcluster/tasks/builds/android_api_15_gradle_dependencies.yml
testing/taskcluster/tasks/builds/android_api_15_partner_sample1.yml
testing/taskcluster/tasks/builds/android_checkstyle.yml
testing/taskcluster/tasks/builds/android_lint.yml
testing/taskcluster/tasks/builds/android_test.yml
testing/taskcluster/tasks/builds/b2g_aries_eng.yml
testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml
testing/taskcluster/tasks/builds/b2g_base.yml
testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml
testing/taskcluster/tasks/builds/b2g_phone_base.yml
testing/taskcluster/tasks/builds/b2g_phone_eng_base.yml
testing/taskcluster/tasks/builds/base_linux32.yml
testing/taskcluster/tasks/builds/base_linux64.yml
testing/taskcluster/tasks/builds/base_macosx64.yml
testing/taskcluster/tasks/builds/dbg_linux32.yml
testing/taskcluster/tasks/builds/dbg_linux64-asan.yml
testing/taskcluster/tasks/builds/dbg_linux64.yml
testing/taskcluster/tasks/builds/dbg_macosx64.yml
testing/taskcluster/tasks/builds/firefox_base.yml
testing/taskcluster/tasks/builds/haz_linux.yml
testing/taskcluster/tasks/builds/haz_shell_linux.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_dogfood.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_noril_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_ota_balrog_debug.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_ota_balrog_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_ota_base.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_ota_debug.yml
testing/taskcluster/tasks/builds/legacy/b2g_aries_spark_ota_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_dolphin_512_eng.yml
testing/taskcluster/tasks/builds/legacy/b2g_dolphin_512_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_dolphin_base.yml
testing/taskcluster/tasks/builds/legacy/b2g_dolphin_eng.yml
testing/taskcluster/tasks/builds/legacy/b2g_dolphin_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_debug.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_eng.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_ota_base.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_ota_debug.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_ota_opt.yml
testing/taskcluster/tasks/builds/legacy/b2g_flame_kk_spark_eng.yml
testing/taskcluster/tasks/builds/legacy/b2g_hamachi_eng.yml
testing/taskcluster/tasks/builds/legacy/b2g_hamachi_user.yml
testing/taskcluster/tasks/builds/legacy/b2g_helix_user.yml
testing/taskcluster/tasks/builds/legacy/b2g_nexus_4_kk_eng.yml
testing/taskcluster/tasks/builds/legacy/b2g_nexus_4_kk_ota_debug.yml
testing/taskcluster/tasks/builds/legacy/b2g_nexus_4_kk_user.yml
testing/taskcluster/tasks/builds/legacy/b2g_nexus_5l_ota_debug.yml
testing/taskcluster/tasks/builds/legacy/b2g_nexus_5l_user.yml
testing/taskcluster/tasks/builds/linux64_clang.yml
testing/taskcluster/tasks/builds/linux64_gcc.yml
testing/taskcluster/tasks/builds/mobile_base.yml
testing/taskcluster/tasks/builds/mulet_haz_linux.yml
testing/taskcluster/tasks/builds/mulet_linux.yml
testing/taskcluster/tasks/builds/opt_linux32.yml
testing/taskcluster/tasks/builds/opt_linux64-asan.yml
testing/taskcluster/tasks/builds/opt_linux64.yml
testing/taskcluster/tasks/builds/opt_linux64_artifact.yml
testing/taskcluster/tasks/builds/opt_linux64_pgo.yml
testing/taskcluster/tasks/builds/opt_linux64_st-an.yml
testing/taskcluster/tasks/builds/opt_linux64_valgrind.yml
testing/taskcluster/tasks/builds/opt_macosx64.yml
testing/taskcluster/tasks/builds/opt_macosx64_st-an.yml
testing/taskcluster/tasks/builds/sm_arm64_sim.yml
testing/taskcluster/tasks/builds/sm_arm_sim.yml
testing/taskcluster/tasks/builds/sm_arm_sim_osx.yml
testing/taskcluster/tasks/builds/sm_base.yml
testing/taskcluster/tasks/builds/sm_compacting.yml
testing/taskcluster/tasks/builds/sm_nonunified.yml
testing/taskcluster/tasks/builds/sm_package.yml
testing/taskcluster/tasks/builds/sm_plain.yml
testing/taskcluster/tasks/builds/sm_plaindebug.yml
testing/taskcluster/tasks/builds/sm_rootanalysis.yml
testing/taskcluster/tasks/builds/sm_variant_base.yml
testing/taskcluster/tasks/decision/branch.yml
testing/taskcluster/tasks/decision/periodic_alder.yml
testing/taskcluster/tasks/decision/try.yml
testing/taskcluster/tasks/harness_test.yml
testing/taskcluster/tasks/image.yml
testing/taskcluster/tasks/lint.yml
testing/taskcluster/tasks/phone_build.yml
testing/taskcluster/tasks/post-builds/mulet_simulator.yml
testing/taskcluster/tasks/post-builds/upload_symbols.yml
testing/taskcluster/tasks/test.yml
testing/taskcluster/tasks/tests/b2g_unittest_base.yml
testing/taskcluster/tasks/tests/eslint-gecko.yml
testing/taskcluster/tasks/tests/fx_desktop_generic.yml
testing/taskcluster/tasks/tests/fx_linux64_cppunit.yml
testing/taskcluster/tasks/tests/fx_linux64_cppunit_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_cppunit_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_crashtest.yml
testing/taskcluster/tasks/tests/fx_linux64_crashtest_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_crashtest_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_crashtest_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_crashtest_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_crashtest_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_external_media_tests.yml
testing/taskcluster/tasks/tests/fx_linux64_external_media_tests_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_external_media_tests_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_gtest.yml
testing/taskcluster/tasks/tests/fx_linux64_gtest_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_gtest_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_jittests.yml
testing/taskcluster/tasks/tests/fx_linux64_jittests_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_jittests_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_jsreftest.yml
testing/taskcluster/tasks/tests/fx_linux64_jsreftest_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_jsreftest_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_jsreftest_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_jsreftest_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_jsreftest_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_luciddream.yml
testing/taskcluster/tasks/tests/fx_linux64_marionette.yml
testing/taskcluster/tasks/tests/fx_linux64_marionette_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_marionette_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_marionette_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_marionette_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_marionette_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_a11y.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_a11y_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_a11y_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_chrome.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_chrome_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_chrome_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_jetpack.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_jetpack_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_jetpack_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_media.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_mochitest_vg.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_reftest_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_opt.yml
testing/taskcluster/tasks/tests/fx_linux64_xpcshell.yml
testing/taskcluster/tasks/tests/fx_linux64_xpcshell_dbg.yml
testing/taskcluster/tasks/tests/fx_linux64_xpcshell_opt.yml
testing/taskcluster/tasks/tests/fx_test_base.yml
testing/taskcluster/tasks/tests/harness_marionette.yml
testing/taskcluster/tasks/tests/mozharness-gecko.yml
testing/taskcluster/tasks/tests/mozlint-flake8.yml
testing/taskcluster/tasks/tests/mulet_build_test.yml
testing/taskcluster/tasks/tests/mulet_build_unit.yml
testing/taskcluster/tasks/tests/mulet_gaia_js_integration_tests.yml
testing/taskcluster/tasks/tests/mulet_gaia_unit.yml
testing/taskcluster/tasks/tests/mulet_gaia_unit_oop.yml
testing/taskcluster/tasks/tests/mulet_linter.yml
testing/taskcluster/tasks/tests/mulet_mochitests.yml
testing/taskcluster/tasks/tests/mulet_reftests.yml
testing/taskcluster/tests/fixtures/child_pass.yml
testing/taskcluster/tests/fixtures/circular.yml
testing/taskcluster/tests/fixtures/circular_ref.yml
testing/taskcluster/tests/fixtures/deep/1.yml
testing/taskcluster/tests/fixtures/deep/2.yml
testing/taskcluster/tests/fixtures/deep/3.yml
testing/taskcluster/tests/fixtures/deep/4.yml
testing/taskcluster/tests/fixtures/extend_child.yml
testing/taskcluster/tests/fixtures/extend_parent.yml
testing/taskcluster/tests/fixtures/inherit.yml
testing/taskcluster/tests/fixtures/inherit_pass.yml
testing/taskcluster/tests/fixtures/simple.yml
testing/taskcluster/tests/fixtures/templates.yml
testing/taskcluster/tests/test_build_task.py
testing/taskcluster/tests/test_commit_parser.py
testing/taskcluster/tests/test_from_now.py
testing/taskcluster/tests/test_slugidjar.py
testing/taskcluster/tests/test_templates.py
testing/taskcluster/tests/test_try_test_parser.py
--- a/.eslintignore
+++ b/.eslintignore
@@ -35,18 +35,18 @@ netwerk/**
 nsprpub/**
 other-licenses/**
 parser/**
 probes/**
 python/**
 rdf/**
 startupcache/**
 testing/**
-!testing/eslint-plugin-mozilla/
-testing/eslint-plugin-mozilla/node_modules/**
+!tools/lint/eslint/eslint-plugin-mozilla/
+tools/lint/eslint/eslint-plugin-mozilla/node_modules/**
 tools/**
 uriloader/**
 view/**
 widget/**
 xpcom/**
 xpfe/**
 xulrunner/**
 
--- a/.gitignore
+++ b/.gitignore
@@ -96,17 +96,17 @@ embedding/ios/GeckoEmbed/GeckoEmbed.xcod
 # Ignore mozharness execution files
 testing/mozharness/.tox/
 testing/mozharness/build/
 testing/mozharness/logs/
 testing/mozharness/.coverage
 testing/mozharness/nosetests.xml
 
 # Ignore node_modules
-testing/eslint/node_modules/
+tools/lint/eslint/node_modules/
 
 # Ignore talos virtualenv and tp5n files.
 # The tp5n set is supposed to be decompressed at
 # testing/talos/talos/page_load_test/tp5n in order to run tests like tps
 # locally. Similarly, running talos requires a Python package virtual
 # environment. Both the virtual environment and tp5n files end up littering
 # the status command, so we ignore them.
 testing/talos/.Python
--- a/.hgignore
+++ b/.hgignore
@@ -113,17 +113,17 @@ GPATH
 ^testing/mozharness/logs/
 ^testing/mozharness/.coverage
 ^testing/mozharness/nosetests.xml
 
 # Ignore tox generated dir
 .tox/
 
 # Ignore node_modules
-^testing/eslint/node_modules/
+^tools/lint/eslint/node_modules/
 
 # Ignore talos virtualenv and tp5n files.
 # The tp5n set is supposed to be decompressed at
 # testing/talos/talos/page_load_test/tp5n in order to run tests like tps
 # locally. Similarly, running talos requires a Python package virtual
 # environment. Both the virtual environment and tp5n files end up littering
 # the status command, so we ignore them.
 ^testing/talos/.Python
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -627,31 +627,30 @@ logging::TreeInfo(const char* aMsg, uint
       while ((descr = va_arg(vl, const char*))) {
         AccessibleInfo(descr, va_arg(vl, Accessible*));
       }
     }
     else {
       MsgBegin("TREE", aMsg);
     }
     va_end(vl);
-
     MsgEnd();
 
     if (aExtraFlags & eStack) {
       Stack();
     }
   }
 }
 
 void
 logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags,
                   const char* aMsg1, Accessible* aAcc,
                   const char* aMsg2, nsINode* aNode)
 {
-  if (IsEnabledAll(logging::eTree | logging::eVerbose)) {
+  if (IsEnabledAll(logging::eTree | aExtraFlags)) {
     MsgBegin("TREE", "%s; doc: %p", aMsg, aAcc ? aAcc->Document() : nullptr);
     AccessibleInfo(aMsg1, aAcc);
     Accessible* acc = aAcc->Document()->GetAccessible(aNode);
     if (acc) {
       AccessibleInfo(aMsg2, acc);
     }
     else {
       Node(aMsg2, aNode);
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1851,27 +1851,18 @@ DocAccessible::FireEventsOnInsertion(Acc
 }
 
 void
 DocAccessible::UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNode)
 {
   // If child node is not accessible then look for its accessible children.
   Accessible* child = GetAccessible(aChildNode);
 #ifdef A11Y_LOG
-  if (logging::IsEnabled(logging::eTree)) {
-    logging::MsgBegin("TREE", "process content removal");
-    logging::Node("container", aContainer->GetNode());
-    logging::Node("child", aChildNode);
-    if (child)
-      logging::Address("child", child);
-    else
-      logging::MsgEntry("child accessible: null");
-
-    logging::MsgEnd();
-  }
+  logging::TreeInfo("process content removal", 0,
+                    "container", aContainer, "child", aChildNode);
 #endif
 
   TreeMutation mt(aContainer);
   if (child) {
     mt.BeforeRemoval(child);
     MOZ_ASSERT(aContainer == child->Parent(), "Wrong parent");
     aContainer->RemoveChild(child);
     UncacheChildrenInSubtree(child);
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -18,16 +18,17 @@ skip-if = true # Bug 561508
 [test_aria_menu.html]
 [test_aria_owns.html]
 [test_aria_presentation.html]
 [test_aria_table.html]
 [test_brokencontext.html]
 [test_button.xul]
 [test_canvas.html]
 [test_combobox.xul]
+[test_cssflexbox.html]
 [test_cssoverflow.html]
 [test_dochierarchy.html]
 [test_dockids.html]
 [test_filectrl.html]
 [test_formctrl.html]
 skip-if = buildapp == "mulet"
 [test_formctrl.xul]
 [test_gencontent.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_cssflexbox.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>CSS flexbox tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      // Ensure that flexbox ordering and absolute positioning do not affect
+      // the accessibility tree.
+      // Note that there is no accessible for a div with display:flex style.
+      var accTree = {
+        role: ROLE_SECTION,
+        children: [
+          { // Bug 1277559. Button outside the flexed content
+            role: ROLE_PUSHBUTTON,
+            name: "Button"
+          },
+          { // Visually first button in the 3 button row
+            role: ROLE_PUSHBUTTON,
+            name: "First"
+          },
+          { // Flushed right third button in the 3 button row
+            role: ROLE_PUSHBUTTON,
+            name: "Second"
+          },
+          { // Middle button in the 3 button row
+            role: ROLE_PUSHBUTTON,
+            name: "Third"
+          }, // end bug 1277559
+          { // Bug 962558: DOM first, Order 2.
+            role: ROLE_PUSHBUTTON,
+            name: "two, tab first"
+          },
+          { // DOM order second, flex order 1
+            role: ROLE_PUSHBUTTON,
+            name: "one, tab second"
+          } // end bug 962558
+        ]
+      };
+      testAccessibleTree("flex_elements", accTree);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="flex_elements">
+    <button type="button">Button</button>
+    <div style="position: relative; display: flex; width: 200px;">
+      <button type="button" style="order: 1">First</button>
+      <button type="button" style="order: 2; position: absolute; right: 0">Second</button>
+      <button type="button" style="order: 3">Third</button>
+    </div>
+    <div style="display: flex">
+      <button id="two" style="order: 2">two, tab first</button>
+      <button id="one" style="order: 1">one, tab second</button>
+    </div>
+  </div>
+</body>
+</html>
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1056,16 +1056,24 @@ pref("dom.mozSettings.allowForceReadOnly
 // the system app in dev mode.
 pref("dom.activities.developer_mode_only", "import-app");
 
 // mulet apparently loads firefox.js as well as b2g.js, so we have to explicitly
 // disable serviceworkers and push here to get them disabled in mulet.
 pref("dom.serviceWorkers.enabled", false);
 pref("dom.push.enabled", false);
 
+#if defined(RELEASE_BUILD)
+// Bug 1278848: Enable service worker notifications on release B2G once
+// they're ready.
+pref("dom.webnotifications.serviceworker.enabled", false);
+#else
+pref("dom.webnotifications.serviceworker.enabled", true);
+#endif
+
 // Retain at most 10 processes' layers buffers
 pref("layers.compositor-lru-size", 10);
 
 // Enable Cardboard VR on mobile, assuming VR at all is enabled
 pref("dom.vr.cardboard.enabled", true);
 
 // In B2G by deafult any AudioChannelAgent is muted when created.
 pref("dom.audiochannel.mutedByDefault", true);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1386,17 +1386,16 @@ pref("reader.parse-node-limit", 0);
 // On desktop, we want the URLs to be included here for ease of debugging,
 // and because (normally) these errors are not persisted anywhere.
 pref("reader.errors.includeURLs", true);
 
 pref("view_source.tab", true);
 
 pref("dom.serviceWorkers.enabled", true);
 pref("dom.serviceWorkers.openWindow.enabled", true);
-pref("dom.webnotifications.serviceworker.enabled", true);
 
 // Enable Push API.
 pref("dom.push.enabled", true);
 
 // These are the thumbnail width/height set in about:newtab.
 // If you change this, ENSURE IT IS THE SAME SIZE SET
 // by about:newtab. These values are in CSS pixels.
 pref("toolkit.pageThumbs.minWidth", 280);
--- a/browser/components/contextualidentity/test/browser/browser.ini
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -1,17 +1,19 @@
 [DEFAULT]
 skip-if = buildapp == "mulet"
 support-files =
   empty_file.html
   file_reflect_cookie_into_title.html
+  favicon-normal32.png
   serviceworker.html
   worker.js
 
 [browser_aboutURLs.js]
+[browser_favicon.js]
 [browser_usercontext.js]
 [browser_usercontextid_tabdrop.js]
 skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
 [browser_windowName.js]
 tags = openwindow
 [browser_windowOpen.js]
 tags = openwindow
 [browser_serviceworkers.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/contextualidentity/test/browser/browser_favicon.js
@@ -0,0 +1,141 @@
+/*
+ * Bug 1270678 - A test case to test does the favicon obey originAttributes.
+ */
+let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+let {HttpServer} = Cu.import("resource://testing-common/httpd.js", {});
+
+const USER_CONTEXTS = [
+  "default",
+  "personal",
+  "work",
+];
+
+let gHttpServer = null;
+let gUserContextId;
+let gFaviconData;
+
+function getIconFile() {
+  new Promise(resolve => {
+    NetUtil.asyncFetch({
+      uri: "http://www.example.com/browser/browser/components/contextualidentity/test/browser/favicon-normal32.png",
+      loadUsingSystemPrincipal: true,
+      contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE
+    }, function(inputStream, status) {
+        let size = inputStream.available();
+        gFaviconData = NetUtil.readInputStreamToString(inputStream, size);
+        resolve();
+    });
+  });
+}
+
+function* openTabInUserContext(uri, userContextId) {
+  // open the tab in the correct userContextId
+  let tab = gBrowser.addTab(uri, {userContextId});
+
+  // select tab and make sure its browser is focused
+  gBrowser.selectedTab = tab;
+  tab.ownerDocument.defaultView.focus();
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  yield BrowserTestUtils.browserLoaded(browser);
+  return {tab, browser};
+}
+
+function loadIndexHandler(metadata, response) {
+  response.setStatusLine(metadata.httpVersion, 200, "Ok");
+  response.setHeader("Content-Type", "text/html", false);
+  let body = `
+    <!DOCTYPE HTML>
+      <html>
+        <head>
+          <meta charset='utf-8'>
+          <title>Favicon Test</title>
+        </head>
+        <body>
+          Favicon!!
+        </body>
+    </html>`;
+  response.bodyOutputStream.write(body, body.length);
+}
+
+function loadFaviconHandler(metadata, response) {
+  let expectedCookie = "userContext=" + USER_CONTEXTS[gUserContextId];
+
+  if (metadata.hasHeader("Cookie")) {
+    is(metadata.getHeader("Cookie"), expectedCookie, "The cookie has matched with the expected cookie.");
+  } else {
+    ok(false, "The request should have a cookie.");
+  }
+
+  response.setStatusLine(metadata.httpVersion, 200, "Ok");
+  response.setHeader("Content-Type", "image/png", false);
+  response.bodyOutputStream.write(gFaviconData, gFaviconData.length);
+}
+
+add_task(function* setup() {
+  // Make sure userContext is enabled.
+  yield new Promise(resolve => {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["privacy.userContext.enabled", true]
+    ]}, resolve);
+  });
+
+  // Create a http server for the image cache test.
+  if (!gHttpServer) {
+    gHttpServer = new HttpServer();
+    gHttpServer.registerPathHandler('/', loadIndexHandler);
+    gHttpServer.registerPathHandler('/favicon.png', loadFaviconHandler);
+    gHttpServer.start(-1);
+  }
+});
+
+registerCleanupFunction(() => {
+  gHttpServer.stop(() => {
+    gHttpServer = null;
+  });
+});
+
+add_task(function* test() {
+  waitForExplicitFinish();
+
+  // First, get the icon data.
+  yield getIconFile();
+
+  let serverPort = gHttpServer.identity.primaryPort;
+  let testURL = "http://localhost:" + serverPort + "/";
+  let testFaviconURL = "http://localhost:" + serverPort + "/favicon.png";
+
+  for (let userContextId of Object.keys(USER_CONTEXTS)) {
+    gUserContextId = userContextId;
+
+    // Load the page in 3 different contexts and set a cookie
+    // which should only be visible in that context.
+    let value = USER_CONTEXTS[userContextId];
+
+    // Open our tab in the given user context.
+    let tabInfo = yield* openTabInUserContext(testURL, userContextId);
+
+    // Write a cookie according to the userContext.
+    yield ContentTask.spawn(tabInfo.browser, { userContext: USER_CONTEXTS[userContextId] }, function (arg) {
+      content.document.cookie = "userContext=" + arg.userContext;
+    });
+
+    let pageURI = NetUtil.newURI(testURL);
+    let favIconURI = NetUtil.newURI(testFaviconURL);
+
+    yield new Promise(resolve => {
+      PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, favIconURI,
+        true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, {
+          onComplete() {
+            resolve();
+          },
+        },
+        tabInfo.browser.contentPrincipal);
+    });
+
+    yield BrowserTestUtils.removeTab(tabInfo.tab);
+  }
+});
new file mode 100644
index 0000000000000000000000000000000000000000..5535363c94df7314765551f65311ec6f98729d8e
GIT binary patch
literal 344
zc$@)P0jK_nP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80003WNkl<ZSi@ud
z|NsAgh5-aj3<C^C9l%0R#sBwE#yKee29*B}N^?LcMg=I}1WL<7#aV`G2>ibbr58i#
zeNc((P#P98>`-}V2r!yL=>({_1(eS*I75IDqa1+6`Tu4pJs&FZfkdNSpkC~N^7XN%
ziNTl#4nlptmQ0_+z#gbM8_{x!@L&&t|69@WIcn7X|AQkj;gW}$#~3qYLI76MeMc4k
zL!iLKDUaQ}p<fv>vJfohhiYxer~!@C3s8YCB*r;9fSSj^Ib=e>8|uYfC?P<0IRG;c
zE&mVZy1*Xl@?ezO@c*9=cpEsFAp@-q8U3Mr{vneF1fh&<D9wk`BKrRaM~jF7M~jF-
q8*kfi5VnX$TC13Gv~M`#9RL8-wO_*zBf!o80000<MNUMnLSTX;M3C|T
--- a/browser/components/preferences/in-content/content.js
+++ b/browser/components/preferences/in-content/content.js
@@ -128,18 +128,20 @@ var gContentPane = {
     let bundlePreferences = document.getElementById("bundlePreferences");
     let params = { permissionType: "desktop-notification" };
     params.windowTitle = bundlePreferences.getString("notificationspermissionstitle");
     params.introText = bundlePreferences.getString("notificationspermissionstext4");
 
     gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
                     "resizable=yes", params);
 
-    Services.telemetry
-            .getHistogramById("WEB_NOTIFICATION_EXCEPTIONS_OPENED").add();
+    try {
+      Services.telemetry
+              .getHistogramById("WEB_NOTIFICATION_EXCEPTIONS_OPENED").add();
+    } catch (e) {}
   },
 
 
   // POP-UPS
 
   /**
    * Displays the popup exceptions dialog where specific site popup preferences
    * can be set.
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -133,17 +133,16 @@ MACH_MODULES = [
     'taskcluster/mach_commands.py',
     'testing/firefox-ui/mach_commands.py',
     'testing/luciddream/mach_commands.py',
     'testing/mach_commands.py',
     'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/mozharness/mach_commands.py',
     'testing/talos/mach_commands.py',
-    'testing/taskcluster/mach_commands.py',
     'testing/web-platform/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'tools/docs/mach_commands.py',
     'tools/lint/mach_commands.py',
     'tools/mercurial/mach_commands.py',
     'tools/mach_commands.py',
     'tools/power/mach_commands.py',
     'mobile/android/mach_commands.py',
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -330,16 +330,18 @@ def old_configure_options(*options):
     '--x-includes',
     '--x-libraries',
 
     # Below are the configure flags used by comm-central.
     '--enable-ldap',
     '--enable-mapi',
     '--enable-calendar',
     '--enable-incomplete-external-linkage',
+
+    '--enable-ipc-fuzzer',
 )
 @imports(_from='__builtin__', _import='compile')
 @imports(_from='__builtin__', _import='open')
 @imports('logging')
 @imports('os')
 @imports('subprocess')
 @imports('sys')
 @imports(_from='mozbuild.shellutil', _import='quote')
--- a/config/mozunit.py
+++ b/config/mozunit.py
@@ -144,28 +144,50 @@ class MockedOpen(object):
         if 'a' in mode:
             file.seek(0, os.SEEK_END)
         return file
 
     def __enter__(self):
         import __builtin__
         self.open = __builtin__.open
         self._orig_path_exists = os.path.exists
+        self._orig_path_isdir = os.path.isdir
+        self._orig_path_isfile = os.path.isfile
         __builtin__.open = self
         os.path.exists = self._wrapped_exists
+        os.path.isdir = self._wrapped_isdir
+        os.path.isfile = self._wrapped_isfile
 
     def __exit__(self, type, value, traceback):
         import __builtin__
         __builtin__.open = self.open
         os.path.exists = self._orig_path_exists
+        os.path.isdir = self._orig_path_isdir
+        os.path.isfile = self._orig_path_isfile
 
     def _wrapped_exists(self, p):
+        return (self._wrapped_isfile(p) or
+                self._wrapped_isdir(p) or
+                self._orig_path_exists(p))
+
+    def _wrapped_isfile(self, p):
         if p in self.files:
             return True
 
         abspath = os.path.abspath(p)
         if abspath in self.files:
             return True
 
+        return self._orig_path_isfile(p)
+
+    def _wrapped_isdir(self, p):
+        p = p if p.endswith(('/', '\\')) else p + os.sep
+        if any(f.startswith(p) for f in self.files):
+            return True
+
+        abspath = os.path.abspath(p) + os.sep
+        if any(f.startswith(abspath) for f in self.files):
+            return True
+
         return self._orig_path_exists(p)
 
 def main(*args, **kwargs):
     unittest.main(testRunner=MozTestRunner(), *args, **kwargs)
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -2011,17 +2011,17 @@ TabActor.prototype = {
    *         True if the window.console object is native, or false otherwise.
    */
   hasNativeConsoleAPI(window) {
     let isNative = false;
     try {
       // We are very explicitly examining the "console" property of
       // the non-Xrayed object here.
       let console = window.wrappedJSObject.console;
-      isNative = console instanceof window.Console;
+      isNative = new XPCNativeWrapper(console).IS_NATIVE_CONSOLE
     } catch (ex) {
       // ignore
     }
     return isNative;
   },
 
   /**
    * Create or return the StyleSheetActor for a style sheet. This method
--- a/devtools/server/tests/browser/browser_navigateEvents.js
+++ b/devtools/server/tests/browser/browser_navigateEvents.js
@@ -30,16 +30,17 @@ function assertEvent(event, data) {
     case x++:
       is(event, "will-navigate", "The very first event is will-navigate on server side");
       is(data.newURI, URL2, "newURI property is correct");
       break;
     case x++:
       is(event, "tabNavigated", "Right after will-navigate, the client receive tabNavigated");
       is(data.state, "start", "state is start");
       is(data.url, URL2, "url property is correct");
+      is(data.nativeConsoleAPI, true, "nativeConsoleAPI is correct");
       break;
     case x++:
       is(event, "request", "Given that locally, the Debugger protocol is sync, the request happens after tabNavigated");
       is(data, URL2);
       break;
     case x++:
       is(event, "DOMContentLoaded");
       is(content.document.readyState, "interactive");
@@ -51,16 +52,17 @@ function assertEvent(event, data) {
     case x++:
       is(event, "navigate", "Then once the second doc is loaded, we get the navigate event");
       is(content.document.readyState, "complete", "navigate is emitted only once the document is fully loaded");
       break;
     case x++:
       is(event, "tabNavigated", "Finally, the receive the client event");
       is(data.state, "stop", "state is stop");
       is(data.url, URL2, "url property is correct");
+      is(data.nativeConsoleAPI, true, "nativeConsoleAPI is correct");
 
       // End of test!
       cleanup();
       break;
   }
 }
 
 function waitForOnBeforeUnloadDialog(browser, callback) {
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/EventStates.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "nsIURL.h"
 #include "nsISizeOf.h"
 #include "nsIDocShell.h"
 #include "nsIPrefetchService.h"
 #include "nsCPrefetchService.h"
+#include "nsStyleLinkElement.h"
 
 #include "nsEscape.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLDNSPrefetch.h"
 #include "nsString.h"
 #include "mozAutoDocUpdate.h"
 
 #include "mozilla/Services.h"
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -3,17 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'mozIDOMWindow.idl',
-    'nsIConsoleAPIStorage.idl',
     'nsIContentPolicy.idl',
     'nsIContentPolicyBase.idl',
     'nsIDocumentEncoder.idl',
     'nsIDOMBlob.idl',
     'nsIDOMDataChannel.idl',
     'nsIDOMDOMCursor.idl',
     'nsIDOMDOMRequest.idl',
     'nsIDOMFileList.idl',
@@ -79,17 +78,16 @@ EXPORTS += [
     'nsFrameMessageManager.h',
     'nsGenericDOMDataNode.h',
     'nsGkAtomList.h',
     'nsGkAtoms.h',
     'nsHostObjectProtocolHandler.h',
     'nsHostObjectURI.h',
     'nsIAnimationObserver.h',
     'nsIAttribute.h',
-    'nsIConsoleReportCollector.h',
     'nsIContent.h',
     'nsIContentInlines.h',
     'nsIContentIterator.h',
     'nsIContentSerializer.h',
     'nsIDocument.h',
     'nsIDocumentInlines.h',
     'nsIDocumentObserver.h',
     'nsIDOMClassInfo.h',
@@ -138,17 +136,16 @@ EXPORTS += [
 
 if CONFIG['MOZ_WEBRTC']:
     EXPORTS += [
         'nsDOMDataChannel.h',
         'nsDOMDataChannelDeclarations.h',
     ]
 
 EXPORTS.mozilla += [
-    'ConsoleReportCollector.h',
     'CORSMode.h',
     'FeedWriterEnabled.h',
     'TextInputProcessor.h',
     'UseCounter.h',
 ]
 
 EXPORTS.mozilla.dom += [
     '!UseCounterList.h',
@@ -156,17 +153,16 @@ EXPORTS.mozilla.dom += [
     'Attr.h',
     'BarProps.h',
     'BlobSet.h',
     'BodyUtil.h',
     'ChildIterator.h',
     'ChromeNodeList.h',
     'ChromeUtils.h',
     'Comment.h',
-    'Console.h',
     'DirectionalityUtils.h',
     'DocumentFragment.h',
     'DocumentType.h',
     'DOMCursor.h',
     'DOMError.h',
     'DOMException.h',
     'DOMImplementation.h',
     'DOMMatrix.h',
@@ -223,18 +219,16 @@ UNIFIED_SOURCES += [
     'AnonymousContent.cpp',
     'Attr.cpp',
     'BarProps.cpp',
     'BodyUtil.cpp',
     'ChildIterator.cpp',
     'ChromeNodeList.cpp',
     'ChromeUtils.cpp',
     'Comment.cpp',
-    'Console.cpp',
-    'ConsoleReportCollector.cpp',
     'Crypto.cpp',
     'DirectionalityUtils.cpp',
     'DocumentFragment.cpp',
     'DocumentType.cpp',
     'DOMCursor.cpp',
     'DOMError.cpp',
     'DOMException.cpp',
     'DOMImplementation.cpp',
@@ -390,18 +384,16 @@ SOURCES += [
 
 # Are we targeting x86-32 or x86-64?  If so, we want to include SSE2 code for
 # nsTextFragment.cpp
 if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += ['nsTextFragmentSSE2.cpp']
     SOURCES['nsTextFragmentSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
 
 EXTRA_COMPONENTS += [
-    'ConsoleAPI.manifest',
-    'ConsoleAPIStorage.js',
     'contentAreaDropListener.js',
     'contentAreaDropListener.manifest',
     'messageWakeupService.js',
     'messageWakeupService.manifest',
     'SlowScriptDebug.js',
     'SlowScriptDebug.manifest',
 ]
 
--- a/dom/base/nsOpenURIInFrameParams.cpp
+++ b/dom/base/nsOpenURIInFrameParams.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "nsOpenURIInFrameParams.h"
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/dom/ToJSValue.h"
 
 NS_IMPL_ISUPPORTS(nsOpenURIInFrameParams, nsIOpenURIInFrameParams)
 
 nsOpenURIInFrameParams::nsOpenURIInFrameParams(const mozilla::DocShellOriginAttributes& aOriginAttributes)
   : mOpenerOriginAttributes(aOriginAttributes)
   , mIsPrivate(false)
 {
 }
--- a/dom/base/nsOpenURIInFrameParams.h
+++ b/dom/base/nsOpenURIInFrameParams.h
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/BasePrincipal.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsString.h"
 
 namespace mozilla {
 class DocShellOriginAttributes;
 }
 
 class nsOpenURIInFrameParams final : public nsIOpenURIInFrameParams
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -7,17 +7,16 @@ support-files =
   file_bug945152_worker.js
   file_bug1008126_worker.js
 
 [test_anonymousContent_xul_window.xul]
 [test_bug715041.xul]
 [test_bug715041_removal.xul]
 [test_domrequesthelper.xul]
 [test_url.xul]
-[test_console.xul]
 [test_navigator_resolve_identity_xrays.xul]
 support-files = file_navigator_resolve_identity_xrays.xul
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_bug1016960.html]
 [test_copypaste.xul]
 subsuite = clipboard
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -550,17 +550,16 @@ skip-if = toolkit == 'android' #bug 6870
 [test_bug628938.html]
 [test_bug631615.html]
 [test_bug638112.html]
 [test_bug647518.html]
 [test_bug650001.html]
 [test_bug650776.html]
 [test_bug650784.html]
 [test_bug656283.html]
-[test_bug659625.html]
 [test_bug664916.html]
 [test_bug666604.html]
 skip-if = buildapp == 'b2g' # b2g(dom.disable_open_during_load not implemented in b2g) b2g-debug(dom.disable_open_during_load not implemented in b2g) b2g-desktop(dom.disable_open_during_load not implemented in b2g)
 [test_bug675121.html]
 skip-if = buildapp == 'b2g' # b2g(bug 901378) b2g-debug(bug 901378) b2g-desktop(bug 901378)
 [test_bug675166.html]
 [test_bug682463.html]
 [test_bug682554.html]
@@ -635,20 +634,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug895974.html]
 [test_bug902847.html]
 [test_bug907892.html]
 [test_bug913761.html]
 [test_bug922681.html]
 [test_bug927196.html]
 [test_bug962251.html]
 [test_bug976673.html]
-[test_bug978522.html]
-[test_bug979109.html]
 [test_bug982153.html]
-[test_bug989665.html]
 [test_bug999456.html]
 [test_bug1022229.html]
 [test_bug1025933.html]
 [test_bug1037687.html]
 [test_bug1043106.html]
 [test_bug1057176.html]
 [test_bug1060938.html]
 [test_bug1064481.html]
@@ -672,17 +668,16 @@ skip-if = buildapp == 'b2g'
 [test_bug1250148.html]
 [test_bug1259588.html]
 [test_bug1263696.html]
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_classList.html]
 [test_clearTimeoutIntervalNoArg.html]
-[test_consoleEmptyStack.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_copyimage.html]
 subsuite = clipboard
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || (toolkit != 'cocoa' && toolkit != 'gonk' && toolkit != 'gtk2' && toolkit != 'gtk3' && toolkit != 'windows') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_copypaste.html]
 subsuite = clipboard
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
@@ -911,11 +906,9 @@ skip-if = toolkit == 'android'
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(12 total, 2 failing - .mozSystem == true - got false, expected true + ) b2g-desktop(12 total, 2 failing - .mozSystem == true - got false, expected true + )
 [test_XHR_timeout.html]
 skip-if = buildapp == 'b2g' || (android_version == '18' && debug) # b2g(flaky on B2G, bug 960743) b2g-debug(flaky on B2G, bug 960743) b2g-desktop(flaky on B2G, bug 960743)
 support-files = test_XHR_timeout.js
 [test_xhr_withCredentials.html]
 [test_XHRDocURI.html]
 [test_XHRResponseURL.html]
 [test_XHRSendData.html]
-[test_console_binding.html]
 [test_unknown_url_origin.html]
-[test_console_proto.html]
rename from dom/base/Console.cpp
rename to dom/console/Console.cpp
--- a/dom/base/Console.cpp
+++ b/dom/console/Console.cpp
@@ -2308,19 +2308,23 @@ Console::StoreCallData(ConsoleCallData* 
 }
 
 void
 Console::UnstoreCallData(ConsoleCallData* aCallData)
 {
   AssertIsOnOwningThread();
 
   MOZ_ASSERT(aCallData);
-  MOZ_ASSERT(mCallDataStorage.Contains(aCallData));
+
   MOZ_ASSERT(!mCallDataStoragePending.Contains(aCallData));
 
+  // It can be that mCallDataStorage has been already cleaned in case the
+  // processing of the argument of some Console methods triggers the
+  // window.close().
+
   mCallDataStorage.RemoveElement(aCallData);
 }
 
 void
 Console::ReleaseCallData(ConsoleCallData* aCallData)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aCallData);
rename from dom/base/Console.h
rename to dom/console/Console.h
rename from dom/base/ConsoleAPI.manifest
rename to dom/console/ConsoleAPI.manifest
rename from dom/base/ConsoleAPIStorage.js
rename to dom/console/ConsoleAPIStorage.js
rename from dom/base/ConsoleReportCollector.cpp
rename to dom/console/ConsoleReportCollector.cpp
rename from dom/base/ConsoleReportCollector.h
rename to dom/console/ConsoleReportCollector.h
new file mode 100644
--- /dev/null
+++ b/dom/console/moz.build
@@ -0,0 +1,45 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPIDL_SOURCES += [
+    'nsIConsoleAPIStorage.idl',
+]
+
+XPIDL_MODULE = 'dom'
+
+EXPORTS += [
+    'nsIConsoleReportCollector.h',
+]
+
+EXPORTS.mozilla += [
+    'ConsoleReportCollector.h',
+]
+
+EXPORTS.mozilla.dom += [
+    'Console.h',
+]
+
+UNIFIED_SOURCES += [
+    'Console.cpp',
+    'ConsoleReportCollector.cpp',
+]
+
+EXTRA_COMPONENTS += [
+    'ConsoleAPI.manifest',
+    'ConsoleAPIStorage.js',
+]
+
+LOCAL_INCLUDES += [
+    '/docshell/base',
+    '/dom/base',
+    '/dom/workers',
+    '/js/xpconnect/src',
+]
+
+MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
+MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
+
+FINAL_LIBRARY = 'xul'
rename from dom/base/nsIConsoleAPIStorage.idl
rename to dom/console/nsIConsoleAPIStorage.idl
rename from dom/base/nsIConsoleReportCollector.h
rename to dom/console/nsIConsoleReportCollector.h
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/chrome.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+skip-if = buildapp == 'b2g' || os == 'android'
+support-files =
+  file_empty.html
+
+[test_console.xul]
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/file_empty.html
@@ -0,0 +1,1 @@
+<!DOCTYPE html><html><body></body></html>
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/mochitest.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+support-files =
+  file_empty.html
+
+[test_bug659625.html]
+[test_bug978522.html]
+[test_bug979109.html]
+[test_bug989665.html]
+[test_consoleEmptyStack.html]
+[test_console_binding.html]
+[test_console_proto.html]
rename from dom/base/test/test_bug659625.html
rename to dom/console/tests/test_bug659625.html
rename from dom/base/test/test_bug978522.html
rename to dom/console/tests/test_bug978522.html
rename from dom/base/test/test_bug979109.html
rename to dom/console/tests/test_bug979109.html
rename from dom/base/test/test_bug989665.html
rename to dom/console/tests/test_bug989665.html
rename from dom/base/test/test_console.xul
rename to dom/console/tests/test_console.xul
--- a/dom/base/test/test_console.xul
+++ b/dom/console/tests/test_console.xul
@@ -16,17 +16,17 @@
   ok("console" in window, "Console exists");
   window.console.log(42);
   ok("table" in console, "Console has the 'table' method.");
   window.console = 42;
   is(window.console, 42, "Console is replacable");
 
   var frame = document.getElementById("iframe");
   ok(frame, "Frame must exist");
-  frame.src="http://mochi.test:8888/tests/dom/base/test/file_empty.html";
+  frame.src="http://mochi.test:8888/tests/dom/console/test/file_empty.html";
   frame.onload = function() {
     ok("console" in frame.contentWindow, "Console exists in the iframe");
     frame.contentWindow.console.log(42);
     frame.contentWindow.console = 42;
     is(frame.contentWindow.console, 42, "Console is replacable in the iframe");
     SimpleTest.finish();
   }
 
rename from dom/base/test/test_consoleEmptyStack.html
rename to dom/console/tests/test_consoleEmptyStack.html
rename from dom/base/test/test_console_binding.html
rename to dom/console/tests/test_console_binding.html
rename from dom/base/test/test_console_proto.html
rename to dom/console/tests/test_console_proto.html
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -690,19 +690,19 @@ public:
   }
 
   void RemoveTextTrack(TextTrack* aTextTrack, bool aPendingListOnly = false) {
     if (mTextTrackManager) {
       mTextTrackManager->RemoveTextTrack(aTextTrack, aPendingListOnly);
     }
   }
 
-  void AddCue(TextTrackCue& aCue) {
+  void NotifyCueAdded(TextTrackCue& aCue) {
     if (mTextTrackManager) {
-      mTextTrackManager->AddCue(aCue);
+      mTextTrackManager->NotifyCueAdded(aCue);
     }
   }
   void NotifyCueRemoved(TextTrackCue& aCue) {
     if (mTextTrackManager) {
       mTextTrackManager->NotifyCueRemoved(aCue);
     }
   }
 
--- a/dom/html/TextTrackManager.cpp
+++ b/dom/html/TextTrackManager.cpp
@@ -250,17 +250,17 @@ TextTrackManager::UpdateCueDisplay()
       sParserWrapper->ProcessCues(window, jsCues, overlay);
     }
   } else if (overlay->Length() > 0) {
     nsContentUtils::SetNodeTextContent(overlay, EmptyString(), true);
   }
 }
 
 void
-TextTrackManager::AddCue(TextTrackCue& aCue)
+TextTrackManager::NotifyCueAdded(TextTrackCue& aCue)
 {
   if (mNewCues) {
     mNewCues->AddCue(aCue);
   }
   DispatchTimeMarchesOn();
 }
 
 void
--- a/dom/html/TextTrackManager.h
+++ b/dom/html/TextTrackManager.h
@@ -51,17 +51,17 @@ public:
                                            const nsAString& aLanguage,
                                            TextTrackMode aMode,
                                            TextTrackReadyState aReadyState,
                                            TextTrackSource aTextTrackSource);
   void AddTextTrack(TextTrack* aTextTrack);
   void RemoveTextTrack(TextTrack* aTextTrack, bool aPendingListOnly);
   void DidSeek();
 
-  void AddCue(TextTrackCue& aCue);
+  void NotifyCueAdded(TextTrackCue& aCue);
   void AddCues(TextTrack* aTextTrack);
   void NotifyCueRemoved(TextTrackCue& aCue);
   /**
    * Overview of WebVTT cuetext and anonymous content setup.
    *
    * WebVTT nodes are the parsed version of WebVTT cuetext. WebVTT cuetext is
    * the portion of a WebVTT cue that specifies what the caption will actually
    * show up as on screen.
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -268,17 +268,18 @@ typedef AlignedBuffer<AudioDataValue> Al
 class MediaData {
 public:
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaData)
 
   enum Type {
     AUDIO_DATA = 0,
     VIDEO_DATA,
-    RAW_DATA
+    RAW_DATA,
+    NULL_DATA
   };
 
   MediaData(Type aType,
             int64_t aOffset,
             int64_t aTimestamp,
             int64_t aDuration,
             uint32_t aFrames)
     : mType(aType)
@@ -349,16 +350,27 @@ protected:
     , mKeyframe(false)
     , mDiscontinuity(false)
   {}
 
   virtual ~MediaData() {}
 
 };
 
+// NullData is for decoder generating a sample which doesn't need to be
+// rendered.
+class NullData : public MediaData {
+public:
+  NullData(int64_t aOffset, int64_t aTime, int64_t aDuration)
+    : MediaData(NULL_DATA, aOffset, aTime, aDuration, 0)
+  {}
+
+  static const Type sType = NULL_DATA;
+};
+
 // Holds chunk a decoded audio frames.
 class AudioData : public MediaData {
 public:
 
   AudioData(int64_t aOffset,
             int64_t aTime,
             int64_t aDuration,
             uint32_t aFrames,
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -457,16 +457,17 @@ MediaFormatReader::EnsureDecoderInitiali
   decoder.mInitPromise.Begin(decoder.mDecoder->Init()
        ->Then(OwnerThread(), __func__,
               [self] (TrackType aTrack) {
                 auto& decoder = self->GetDecoderData(aTrack);
                 decoder.mInitPromise.Complete();
                 decoder.mDecoderInitialized = true;
                 MonitorAutoLock mon(decoder.mMonitor);
                 decoder.mDescription = decoder.mDecoder->GetDescriptionName();
+                self->SetVideoDecodeThreshold();
                 self->ScheduleUpdate(aTrack);
               },
               [self, aTrack] (MediaDataDecoder::DecoderFailureReason aResult) {
                 auto& decoder = self->GetDecoderData(aTrack);
                 decoder.mInitPromise.Complete();
                 decoder.ShutdownDecoder();
                 self->NotifyError(aTrack);
               }));
@@ -1033,16 +1034,17 @@ MediaFormatReader::InternalSeek(TrackTyp
   decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
              ->Then(OwnerThread(), __func__,
                     [self, aTrack] (media::TimeUnit aTime) {
                       auto& decoder = self->GetDecoderData(aTrack);
                       decoder.mSeekRequest.Complete();
                       MOZ_ASSERT(decoder.mTimeThreshold,
                                  "Seek promise must be disconnected when timethreshold is reset");
                       decoder.mTimeThreshold.ref().mHasSeeked = true;
+                      self->SetVideoDecodeThreshold();
                       self->NotifyDecodingRequested(aTrack);
                     },
                     [self, aTrack] (DemuxerFailureReason aResult) {
                       auto& decoder = self->GetDecoderData(aTrack);
                       decoder.mSeekRequest.Complete();
                       switch (aResult) {
                         case DemuxerFailureReason::WAITING_FOR_DATA:
                           self->NotifyWaitingForData(aTrack);
@@ -1145,16 +1147,22 @@ MediaFormatReader::Update(TrackType aTra
            media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(),
            target.Time().ToSeconds(),
            output->mKeyframe);
       decoder.mOutput.RemoveElementAt(0);
       decoder.mSizeOfQueue -= 1;
     }
   }
 
+  while (decoder.mOutput.Length() && decoder.mOutput[0]->mType == MediaData::NULL_DATA) {
+    LOGV("Dropping null data. Time: %lld", decoder.mOutput[0]->mTime);
+    decoder.mOutput.RemoveElementAt(0);
+    decoder.mSizeOfQueue -= 1;
+  }
+
   if (decoder.HasPromise()) {
     needOutput = true;
     if (decoder.mOutput.Length()) {
       RefPtr<MediaData> output = decoder.mOutput[0];
       decoder.mOutput.RemoveElementAt(0);
       decoder.mSizeOfQueue -= 1;
       decoder.mLastSampleTime =
         Some(TimeInterval(TimeUnit::FromMicroseconds(output->mTime),
@@ -1264,16 +1272,17 @@ MediaFormatReader::Update(TrackType aTra
   HandleDemuxedSamples(aTrack, a);
 }
 
 void
 MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack)
 {
   auto& decoder = GetDecoderData(aTrack);
   MOZ_ASSERT(decoder.HasPromise());
+  MOZ_DIAGNOSTIC_ASSERT(aData->mType != MediaData::NULL_DATA);
   if (decoder.mDiscontinuity) {
     LOGV("Setting discontinuity flag");
     decoder.mDiscontinuity = false;
     aData->mDiscontinuity = true;
   }
 
   LOG("Resolved data promise for %s [%lld, %lld]", TrackTypeToStr(aTrack),
       aData->mTime, aData->GetEndTime());
@@ -1724,31 +1733,71 @@ MediaFormatReader::DoVideoSeek()
 
 void
 MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   LOGV("Video seeked to %lld", aTime.ToMicroseconds());
   mVideo.mSeekRequest.Complete();
 
+  SetVideoDecodeThreshold();
+
   if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) {
     MOZ_ASSERT(mPendingSeekTime.isSome());
     if (mOriginalSeekTarget.IsFast()) {
       // We are performing a fast seek. We need to seek audio to where the
       // video seeked to, to ensure proper A/V sync once playback resume.
       mPendingSeekTime = Some(aTime);
     }
     DoAudioSeek();
   } else {
     mPendingSeekTime.reset();
     mSeekPromise.Resolve(aTime, __func__);
   }
 }
 
 void
+MediaFormatReader::SetVideoDecodeThreshold()
+{
+  MOZ_ASSERT(OnTaskQueue());
+
+  if (!HasVideo() || !mVideo.mDecoder) {
+    return;
+  }
+
+  if (!mVideo.mTimeThreshold && !IsSeeking()) {
+    return;
+  }
+
+  TimeUnit threshold;
+  if (mVideo.mTimeThreshold) {
+    // For internalSeek.
+    threshold = mVideo.mTimeThreshold.ref().Time();
+  } else if (IsSeeking()) {
+    // If IsSeeking() is true, then video seek must have completed already.
+    TimeUnit keyframe;
+    if (NS_FAILED(mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&keyframe))) {
+      return;
+    }
+
+    // If the key frame is invalid/infinite, it means the target position is
+    // closing to end of stream. We don't want to skip any frame at this point.
+    if (!keyframe.IsValid() || keyframe.IsInfinite()) {
+      return;
+    }
+    threshold = mOriginalSeekTarget.GetTime();
+  } else {
+    return;
+  }
+
+  LOG("Set seek threshold to %lld", threshold.ToMicroseconds());
+  mVideo.mDecoder->SetSeekThreshold(threshold);
+}
+
+void
 MediaFormatReader::DoAudioSeek()
 {
   MOZ_ASSERT(mPendingSeekTime.isSome());
   LOGV("Seeking audio to %lld", mPendingSeekTime.ref().ToMicroseconds());
   media::TimeUnit seekTime = mPendingSeekTime.ref();
   mAudio.mSeekRequest.Begin(mAudio.mTrackDemuxer->Seek(seekTime)
                          ->Then(OwnerThread(), __func__, this,
                                 &MediaFormatReader::OnAudioSeekCompleted,
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -178,16 +178,18 @@ private:
   void InputExhausted(TrackType aTrack);
   void Error(TrackType aTrack, MediaDataDecoderError aError = MediaDataDecoderError::FATAL_ERROR);
   void Reset(TrackType aTrack);
   void DrainComplete(TrackType aTrack);
   void DropDecodedSamples(TrackType aTrack);
 
   bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
 
+  void SetVideoDecodeThreshold();
+
   size_t SizeOfQueue(TrackType aTrack);
 
   RefPtr<PDMFactory> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
   public:
     DecoderCallback(MediaFormatReader* aReader, TrackType aType)
       : mReader(aReader)
--- a/dom/media/TextTrack.cpp
+++ b/dom/media/TextTrack.cpp
@@ -89,17 +89,35 @@ TextTrack::WrapObject(JSContext* aCx, JS
 
 void
 TextTrack::SetMode(TextTrackMode aValue)
 {
   if (mMode != aValue) {
     mMode = aValue;
     if (aValue == TextTrackMode::Disabled) {
       SetCuesInactive();
-      //TODO: Apply the rules for text track cue rendering Bug 865407
+      // Remove all the cues in MediaElement.
+      if (mTextTrackList) {
+        HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
+        if (mediaElement) {
+          for (size_t i = 0; i < mCueList->Length(); ++i) {
+            mediaElement->NotifyCueRemoved(*(*mCueList)[i]);
+          }
+        }
+      }
+    } else {
+      // Add all the cues into MediaElement.
+      if (mTextTrackList) {
+        HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
+        if (mediaElement) {
+          for (size_t i = 0; i < mCueList->Length(); ++i) {
+            mediaElement->NotifyCueAdded(*(*mCueList)[i]);
+          }
+        }
+      }
     }
     if (mTextTrackList) {
       mTextTrackList->CreateAndDispatchChangeEvent();
     }
   }
 }
 
 void
@@ -114,18 +132,18 @@ TextTrack::GetId(nsAString& aId) const
 
 void
 TextTrack::AddCue(TextTrackCue& aCue)
 {
   mCueList->AddCue(aCue);
   aCue.SetTrack(this);
   if (mTextTrackList) {
     HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
-    if (mediaElement) {
-      mediaElement->AddCue(aCue);
+    if (mediaElement && (mMode != TextTrackMode::Disabled)) {
+      mediaElement->NotifyCueAdded(aCue);
     }
   }
   SetDirty();
 }
 
 void
 TextTrack::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
 {
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -230,13 +230,21 @@ public:
   {
     return NS_OK;
   }
 
   // Return the name of the MediaDataDecoder, only used for decoding.
   // Only return a static const string, as the information may be accessed
   // in a non thread-safe fashion.
   virtual const char* GetDescriptionName() const = 0;
+
+  // Set a hint of seek target time to decoder. Decoder will drop any decoded
+  // data which pts is smaller than this value. This threshold needs to be clear
+  // after reset decoder.
+  // Decoder may not honor this value. However, it'd be better that
+  // video decoder implements this API to improve seek performance.
+  // Note: it should be called before Input() or after Flush().
+  virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/platforms/apple/AppleVDADecoder.cpp
+++ b/dom/media/platforms/apple/AppleVDADecoder.cpp
@@ -148,16 +148,19 @@ AppleVDADecoder::Flush()
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &AppleVDADecoder::ProcessFlush);
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
   // All ProcessDecode() tasks should be done.
   MOZ_ASSERT(mInputIncoming == 0);
+
+  mSeekTargetThreshold.reset();
+
   return NS_OK;
 }
 
 nsresult
 AppleVDADecoder::Drain()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   nsCOMPtr<nsIRunnable> runnable =
@@ -285,16 +288,23 @@ AppleVDADecoder::ClearReorderedFrames()
 {
   MonitorAutoLock mon(mMonitor);
   while (!mReorderQueue.IsEmpty()) {
     mReorderQueue.Pop();
   }
   mQueuedSamples = 0;
 }
 
+void
+AppleVDADecoder::SetSeekThreshold(const media::TimeUnit& aTime)
+{
+  LOG("SetSeekThreshold %lld", aTime.ToMicroseconds());
+  mSeekTargetThreshold = Some(aTime);
+}
+
 // Copy and return a decoded frame.
 nsresult
 AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
                              AppleVDADecoder::AppleFrameRef aFrameRef)
 {
   if (mIsShutDown || mIsFlushing) {
     // We are in the process of flushing or shutting down; ignore frame.
     return NS_OK;
@@ -316,27 +326,40 @@ AppleVDADecoder::OutputFrame(CVPixelBuff
   MOZ_ASSERT(mQueuedSamples);
   mQueuedSamples--;
 
   if (!aImage) {
     // Image was dropped by decoder.
     return NS_OK;
   }
 
+  bool useNullSample = false;
+  if (mSeekTargetThreshold.isSome()) {
+    if ((aFrameRef.composition_timestamp + aFrameRef.duration) < mSeekTargetThreshold.ref()) {
+      useNullSample = true;
+    } else {
+      mSeekTargetThreshold.reset();
+    }
+  }
+
   // Where our resulting image will end up.
-  RefPtr<VideoData> data;
+  RefPtr<MediaData> data;
   // Bounds.
   VideoInfo info;
   info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);
   gfx::IntRect visible = gfx::IntRect(0,
                                       0,
                                       mPictureWidth,
                                       mPictureHeight);
 
-  if (mUseSoftwareImages) {
+  if (useNullSample) {
+    data = new NullData(aFrameRef.byte_offset,
+                        aFrameRef.composition_timestamp.ToMicroseconds(),
+                        aFrameRef.duration.ToMicroseconds());
+  } else if (mUseSoftwareImages) {
     size_t width = CVPixelBufferGetWidth(aImage);
     size_t height = CVPixelBufferGetHeight(aImage);
     DebugOnly<size_t> planes = CVPixelBufferGetPlaneCount(aImage);
     MOZ_ASSERT(planes == 2, "Likely not NV12 format and it must be.");
 
     VideoData::YCbCrBuffer buffer;
 
     // Lock the returned image data.
--- a/dom/media/platforms/apple/AppleVDADecoder.h
+++ b/dom/media/platforms/apple/AppleVDADecoder.h
@@ -81,16 +81,18 @@ public:
     return true;
   }
 
   const char* GetDescriptionName() const override
   {
     return "apple VDA decoder";
   }
 
+  void SetSeekThreshold(const media::TimeUnit& aTime) override;
+
 protected:
   AppleVDADecoder(const VideoInfo& aConfig,
                   TaskQueue* aTaskQueue,
                   MediaDataDecoderCallback* aCallback,
                   layers::ImageContainer* aImageContainer);
   virtual ~AppleVDADecoder();
 
   void AssertOnTaskQueueThread()
@@ -134,16 +136,20 @@ private:
 
   // Protects mReorderQueue.
   Monitor mMonitor;
   // Set on reader/decode thread calling Flush() to indicate that output is
   // not required and so input samples on mTaskQueue need not be processed.
   // Cleared on mTaskQueue in ProcessDrain().
   Atomic<bool> mIsFlushing;
   ReorderQueue mReorderQueue;
+  // Decoded frame will be dropped if its pts is smaller than this
+  // value. It shold be initialized before Input() or after Flush(). So it is
+  // safe to access it in OutputFrame without protecting.
+  Maybe<media::TimeUnit> mSeekTargetThreshold;
 
   // Method to set up the decompression session.
   nsresult InitializeSession();
 
   // Method to pass a frame to VideoToolbox for decoding.
   nsresult ProcessDecode(MediaRawData* aSample);
   virtual nsresult DoDecode(MediaRawData* aSample);
   CFDictionaryRef CreateDecoderSpecification();
--- a/dom/media/platforms/apple/ReorderQueue.h
+++ b/dom/media/platforms/apple/ReorderQueue.h
@@ -11,19 +11,19 @@
 
 #include <MediaData.h>
 #include <nsTPriorityQueue.h>
 
 namespace mozilla {
 
 struct ReorderQueueComparator
 {
-  bool LessThan(VideoData* const& a, VideoData* const& b) const
+  bool LessThan(MediaData* const& a, MediaData* const& b) const
   {
     return a->mTime < b->mTime;
   }
 };
 
-typedef nsTPriorityQueue<RefPtr<VideoData>, ReorderQueueComparator> ReorderQueue;
+typedef nsTPriorityQueue<RefPtr<MediaData>, ReorderQueueComparator> ReorderQueue;
 
 } // namespace mozilla
 
 #endif // mozilla_ReorderQueue_h
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -107,16 +107,17 @@ DIRS += [
     'xml',
     'xslt',
     'xul',
     'resourcestats',
     'manifest',
     'vr',
     'newapps',
     'u2f',
+    'console',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['plugins/ipc/hangui']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += [
         'speakermanager',
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -959,21 +959,21 @@ var interfaceNamesInGlobalScope =
     {name: "PresentationSessionConnectEvent", disabled: true, permission: ["presentation"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ProcessingInstruction",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ProgressEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Promise",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "PushManager", b2g: false, nightlyAndroid: true, android: false},
-// IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "PushSubscription", b2g: false, nightlyAndroid: true, android: false},
-// IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "PushSubscriptionOptions", b2g: false, nightlyAndroid: true, android: false},
+    {name: "PushManager", b2g: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PushSubscription", b2g: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PushSubscriptionOptions", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "RadioNodeList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Range",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "RecordErrorEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Rect",
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -154,45 +154,43 @@ var interfaceNamesInGlobalScope =
     "ImageData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessageChannel",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessageEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessagePort",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "Notification", nonReleaseB2G: true, nonReleaseAndroid: true,
-                            b2g: false, android: false },
+    { name: "Notification", nonReleaseB2G: true, b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "NotificationEvent", nonReleaseB2G: true, nonReleaseAndroid: true,
-                                 b2g: false, android: false },
+    { name: "NotificationEvent", nonReleaseB2G: true, b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Performance",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceEntry",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceMark",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceMeasure",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PerformanceObserver", nightly: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PerformanceObserverEntryList", nightly: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Promise",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushEvent", b2g: false, android: false, nightlyAndroid: true },
+    { name: "PushEvent", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushManager", b2g: false, android: false, nightlyAndroid: true },
+    { name: "PushManager", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushMessageData", b2g: false, android: false, nightlyAndroid: true },
+    { name: "PushMessageData", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushSubscription", b2g: false, android: false, nightlyAndroid: true },
+    { name: "PushSubscription", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushSubscriptionOptions", b2g: false, android: false, nightlyAndroid: true },
+    { name: "PushSubscriptionOptions", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Request",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Response",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerGlobalScope",
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -164,21 +164,21 @@ var interfaceNamesInGlobalScope =
     "PerformanceMeasure",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PerformanceObserver", nightly: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PerformanceObserverEntryList", nightly: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Promise",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushManager", b2g: false, nightlyAndroid: true, android: false },
+    { name: "PushManager", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushSubscription", b2g: false, nightlyAndroid: true, android: false },
+    { name: "PushSubscription", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "PushSubscriptionOptions", b2g: false, nightlyAndroid: true, android: false },
+    { name: "PushSubscriptionOptions", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Request",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Response",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "ServiceWorkerRegistration", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SubtleCrypto",
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -8,23 +8,31 @@
     // we're using default display for now
     #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW)))
 #elif defined(MOZ_WIDGET_QT)
     #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
 #else
     #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+    #define GET_JAVA_SURFACE(aWidget) (aWidget->GetNativeData(NS_JAVA_SURFACE))
+#endif
+
 #if defined(XP_UNIX)
     #ifdef MOZ_WIDGET_GONK
         #include "libdisplay/GonkDisplay.h"
         #include "nsWindow.h"
         #include "nsScreenManagerGonk.h"
     #endif
 
+    #ifdef MOZ_WIDGET_ANDROID
+        #include "AndroidBridge.h"
+    #endif
+
     #ifdef ANDROID
         #include <android/log.h>
         #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 
         #ifdef MOZ_WIDGET_GONK
             #include "cutils/properties.h"
             #include <ui/GraphicBuffer.h>
 
@@ -164,17 +172,25 @@ DestroySurface(EGLSurface oldSurface) {
 }
 
 static EGLSurface
 CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
     EGLSurface newSurface = nullptr;
 
     MOZ_ASSERT(widget);
 #ifdef MOZ_WIDGET_ANDROID
-    newSurface = EGLSurface(widget->GetNativeData(NS_NATIVE_NEW_EGL_SURFACE));
+    void* javaSurface = GET_JAVA_SURFACE(widget);
+    if (!javaSurface) {
+        MOZ_CRASH("GFX: Failed to get Java surface.\n");
+    }
+    JNIEnv* const env = jni::GetEnvForThread();
+    void* nativeWindow = AndroidBridge::Bridge()->AcquireNativeWindow(env, reinterpret_cast<jobject>(javaSurface));
+    newSurface = sEGLLibrary.fCreateWindowSurface(sEGLLibrary.fGetDisplay(EGL_DEFAULT_DISPLAY), config,
+                                                  nativeWindow, 0);
+    AndroidBridge::Bridge()->ReleaseNativeWindow(nativeWindow);
 #else
     newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config,
                                                   GET_NATIVE_WINDOW(widget), 0);
 #endif
     return newSurface;
 }
 
 GLContextEGL::GLContextEGL(
--- a/gfx/layers/apz/util/TouchActionHelper.cpp
+++ b/gfx/layers/apz/util/TouchActionHelper.cpp
@@ -42,16 +42,23 @@ TouchActionHelper::UpdateAllowedBehavior
     }
   }
 }
 
 mozilla::layers::TouchBehaviorFlags
 TouchActionHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const LayoutDeviceIntPoint& aPoint)
 {
   nsView *view = nsView::GetViewFor(aWidget);
+  TouchBehaviorFlags behavior = AllowedTouchBehavior::VERTICAL_PAN | AllowedTouchBehavior::HORIZONTAL_PAN |
+                                AllowedTouchBehavior::PINCH_ZOOM | AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
+
+  if (!view) {
+    return behavior;
+  }
+
   nsIFrame *viewFrame = view->GetFrame();
 
   nsPoint relativePoint =
     nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, viewFrame);
 
   nsIFrame *target = nsLayoutUtils::GetFrameForPoint(viewFrame, relativePoint, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
   nsIScrollableFrame *nearestScrollableParent = nsLayoutUtils::GetNearestScrollableFrame(target, 0);
   nsIFrame* nearestScrollableFrame = do_QueryFrame(nearestScrollableParent);
@@ -68,18 +75,16 @@ TouchActionHelper::GetAllowedTouchBehavi
 
   // Currently we support only two touch behaviors: panning and zooming.
   // For panning we walk up until we meet the first scrollable element (the element that supports panning)
   // or root element.
   // For zooming we walk up until the root element since Firefox currently supports only zooming of the
   // root frame but not the subframes.
 
   bool considerPanning = true;
-  TouchBehaviorFlags behavior = AllowedTouchBehavior::VERTICAL_PAN | AllowedTouchBehavior::HORIZONTAL_PAN |
-                                AllowedTouchBehavior::PINCH_ZOOM | AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
 
   for (nsIFrame *frame = target; frame && frame->GetContent() && behavior; frame = frame->GetParent()) {
     UpdateAllowedBehavior(nsLayoutUtils::GetTouchActionFromFrame(frame), considerPanning, behavior);
 
     if (frame == nearestScrollableFrame) {
       // We met the scrollable element, after it we shouldn't consider touch-action
       // values for the purpose of panning but only for zooming.
       considerPanning = false;
--- a/ipc/chromium/src/base/logging.h
+++ b/ipc/chromium/src/base/logging.h
@@ -113,17 +113,17 @@ const mozilla::EmptyLog& operator <<(con
 #undef LOG_ASSERT
 #define LOG_ASSERT(cond) CHECK(0)
 #define DLOG_ASSERT(cond) DCHECK(0)
 
 #define NOTREACHED() CHROMIUM_LOG(ERROR)
 #define NOTIMPLEMENTED() CHROMIUM_LOG(ERROR)
 
 #undef CHECK
-#define CHECK(condition) LOG_IF(FATAL, condition)
+#define CHECK(condition) LOG_IF(WARNING, condition)
 
 #define DCHECK_EQ(v1, v2) DCHECK((v1) == (v2))
 #define DCHECK_NE(v1, v2) DCHECK((v1) != (v2))
 #define DCHECK_LE(v1, v2) DCHECK((v1) <= (v2))
 #define DCHECK_LT(v1, v2) DCHECK((v1) < (v2))
 #define DCHECK_GE(v1, v2) DCHECK((v1) >= (v2))
 #define DCHECK_GT(v1, v2) DCHECK((v1) > (v2))
 
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -511,32 +511,57 @@ bool Pickle::WriteBytes(const void* data
 
   buffers_.WriteBytes(reinterpret_cast<const char*>(data), data_len);
 
   EndWrite(data_len);
   return true;
 }
 
 bool Pickle::WriteString(const std::string& value) {
+#ifdef MOZ_FAULTY
+  std::string v(value);
+  Singleton<mozilla::ipc::Faulty>::get()->FuzzString(v);
+  if (!WriteInt(static_cast<int>(v.size())))
+    return false;
+
+  return WriteBytes(v.data(), static_cast<int>(v.size()));
+#else
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(), static_cast<int>(value.size()));
+#endif
 }
 
 bool Pickle::WriteWString(const std::wstring& value) {
+#ifdef MOZ_FAULTY
+  std::wstring v(value);
+  Singleton<mozilla::ipc::Faulty>::get()->FuzzWString(v);
+  if (!WriteInt(static_cast<int>(v.size())))
+    return false;
+
+  return WriteBytes(v.data(),
+                    static_cast<int>(v.size() * sizeof(wchar_t)));
+#else
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(),
                     static_cast<int>(value.size() * sizeof(wchar_t)));
+#endif
 }
 
 bool Pickle::WriteData(const char* data, uint32_t length) {
-  return WriteInt(length) && WriteBytes(data, length);
+#ifdef MOZ_FAULTY
+  std::string v(data, length);
+  Singleton<mozilla::ipc::Faulty>::get()->FuzzData(v, v.size());
+  return WriteInt(v.size()) && WriteBytes(v.data(), v.size());
+#else
+   return WriteInt(length) && WriteBytes(data, length);
+#endif
 }
 
 void Pickle::InputBytes(const char* data, uint32_t length) {
   buffers_.WriteBytes(data, length);
 }
 
 int32_t* Pickle::GetInt32PtrForTest(uint32_t offset) {
   size_t pos = buffers_.Size() - offset;
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -12,16 +12,21 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/string16.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/BufferList.h"
 #include "mozilla/mozalloc.h"
 
+#ifdef MOZ_FAULTY
+#include "base/singleton.h"
+#include "mozilla/ipc/Faulty.h"
+#endif
+
 class Pickle;
 
 class PickleIterator {
 public:
   explicit PickleIterator(const Pickle& pickle);
 
 private:
   friend class Pickle;
@@ -113,63 +118,102 @@ class Pickle {
 
   void EndRead(PickleIterator& iter) const;
 
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
   // to the Pickle.
   bool WriteBool(bool value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzBool(&value);
+#endif
     return WriteInt(value ? 1 : 0);
   }
   bool WriteInt16(int16_t value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzInt16(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteUInt16(uint16_t value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt16(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteInt(int value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteLong(long value) {
     // Always written as a 64-bit value since the size for this type can
     // differ between architectures.
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzLong(&value);
+#endif
     return WriteInt64(int64_t(value));
   }
   bool WriteULong(unsigned long value) {
     // Always written as a 64-bit value since the size for this type can
     // differ between architectures.
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzULong(&value);
+#endif
     return WriteUInt64(uint64_t(value));
   }
   bool WriteSize(size_t value) {
     // Always written as a 64-bit value since the size for this type can
     // differ between architectures.
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzSize(&value);
+#endif
     return WriteUInt64(uint64_t(value));
   }
   bool WriteInt32(int32_t value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteUInt32(uint32_t value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt32(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteInt64(int64_t value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzInt64(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteUInt64(uint64_t value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt64(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteDouble(double value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzDouble(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteIntPtr(intptr_t value) {
     // Always written as a 64-bit value since the size for this type can
     // differ between architectures.
     return WriteInt64(int64_t(value));
   }
   bool WriteUnsignedChar(unsigned char value) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->FuzzUChar(&value);
+#endif
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteString(const std::string& value);
   bool WriteWString(const std::wstring& value);
   bool WriteData(const char* data, uint32_t length);
   bool WriteBytes(const void* data, uint32_t data_len,
                   uint32_t alignment = sizeof(memberAlignmentType));
 
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -30,16 +30,20 @@
 #include "base/string_util.h"
 #include "base/singleton.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/file_descriptor_set_posix.h"
 #include "chrome/common/ipc_message_utils.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/UniquePtr.h"
 
+#ifdef MOZ_FAULTY
+#include "mozilla/ipc/Faulty.h"
+#endif
+
 // Work around possible OS limitations.
 static const size_t kMaxIOVecSize = 256;
 
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracerImpl.h"
 using namespace mozilla::tasktracer;
 #endif
 
@@ -556,16 +560,19 @@ bool Channel::ChannelImpl::ProcessOutgoi
     return true;
 
   if (pipe_ == -1)
     return false;
 
   // Write out all the messages we can till the write blocks or there are no
   // more outgoing messages.
   while (!output_queue_.empty()) {
+#ifdef MOZ_FAULTY
+    Singleton<mozilla::ipc::Faulty>::get()->MaybeCollectAndClosePipe(pipe_);
+#endif
     Message* msg = output_queue_.front();
 
     struct msghdr msgh = {0};
 
     static const int tmp = CMSG_SPACE(sizeof(
         int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
     char buf[tmp];
 
new file mode 100644
--- /dev/null
+++ b/ipc/glue/Faulty.cpp
@@ -0,0 +1,654 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/ipc/Faulty.h"
+#include <cerrno>
+#include <prinrval.h>
+#include "nsXULAppAPI.h"
+#include "base/string_util.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/ipc_channel.h"
+#include "prenv.h"
+#include "mozilla/TypeTraits.h"
+#include <cmath>
+#include <climits>
+
+namespace mozilla {
+namespace ipc {
+
+const unsigned int Faulty::sDefaultProbability = Faulty::DefaultProbability();
+const bool Faulty::sIsLoggingEnabled = Faulty::Logging();
+
+/**
+ * RandomNumericValue generates negative and positive integrals.
+ */
+template <typename T>
+T RandomIntegral()
+{
+  static_assert(mozilla::IsIntegral<T>::value == true,
+                "T must be an integral type");
+  double r = static_cast<double>(random() % ((sizeof(T) * CHAR_BIT) + 1));
+  T x = static_cast<T>(pow(2.0, r)) - 1;
+  if (std::numeric_limits<T>::is_signed && random() % 2 == 0) {
+    return (x * -1) - 1;
+  }
+  return x;
+}
+
+/**
+ * RandomNumericLimit returns either the min or max limit of an arithmetic
+ * data type.
+ */
+template <typename T>
+T RandomNumericLimit() {
+  static_assert(mozilla::IsArithmetic<T>::value == true,
+                "T must be an arithmetic type");
+  return random() % 2 == 0 ? std::numeric_limits<T>::min()
+                           : std::numeric_limits<T>::max();
+}
+
+/**
+ * RandomIntegerRange returns a random integral within a user defined range.
+ */
+template <typename T>
+T RandomIntegerRange(T min, T max)
+{
+  static_assert(mozilla::IsIntegral<T>::value == true,
+                "T must be an integral type");
+  MOZ_ASSERT(min < max);
+  return static_cast<T>(random() % (max - min) + min);
+}
+
+/**
+ * RandomFloatingPointRange returns a random floating-point number within a
+ * user defined range.
+ */
+template <typename T>
+T RandomFloatingPointRange(T min, T max)
+{
+  static_assert(mozilla::IsFloatingPoint<T>::value == true,
+                "T must be a floating point type");
+  MOZ_ASSERT(min < max);
+  T x = static_cast<T>(random()) / static_cast<T>(RAND_MAX);
+  return min + x * (max - min);
+}
+
+/**
+ * RandomFloatingPoint returns a random floating-point number.
+ */
+template <typename T>
+T RandomFloatingPoint()
+{
+  static_assert(mozilla::IsFloatingPoint<T>::value == true,
+                "T must be a floating point type");
+  int radix = RandomIntegerRange<int>(std::numeric_limits<T>::min_exponent,
+                                      std::numeric_limits<T>::max_exponent);
+  T x = static_cast<T>(pow(2.0, static_cast<double>(radix)));
+  return x * RandomFloatingPointRange<T>(1.0, 2.0);
+}
+
+/**
+ * FuzzIntegralType mutates an incercepted integral type of a pickled message.
+ */
+template <typename T>
+void FuzzIntegralType(T* v, bool largeValues)
+{
+  static_assert(mozilla::IsIntegral<T>::value == true,
+                "T must be an integral type");
+  switch (random() % 6) {
+    case 0:
+      if (largeValues) {
+        (*v) = RandomIntegral<T>();
+        break;
+      }
+      // Fall through
+    case 1:
+      if (largeValues) {
+        (*v) = RandomNumericLimit<T>();
+        break;
+      }
+      // Fall through
+    case 2:
+      if (largeValues) {
+        (*v) = RandomIntegerRange<T>(std::numeric_limits<T>::min(),
+                                     std::numeric_limits<T>::max());
+        break;
+      }
+      // Fall through
+    default:
+      switch(random() % 2) {
+        case 0:
+          // Prevent underflow
+          if (*v != std::numeric_limits<T>::min()) {
+            (*v)--;
+            break;
+          }
+          // Fall through
+        case 1:
+          // Prevent overflow
+          if (*v != std::numeric_limits<T>::max()) {
+            (*v)++;
+            break;
+          }
+      }
+  }
+}
+
+/**
+ * FuzzFloatingPointType mutates an incercepted floating-point type of a
+ * pickled message.
+ */
+template <typename T>
+void FuzzFloatingPointType(T* v, bool largeValues)
+{
+  static_assert(mozilla::IsFloatingPoint<T>::value == true,
+                "T must be a floating point type");
+  switch (random() % 6) {
+    case 0:
+      if (largeValues) {
+        (*v) = RandomNumericLimit<T>();
+        break;
+    }
+    // Fall through
+    case 1:
+      if (largeValues) {
+        (*v) = RandomFloatingPointRange<T>(std::numeric_limits<T>::min(),
+                                           std::numeric_limits<T>::max());
+        break;
+      }
+    // Fall through
+    default:
+      (*v) = RandomFloatingPoint<T>();
+  }
+}
+
+/**
+ * FuzzStringType mutates an incercepted string type of a pickled message.
+ */
+template <typename T>
+void FuzzStringType(T& v, const T& literal1, const T& literal2)
+{
+  switch (random() % 5) {
+    case 4:
+      v = v + v;
+      // Fall through
+    case 3:
+      v = v + v;
+      // Fall through
+    case 2:
+      v = v + v;
+      break;
+    case 1:
+      v += literal1;
+      break;
+    case 0:
+      v = literal2;
+      break;
+  }
+}
+
+
+Faulty::Faulty()
+  // Enables the strategy for fuzzing pipes.
+  : mFuzzPipes(!!PR_GetEnv("FAULTY_PIPE"))
+  // Enables the strategy for fuzzing pickled messages.
+  , mFuzzPickle(!!PR_GetEnv("FAULTY_PICKLE"))
+  // Uses very large values while fuzzing pickled messages.
+  // This may cause a high amount of malloc_abort() / NS_ABORT_OOM crashes.
+  , mUseLargeValues(!!PR_GetEnv("FAULTY_LARGE_VALUES"))
+  // Sets up our target process.
+  , mIsValidProcessType(IsValidProcessType())
+{
+  FAULTY_LOG("Initializing.");
+
+  const char* userSeed = PR_GetEnv("FAULTY_SEED");
+  unsigned long randomSeed = static_cast<unsigned long>(PR_IntervalNow());
+  if (userSeed) {
+    long n = std::strtol(userSeed, nullptr, 10);
+    if (n != 0) {
+      randomSeed = static_cast<unsigned long>(n);
+    }
+  }
+  srandom(randomSeed);
+
+  FAULTY_LOG("Fuzz probability = %u", sDefaultProbability);
+  FAULTY_LOG("Random seed      = %lu", randomSeed);
+  FAULTY_LOG("Strategy: pickle = %s", mFuzzPickle ? "enabled" : "disabled");
+  FAULTY_LOG("Strategy: pipe   = %s", mFuzzPipes ? "enabled" : "disabled");
+}
+
+// static
+bool
+Faulty::IsValidProcessType(void)
+{
+  bool isValidProcessType;
+  const bool targetChildren = !!PR_GetEnv("FAULTY_CHILDREN");
+  const bool targetParent = !!PR_GetEnv("FAULTY_PARENT");
+
+  if (targetChildren && !targetParent) {
+    // Fuzz every process type but not the content process.
+    isValidProcessType = XRE_GetProcessType() != GeckoProcessType_Content;
+  } else if (targetChildren && targetParent) {
+    // Fuzz every process type.
+    isValidProcessType = true;
+  } else {
+    // Fuzz the content process only.
+    isValidProcessType = XRE_GetProcessType() == GeckoProcessType_Content;
+  }
+
+  // Parent and children are different threads in the same process on
+  // desktop builds.
+  if (!isValidProcessType) {
+    FAULTY_LOG("Invalid process type for pid=%d", getpid());
+  }
+
+  return isValidProcessType;
+}
+
+// static
+unsigned int
+Faulty::DefaultProbability(void)
+{
+  // Defines the likelihood of fuzzing a message.
+  const char* probability = PR_GetEnv("FAULTY_PROBABILITY");
+  if (probability) {
+    long n = std::strtol(probability, nullptr, 10);
+    if (n != 0) {
+      return n;
+    }
+  }
+  return FAULTY_DEFAULT_PROBABILITY;
+}
+
+// static
+bool
+Faulty::Logging(void)
+{
+  // Enables logging of sendmsg() calls even in optimized builds.
+  return !!PR_GetEnv("FAULTY_ENABLE_LOGGING");
+}
+
+unsigned int
+Faulty::Random(unsigned int aMax)
+{
+  MOZ_ASSERT(aMax > 0);
+  return static_cast<unsigned int>(random() % aMax);
+}
+
+bool
+Faulty::GetChance(unsigned int aProbability)
+{
+  return Random(aProbability) == 0;
+}
+
+//
+// Strategy: Pipes
+//
+
+void
+Faulty::MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability)
+{
+  if (!mFuzzPipes) {
+    return;
+  }
+
+  if (aPipe > -1) {
+    FAULTY_LOG("collecting pipe %d to bucket of pipes (count: %ld)",
+               aPipe, mFds.size());
+    mFds.insert(aPipe);
+  }
+
+  if (mFds.size() > 0 && GetChance(aProbability)) {
+    std::set<int>::iterator it(mFds.begin());
+    std::advance(it, Random(mFds.size()));
+    FAULTY_LOG("trying to close collected pipe: %d", *it);
+    errno = 0;
+    while ((close(*it) == -1 && (errno == EINTR))) {
+      ;
+    }
+    FAULTY_LOG("pipe status after attempt to close: %d", errno);
+    mFds.erase(it);
+  }
+}
+
+//
+// Strategy: Pickle
+//
+
+void
+Faulty::MutateBool(bool* aValue)
+{
+  *aValue = !(*aValue);
+}
+
+void
+Faulty::FuzzBool(bool* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      bool oldValue = *aValue;
+      MutateBool(aValue);
+      FAULTY_LOG("pickle field {bool} of value: %d changed to: %d",
+                 (int)oldValue, (int)*aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateChar(char* aValue)
+{
+  FuzzIntegralType<char>(aValue, true);
+}
+
+void
+Faulty::FuzzChar(char* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      char oldValue = *aValue;
+      MutateChar(aValue);
+      FAULTY_LOG("pickle field {char} of value: %c changed to: %c",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateUChar(unsigned char* aValue)
+{
+  FuzzIntegralType<unsigned char>(aValue, true);
+}
+
+void
+Faulty::FuzzUChar(unsigned char* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      unsigned char oldValue = *aValue;
+      MutateUChar(aValue);
+      FAULTY_LOG("pickle field {unsigned char} of value: %u changed to: %u",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateInt16(int16_t* aValue)
+{
+  FuzzIntegralType<int16_t>(aValue, true);
+}
+
+void
+Faulty::FuzzInt16(int16_t* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      int16_t oldValue = *aValue;
+      MutateInt16(aValue);
+      FAULTY_LOG("pickle field {Int16} of value: %d changed to: %d",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateUInt16(uint16_t* aValue)
+{
+  FuzzIntegralType<uint16_t>(aValue, true);
+}
+
+void
+Faulty::FuzzUInt16(uint16_t* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      uint16_t oldValue = *aValue;
+      MutateUInt16(aValue);
+      FAULTY_LOG("pickle field {UInt16} of value: %d changed to: %d",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateInt(int* aValue)
+{
+  FuzzIntegralType<int>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzInt(int* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      int oldValue = *aValue;
+      MutateInt(aValue);
+      FAULTY_LOG("pickle field {int} of value: %d changed to: %d",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateUInt32(uint32_t* aValue)
+{
+  FuzzIntegralType<uint32_t>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzUInt32(uint32_t* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      uint32_t oldValue = *aValue;
+      MutateUInt32(aValue);
+      FAULTY_LOG("pickle field {UInt32} of value: %u changed to: %u",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateLong(long* aValue)
+{
+  FuzzIntegralType<long>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzLong(long* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      long oldValue = *aValue;
+      MutateLong(aValue);
+      FAULTY_LOG("pickle field {long} of value: %ld changed to: %ld",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateULong(unsigned long* aValue)
+{
+  FuzzIntegralType<unsigned long>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzULong(unsigned long* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      unsigned long oldValue = *aValue;
+      MutateULong(aValue);
+      FAULTY_LOG("pickle field {unsigned long} of value: %lu changed to: %lu",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateSize(size_t* aValue)
+{
+  FuzzIntegralType<size_t>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzSize(size_t* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      size_t oldValue = *aValue;
+      MutateSize(aValue);
+      FAULTY_LOG("pickle field {size_t} of value: %zu changed to: %zu",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateUInt64(uint64_t* aValue)
+{
+  FuzzIntegralType<uint64_t>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzUInt64(uint64_t* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      uint64_t oldValue = *aValue;
+      MutateUInt64(aValue);
+      FAULTY_LOG("pickle field {UInt64} of value: %llu changed to: %llu",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateInt64(int64_t* aValue)
+{
+  FuzzIntegralType<int64_t>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzInt64(int64_t* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      int64_t oldValue = *aValue;
+      MutateInt64(aValue);
+      FAULTY_LOG("pickle field {Int64} of value: %lld changed to: %lld",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateDouble(double* aValue)
+{
+  FuzzFloatingPointType<double>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzDouble(double* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      double oldValue = *aValue;
+      MutateDouble(aValue);
+      FAULTY_LOG("pickle field {double} of value: %f changed to: %f",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::MutateFloat(float* aValue)
+{
+  FuzzFloatingPointType<float>(aValue, mUseLargeValues);
+}
+
+void
+Faulty::FuzzFloat(float* aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      float oldValue = *aValue;
+      MutateFloat(aValue);
+      FAULTY_LOG("pickle field {float} of value: %f changed to: %f",
+                 oldValue, *aValue);
+    }
+  }
+}
+
+void
+Faulty::FuzzString(std::string& aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      std::string oldValue = aValue;
+      FuzzStringType<std::string>(aValue, "xoferiF", std::string());
+      FAULTY_LOG("pickle field {string} of value: %s changed to: %s",
+                 oldValue.c_str(), aValue.c_str());
+    }
+  }
+}
+
+void
+Faulty::FuzzWString(std::wstring& aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      std::wstring oldValue = aValue;
+      FAULTY_LOG("pickle field {wstring}");
+      FuzzStringType<std::wstring>(aValue, L"xoferiF", std::wstring());
+    }
+  }
+}
+
+void
+Faulty::FuzzString16(string16& aValue, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      string16 oldValue = aValue;
+      FAULTY_LOG("pickle field {string16}");
+      FuzzStringType<string16>(aValue,
+        string16(ASCIIToUTF16(std::string("xoferiF"))),
+        string16(ASCIIToUTF16(std::string())));
+    }
+  }
+}
+
+void
+Faulty::FuzzBytes(void* aData, int aLength, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      FAULTY_LOG("pickle field {bytes}");
+      // Too destructive. |WriteBytes| is used in many of the above data
+      // types as base function.
+      //FuzzData(static_cast<char*>(aData), aLength);
+    }
+  }
+}
+
+void
+Faulty::FuzzData(std::string& aValue, int aLength, unsigned int aProbability)
+{
+  if (mIsValidProcessType) {
+    if (mFuzzPickle && GetChance(aProbability)) {
+      FAULTY_LOG("pickle field {data}");
+      for (int i = 0; i < aLength; ++i) {
+        if (GetChance(aProbability)) {
+          FuzzIntegralType<char>(&aValue[i], true);
+        }
+      }
+    }
+  }
+}
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/glue/Faulty.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_Faulty_h
+#define mozilla_ipc_Faulty_h
+
+#include <set>
+#include <string>
+#include "nsDebug.h"
+#include "base/string16.h"
+#include "base/singleton.h"
+
+#define FAULTY_DEFAULT_PROBABILITY 1000
+#define FAULTY_LOG(fmt, args...) \
+  if (mozilla::ipc::Faulty::IsLoggingEnabled()) { \
+    printf_stderr("[Faulty] " fmt "\n", ## args); \
+  }
+
+namespace IPC {
+  // Needed for blacklisting messages.
+  class Message;
+}
+
+namespace mozilla {
+namespace ipc {
+
+class Faulty
+{
+  public:
+    // Used as a default argument for the Fuzz|datatype| methods.
+    static const unsigned int sDefaultProbability;
+
+    static unsigned int DefaultProbability(void);
+    static bool Logging(void);
+    static bool IsLoggingEnabled(void) { return sIsLoggingEnabled; }
+
+    void FuzzBool(bool* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzChar(char* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzUChar(unsigned char* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzInt16(int16_t* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzUInt16(uint16_t* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzInt(int* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzUInt32(uint32_t* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzLong(long* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzULong(unsigned long* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzInt64(int64_t* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzUInt64(uint64_t* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzSize(size_t* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzFloat(float* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzDouble(double* aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzString(std::string& aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzWString(std::wstring& aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzString16(string16& aValue, unsigned int aProbability=sDefaultProbability);
+    void FuzzData(std::string& aData, int aLength, unsigned int aProbability=sDefaultProbability);
+    void FuzzBytes(void* aData, int aLength, unsigned int aProbability=sDefaultProbability);
+
+    void MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability=sDefaultProbability);
+
+  private:
+    std::set<int> mFds;
+
+    const bool mFuzzPipes;
+    const bool mFuzzPickle;
+    const bool mUseLargeValues;
+    const bool mIsValidProcessType;
+
+    static const bool sIsLoggingEnabled;
+
+    Faulty();
+    friend struct DefaultSingletonTraits<Faulty>;
+    DISALLOW_EVIL_CONSTRUCTORS(Faulty);
+
+    static bool IsValidProcessType(void);
+
+    unsigned int Random(unsigned int aMax);
+    bool GetChance(unsigned int aProbability);
+
+    void MutateBool(bool* aValue);
+    void MutateChar(char* aValue);
+    void MutateUChar(unsigned char* aValue);
+    void MutateInt16(int16_t* aValue);
+    void MutateUInt16(uint16_t* aValue);
+    void MutateInt(int* aValue);
+    void MutateUInt32(uint32_t* aValue);
+    void MutateLong(long* aValue);
+    void MutateULong(unsigned long* aValue);
+    void MutateInt64(int64_t* aValue);
+    void MutateUInt64(uint64_t* aValue);
+    void MutateSize(size_t* aValue);
+    void MutateFloat(float* aValue);
+    void MutateDouble(double* aValue);
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -35,16 +35,20 @@ EXPORTS.mozilla.ipc += [
     'SharedMemory.h',
     'SharedMemoryBasic.h',
     'Shmem.h',
     'Transport.h',
     'URIUtils.h',
     'WindowsMessageLoop.h',
 ]
 
+if CONFIG['MOZ_FAULTY'] == '1':
+    EXPORTS.mozilla.ipc += ['Faulty.h']
+    SOURCES += ['Faulty.cpp']
+
 if CONFIG['OS_ARCH'] == 'WINNT':
     DEFINES['WEBRTC_WIN'] = True
     EXPORTS.mozilla.ipc += [
         'Transport_win.h',
     ]
     SOURCES += [
         'SharedMemory_windows.cpp',
         'Transport_win.cpp',
--- a/js/src/devtools/rootAnalysis/README.md
+++ b/js/src/devtools/rootAnalysis/README.md
@@ -18,23 +18,23 @@ 3.  Install taskcluster-vcs, eg by doing
         npm install taskcluster-vcs
         export PATH="$PATH:$(pwd)/node_modules/.bin"
 
 4. In some directory, using $SRCDIR as the top of your Gecko source checkout,
     run these commands:
 
         mkdir work
         cd work
-        GECKO_DIR=$SRCDIR $SRCDIR/testing/taskcluster/scripts/builder/build-haz-linux.sh $(pwd) --dep
+        GECKO_DIR=$SRCDIR $SRCDIR/taskcluster/scripts/builder/build-haz-linux.sh $(pwd) --dep
 
 The `--dep` is optional, and will avoid rebuilding the JS shell used to run the
 analysis later. Output goes to `analysis/hazards.txt`. This will run the
 analysis on the js/src tree only; if you wish to analyze the full browser, use
 
-    GECKO_DIR=$SRCDIR $SRCDIR/testing/taskcluster/scripts/builder/build-haz-linux.sh --project browser $(pwd)
+    GECKO_DIR=$SRCDIR $SRCDIR/taskcluster/scripts/builder/build-haz-linux.sh --project browser $(pwd)
 
 After running the analysis once, you can reuse the `*.xdb` database files
 generated, using modified analysis scripts, by running
 `analysis/run-analysis.sh` (or pass `--list` to see ways to select even more
 restrictive parts of the overall analysis; the default is `gcTypes` which will
 do everything but regenerate the xdb files).
 
 Also, you can pass `-v` to get exact command lines to cut & paste for running the
--- a/js/src/devtools/rootAnalysis/run-analysis.sh
+++ b/js/src/devtools/rootAnalysis/run-analysis.sh
@@ -1,4 +1,4 @@
 #!/bin/sh
 
 SRCDIR=$(cd $(dirname $0)/../../../..; pwd)
-GECKO_DIR=$SRCDIR $SRCDIR/testing/taskcluster/scripts/builder/build-haz-linux.sh $(pwd) "$@"
+GECKO_DIR=$SRCDIR $SRCDIR/taskcluster/scripts/builder/build-haz-linux.sh $(pwd) "$@"
--- a/js/src/doc/Debugger/Debugger.Object.md
+++ b/js/src/doc/Debugger/Debugger.Object.md
@@ -153,37 +153,44 @@ from its prototype:
     environment enclosing the function when it was created. If the referent
     is a function proxy or not debuggee code, this is `undefined`.
 
 `errorMessageName`
 :  If the referent is an error created with an engine internal message template
    this is a string which is the name of the template; `undefined` otherwise.
 
 `isBoundFunction`
-:   `true` if the referent is a bound function; `false` otherwise.
+:   If the referent is a debuggee function, returns `true` if the referent is a
+    bound function; `false` otherwise. If the referent is not a debuggee
+    function, or not a function at all, returns `undefined` instead.
 
 `isArrowFunction`
-:   `true` if the referent is an arrow function; `false` otherwise.
+:   If the referent is a debuggee function, returns `true` if the referent is an
+    arrow function; `false` otherwise. If the referent is not a debuggee
+    function, or not a function at all, returns `undefined` instead.
 
 `isPromise`
 :   `true` if the referent is a Promise; `false` otherwise.
 
 `boundTargetFunction`
-:   If the referent is a bound function, this is its target function—the
-    function that was bound to a particular `this` object. If the referent
-    is not a bound function, this is `undefined`.
+:   If the referent is a bound debuggee function, this is its target function—
+    the function that was bound to a particular `this` object. If the referent
+    is either not a bound function, not a debuggee function, or not a function
+    at all, this is `undefined`.
 
 `boundThis`
-:   If the referent is a bound function, this is the `this` value it was
-    bound to. If the referent is not a bound function, this is `undefined`.
+:   If the referent is a bound debuggee function, this is the `this` value it
+    was bound to. If the referent is either not a bound function, not a debuggee
+    function, or not a function at all, this is `undefined`.
 
 `boundArguments`
-:   If the referent is a bound function, this is an array (in the Debugger
-    object's compartment) that contains the debuggee values of the `arguments`
-    object it was bound to. If the referent is not a bound function, this is
+:   If the referent is a bound debuggee function, this is an array (in the
+    Debugger object's compartment) that contains the debuggee values of the
+    `arguments` object it was bound to. If the referent is either not a bound
+    function, not a debuggee function, or not a function at all, this is
     `undefined`.
 
 `proxyHandler`
 :   If the referent is a proxy whose handler object was allocated by
     debuggee code, this is its handler object—the object whose methods are
     invoked to implement accesses of the proxy's properties. If the referent
     is not a proxy whose handler object was allocated by debuggee code, this
     is `null`.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1266768.js
@@ -0,0 +1,16 @@
+if (!this.SharedArrayBuffer)
+    quit();
+
+function mod(stdlib) {
+    add = stdlib.Atomics.add;
+    function f3() {
+        add(i8a, 0 | 0 && this && BUGNUMBER, 0);
+    }
+    return {f3: f3, 0: 0};
+}
+i8a = new Int8Array(new SharedArrayBuffer(1));
+var {
+    f3
+} = mod(this, {})
+for (i = 0; i < 1000; i++)
+    f3();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/self-test/readlineBuf.js
@@ -0,0 +1,40 @@
+load(libdir + "asserts.js");
+
+assertThrowsInstanceOf(function () { readlineBuf() }, Error);
+
+var testBuffers = [
+    "foo\nbar\nbaz\n",
+    "foo\nbar\nbaz",
+    "foo\n\nbar\nbaz",
+    "f",
+    "\n",
+    "\nf",
+    ""
+];
+
+var expected = [
+    [ "foo", "bar", "baz" ],
+    [ "foo", "bar", "baz" ],
+    [ "foo", "", "bar", "baz" ],
+    [ "f" ],
+    [ "" ],
+    [ "", "f" ],
+    []
+];
+
+for (var idx in testBuffers) {
+    readlineBuf(testBuffers[idx]);
+    var result = [];
+
+    while ((line = readlineBuf()) != null) {
+        result.push(line);
+    }
+
+    assertDeepEq(result, expected[idx]);
+}
+
+readlineBuf(testBuffers[0]);
+readlineBuf();
+readlineBuf();
+readlineBuf(testBuffers[3]);
+assertEq(readlineBuf(), expected[3][0]);
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -35,21 +35,21 @@ OptimizationInfo::initNormalOptimization
     gvn_ = true;
     rangeAnalysis_ = true;
     reordering_ = true;
     sincos_ = true;
     sink_ = true;
 
     registerAllocator_ = RegisterAllocator_Backtracking;
 
-    inlineMaxBytecodePerCallSiteMainThread_ = 500;
-    inlineMaxBytecodePerCallSiteOffThread_ = 1000;
-    inlineMaxCalleeInlinedBytecodeLength_ = 3350;
-    inlineMaxTotalBytecodeLength_ = 80000;
-    inliningMaxCallerBytecodeLength_ = 1500;
+    inlineMaxBytecodePerCallSiteMainThread_ = 550;
+    inlineMaxBytecodePerCallSiteOffThread_ = 1100;
+    inlineMaxCalleeInlinedBytecodeLength_ = 3550;
+    inlineMaxTotalBytecodeLength_ = 85000;
+    inliningMaxCallerBytecodeLength_ = 1600;
     maxInlineDepth_ = 3;
     scalarReplacement_ = true;
     smallFunctionMaxInlineDepth_ = 10;
     compilerWarmUpThreshold_ = CompilerWarmupThreshold;
     compilerSmallFunctionWarmUpThreshold_ = CompilerSmallFunctionWarmupThreshold;
     inliningWarmUpThresholdFactor_ = 0.125;
     inliningRecompileThresholdFactor_ = 4;
 }
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -161,17 +161,17 @@ DefaultJitOptions::DefaultJitOptions()
     // How many actual arguments are accepted on the C stack.
     SET_DEFAULT(maxStackArgs, 4096);
 
     // How many times we will try to enter a script via OSR before
     // invalidating the script.
     SET_DEFAULT(osrPcMismatchesBeforeRecompile, 6000);
 
     // The bytecode length limit for small function.
-    SET_DEFAULT(smallFunctionMaxBytecodeLength_, 120);
+    SET_DEFAULT(smallFunctionMaxBytecodeLength_, 130);
 
     // An artificial testing limit for the maximum supported offset of
     // pc-relative jump and call instructions.
     SET_DEFAULT(jumpThreshold, UINT32_MAX);
 
     // Force how many invocation or loop iterations are needed before compiling
     // a function with the highest ionmonkey optimization level.
     // (i.e. OptimizationLevel_Normal)
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2928,18 +2928,22 @@ LIRGenerator::visitNot(MNot* ins)
       default:
         MOZ_CRASH("Unexpected MIRType.");
     }
 }
 
 void
 LIRGenerator::visitBoundsCheck(MBoundsCheck* ins)
 {
-     if (!ins->fallible())
-         return;
+    MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
+    MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
+    MOZ_ASSERT(ins->type() == MIRType::Int32);
+
+    if (!ins->fallible())
+        return;
 
     LInstruction* check;
     if (ins->minimum() || ins->maximum()) {
         check = new(alloc()) LBoundsCheckRange(useRegisterOrConstant(ins->index()),
                                                useAny(ins->length()),
                                                temp());
     } else {
         check = new(alloc()) LBoundsCheck(useRegisterOrConstant(ins->index()),
@@ -2947,16 +2951,18 @@ LIRGenerator::visitBoundsCheck(MBoundsCh
     }
     assignSnapshot(check, Bailout_BoundsCheck);
     add(check, ins);
 }
 
 void
 LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins)
 {
+    MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
+
     if (!ins->fallible())
         return;
 
     LInstruction* check = new(alloc()) LBoundsCheckLower(useRegister(ins->index()));
     assignSnapshot(check, Bailout_BoundsCheck);
     add(check, ins);
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9374,17 +9374,17 @@ class MNot
     }
 };
 
 // Bailout if index + minimum < 0 or index + maximum >= length. The length used
 // in a bounds check must not be negative, or the wrong result may be computed
 // (unsigned comparisons may be used).
 class MBoundsCheck
   : public MBinaryInstruction,
-    public NoTypePolicy::Data
+    public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
 {
     // Range over which to perform the bounds check, may be modified by GVN.
     int32_t minimum_;
     int32_t maximum_;
     bool fallible_;
 
     MBoundsCheck(MDefinition* index, MDefinition* length)
       : MBinaryInstruction(index, length), minimum_(0), maximum_(0), fallible_(true)
@@ -9445,17 +9445,17 @@ class MBoundsCheck
     void collectRangeInfoPreTrunc() override;
 
     ALLOW_CLONE(MBoundsCheck)
 };
 
 // Bailout if index < minimum.
 class MBoundsCheckLower
   : public MUnaryInstruction,
-    public NoTypePolicy::Data
+    public IntPolicy<0>::Data
 {
     int32_t minimum_;
     bool fallible_;
 
     explicit MBoundsCheckLower(MDefinition* index)
       : MUnaryInstruction(index), minimum_(0), fallible_(true)
     {
         setGuard();
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -1231,16 +1231,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \
     _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3> >) \
     _(Mix3Policy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>)  \
     _(Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \
     _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >)                        \
     _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >)   \
     _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >)            \
     _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >)                     \
+    _(MixPolicy<IntPolicy<0>, IntPolicy<1> >)                           \
     _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>>)                     \
     _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >)            \
     _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, IntPolicy<2> >)                        \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >)                    \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >)                    \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >)                    \
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
@@ -112,17 +112,19 @@ MacroAssembler::popcnt32(Register input,
         popcntl(input, output);
         return;
     }
 
     MOZ_ASSERT(tmp != InvalidReg);
 
     // Equivalent to mozilla::CountPopulation32()
 
-    movl(input, output);
+    movl(input, tmp);
+    if (input != output)
+        movl(input, output);
     shrl(Imm32(1), output);
     andl(Imm32(0x55555555), output);
     subl(output, tmp);
     movl(tmp, output);
     andl(Imm32(0x33333333), output);
     shrl(Imm32(2), tmp);
     andl(Imm32(0x33333333), tmp);
     addl(output, tmp);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -175,16 +175,19 @@ struct ShellRuntime
     ConditionVariable watchdogWakeup;
     Maybe<Thread> watchdogThread;
     Maybe<TimeStamp> watchdogTimeout;
 
     ConditionVariable sleepWakeup;
 
     int exitCode;
     bool quitting;
+
+    UniqueChars readLineBuf;
+    size_t readLineBufPos;
 };
 
 struct MOZ_STACK_CLASS EnvironmentPreparer : public js::ScriptEnvironmentPreparer {
     JSContext* cx;
     explicit EnvironmentPreparer(JSContext* cx)
       : cx(cx)
     {
         js::SetScriptEnvironmentPreparer(JS_GetRuntime(cx), this);
@@ -321,17 +324,18 @@ ShellRuntime::ShellRuntime(JSRuntime* rt
     haveInterruptFunc(false),
     interruptFunc(rt, NullValue()),
     lastWarningEnabled(false),
     lastWarning(rt, NullValue()),
 #ifdef SPIDERMONKEY_PROMISE
     promiseRejectionTrackerCallback(rt, NullValue()),
 #endif // SPIDERMONKEY_PROMISE
     exitCode(0),
-    quitting(false)
+    quitting(false),
+    readLineBufPos(0)
 {}
 
 static ShellRuntime*
 GetShellRuntime(JSRuntime *rt)
 {
     ShellRuntime* sr = static_cast<ShellRuntime*>(JS_GetRuntimePrivate(rt));
     MOZ_ASSERT(sr);
     return sr;
@@ -1712,16 +1716,79 @@ ReadLine(JSContext* cx, unsigned argc, V
     JS_free(cx, buf);
     if (!str)
         return false;
 
     args.rval().setString(str);
     return true;
 }
 
+/*
+ * function readlineBuf()
+ * Provides a hook for scripts to emulate readline() using a string object.
+ */
+static bool
+ReadLineBuf(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    ShellRuntime* sr = GetShellRuntime(cx);
+
+    if (!args.length()) {
+        if (!sr->readLineBuf) {
+            JS_ReportError(cx, "No source buffer set. You must initially call readlineBuf with an argument.");
+            return false;
+        }
+
+        char* currentBuf = sr->readLineBuf.get() + sr->readLineBufPos;
+        size_t buflen = strlen(currentBuf);
+
+        if (!buflen) {
+            args.rval().setNull();
+            return true;
+        }
+
+        size_t len = 0;
+        while(len < buflen) {
+            if (currentBuf[len] == '\n')
+                break;
+            len++;
+        }
+
+        JSString* str = JS_NewStringCopyN(cx, currentBuf, len);
+        if (!str)
+            return false;
+
+        if (currentBuf[len] == '\0')
+            sr->readLineBufPos += len;
+        else
+            sr->readLineBufPos += len + 1;
+
+        args.rval().setString(str);
+        return true;
+    }
+
+    if (args.length() == 1) {
+        if (sr->readLineBuf)
+            sr->readLineBuf.reset();
+
+        RootedString str(cx, JS::ToString(cx, args[0]));
+        if (!str)
+            return false;
+        sr->readLineBuf = UniqueChars(JS_EncodeStringToUTF8(cx, str));
+        if (!sr->readLineBuf)
+            return false;
+
+        sr->readLineBufPos = 0;
+        return true;
+    }
+
+    JS_ReportError(cx, "Must specify at most one argument");
+    return false;
+}
+
 static bool
 PutStr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 0) {
         if (!gOutFile->isOpen()) {
             JS_ReportError(cx, "output file is closed");
@@ -5214,16 +5281,22 @@ static const JSFunctionSpecWithHelp shel
 "run('foo.js')",
 "  Run the file named by the first argument, returning the number of\n"
 "  of milliseconds spent compiling and executing it."),
 
     JS_FN_HELP("readline", ReadLine, 0, 0,
 "readline()",
 "  Read a single line from stdin."),
 
+    JS_FN_HELP("readlineBuf", ReadLineBuf, 1, 0,
+"readlineBuf([ buf ])",
+"  Emulate readline() on the specified string. The first call with a string\n"
+"  argument sets the source buffer. Subsequent calls without an argument\n"
+"  then read from this buffer line by line.\n"),
+
     JS_FN_HELP("print", Print, 0, 0,
 "print([exp ...])",
 "  Evaluate and print expressions to stdout."),
 
     JS_FN_HELP("printErr", PrintErr, 0, 0,
 "printErr([exp ...])",
 "  Evaluate and print expressions to stderr."),
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7864,53 +7864,81 @@ DebuggerObject_checkThis(JSContext* cx, 
 static bool
 DebuggerObject_construct(JSContext* cx, unsigned argc, Value* vp)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
                          "Debugger.Object");
     return false;
 }
 
-static bool
-DebuggerObject_getProto(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::callableGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    THIS_DEBUGOBJECT(cx, argc, vp, "get callable", args, object)
+
+    args.rval().setBoolean(DebuggerObject::isCallable(cx, object));
+    return true;
+}
+
+/* static */ bool
+DebuggerObject::isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    THIS_DEBUGOBJECT(cx, argc, vp, "get isBoundFunction", args, object)
+
+    if (!DebuggerObject::isDebuggeeFunction(cx, object)) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    args.rval().setBoolean(DebuggerObject::isBoundFunction(cx, object));
+    return true;
+}
+
+/* static */ bool
+DebuggerObject::isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    THIS_DEBUGOBJECT(cx, argc, vp, "get isArrowFunction", args, object)
+
+    if (!DebuggerObject::isDebuggeeFunction(cx, object)) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    args.rval().setBoolean(DebuggerObject::isArrowFunction(cx, object));
+    return true;
+}
+
+/* static */ bool
+DebuggerObject::protoGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get proto", args, object)
 
     RootedObject result(cx);
     if (!DebuggerObject::getPrototypeOf(cx, object, &result))
         return false;
 
     args.rval().setObjectOrNull(result);
     return true;
 }
 
-static bool
-DebuggerObject_getClass(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::classGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get class", args, object)
 
     RootedString result(cx);
     if (!DebuggerObject::className(cx, object, &result))
         return false;
 
     args.rval().setString(result);
     return true;
 }
 
-static bool
-DebuggerObject_getCallable(JSContext* cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT(cx, argc, vp, "get callable", args, object)
-
-    args.rval().setBoolean(DebuggerObject::isCallable(cx, object));
-    return true;
-}
-
-static bool
-DebuggerObject_getName(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::nameGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get name", args, object)
 
     if (!DebuggerObject::isFunction(cx, object)) {
         args.rval().setUndefined();
         return true;
     }
 
@@ -7920,18 +7948,18 @@ DebuggerObject_getName(JSContext* cx, un
 
     if (result)
         args.rval().setString(result);
     else
         args.rval().setUndefined();
     return true;
 }
 
-static bool
-DebuggerObject_getDisplayName(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::displayNameGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get displayName", args, object)
 
     if (!DebuggerObject::isFunction(cx, object)) {
         args.rval().setUndefined();
         return true;
     }
 
@@ -7941,18 +7969,18 @@ DebuggerObject_getDisplayName(JSContext*
 
     if (result)
         args.rval().setString(result);
     else
         args.rval().setUndefined();
     return true;
 }
 
-static bool
-DebuggerObject_getParameterNames(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::parameterNamesGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get parameterNames", args, object)
 
     if (!DebuggerObject::isDebuggeeFunction(cx, object)) {
         args.rval().setUndefined();
         return true;
     }
 
@@ -7973,18 +8001,18 @@ DebuggerObject_getParameterNames(JSConte
             v = UndefinedValue();
         obj->setDenseElement(i, v);
     }
 
     args.rval().setObject(*obj);
     return true;
 }
 
-static bool
-DebuggerObject_getScript(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::scriptGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get script", args, dbg, obj);
 
     if (!obj->is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
 
@@ -8007,18 +8035,18 @@ DebuggerObject_getScript(JSContext* cx, 
     RootedObject scriptObject(cx, dbg->wrapScript(cx, script));
     if (!scriptObject)
         return false;
 
     args.rval().setObject(*scriptObject);
     return true;
 }
 
-static bool
-DebuggerObject_getEnvironment(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::environmentGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get environment", args, dbg, obj);
 
     /* Don't bother switching compartments just to check obj's type and get its env. */
     if (!obj->is<JSFunction>() || !obj->as<JSFunction>().isInterpreted()) {
         args.rval().setUndefined();
         return true;
     }
@@ -8036,46 +8064,18 @@ DebuggerObject_getEnvironment(JSContext*
         env = GetDebugScopeForFunction(cx, fun);
         if (!env)
             return false;
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval());
 }
 
-static bool
-DebuggerObject_getIsArrowFunction(JSContext* cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT(cx, argc, vp, "get isArrowFunction", args, object)
-
-    if (!DebuggerObject::isDebuggeeFunction(cx, object)) {
-        args.rval().setUndefined();
-        return true;
-    }
-
-    args.rval().setBoolean(DebuggerObject::isArrowFunction(cx, object));
-    return true;
-}
-
-static bool
-DebuggerObject_getIsBoundFunction(JSContext* cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT(cx, argc, vp, "get isBoundFunction", args, object)
-
-    if (!DebuggerObject::isDebuggeeFunction(cx, object)) {
-        args.rval().setUndefined();
-        return true;
-    }
-
-    args.rval().setBoolean(DebuggerObject::isBoundFunction(cx, object));
-    return true;
-}
-
-static bool
-DebuggerObject_getBoundTargetFunction(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::boundTargetFunctionGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get boundTargetFunction", args, object)
 
     if (!DebuggerObject::isDebuggeeFunction(cx, object) ||
         !DebuggerObject::isBoundFunction(cx, object))
     {
         args.rval().setUndefined();
         return true;
@@ -8084,33 +8084,33 @@ DebuggerObject_getBoundTargetFunction(JS
     RootedObject result(cx);
     if (!DebuggerObject::boundTargetFunction(cx, object, &result))
         return false;
 
     args.rval().setObjectOrNull(result);
     return true;
 }
 
-static bool
-DebuggerObject_getBoundThis(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::boundThisGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get boundThis", args, object)
 
     if (!DebuggerObject::isDebuggeeFunction(cx, object) ||
         !DebuggerObject::isBoundFunction(cx, object))
     {
         args.rval().setUndefined();
         return true;
     }
 
     return DebuggerObject::boundThis(cx, object, args.rval());
 }
 
-static bool
-DebuggerObject_getBoundArguments(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::boundArgumentsGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get boundArguments", args, object)
 
     if (!DebuggerObject::isDebuggeeFunction(cx, object) ||
         !DebuggerObject::isBoundFunction(cx, object))
     {
         args.rval().setUndefined();
         return true;
@@ -8123,16 +8123,61 @@ DebuggerObject_getBoundArguments(JSConte
     RootedObject obj(cx, NewDenseCopiedArray(cx, result.length(), result.begin()));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
+/* static */ bool
+DebuggerObject::globalGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    THIS_DEBUGOBJECT(cx, argc, vp, "get global", args, object)
+
+    RootedObject result(cx);
+    if (!DebuggerObject::global(cx, object, &result))
+        return false;
+
+    args.rval().setObject(*result);
+    return true;
+}
+
+/* static */ bool
+DebuggerObject::allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    THIS_DEBUGOBJECT(cx, argc, vp, "get allocationSite", args, object)
+
+    RootedObject result(cx);
+    if (!DebuggerObject::allocationSite(cx, object, &result))
+        return false;
+
+    args.rval().setObjectOrNull(result);
+    return true;
+}
+
+// Returns the "name" field (see js.msg), which may be used as a unique
+// identifier, for any error object with a JSErrorReport or undefined
+// if the object has no JSErrorReport.
+/* static */ bool
+DebuggerObject::errorMessageNameGetter(JSContext *cx, unsigned argc, Value* vp)
+{
+    THIS_DEBUGOBJECT(cx, argc, vp, "get errorMessageName", args, object)
+
+    RootedString result(cx);
+    if (!DebuggerObject::errorMessageName(cx, object, &result))
+        return false;
+
+    if (result)
+        args.rval().setString(result);
+    else
+        args.rval().setUndefined();
+    return true;
+}
+
 #ifdef SPIDERMONKEY_PROMISE
 static bool
 DebuggerObject_getIsPromise(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get isPromise", args, refobj);
 
     refobj = CheckedUnwrap(refobj);
     args.rval().setBoolean(refobj->is<PromiseObject>());
@@ -8266,89 +8311,44 @@ DebuggerObject_getPromiseDependentPromis
         promises = NewDenseCopiedArray(cx, values.length(), values[0].address());
     if (!promises)
         return false;
     args.rval().setObject(*promises);
     return true;
 }
 #endif // SPIDERMONKEY_PROMISE
 
-static bool
-DebuggerObject_getGlobal(JSContext* cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT(cx, argc, vp, "get global", args, object)
-
-    RootedObject result(cx);
-    if (!DebuggerObject::global(cx, object, &result))
-        return false;
-
-    args.rval().setObject(*result);
-    return true;
-}
-
-static bool
-DebuggerObject_getAllocationSite(JSContext* cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT(cx, argc, vp, "get allocationSite", args, object)
-
-    RootedObject result(cx);
-    if (!DebuggerObject::allocationSite(cx, object, &result))
-        return false;
-
-    args.rval().setObjectOrNull(result);
-    return true;
-}
-
-// Returns the "name" field (see js.msg), which may be used as a unique
-// identifier, for any error object with a JSErrorReport or undefined
-// if the object has no JSErrorReport.
-static bool
-DebuggerObject_getErrorMessageName(JSContext *cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT(cx, argc, vp, "get errorMessageName", args, object)
-
-    RootedString result(cx);
-    if (!DebuggerObject::errorMessageName(cx, object, &result))
-        return false;
-
-    if (result)
-        args.rval().setString(result);
-    else
-        args.rval().setUndefined();
-    return true;
-}
-
-static bool
-DebuggerObject_isExtensible(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "isExtensible", args, object)
 
     bool result;
     if (!DebuggerObject::isExtensible(cx, object, result))
         return false;
 
     args.rval().setBoolean(result);
     return true;
 }
 
-static bool
-DebuggerObject_isSealed(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::isSealedMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "isSealed", args, object)
 
     bool result;
     if (!DebuggerObject::isSealed(cx, object, result))
         return false;
 
     args.rval().setBoolean(result);
     return true;
 }
 
-static bool
-DebuggerObject_isFrozen(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::isFrozenMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "isFrozen", args, object)
 
     bool result;
     if (!DebuggerObject::isFrozen(cx, object, result))
         return false;
 
     args.rval().setBoolean(result);
@@ -8376,104 +8376,104 @@ IdVectorToArray(JSContext* cx, Handle<Id
          } else {
              MOZ_ASSERT_UNREACHABLE("IdVector must contain only string, int, and Symbol jsids");
          }
     }
 
     return NewDenseCopiedArray(cx, vals.length(), vals.begin());
 }
 
-static bool
-DebuggerObject_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::getOwnPropertyNamesMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "getOwnPropertyNames", args, object)
 
     Rooted<IdVector> ids(cx, IdVector(cx));
     if (!DebuggerObject::getOwnPropertyNames(cx, object, &ids))
         return false;
 
     RootedObject obj(cx, IdVectorToArray(cx, ids));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
-static bool
-DebuggerObject_getOwnPropertySymbols(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::getOwnPropertySymbolsMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "getOwnPropertySymbols", args, object)
 
     Rooted<IdVector> ids(cx, IdVector(cx));
     if (!DebuggerObject::getOwnPropertySymbols(cx, object, &ids))
         return false;
 
     RootedObject obj(cx, IdVectorToArray(cx, ids));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
-static bool
-DebuggerObject_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::getOwnPropertyDescriptorMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "getOwnPropertyDescriptor", args, object)
 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, args.get(0), &id))
         return false;
 
     Rooted<PropertyDescriptor> desc(cx);
     if (!DebuggerObject::getOwnPropertyDescriptor(cx, object, id, &desc))
       return false;
 
     return JS::FromPropertyDescriptor(cx, desc, args.rval());
 }
 
-static bool
-DebuggerObject_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::preventExtensionsMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "preventExtensions", args, object)
 
     if (!DebuggerObject::preventExtensions(cx, object))
         return false;
 
     args.rval().setUndefined();
     return true;
 }
 
-static bool
-DebuggerObject_seal(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::sealMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "seal", args, object)
 
     if (!DebuggerObject::seal(cx, object))
         return false;
 
     args.rval().setUndefined();
     return true;
 }
 
-static bool
-DebuggerObject_freeze(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::freezeMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "freeze", args, object)
 
     if (!DebuggerObject::freeze(cx, object))
         return false;
 
     args.rval().setUndefined();
     return true;
 }
 
-static bool
-DebuggerObject_defineProperty(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::definePropertyMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "defineProperty", args, object)
     if (!args.requireAtLeast(cx, "Debugger.Object.defineProperty", 2))
         return false;
 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, args[0], &id))
         return false;
@@ -8484,18 +8484,18 @@ DebuggerObject_defineProperty(JSContext*
 
     if (!DebuggerObject::defineProperty(cx, object, id, desc))
         return false;
 
     args.rval().setUndefined();
     return true;
 }
 
-static bool
-DebuggerObject_defineProperties(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::definePropertiesMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "defineProperties", args, object);
     if (!args.requireAtLeast(cx, "Debugger.Object.defineProperties", 1))
         return false;
 
     RootedValue arg(cx, args[0]);
     RootedObject props(cx, ToObject(cx, arg));
     if (!props)
@@ -8514,53 +8514,53 @@ DebuggerObject_defineProperties(JSContex
     args.rval().setUndefined();
     return true;
 }
 
 /*
  * This does a non-strict delete, as a matter of API design. The case where the
  * property is non-configurable isn't necessarily exceptional here.
  */
-static bool
-DebuggerObject_deleteProperty(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::deletePropertyMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "deleteProperty", args, object)
 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, args.get(0), &id))
         return false;
 
     ObjectOpResult result;
     if (!DebuggerObject::deleteProperty(cx, object, id, result))
         return false;
 
     args.rval().setBoolean(result.ok());
     return true;
 }
 
-static bool
-DebuggerObject_call(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::callMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "call", callArgs, object);
 
     RootedValue thisv(cx, callArgs.get(0));
 
     Rooted<ValueVector> args(cx, ValueVector(cx));
     if (callArgs.length() >= 2) {
         if (!args.growBy(callArgs.length() - 1))
             return false;
         for (size_t i = 1; i < callArgs.length(); ++i)
             args[i - 1].set(callArgs[i]);
     }
 
     return object->call(cx, object, thisv, args, callArgs.rval());
 }
 
-static bool
-DebuggerObject_apply(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::applyMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "apply", callArgs, object);
 
     RootedValue thisv(cx, callArgs.get(0));
 
     Rooted<ValueVector> args(cx, ValueVector(cx));
     if (callArgs.length() >= 2 && !callArgs[1].isNullOrUndefined()) {
         if (!callArgs[1].isObject()) {
@@ -8578,18 +8578,18 @@ DebuggerObject_apply(JSContext* cx, unsi
 
         if (!args.growBy(argc) || !GetElements(cx, argsobj, argc, args.begin()))
             return false;
     }
 
     return object->call(cx, object, thisv, args, callArgs.rval());
 }
 
-static bool
-DebuggerObject_asEnvironment(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::asEnvironmentMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "asEnvironment", args, dbg, referent);
     if (!RequireGlobalObject(cx, args.thisv(), referent))
         return false;
 
     Rooted<Env*> env(cx);
     {
         AutoCompartment ac(cx, referent);
@@ -8600,18 +8600,18 @@ DebuggerObject_asEnvironment(JSContext* 
 
     return dbg->wrapEnvironment(cx, env, args.rval());
 }
 
 // Lookup a binding on the referent's global scope and change it to undefined
 // if it is an uninitialized lexical, otherwise do nothing. The method's
 // JavaScript return value is true _only_ when an uninitialized lexical has been
 // altered, otherwise it is false.
-bool
-DebuggerObject_forceLexicalInitializationByName(JSContext *cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::forceLexicalInitializationByNameMethod(JSContext *cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "forceLexicalInitializationByName", args, object)
     if (!args.requireAtLeast(cx, "Debugger.Object.prototype.forceLexicalInitializationByName", 1))
         return false;
 
     if (!DebuggerObject::requireGlobal(cx, object))
         return false;
 
@@ -8622,18 +8622,18 @@ DebuggerObject_forceLexicalInitializatio
     bool result;
     if (!DebuggerObject::forceLexicalInitializationByName(cx, object, id, result))
         return false;
 
     args.rval().setBoolean(result);
     return true;
 }
 
-static bool
-DebuggerObject_executeInGlobal(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::executeInGlobalMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "executeInGlobal", args, object);
     if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobal", 1))
         return false;
 
     if (!DebuggerObject::requireGlobal(cx, object))
         return false;
 
@@ -8647,18 +8647,18 @@ DebuggerObject_executeInGlobal(JSContext
 
     EvalOptions options;
     if (!ParseEvalOptions(cx, args.get(1), options))
         return false;
 
     return DebuggerObject::executeInGlobal(cx, object, chars, nullptr, options, args.rval());
 }
 
-static bool
-DebuggerObject_executeInGlobalWithBindings(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::executeInGlobalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "executeInGlobalWithBindings", args, object);
     if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobalWithBindings", 2))
         return false;
 
     if (!DebuggerObject::requireGlobal(cx, object))
         return false;
 
@@ -8676,69 +8676,69 @@ DebuggerObject_executeInGlobalWithBindin
 
     EvalOptions options;
     if (!ParseEvalOptions(cx, args.get(2), options))
         return false;
 
     return DebuggerObject::executeInGlobal(cx, object, chars, bindings, options, args.rval());
 }
 
-static bool
-DebuggerObject_makeDebuggeeValue(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::makeDebuggeeValueMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "makeDebuggeeValue", args, object);
     if (!args.requireAtLeast(cx, "Debugger.Object.prototype.makeDebuggeeValue", 1))
         return false;
 
     return DebuggerObject::makeDebuggeeValue(cx, object, args[0], args.rval());
 }
 
-static bool
-DebuggerObject_unsafeDereference(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::unsafeDereferenceMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "unsafeDereference", args, object);
 
     RootedObject result(cx);
     if (!DebuggerObject::unsafeDereference(cx, object, &result))
        return false;
 
     args.rval().setObject(*result);
     return true;
 }
 
-static bool
-DebuggerObject_unwrap(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerObject::unwrapMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "unwrap", args, object);
 
     Rooted<DebuggerObject*> result(cx);
     if (!DebuggerObject::unwrap(cx, object, &result))
         return false;
 
     args.rval().setObjectOrNull(result);
     return true;
 }
 
 const JSPropertySpec DebuggerObject::properties_[] = {
-    JS_PSG("proto", DebuggerObject_getProto, 0),
-    JS_PSG("class", DebuggerObject_getClass, 0),
-    JS_PSG("callable", DebuggerObject_getCallable, 0),
-    JS_PSG("name", DebuggerObject_getName, 0),
-    JS_PSG("displayName", DebuggerObject_getDisplayName, 0),
-    JS_PSG("parameterNames", DebuggerObject_getParameterNames, 0),
-    JS_PSG("script", DebuggerObject_getScript, 0),
-    JS_PSG("environment", DebuggerObject_getEnvironment, 0),
-    JS_PSG("isArrowFunction", DebuggerObject_getIsArrowFunction, 0),
-    JS_PSG("isBoundFunction", DebuggerObject_getIsBoundFunction, 0),
-    JS_PSG("boundTargetFunction", DebuggerObject_getBoundTargetFunction, 0),
-    JS_PSG("boundThis", DebuggerObject_getBoundThis, 0),
-    JS_PSG("boundArguments", DebuggerObject_getBoundArguments, 0),
-    JS_PSG("global", DebuggerObject_getGlobal, 0),
-    JS_PSG("allocationSite", DebuggerObject_getAllocationSite, 0),
-    JS_PSG("errorMessageName", DebuggerObject_getErrorMessageName, 0),
+    JS_PSG("callable", DebuggerObject::callableGetter, 0),
+    JS_PSG("isBoundFunction", DebuggerObject::isBoundFunctionGetter, 0),
+    JS_PSG("isArrowFunction", DebuggerObject::isArrowFunctionGetter, 0),
+    JS_PSG("proto", DebuggerObject::protoGetter, 0),
+    JS_PSG("class", DebuggerObject::classGetter, 0),
+    JS_PSG("name", DebuggerObject::nameGetter, 0),
+    JS_PSG("displayName", DebuggerObject::displayNameGetter, 0),
+    JS_PSG("parameterNames", DebuggerObject::parameterNamesGetter, 0),
+    JS_PSG("script", DebuggerObject::scriptGetter, 0),
+    JS_PSG("environment", DebuggerObject::environmentGetter, 0),
+    JS_PSG("boundTargetFunction", DebuggerObject::boundTargetFunctionGetter, 0),
+    JS_PSG("boundThis", DebuggerObject::boundThisGetter, 0),
+    JS_PSG("boundArguments", DebuggerObject::boundArgumentsGetter, 0),
+    JS_PSG("global", DebuggerObject::globalGetter, 0),
+    JS_PSG("allocationSite", DebuggerObject::allocationSiteGetter, 0),
+    JS_PSG("errorMessageName", DebuggerObject::errorMessageNameGetter, 0),
     JS_PS_END
 };
 
 #ifdef SPIDERMONKEY_PROMISE
 const JSPropertySpec DebuggerObject::promiseProperties_[] = {
     JS_PSG("isPromise", DebuggerObject_getIsPromise, 0),
     JS_PSG("promiseState", DebuggerObject_getPromiseState, 0),
     JS_PSG("promiseLifetime", DebuggerObject_getPromiseLifetime, 0),
@@ -8747,37 +8747,37 @@ const JSPropertySpec DebuggerObject::pro
     JS_PSG("promiseResolutionSite", DebuggerObject_getPromiseResolutionSite, 0),
     JS_PSG("promiseID", DebuggerObject_getPromiseID, 0),
     JS_PSG("promiseDependentPromises", DebuggerObject_getPromiseDependentPromises, 0),
     JS_PS_END
 };
 #endif // SPIDERMONKEY_PROMISE
 
 const JSFunctionSpec DebuggerObject::methods_[] = {
-    JS_FN("isExtensible", DebuggerObject_isExtensible, 0, 0),
-    JS_FN("isSealed", DebuggerObject_isSealed, 0, 0),
-    JS_FN("isFrozen", DebuggerObject_isFrozen, 0, 0),
-    JS_FN("getOwnPropertyNames", DebuggerObject_getOwnPropertyNames, 0, 0),
-    JS_FN("getOwnPropertySymbols", DebuggerObject_getOwnPropertySymbols, 0, 0),
-    JS_FN("getOwnPropertyDescriptor", DebuggerObject_getOwnPropertyDescriptor, 1, 0),
-    JS_FN("preventExtensions", DebuggerObject_preventExtensions, 0, 0),
-    JS_FN("seal", DebuggerObject_seal, 0, 0),
-    JS_FN("freeze", DebuggerObject_freeze, 0, 0),
-    JS_FN("defineProperty", DebuggerObject_defineProperty, 2, 0),
-    JS_FN("defineProperties", DebuggerObject_defineProperties, 1, 0),
-    JS_FN("deleteProperty", DebuggerObject_deleteProperty, 1, 0),
-    JS_FN("call", DebuggerObject_call, 0, 0),
-    JS_FN("apply", DebuggerObject_apply, 0, 0),
-    JS_FN("asEnvironment", DebuggerObject_asEnvironment, 0, 0),
-    JS_FN("forceLexicalInitializationByName", DebuggerObject_forceLexicalInitializationByName, 1, 0),
-    JS_FN("executeInGlobal", DebuggerObject_executeInGlobal, 1, 0),
-    JS_FN("executeInGlobalWithBindings", DebuggerObject_executeInGlobalWithBindings, 2, 0),
-    JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
-    JS_FN("unsafeDereference", DebuggerObject_unsafeDereference, 0, 0),
-    JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
+    JS_FN("isExtensible", DebuggerObject::isExtensibleMethod, 0, 0),
+    JS_FN("isSealed", DebuggerObject::isSealedMethod, 0, 0),
+    JS_FN("isFrozen", DebuggerObject::isFrozenMethod, 0, 0),
+    JS_FN("getOwnPropertyNames", DebuggerObject::getOwnPropertyNamesMethod, 0, 0),
+    JS_FN("getOwnPropertySymbols", DebuggerObject::getOwnPropertySymbolsMethod, 0, 0),
+    JS_FN("getOwnPropertyDescriptor", DebuggerObject::getOwnPropertyDescriptorMethod, 1, 0),
+    JS_FN("preventExtensions", DebuggerObject::preventExtensionsMethod, 0, 0),
+    JS_FN("seal", DebuggerObject::sealMethod, 0, 0),
+    JS_FN("freeze", DebuggerObject::freezeMethod, 0, 0),
+    JS_FN("defineProperty", DebuggerObject::definePropertyMethod, 2, 0),
+    JS_FN("defineProperties", DebuggerObject::definePropertiesMethod, 1, 0),
+    JS_FN("deleteProperty", DebuggerObject::deletePropertyMethod, 1, 0),
+    JS_FN("call", DebuggerObject::callMethod, 0, 0),
+    JS_FN("apply", DebuggerObject::applyMethod, 0, 0),
+    JS_FN("asEnvironment", DebuggerObject::asEnvironmentMethod, 0, 0),
+    JS_FN("forceLexicalInitializationByName", DebuggerObject::forceLexicalInitializationByNameMethod, 1, 0),
+    JS_FN("executeInGlobal", DebuggerObject::executeInGlobalMethod, 1, 0),
+    JS_FN("executeInGlobalWithBindings", DebuggerObject::executeInGlobalWithBindingsMethod, 2, 0),
+    JS_FN("makeDebuggeeValue", DebuggerObject::makeDebuggeeValueMethod, 1, 0),
+    JS_FN("unsafeDereference", DebuggerObject::unsafeDereferenceMethod, 0, 0),
+    JS_FN("unwrap", DebuggerObject::unwrapMethod, 0, 0),
     JS_FS_END
 };
 
 /* static */ NativeObject*
 DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor)
 {
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
     RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -1058,17 +1058,16 @@ class DebuggerObject : public NativeObje
     static bool isArrowFunction(JSContext* cx, Handle<DebuggerObject*> object);
     static bool isGlobal(JSContext* cx, Handle<DebuggerObject*> object);
     static bool className(JSContext* cx, Handle<DebuggerObject*> object,
                           MutableHandleString result);
     static bool global(JSContext* cx, Handle<DebuggerObject*> object, MutableHandleObject result);
     static bool name(JSContext* cx, Handle<DebuggerObject*> object, MutableHandleString result);
     static bool displayName(JSContext* cx, Handle<DebuggerObject*> object,
                             MutableHandleString result);
-
     static bool parameterNames(JSContext* cx, Handle<DebuggerObject*> object,
                                MutableHandle<StringVector> result);
     static bool boundTargetFunction(JSContext* cx, Handle<DebuggerObject*> object,
                                     MutableHandleObject result);
     static bool boundThis(JSContext* cx, Handle<DebuggerObject*> object,
                           MutableHandleValue result);
     static bool boundArguments(JSContext* cx, Handle<DebuggerObject*> object,
                                MutableHandle<ValueVector> result);
@@ -1129,16 +1128,55 @@ class DebuggerObject : public NativeObje
 
     JSObject* referent() const {
         JSObject* obj = (JSObject*) getPrivate();
         MOZ_ASSERT(obj);
         return obj;
     }
 
     Debugger* owner() const;
+
+    static bool callableGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool protoGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool classGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool nameGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool displayNameGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool parameterNamesGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool scriptGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool environmentGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool boundTargetFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool boundThisGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool boundArgumentsGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool globalGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool errorMessageNameGetter(JSContext* cx, unsigned argc, Value* vp);
+
+    static bool isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool isSealedMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool isFrozenMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool getOwnPropertyNamesMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool getOwnPropertySymbolsMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool getOwnPropertyDescriptorMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool preventExtensionsMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool sealMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool freezeMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool definePropertyMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool definePropertiesMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool deletePropertyMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool callMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool applyMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool asEnvironmentMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool forceLexicalInitializationByNameMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool executeInGlobalMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool executeInGlobalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool makeDebuggeeValueMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool unsafeDereferenceMethod(JSContext* cx, unsigned argc, Value* vp);
+    static bool unwrapMethod(JSContext* cx, unsigned argc, Value* vp);
 };
 
 class BreakpointSite {
     friend class Breakpoint;
     friend struct ::JSCompartment;
     friend class ::JSScript;
     friend class Debugger;
 
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1400,144 +1400,149 @@ nsSVGUtils::SetupContextPaint(const Draw
     aThisContextPaint->SetStrokeOpacity(opacity);
 
     toDraw |= DrawMode::GLYPH_STROKE;
   }
 
   return toDraw;
 }
 
-static float
-MaybeOptimizeOpacity(nsIFrame *aFrame, float aFillOrStrokeOpacity)
-{
-  float opacity = aFrame->StyleEffects()->mOpacity;
-  if (opacity < 1 && nsSVGUtils::CanOptimizeOpacity(aFrame)) {
-    return aFillOrStrokeOpacity * opacity;
-  }
-  return aFillOrStrokeOpacity;
-}
-
 /* static */ void
 nsSVGUtils::MakeFillPatternFor(nsIFrame* aFrame,
                                gfxContext* aContext,
                                GeneralPattern* aOutPattern,
                                gfxTextContextPaint* aContextPaint)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mFill.mType == eStyleSVGPaintType_None) {
     return;
   }
 
-  float opacity = MaybeOptimizeOpacity(aFrame,
-                                       GetOpacity(style->FillOpacitySource(),
-                                                  style->mFillOpacity,
-                                                  aContextPaint));
+  const float opacity = aFrame->StyleEffects()->mOpacity;
+
+  float fillOpacity = GetOpacity(style->FillOpacitySource(),
+                                 style->mFillOpacity,
+                                 aContextPaint);
+  if (opacity < 1.0f &&
+      nsSVGUtils::CanOptimizeOpacity(aFrame)) {
+    // Combine the group opacity into the fill opacity (we will have skipped
+    // creating an offscreen surface to apply the group opacity).
+    fillOpacity *= opacity;
+  }
+
   const DrawTarget* dt = aContext->GetDrawTarget();
 
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, &style->mFill,
                                  nsSVGEffects::FillProperty());
   if (ps) {
     RefPtr<gfxPattern> pattern =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrix(),
-                                &nsStyleSVG::mFill, opacity);
+                                &nsStyleSVG::mFill, fillOpacity);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
       return;
     }
   }
 
   if (aContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch (style->mFill.mType) {
     case eStyleSVGPaintType_ContextFill:
-      pattern = aContextPaint->GetFillPattern(dt, opacity,
+      pattern = aContextPaint->GetFillPattern(dt, fillOpacity,
                                               aContext->CurrentMatrix());
       break;
     case eStyleSVGPaintType_ContextStroke:
-      pattern = aContextPaint->GetStrokePattern(dt, opacity,
+      pattern = aContextPaint->GetStrokePattern(dt, fillOpacity,
                                                 aContext->CurrentMatrix());
       break;
     default:
       ;
     }
     if (pattern) {
       aOutPattern->Init(*pattern->GetPattern(dt));
       return;
     }
   }
 
   // On failure, use the fallback colour in case we have an
   // objectBoundingBox where the width or height of the object is zero.
   // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
   Color color(Color::FromABGR(GetFallbackOrPaintColor(aFrame->StyleContext(),
                                                       &nsStyleSVG::mFill)));
-  color.a *= opacity;
+  color.a *= fillOpacity;
   aOutPattern->InitColorPattern(ToDeviceColor(color));
 }
 
 /* static */ void
 nsSVGUtils::MakeStrokePatternFor(nsIFrame* aFrame,
                                  gfxContext* aContext,
                                  GeneralPattern* aOutPattern,
                                  gfxTextContextPaint* aContextPaint)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mStroke.mType == eStyleSVGPaintType_None) {
     return;
   }
 
-  float opacity = MaybeOptimizeOpacity(aFrame,
-                                       GetOpacity(style->StrokeOpacitySource(),
-                                                  style->mStrokeOpacity,
-                                                  aContextPaint));
+  const float opacity = aFrame->StyleEffects()->mOpacity;
+
+  float strokeOpacity = GetOpacity(style->StrokeOpacitySource(),
+                                   style->mStrokeOpacity,
+                                   aContextPaint);
+  if (opacity < 1.0f &&
+      nsSVGUtils::CanOptimizeOpacity(aFrame)) {
+    // Combine the group opacity into the stroke opacity (we will have skipped
+    // creating an offscreen surface to apply the group opacity).
+    strokeOpacity *= opacity;
+  }
 
   const DrawTarget* dt = aContext->GetDrawTarget();
 
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, &style->mStroke,
                                  nsSVGEffects::StrokeProperty());
   if (ps) {
     RefPtr<gfxPattern> pattern =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrix(),
-                                &nsStyleSVG::mStroke, opacity);
+                                &nsStyleSVG::mStroke, strokeOpacity);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
       return;
     }
   }
 
   if (aContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch (style->mStroke.mType) {
     case eStyleSVGPaintType_ContextFill:
-      pattern = aContextPaint->GetFillPattern(dt, opacity,
+      pattern = aContextPaint->GetFillPattern(dt, strokeOpacity,
                                               aContext->CurrentMatrix());
       break;
     case eStyleSVGPaintType_ContextStroke:
-      pattern = aContextPaint->GetStrokePattern(dt, opacity,
+      pattern = aContextPaint->GetStrokePattern(dt, strokeOpacity,
                                                 aContext->CurrentMatrix());
       break;
     default:
       ;
     }
     if (pattern) {
       aOutPattern->Init(*pattern->GetPattern(dt));
       return;
     }
   }
 
   // On failure, use the fallback colour in case we have an
   // objectBoundingBox where the width or height of the object is zero.
   // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
   Color color(Color::FromABGR(GetFallbackOrPaintColor(aFrame->StyleContext(),
                                                       &nsStyleSVG::mStroke)));
-  color.a *= opacity;
+  color.a *= strokeOpacity;
   aOutPattern->InitColorPattern(ToDeviceColor(color));
 }
 
 /* static */ float
 nsSVGUtils::GetOpacity(nsStyleSVGOpacitySource aOpacityType,
                        const float& aOpacity,
                        gfxTextContextPaint *aContextPaint)
 {
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
@@ -8,69 +8,37 @@ package org.mozilla.gecko.gfx;
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.mozglue.JNIObject;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.util.Log;
 
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-
 /**
  * This class is a singleton that tracks EGL and compositor things over
  * the lifetime of Fennec running.
  * We only ever create one C++ compositor over Fennec's lifetime, but
  * most of the Java-side objects (e.g. LayerView, GeckoLayerClient,
  * LayerRenderer) can all get destroyed and re-created if the GeckoApp
  * activity is destroyed. This GLController is never destroyed, so that
  * the mCompositorCreated field and other state variables are always
  * accurate.
  */
 public class GLController extends JNIObject {
-    private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
     private static final String LOGTAG = "GeckoGLController";
 
     /* package */ LayerView mView;
     private boolean mServerSurfaceValid;
     private int mWidth, mHeight;
 
     /* This is written by the compositor thread (while the UI thread
      * is blocked on it) and read by the UI thread. */
     private volatile boolean mCompositorCreated;
 
-    private static EGL10 sEGL;
-    private static EGLDisplay sEGLDisplay;
-    private static EGLConfig sEGLConfig;
-    private EGLSurface mEGLSurfaceForCompositor;
-
-    private static final int LOCAL_EGL_OPENGL_ES2_BIT = 4;
-
-    private static final int[] CONFIG_SPEC_16BPP = {
-        EGL10.EGL_RED_SIZE, 5,
-        EGL10.EGL_GREEN_SIZE, 6,
-        EGL10.EGL_BLUE_SIZE, 5,
-        EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
-        EGL10.EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
-        EGL10.EGL_NONE
-    };
-
-    private static final int[] CONFIG_SPEC_24BPP = {
-        EGL10.EGL_RED_SIZE, 8,
-        EGL10.EGL_GREEN_SIZE, 8,
-        EGL10.EGL_BLUE_SIZE, 8,
-        EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
-        EGL10.EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
-        EGL10.EGL_NONE
-    };
-
     @WrapForJNI @Override // JNIObject
     protected native void disposeNative();
 
     // Gecko thread sets its Java instances; does not block UI thread.
     @WrapForJNI
     /* package */ native void attachToJava(GeckoLayerClient layerClient,
                                            NativePanZoomController npzc);
 
@@ -96,52 +64,39 @@ public class GLController extends JNIObj
     public GLController() {
     }
 
     synchronized void serverSurfaceDestroyed() {
         ThreadUtils.assertOnUiThread();
 
         mServerSurfaceValid = false;
 
-        if (mEGLSurfaceForCompositor != null) {
-          sEGL.eglDestroySurface(sEGLDisplay, mEGLSurfaceForCompositor);
-          mEGLSurfaceForCompositor = null;
-        }
-
         // We need to coordinate with Gecko when pausing composition, to ensure
         // that Gecko never executes a draw event while the compositor is paused.
         // This is sent synchronously to make sure that we don't attempt to use
         // any outstanding Surfaces after we call this (such as from a
         // serverSurfaceDestroyed notification), and to make sure that any in-flight
         // Gecko draw events have been processed.  When this returns, composition is
         // definitely paused -- it'll synchronize with the Gecko event loop, which
         // in turn will synchronize with the compositor thread.
         if (mCompositorCreated) {
             pauseCompositor();
         }
     }
 
-    synchronized void serverSurfaceChanged(int newWidth, int newHeight) {
+    void serverSurfaceChanged(int newWidth, int newHeight) {
         ThreadUtils.assertOnUiThread();
 
-        mWidth = newWidth;
-        mHeight = newHeight;
-        mServerSurfaceValid = true;
+        synchronized (this) {
+            mWidth = newWidth;
+            mHeight = newHeight;
+            mServerSurfaceValid = true;
+        }
 
-        // we defer to a runnable the task of updating the compositor, because this is going to
-        // call back into createEGLSurface, which will try to create an EGLSurface
-        // against mView, which we suspect might fail if called too early. By posting this to
-        // mView, we hope to ensure that it is deferred until mView is actually "ready" for some
-        // sense of "ready".
-        mView.post(new Runnable() {
-            @Override
-            public void run() {
-                updateCompositor();
-            }
-        });
+        updateCompositor();
     }
 
     void updateCompositor() {
         ThreadUtils.assertOnUiThread();
 
         if (mView == null) {
             return;
         }
@@ -149,143 +104,43 @@ public class GLController extends JNIObj
         if (mCompositorCreated) {
             // If the compositor has already been created, just resume it instead. We don't need
             // to block here because if the surface is destroyed before the compositor grabs it,
             // we can handle that gracefully (i.e. the compositor will remain paused).
             resumeCompositor(mWidth, mHeight);
             return;
         }
 
-        if (!AttemptPreallocateEGLSurfaceForCompositor()) {
-            return;
-        }
-
         // Only try to create the compositor if we have a valid surface and gecko is up. When these
         // two conditions are satisfied, we can be relatively sure that the compositor creation will
         // happen without needing to block anywhere. Do it with a synchronous Gecko event so that the
         // Android doesn't have a chance to destroy our surface in between.
-        if (mView.getLayerClient().isGeckoReady()) {
+        if (isServerSurfaceValid() && mView.getLayerClient().isGeckoReady()) {
             createCompositor(mWidth, mHeight);
+            compositorCreated();
         }
     }
 
     void compositorCreated() {
         // This is invoked on the compositor thread, while the java UI thread
         // is blocked on the gecko sync event in updateCompositor() above
         mCompositorCreated = true;
     }
 
     public boolean isServerSurfaceValid() {
         return mServerSurfaceValid;
     }
 
-    private static void initEGL() {
-        if (sEGL != null) {
-            return;
-        }
-
-        sEGL = (EGL10)EGLContext.getEGL();
-
-        sEGLDisplay = sEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-        if (sEGLDisplay == EGL10.EGL_NO_DISPLAY) {
-            Log.w(LOGTAG, "can't get EGL display!");
-            return;
-        }
-
-        // while calling eglInitialize here should not be necessary as it was already called
-        // by the EGLPreloadingThread, it really doesn't cost much to call it again here,
-        // and makes this code easier to think about: EGLPreloadingThread is only a
-        // preloading optimization, not something we rely on for anything else.
-        //
-        // Also note that while calling eglInitialize isn't necessary on Android 4.x
-        // (at least Android's HardwareRenderer does it for us already), it is necessary
-        // on Android 2.x.
-        int[] returnedVersion = new int[2];
-        if (!sEGL.eglInitialize(sEGLDisplay, returnedVersion)) {
-            Log.w(LOGTAG, "eglInitialize failed");
-            return;
-        }
-
-        sEGLConfig = chooseConfig();
-    }
-
-    private static EGLConfig chooseConfig() {
-        int[] desiredConfig;
-        int rSize, gSize, bSize;
-        int[] numConfigs = new int[1];
-
-        switch (GeckoAppShell.getScreenDepth()) {
-        case 24:
-            desiredConfig = CONFIG_SPEC_24BPP;
-            rSize = gSize = bSize = 8;
-            break;
-        case 16:
-        default:
-            desiredConfig = CONFIG_SPEC_16BPP;
-            rSize = 5; gSize = 6; bSize = 5;
-            break;
-        }
-
-        if (!sEGL.eglChooseConfig(sEGLDisplay, desiredConfig, null, 0, numConfigs) ||
-                numConfigs[0] <= 0) {
-            throw new GLControllerException("No available EGL configurations " +
-                                            getEGLError());
+    @WrapForJNI(allowMultithread = true)
+    private synchronized Object getSurface() {
+        if (mView != null && isServerSurfaceValid()) {
+            return mView.getSurface();
+        } else {
+            return null;
         }
-
-        EGLConfig[] configs = new EGLConfig[numConfigs[0]];
-        if (!sEGL.eglChooseConfig(sEGLDisplay, desiredConfig, configs, numConfigs[0], numConfigs)) {
-            throw new GLControllerException("No EGL configuration for that specification " +
-                                            getEGLError());
-        }
-
-        // Select the first configuration that matches the screen depth.
-        int[] red = new int[1], green = new int[1], blue = new int[1];
-        for (EGLConfig config : configs) {
-            sEGL.eglGetConfigAttrib(sEGLDisplay, config, EGL10.EGL_RED_SIZE, red);
-            sEGL.eglGetConfigAttrib(sEGLDisplay, config, EGL10.EGL_GREEN_SIZE, green);
-            sEGL.eglGetConfigAttrib(sEGLDisplay, config, EGL10.EGL_BLUE_SIZE, blue);
-            if (red[0] == rSize && green[0] == gSize && blue[0] == bSize) {
-                return config;
-            }
-        }
-
-        throw new GLControllerException("No suitable EGL configuration found");
-    }
-
-    private synchronized boolean AttemptPreallocateEGLSurfaceForCompositor() {
-        if (mEGLSurfaceForCompositor == null) {
-            initEGL();
-            try {
-                mEGLSurfaceForCompositor = sEGL.eglCreateWindowSurface(sEGLDisplay, sEGLConfig, mView.getNativeWindow(), null);
-                // In failure cases, eglCreateWindowSurface should return EGL_NO_SURFACE.
-                // We currently normalize this to null, and compare to null in all our checks.
-                if (mEGLSurfaceForCompositor == EGL10.EGL_NO_SURFACE) {
-                    mEGLSurfaceForCompositor = null;
-                }
-            } catch (Exception e) {
-                Log.e(LOGTAG, "eglCreateWindowSurface threw", e);
-            }
-        }
-        if (mEGLSurfaceForCompositor == null) {
-            Log.w(LOGTAG, "eglCreateWindowSurface returned no surface!");
-        }
-        return mEGLSurfaceForCompositor != null;
-    }
-
-    @WrapForJNI(allowMultithread = true)
-    private synchronized EGLSurface createEGLSurface() {
-        compositorCreated();
-        AttemptPreallocateEGLSurfaceForCompositor();
-        EGLSurface result = mEGLSurfaceForCompositor;
-        mEGLSurfaceForCompositor = null;
-        return result;
-    }
-
-    private static String getEGLError() {
-        return "Error " + (sEGL == null ? "(no sEGL)" : sEGL.eglGetError());
     }
 
     void resumeCompositor(int width, int height) {
         // Asking Gecko to resume the compositor takes too long (see
         // https://bugzilla.mozilla.org/show_bug.cgi?id=735230#c23), so we
         // resume the compositor directly. We still need to inform Gecko about
         // the compositor resuming, so that Gecko knows that it can now draw.
         // It is important to not notify Gecko until after the compositor has
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
@@ -514,16 +514,23 @@ public class LayerView extends ScrollVie
 
     public Object getNativeWindow() {
         if (mSurfaceView != null)
             return mSurfaceView.getHolder();
 
         return mTextureView.getSurfaceTexture();
     }
 
+    public Object getSurface() {
+      if (mSurfaceView != null) {
+        return mSurfaceView.getHolder().getSurface();
+      }
+      return null;
+    }
+
     //This method is called on the Gecko main thread.
     @WrapForJNI(allowMultithread = true, stubName = "updateZoomedView")
     public static void updateZoomedView(ByteBuffer data) {
         LayerView layerView = GeckoAppShell.getLayerView();
         if (layerView != null) {
             LayerRenderer layerRenderer = layerView.getRenderer();
             if (layerRenderer != null) {
                 layerRenderer.updateZoomedView(data);
@@ -591,17 +598,17 @@ public class LayerView extends ScrollVie
         @Override
         protected void onMeasure(int aWidthSpec, int aHeightSpec) {
             setMeasuredDimension(mForcedWidth, mForcedHeight);
         }
 
         @Override
         protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
             super.onLayout(changed, left, top, right, bottom);
-            if (changed) {
+            if (changed && mParent.mGLController.isServerSurfaceValid()) {
                 mParent.surfaceChanged(right - left, bottom - top);
             }
         }
     }
 
     private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
         @Override
         public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
--- a/mobile/android/config/mozconfigs/common
+++ b/mobile/android/config/mozconfigs/common
@@ -12,17 +12,17 @@ MOZ_AUTOMATION_L10N_CHECK=0
 
 # In TaskCluster, the Java JRE/JDK are installed from tooltool, but that
 # install doesn't work on the old Buildbot mock builders (CentOS 6.2), so
 # the relevant env vars are not set up in that case, leaving the build to
 # run from the JRE/JDK in /usr/lib/jvm.
 if [ ! -f /etc/redhat-release ] || [ "$(< /etc/redhat-release)" != "CentOS release 6.2 (Final)" ]; then
     # set JAVA_HOME to find the JRE/JDK from tooltool.  Several scripts in the JDK
     # assume `java` is in PATH, so set that too.  To see how this tarball is built,
-    # see testing/taskcluster/scripts/misc/repackage-jdk.sh
+    # see taskcluster/scripts/misc/repackage-jdk.sh
     export JAVA_HOME="$topsrcdir/java_home"
     export PATH="$PATH:$topsrcdir/java_home/bin"
 
     mk_add_options "export JAVA_HOME=$topsrcdir/java_home"
     mk_add_options "export PATH=$PATH:$topsrcdir/java_home/bin"
 fi
 
 # Set the most aggressive settings for szip. Not the default because it's
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4623,19 +4623,17 @@ pref("extensions.webExtensionsMinPlatfor
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  32768);
 
 // Desktop Notification
 pref("notification.feature.enabled", false);
 
 // Web Notification
 pref("dom.webnotifications.enabled", true);
-#if !defined(RELEASE_BUILD)
 pref("dom.webnotifications.serviceworker.enabled", true);
-#endif
 
 // Alert animation effect, name is disableSlidingEffect for backwards-compat.
 pref("alerts.disableSlidingEffect", false);
 // Show favicons in web notifications.
 pref("alerts.showFavicons", false);
 
 // DOM full-screen API.
 pref("full-screen-api.enabled", false);
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -1261,24 +1261,34 @@ NS_UsePrivateBrowsing(nsIChannel *channe
     return loadContext && loadContext->UsePrivateBrowsing();
 }
 
 bool
 NS_GetOriginAttributes(nsIChannel *aChannel,
                        mozilla::NeckoOriginAttributes &aAttributes)
 {
     nsCOMPtr<nsILoadContext> loadContext;
+    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     NS_QueryNotificationCallbacks(aChannel, loadContext);
-    if (!loadContext) {
+
+    if (!loadContext && !loadInfo) {
         return false;
     }
 
-    DocShellOriginAttributes doa;
-    loadContext->GetOriginAttributes(doa);
-    aAttributes.InheritFromDocShellToNecko(doa);
+    // Bug 1270678 - By default, we would acquire the originAttributes from
+    // the loadContext. But in some cases, say, loading the favicon, that the
+    // loadContext is not available. We would use the loadInfo to get
+    // originAttributes instead.
+    if (loadContext) {
+        DocShellOriginAttributes doa;
+        loadContext->GetOriginAttributes(doa);
+        aAttributes.InheritFromDocShellToNecko(doa);
+    } else {
+        loadInfo->GetOriginAttributes(&aAttributes);
+    }
     aAttributes.SyncAttributesWithPrivateBrowsing(NS_UsePrivateBrowsing(aChannel));
     return true;
 }
 
 bool
 NS_GetAppInfo(nsIChannel *aChannel,
               uint32_t *aAppID,
               bool *aIsInIsolatedMozBrowserElement)
--- a/netwerk/test/unit/test_authentication.js
+++ b/netwerk/test/unit/test_authentication.js
@@ -288,18 +288,17 @@ var listener = {
 function makeChan(url, loadingUrl) {
   var ios = Cc["@mozilla.org/network/io-service;1"].
               getService(Ci.nsIIOService);
   var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
               .getService(Ci.nsIScriptSecurityManager);
   var principal = ssm.createCodebasePrincipal(ios.newURI(loadingUrl, null, null), {});
   return NetUtil.newChannel(
     { uri: url, loadingPrincipal: principal,
-      securityFlags: Ci.nsILoadInfo.SEC_NORMAL |
-                     Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
+      securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
       contentPolicyType: Components.interfaces.nsIContentPolicy.TYPE_OTHER
     });
 }
 
 var tests = [test_noauth, test_returnfalse1, test_wrongpw1, test_prompt1,
              test_prompt1CrossOrigin, test_prompt2CrossOrigin,
              test_returnfalse2, test_wrongpw2, test_prompt2, test_ntlm,
              test_basicrealm, test_digest_noauth, test_digest,
--- a/old-configure.in
+++ b/old-configure.in
@@ -1085,16 +1085,34 @@ if test "$MOZ_PROFILING" -a -z "$STRIP_F
     case "$OS_TARGET" in
     Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
         STRIP_FLAGS="--strip-debug"
         ;;
     esac
 fi
 
 dnl ========================================================
+dnl = Enable Gecko integrated IPC fuzzer
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(ipc-fuzzer,
+[  --enable-ipc-fuzzer       Enable IPC fuzzer (default=no)],
+    MOZ_FAULTY=1,
+    MOZ_FAULTY= )
+AC_SUBST(MOZ_FAULTY)
+
+if test -n "$MOZ_FAULTY" && test "$OS_ARCH" = "WINNT"; then
+    AC_MSG_ERROR([--enable-ipc-fuzzer is not supported on this platform.])
+fi
+
+if test -n "$MOZ_FAULTY"; then
+    MOZ_FAULTY=1
+    AC_DEFINE(MOZ_FAULTY)
+fi
+
+dnl ========================================================
 dnl = Enable DMD
 dnl ========================================================
 
 if test "$MOZ_DMD"; then
     if test "${CPU_ARCH}" = "arm"; then
         CFLAGS="$CFLAGS -funwind-tables"
         CXXFLAGS="$CXXFLAGS -funwind-tables"
     fi
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -1,68 +1,30 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import __main__
 import argparse
-import json
 import logging
 import mozpack.path as mozpath
 import os
-import platform
-import subprocess
-import sys
-import which
-from distutils.version import LooseVersion
 
 from mozbuild.base import (
     MachCommandBase,
 )
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
-ESLINT_PACKAGES = [
-    "eslint@2.9.0",
-    "eslint-plugin-html@1.4.0",
-    "eslint-plugin-mozilla@0.0.3",
-    "eslint-plugin-react@4.2.3"
-]
-
-ESLINT_NOT_FOUND_MESSAGE = '''
-Could not find eslint!  We looked at the --binary option, at the ESLINT
-environment variable, and then at your local node_modules path. Please Install
-eslint and needed plugins with:
-
-mach eslint --setup
-
-and try again.
-'''.strip()
-
-NODE_NOT_FOUND_MESSAGE = '''
-nodejs v4.2.3 is either not installed or is installed to a non-standard path.
-Please install nodejs from https://nodejs.org and try again.
-
-Valid installation paths:
-'''.strip()
-
-NPM_NOT_FOUND_MESSAGE = '''
-Node Package Manager (npm) is either not installed or installed to a
-non-standard path. Please install npm from https://nodejs.org (it comes as an
-option in the node installation) and try again.
-
-Valid installation paths:
-'''.strip()
-
 
 @CommandProvider
 class MachCommands(MachCommandBase):
     @Command('python', category='devenv',
         description='Run Python.')
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def python(self, args):
         # Avoid logging the command
@@ -194,277 +156,8 @@ class MachCommands(MachCommandBase):
             message = 'TEST-UNEXPECTED-FAIL | No tests collected'
             if not path_only:
                  message += ' (Not in PYTHON_UNIT_TESTS? Try --path-only?)'
             self.log(logging.WARN, 'python-test', {}, message)
             return 1
 
         return 0 if return_code == 0 else 1
 
-    @Command('eslint', category='devenv',
-        description='Run eslint or help configure eslint for optimal development.')
-    @CommandArgument('-s', '--setup', default=False, action='store_true',
-        help='configure eslint for optimal development.')
-    @CommandArgument('-e', '--ext', default='[.js,.jsm,.jsx,.xml,.html]',
-        help='Filename extensions to lint, default: "[.js,.jsm,.jsx,.xml,.html]".')
-    @CommandArgument('-b', '--binary', default=None,
-        help='Path to eslint binary.')
-    @CommandArgument('args', nargs=argparse.REMAINDER)  # Passed through to eslint.
-    def eslint(self, setup, ext=None, binary=None, args=None):
-        '''Run eslint.'''
-
-        module_path = self.get_eslint_module_path()
-
-        # eslint requires at least node 4.2.3
-        nodePath = self.getNodeOrNpmPath("node", LooseVersion("4.2.3"))
-        if not nodePath:
-            return 1
-
-        if setup:
-            return self.eslint_setup()
-
-        npmPath = self.getNodeOrNpmPath("npm")
-        if not npmPath:
-            return 1
-
-        if self.eslintModuleHasIssues():
-            install = self._prompt_yn("\nContinuing will automatically fix "
-                                      "these issues. Would you like to "
-                                      "continue")
-            if install:
-                self.eslint_setup()
-            else:
-                return 1
-
-        # Valid binaries are:
-        #  - Any provided by the binary argument.
-        #  - Any pointed at by the ESLINT environmental variable.
-        #  - Those provided by mach eslint --setup.
-        #
-        #  eslint --setup installs some mozilla specific plugins and installs
-        #  all node modules locally. This is the preferred method of
-        #  installation.
-
-        if not binary:
-            binary = os.environ.get('ESLINT', None)
-
-            if not binary:
-                binary = os.path.join(module_path, "node_modules", ".bin", "eslint")
-                if not os.path.isfile(binary):
-                    binary = None
-
-        if not binary:
-            print(ESLINT_NOT_FOUND_MESSAGE)
-            return 1
-
-        self.log(logging.INFO, 'eslint', {'binary': binary, 'args': args},
-            'Running {binary}')
-
-        args = args or ['.']
-
-        cmd_args = [binary,
-                    # Enable the HTML plugin.
-                    # We can't currently enable this in the global config file
-                    # because it has bad interactions with the SublimeText
-                    # ESLint plugin (bug 1229874).
-                    '--plugin', 'html',
-                    '--ext', ext,  # This keeps ext as a single argument.
-                    ] + args
-
-        success = self.run_process(cmd_args,
-            pass_thru=True,  # Allow user to run eslint interactively.
-            ensure_exit_code=False,  # Don't throw on non-zero exit code.
-            require_unix_environment=True # eslint is not a valid Win32 binary.
-        )
-
-        self.log(logging.INFO, 'eslint', {'msg': ('No errors' if success == 0 else 'Errors')},
-            'Finished eslint. {msg} encountered.')
-        return success
-
-    def eslint_setup(self, update_only=False):
-        """Ensure eslint is optimally configured.
-
-        This command will inspect your eslint configuration and
-        guide you through an interactive wizard helping you configure
-        eslint for optimal use on Mozilla projects.
-        """
-        orig_cwd = os.getcwd()
-        sys.path.append(os.path.dirname(__file__))
-
-        module_path = self.get_eslint_module_path()
-
-        # npm sometimes fails to respect cwd when it is run using check_call so
-        # we manually switch folders here instead.
-        os.chdir(module_path)
-
-        npmPath = self.getNodeOrNpmPath("npm")
-        if not npmPath:
-            return 1
-
-        # Install eslint and necessary plugins.
-        for pkg in ESLINT_PACKAGES:
-            name, version = pkg.split("@")
-            success = False
-
-            if self.node_package_installed(pkg, cwd=module_path):
-                success = True
-            else:
-                if pkg.startswith("eslint-plugin-mozilla"):
-                    cmd = [npmPath, "install",
-                           os.path.join(module_path, "eslint-plugin-mozilla")]
-                else:
-                    cmd = [npmPath, "install", pkg]
-
-                print("Installing %s v%s using \"%s\"..."
-                      % (name, version, " ".join(cmd)))
-                success = self.callProcess(pkg, cmd)
-
-            if not success:
-                return 1
-
-        eslint_path = os.path.join(module_path, "node_modules", ".bin", "eslint")
-
-        print("\nESLint and approved plugins installed successfully!")
-        print("\nNOTE: Your local eslint binary is at %s\n" % eslint_path)
-
-        os.chdir(orig_cwd)
-
-    def callProcess(self, name, cmd, cwd=None):
-        try:
-            with open(os.devnull, "w") as fnull:
-                subprocess.check_call(cmd, cwd=cwd, stdout=fnull)
-        except subprocess.CalledProcessError:
-            if cwd:
-                print("\nError installing %s in the %s folder, aborting." % (name, cwd))
-            else:
-                print("\nError installing %s, aborting." % name)
-
-            return False
-
-        return True
-
-    def eslintModuleHasIssues(self):
-        has_issues = False
-        node_module_path = os.path.join(self.get_eslint_module_path(), "node_modules")
-
-        for pkg in ESLINT_PACKAGES:
-            name, req_version = pkg.split("@")
-            path = os.path.join(node_module_path, name, "package.json")
-
-            if not os.path.exists(path):
-                print("%s v%s needs to be installed locally." % (name, req_version))
-                has_issues = True
-                continue
-
-            data = json.load(open(path))
-
-            if data["version"] != req_version:
-                print("%s v%s should be v%s." % (name, version, req_version))
-                has_issues = True
-
-        return has_issues
-
-    def node_package_installed(self, package_name="", globalInstall=False, cwd=None):
-        try:
-            npmPath = self.getNodeOrNpmPath("npm")
-
-            cmd = [npmPath, "ls", "--parseable", package_name]
-
-            if globalInstall:
-                cmd.append("-g")
-
-            with open(os.devnull, "w") as fnull:
-                subprocess.check_call(cmd, stdout=fnull, stderr=fnull, cwd=cwd)
-
-            return True
-        except subprocess.CalledProcessError:
-            return False
-
-    def getPossibleNodePathsWin(self):
-        """
-        Return possible nodejs paths on Windows.
-        """
-        if platform.system() != "Windows":
-            return []
-
-        return list({
-            "%s\\nodejs" % os.environ.get("SystemDrive"),
-            os.path.join(os.environ.get("ProgramFiles"), "nodejs"),
-            os.path.join(os.environ.get("PROGRAMW6432"), "nodejs"),
-            os.path.join(os.environ.get("PROGRAMFILES"), "nodejs")
-        })
-
-    def getNodeOrNpmPath(self, filename, minversion=None):
-        """
-        Return the nodejs or npm path.
-        """
-        if platform.system() == "Windows":
-            for ext in [".cmd", ".exe", ""]:
-                try:
-                    nodeOrNpmPath = which.which(filename + ext,
-                                                path=self.getPossibleNodePathsWin())
-                    if self.is_valid(nodeOrNpmPath, minversion):
-                        return nodeOrNpmPath
-                except which.WhichError:
-                    pass
-        else:
-            try:
-                nodeOrNpmPath = which.which(filename)
-                if self.is_valid(nodeOrNpmPath, minversion):
-                    return nodeOrNpmPath
-            except which.WhichError:
-                pass
-
-        if filename == "node":
-            print(NODE_NOT_FOUND_MESSAGE)
-        elif filename == "npm":
-            print(NPM_NOT_FOUND_MESSAGE)
-
-        if platform.system() == "Windows":
-            appPaths = self.getPossibleNodePathsWin()
-
-            for p in appPaths:
-                print("  - %s" % p)
-        elif platform.system() == "Darwin":
-            print("  - /usr/local/bin/node")
-        elif platform.system() == "Linux":
-            print("  - /usr/bin/nodejs")
-
-        return None
-
-    def is_valid(self, path, minversion = None):
-        try:
-            version_str = subprocess.check_output([path, "--version"],
-                                                  stderr=subprocess.STDOUT)
-            if minversion:
-                # nodejs prefixes its version strings with "v"
-                version = LooseVersion(version_str.lstrip('v'))
-                return version >= minversion
-            return True
-        except (subprocess.CalledProcessError, OSError):
-            return False
-
-    def get_project_root(self):
-        fullpath = os.path.abspath(sys.modules['__main__'].__file__)
-        return os.path.dirname(fullpath)
-
-    def get_eslint_module_path(self):
-        return os.path.join(self.get_project_root(), "testing", "eslint")
-
-    def _prompt_yn(self, msg):
-        if not sys.stdin.isatty():
-            return False
-
-        print('%s? [Y/n]' % msg)
-
-        while True:
-            choice = raw_input().lower().strip()
-
-            if not choice:
-                return True
-
-            if choice in ('y', 'yes'):
-                return True
-
-            if choice in ('n', 'no'):
-                return False
-
-            print('Must reply with one of {yes, no, y, n}.')
--- a/taskcluster/ci/legacy/kind.yml
+++ b/taskcluster/ci/legacy/kind.yml
@@ -1,6 +1,6 @@
 # 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/.
 
 implementation: 'taskgraph.kind.legacy:LegacyKind'
-legacy_path: '../../../testing/taskcluster'
+legacy_path: '.'
rename from testing/taskcluster/routes.json
rename to taskcluster/ci/legacy/routes.json
rename from testing/taskcluster/tasks/branches/alder/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/alder/job_flags.yml
rename from testing/taskcluster/tasks/branches/ash/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/ash/job_flags.yml
rename from testing/taskcluster/tasks/branches/autoland/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/autoland/job_flags.yml
rename from testing/taskcluster/tasks/branches/b2g-inbound/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/b2g-inbound/job_flags.yml
rename from testing/taskcluster/tasks/branches/base_job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/base_job_flags.yml
--- a/testing/taskcluster/tasks/branches/base_job_flags.yml
+++ b/taskcluster/ci/legacy/tasks/branches/base_job_flags.yml
@@ -1,88 +1,12 @@
 ---
 # List of all possible flags for each category of tests used in the case where
 # "all" is specified.
 flags:
-  aliases:
-    # Aliases specify shorthands that can be used in try syntax.  An alias can
-    # specify a simple replacement:
-    #   fb: foobar  -- replaces fb with foobar
-    #
-    # or an expansion into several test suites (which cannot themselves be
-    # aliases):
-    #   footests:
-    #     - foo
-    #     - bar
-    #     - bing
-    #
-    # or a pattern or patterns (identified by leading and trailing /) that
-    # will be matched against the available flags
-    #   dt: /devtools.*/
-    #   footests:
-    #     - browser-foo
-    #     - /foo.*/   -- selects all defined flags starting with "foo"
-    #
-    # Note that alias expansion is performed in the absence of any chunk
-    # prefixes.  For example, the first example above would replace "foo-7"
-    # with "foobar-7".  Note that a few aliases allowed chunks to be specified
-    # without a leading `-`, for example 'mochitest-dt1'. That's no longer
-    # supported.
-    cppunit: /cppunit.*/
-    crashtest: /crashtest.*/
-    crashtest-e10s: /crashtest-e10s.*/
-    e10s: /.*e10s.*/
-    external-media-tests: /external-media-tests.*/
-    firefox-ui-functional: /firefox-ui-functional.*/
-    firefox-ui-functional-e10s: /firefox-ui-functional-e10s.*/
-    gaia-js-integration: /.*gaia-js-integration.*/
-    gtest: /gtest.*/
-    jittest: /jittest.*/
-    jittests: /jittest.*/
-    jsreftest: /jsreftest.*/
-    jsreftest-e10s: /jsreftest-e10s.*/
-    luciddream: /luciddream.*/
-    marionette: /marionette.*/
-    marionette-e10s: /marionette-e10s.*/
-    mochitest: /mochitest.*/
-    mochitests: /mochitest.*/
-    mochitest-e10s: /mochitest-e10s.*/
-    mochitests-e10s: /mochitest-e10s.*/
-    mochitest-debug: /mochitest-debug-.*/
-    mochitest-a11y: /.*mochitest-a11y.*/
-    mochitest-bc: /mochitest-browser-chrome.*/
-    mochitest-bc-e10s: /mochitest-browser-chrome-e10s.*/
-    mochitest-browser-chrome: /mochitest-browser-chrome.*/
-    mochitest-browser-chrome-e10s: /mochitest-browser-chrome-e10s.*/
-    mochitest-chrome: /.*mochitest-chrome.*/
-    mochitest-dt: /mochitest-devtools-chrome.*/
-    mochitest-dt-e10s: /mochitest-devtools-chrome-e10s.*/
-    mochitest-gl: /mochitest-webgl.*/
-    mochitest-gl-e10s: /mochitest-webgl-e10s.*/
-    mochitest-gpu: /mochitest-gpu.*/
-    mochitest-gpu-e10s: /mochitest-gpu-e10s.*/
-    mochitest-clipboard: /mochitest-clipboard.*/
-    mochitest-clipboard-e10s: /mochitest-clipboard-e10s.*/
-    mochitest-jetpack: /mochitest-jetpack.*/
-    mochitest-media: /mochitest-media.*/
-    mochitest-media-e10s: /mochitest-media-e10s.*/
-    mochitest-vg: /mochitest-valgrind.*/
-    reftest: /(plain-)?reftest.*/
-    reftest-no-accel: /(plain-)?reftest-no-accel.*/
-    reftests: /(plain-)?reftest.*/
-    reftests-e10s: /(plain-)?reftest-e10s.*/
-    reftest-no-accel-e10s: /(plain-)?reftest-no-accel-e10s.*/
-    robocop: /robocop.*/
-    web-platform-test: /web-platform-tests.*/
-    web-platform-tests: /web-platform-tests.*/
-    web-platform-tests-e10s: /web-platform-tests-e10s.*/
-    web-platform-tests-reftests: /web-platform-tests-reftests.*/
-    web-platform-tests-reftests-e10s: /web-platform-tests-reftests-e10s.*/
-    xpcshell: /xpcshell.*/
-
   builds:
     - linux32_gecko  # b2g desktop linux 32 bit
     - linux64_gecko  # b2g desktop linux 64 bit
     - linux64-mulet  # Firefox desktop - b2g gecko linux 64 bit
     - linux64-haz    # Firefox desktop browser, rooting hazard analysis
     - linux64-shell-haz  # JS shell, rooting hazard analysis
     - linux64-mulet-haz  # Firefox desktop - b2g gecko linux 64 bit, rooting hazard analysis
     - macosx64_gecko # b2g desktop osx 64 bit
rename from testing/taskcluster/tasks/branches/base_jobs.yml
rename to taskcluster/ci/legacy/tasks/branches/base_jobs.yml
--- a/testing/taskcluster/tasks/branches/base_jobs.yml
+++ b/taskcluster/ci/legacy/tasks/branches/base_jobs.yml
@@ -523,17 +523,17 @@ tasks:
         - '**/*.jsm'
         - '**/*.jsx'
         - '**/*.html'
         - '**/*.xml'
         # Run when eslint policies change.
         - '**/.eslintignore'
         - '**/*eslintrc*'
         # The plugin implementing custom checks.
-        - 'testing/eslint/eslint-plugin-mozilla/**'
+        - 'tools/lint/eslint/eslint-plugin-mozilla/**'
         # Other misc lint related files.
         - 'tools/lint/**'
         - 'testing/docker/lint/**'
   flake8-gecko:
     task: tasks/tests/mozlint-flake8.yml
     root: true
     when:
       file_patterns:
@@ -592,16 +592,16 @@ tasks:
           - 'testing/marionette/harness/**'
           - 'testing/mozharness/scripts/marionette_harness_tests.py'
   linux64-gcc:
     task: tasks/builds/linux64_gcc.yml
     root: true
     when:
         file_patterns:
           - 'build/unix/build-gcc/**'
-          - 'testing/taskcluster/scripts/misc/build-gcc-linux.sh'
+          - 'taskcluster/scripts/misc/build-gcc-linux.sh'
   linux64-clang:
     task: tasks/builds/linux64_clang.yml
     root: true
     when:
         file_patterns:
           - 'build/build-clang/**'
-          - 'testing/taskcluster/scripts/misc/build-clang-linux.sh'
+          - 'taskcluster/scripts/misc/build-clang-linux.sh'
rename from testing/taskcluster/tasks/branches/fx-team/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/fx-team/job_flags.yml
rename from testing/taskcluster/tasks/branches/larch/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/larch/job_flags.yml
rename from testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/mozilla-central/job_flags.yml
rename from testing/taskcluster/tasks/branches/mozilla-inbound/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/mozilla-inbound/job_flags.yml
rename from testing/taskcluster/tasks/branches/try/job_flags.yml
rename to taskcluster/ci/legacy/tasks/branches/try/job_flags.yml
rename from testing/taskcluster/tasks/build.yml
rename to taskcluster/ci/legacy/tasks/build.yml
rename from testing/taskcluster/tasks/builds/android_api_15.yml
rename to taskcluster/ci/legacy/tasks/builds/android_api_15.yml
rename from testing/taskcluster/tasks/builds/android_api_15_gradle_dependencies.yml
rename to taskcluster/ci/legacy/tasks/builds/android_api_15_gradle_dependencies.yml
rename from testing/taskcluster/tasks/builds/android_api_15_partner_sample1.yml
rename to taskcluster/ci/legacy/tasks/builds/android_api_15_partner_sample1.yml
rename from testing/taskcluster/tasks/builds/android_checkstyle.yml
rename to taskcluster/ci/legacy/tasks/builds/android_checkstyle.yml
rename from testing/taskcluster/tasks/builds/android_lint.yml
rename to taskcluster/ci/legacy/tasks/builds/android_lint.yml
rename from testing/taskcluster/tasks/builds/android_test.yml
rename to taskcluster/ci/legacy/tasks/builds/android_test.yml
rename from testing/taskcluster/tasks/builds/b2g_aries_eng.yml
rename to taskcluster/ci/legacy/tasks/builds/b2g_aries_eng.yml
rename from testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml
rename to taskcluster/ci/legacy/tasks/builds/b2g_aries_spark_debug.yml
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml
+++ b/taskcluster/ci/legacy/tasks/builds/b2g_aries_spark_debug.yml
@@ -20,17 +20,17 @@ task:
       DEBUG: 0
       VARIANT: userdebug
       GAIA_OPTIMIZE: '1'
       B2G_SYSTEM_APPS: '1'
       MOZHARNESS_CONFIG: b2g/taskcluster-spark.py
     command:
       - >
         checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder &&
+        cd ./workspace/gecko/taskcluster/scripts/phone-builder &&
         buildbot_step 'Build' ./build-phone.sh $HOME/workspace
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
       groupSymbol: Aries
rename from testing/taskcluster/tasks/builds/b2g_base.yml
rename to taskcluster/ci/legacy/tasks/builds/b2g_base.yml
rename from testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml
rename to taskcluster/ci/legacy/tasks/builds/b2g_nexus_5l_eng.yml
--- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml
+++ b/taskcluster/ci/legacy/tasks/builds/b2g_nexus_5l_eng.yml
@@ -15,17 +15,17 @@ task:
       level-{{level}}-{{project}}-build-nexus-5-l-eng: /home/worker/object-folder
       level-{{level}}-{{project}}-build-nexus-5-l-eng-objdir-gecko: /home/worker/objdir-gecko
     env:
       TARGET: 'nexus-5-l'
       DEBUG: 0
     command:
       - >
         checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder &&
+        cd ./workspace/gecko/taskcluster/scripts/phone-builder &&
         buildbot_step 'Build' ./build-phone.sh $HOME/workspace
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Nexus 5-L
rename from testing/taskcluster/tasks/builds/b2g_phone_base.yml
rename to taskcluster/ci/legacy/tasks/builds/b2g_phone_base.yml
rename from testing/taskcluster/tasks/builds/b2g_phone_eng_base.yml
rename to taskcluster/ci/legacy/tasks/builds/b2g_phone_eng_base.yml
--- a/testing/taskcluster/tasks/builds/b2g_phone_eng_base.yml
+++ b/taskcluster/ci/legacy/tasks/builds/b2g_phone_eng_base.yml
@@ -11,10 +11,10 @@ task:
       B2G_SYSTEM_APPS: '1'
       MOZ_TELEMETRY_REPORTING: '1'
       MOZ_CRASHREPORTER_NO_REPORT: '1'
       GAIA_KEYBOARD_LAYOUTS: 'en,pt-BR,es,de,fr,pl,zh-Hans-Pinyin,zh-Hant-Zhuyin,en-Dvorak'
       B2G_UPDATE_CHANNEL: 'default'
     command:
       - >
         checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder &&
+        cd ./workspace/gecko/taskcluster/scripts/phone-builder &&
         buildbot_step 'Build' ./build-phone.sh $HOME/workspace
rename from testing/taskcluster/tasks/builds/base_linux32.yml
rename to taskcluster/ci/legacy/tasks/builds/base_linux32.yml
rename from testing/taskcluster/tasks/builds/base_linux64.yml
rename to taskcluster/ci/legacy/tasks/builds/base_linux64.yml
rename from testing/taskcluster/tasks/builds/base_macosx64.yml
rename to taskcluster/ci/legacy/tasks/builds/base_macosx64.yml
rename from testing/taskcluster/tasks/builds/dbg_linux32.yml
rename to taskcluster/ci/legacy/tasks/builds/dbg_linux32.yml
rename from testing/taskcluster/tasks/builds/dbg_linux64-asan.yml
rename to taskcluster/ci/legacy/tasks/builds/dbg_linux64-asan.yml
rename from testing/taskcluster/tasks/builds/dbg_linux64.yml
rename to taskcluster/ci/legacy/tasks/builds/dbg_linux64.yml
rename from testing/taskcluster/tasks/builds/dbg_macosx64.yml
rename to taskcluster/ci/legacy/tasks/builds/dbg_macosx64.yml
rename from testing/taskcluster/tasks/builds/firefox_base.yml
rename to taskcluster/ci/legacy/tasks/builds/firefox_base.yml
rename from testing/taskcluster/tasks/builds/haz_linux.yml
rename to taskcluster/ci/legacy/tasks/builds/haz_linux.yml
--- a/testing/taskcluster/tasks/builds/haz_linux.yml
+++ b/taskcluster/ci/legacy/tasks/builds/haz_linux.yml
@@ -30,17 +30,17 @@ task:
 
     maxRunTime: 36000
 
     command:
       - /bin/bash
       - -c
       - >
         tc-vcs checkout workspace/gecko "$GECKO_BASE_REPOSITORY" "$GECKO_HEAD_REPOSITORY" "$GECKO_HEAD_REV" "$GECKO_HEAD_REF" &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/builder &&
+        cd ./workspace/gecko/taskcluster/scripts/builder &&
         ./build-haz-linux.sh --project browser $HOME/workspace
 
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       machine:
rename from testing/taskcluster/tasks/builds/haz_shell_linux.yml
rename to taskcluster/ci/legacy/tasks/builds/haz_shell_linux.yml
--- a/testing/taskcluster/tasks/builds/haz_shell_linux.yml
+++ b/taskcluster/ci/legacy/tasks/builds/haz_shell_linux.yml
@@ -29,17 +29,17 @@ task:
 
     maxRunTime: 36000
 
     command:
       - /bin/bash
       - -c
       - >
         tc-vcs checkout workspace/gecko "$GECKO_BASE_REPOSITORY" "$GECKO_HEAD_REPOSITORY" "$GECKO_HEAD_REV" "$GECKO_HEAD_REF" &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/builder &&
+        cd ./workspace/gecko/taskcluster/scripts/builder &&
         ./build-haz-linux.sh --project shell $HOME/workspace
 
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       machine:
rename from testing/taskcluster/tasks/builds/linux64_clang.yml
rename to taskcluster/ci/legacy/tasks/builds/linux64_clang.yml
--- a/testing/taskcluster/tasks/builds/linux64_clang.yml
+++ b/taskcluster/ci/legacy/tasks/builds/linux64_clang.yml
@@ -23,17 +23,17 @@ task:
 
     env:
       MOZHARNESS_DISABLE: 'true'
       TOOLS_DISABLE: 'true'
       TOOLTOOL_CACHE: '/home/worker/tooltool-cache'
 
     maxRunTime: 36000
 
-    command: ["/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/testing/taskcluster/scripts/misc/build-clang-linux.sh" ]
+    command: ["/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/taskcluster/scripts/misc/build-clang-linux.sh" ]
 
     artifacts:
       'public/clang.tar.xz':
         type: file
         path: '/home/worker/workspace/artifacts/clang.tar.xz'
         expires: '{{#from_now}}1 year{{/from_now}}'
 
   extra:
rename from testing/taskcluster/tasks/builds/linux64_gcc.yml
rename to taskcluster/ci/legacy/tasks/builds/linux64_gcc.yml
--- a/testing/taskcluster/tasks/builds/linux64_gcc.yml
+++ b/taskcluster/ci/legacy/tasks/builds/linux64_gcc.yml
@@ -16,17 +16,17 @@ task:
 
   payload:
     env:
       MOZHARNESS_DISABLE: 'true'
       TOOLS_DISABLE: 'true'
 
     maxRunTime: 36000
 
-    command: ["/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/testing/taskcluster/scripts/misc/build-gcc-linux.sh" ]
+    command: ["/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/taskcluster/scripts/misc/build-gcc-linux.sh" ]
 
     artifacts:
       'public/gcc.tar.xz':
         type: file
         path: '/home/worker/workspace/artifacts/gcc.tar.xz'
         expires: '{{#from_now}}1 year{{/from_now}}'
 
   extra:
rename from testing/taskcluster/tasks/builds/mobile_base.yml
rename to taskcluster/ci/legacy/tasks/builds/mobile_base.yml
rename from testing/taskcluster/tasks/builds/mulet_haz_linux.yml
rename to taskcluster/ci/legacy/tasks/builds/mulet_haz_linux.yml
--- a/testing/taskcluster/tasks/builds/mulet_haz_linux.yml
+++ b/taskcluster/ci/legacy/tasks/builds/mulet_haz_linux.yml
@@ -33,17 +33,17 @@ task:
 
     maxRunTime: 36000
 
     command:
       - /bin/bash
       - -c
       - >
         checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/builder &&
+        cd ./workspace/gecko/taskcluster/scripts/builder &&
         buildbot_step 'Build' ./build-mulet-haz-linux.sh $HOME/workspace
 
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       groupSymbol: "tc"
rename from testing/taskcluster/tasks/builds/mulet_linux.yml
rename to taskcluster/ci/legacy/tasks/builds/mulet_linux.yml
--- a/testing/taskcluster/tasks/builds/mulet_linux.yml
+++ b/taskcluster/ci/legacy/tasks/builds/mulet_linux.yml
@@ -33,17 +33,17 @@ task:
 
     maxRunTime: 3600
 
     command:
       - /bin/bash
       - -c
       - >
         checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/builder &&
+        cd ./workspace/gecko/taskcluster/scripts/builder &&
         buildbot_step 'Build' ./build-mulet-linux.sh $HOME/workspace
 
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       # Disable "TC" prefix...
rename from testing/taskcluster/tasks/builds/opt_linux32.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux32.yml
rename from testing/taskcluster/tasks/builds/opt_linux64-asan.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux64-asan.yml
rename from testing/taskcluster/tasks/builds/opt_linux64.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux64.yml
rename from testing/taskcluster/tasks/builds/opt_linux64_artifact.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux64_artifact.yml
rename from testing/taskcluster/tasks/builds/opt_linux64_pgo.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux64_pgo.yml
rename from testing/taskcluster/tasks/builds/opt_linux64_st-an.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux64_st-an.yml
rename from testing/taskcluster/tasks/builds/opt_linux64_valgrind.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_linux64_valgrind.yml
rename from testing/taskcluster/tasks/builds/opt_macosx64.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_macosx64.yml
rename from testing/taskcluster/tasks/builds/opt_macosx64_st-an.yml
rename to taskcluster/ci/legacy/tasks/builds/opt_macosx64_st-an.yml
rename from testing/taskcluster/tasks/builds/sm_arm64_sim.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_arm64_sim.yml
rename from testing/taskcluster/tasks/builds/sm_arm_sim.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_arm_sim.yml
rename from testing/taskcluster/tasks/builds/sm_arm_sim_osx.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_arm_sim_osx.yml
rename from testing/taskcluster/tasks/builds/sm_base.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_base.yml
rename from testing/taskcluster/tasks/builds/sm_compacting.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_compacting.yml
rename from testing/taskcluster/tasks/builds/sm_nonunified.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_nonunified.yml
rename from testing/taskcluster/tasks/builds/sm_package.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_package.yml
--- a/testing/taskcluster/tasks/builds/sm_package.yml
+++ b/taskcluster/ci/legacy/tasks/builds/sm_package.yml
@@ -3,16 +3,16 @@
   variables:
     build_name: 'sm-package'
     build_type: 'opt'
 task:
   payload:
     env:
       SPIDERMONKEY_VARIANT: 'plain'
 
-    command: [ "/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/testing/taskcluster/scripts/builder/build-sm-package.sh" ]
+    command: [ "/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/taskcluster/scripts/builder/build-sm-package.sh" ]
 
   metadata:
     name: '[TC] Spidermonkey Package'
     description: 'Spidermonkey Package'
   extra:
     treeherder:
       symbol: pkg
rename from testing/taskcluster/tasks/builds/sm_plain.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_plain.yml
rename from testing/taskcluster/tasks/builds/sm_plaindebug.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_plaindebug.yml
rename from testing/taskcluster/tasks/builds/sm_rootanalysis.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_rootanalysis.yml
rename from testing/taskcluster/tasks/builds/sm_variant_base.yml
rename to taskcluster/ci/legacy/tasks/builds/sm_variant_base.yml
--- a/testing/taskcluster/tasks/builds/sm_variant_base.yml
+++ b/taskcluster/ci/legacy/tasks/builds/sm_variant_base.yml
@@ -1,5 +1,5 @@
 $inherits:
   from: 'tasks/builds/sm_base.yml'
 task:
   payload:
-    command: ["/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/testing/taskcluster/scripts/builder/build-sm.sh" ]
+    command: ["/bin/bash", "-c", "cd /home/worker/ && ./bin/checkout-sources.sh && ./workspace/build/src/taskcluster/scripts/builder/build-sm.sh" ]
rename from testing/taskcluster/tasks/decision/branch.yml
rename to taskcluster/ci/legacy/tasks/decision/branch.yml
rename from testing/taskcluster/tasks/decision/periodic_alder.yml
rename to taskcluster/ci/legacy/tasks/decision/periodic_alder.yml
rename from testing/taskcluster/tasks/decision/try.yml
rename to taskcluster/ci/legacy/tasks/decision/try.yml
rename from testing/taskcluster/tasks/harness_test.yml
rename to taskcluster/ci/legacy/tasks/harness_test.yml
rename from testing/taskcluster/tasks/image.yml
rename to taskcluster/ci/legacy/tasks/image.yml
rename from testing/taskcluster/tasks/lint.yml
rename to taskcluster/ci/legacy/tasks/lint.yml
rename from testing/taskcluster/tasks/phone_build.yml
rename to taskcluster/ci/legacy/tasks/phone_build.yml
rename from testing/taskcluster/tasks/post-builds/mulet_simulator.yml
rename to taskcluster/ci/legacy/tasks/post-builds/mulet_simulator.yml
rename from testing/taskcluster/tasks/post-builds/upload_symbols.yml
rename to taskcluster/ci/legacy/tasks/post-builds/upload_symbols.yml
rename from testing/taskcluster/tasks/test.yml
rename to taskcluster/ci/legacy/tasks/test.yml
rename from testing/taskcluster/tasks/tests/b2g_unittest_base.yml
rename to taskcluster/ci/legacy/tasks/tests/b2g_unittest_base.yml
rename from testing/taskcluster/tasks/tests/eslint-gecko.yml
rename to taskcluster/ci/legacy/tasks/tests/eslint-gecko.yml
--- a/testing/taskcluster/tasks/tests/eslint-gecko.yml
+++ b/taskcluster/ci/legacy/tasks/tests/eslint-gecko.yml
@@ -19,22 +19,22 @@ task:
       taskId:
         task-reference: "<docker-image>"
 
     command:
       - bash
       - -cx
       - >
           tc-vcs checkout ./gecko {{base_repository}} {{head_repository}} {{head_rev}} {{head_ref}} &&
-          cd gecko/testing/eslint &&
+          cd gecko/tools/lint/eslint &&
           /build/tooltool.py fetch -m manifest.tt &&
           tar xvfz eslint.tar.gz &&
           rm eslint.tar.gz &&
-          cd ../.. &&
-          testing/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter .
+          cd ../../.. &&
+          tools/lint/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter .
 
   extra:
     locations:
         build: null
         tests: null
     treeherder:
         machine:
             platform: lint
rename from testing/taskcluster/tasks/tests/fx_desktop_generic.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_desktop_generic.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_cppunit.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_cppunit.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_cppunit_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_cppunit_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_cppunit_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_cppunit_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_crashtest.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_crashtest.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_crashtest_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_crashtest_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_crashtest_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_crashtest_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_crashtest_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_crashtest_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_crashtest_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_crashtest_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_crashtest_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_crashtest_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_external_media_tests.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_external_media_tests.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_external_media_tests_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_external_media_tests_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_external_media_tests_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_external_media_tests_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_firefox_ui_functional.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_firefox_ui_functional_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_firefox_ui_functional_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_firefox_ui_functional_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_firefox_ui_functional_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_functional_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_firefox_ui_functional_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_gtest.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_gtest.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_gtest_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_gtest_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_gtest_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_gtest_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jittests.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jittests.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jittests_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jittests_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jittests_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jittests_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jsreftest.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jsreftest.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jsreftest_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jsreftest_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jsreftest_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jsreftest_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jsreftest_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jsreftest_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jsreftest_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jsreftest_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_jsreftest_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_jsreftest_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_luciddream.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_luciddream.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_marionette.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_marionette.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_marionette_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_marionette_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_marionette_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_marionette_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_marionette_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_marionette_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_marionette_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_marionette_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_marionette_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_marionette_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_a11y.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_a11y.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_a11y_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_a11y_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_a11y_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_a11y_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_bc.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_bc_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_bc_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_bc_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_bc_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_bc_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_bc_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_chrome.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_chrome.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_chrome_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_chrome_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_chrome_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_chrome_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_clipboard.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_clipboard_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_clipboard_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_clipboard_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_clipboard_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_clipboard_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_dt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_dt_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_dt_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_dt_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_dt_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_dt_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_dt_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gl.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gl_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gl_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gl_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gl_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gl_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gl_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gpu.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gpu_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gpu_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gpu_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gpu_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_gpu_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_jetpack.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_jetpack.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_jetpack_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_jetpack_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_jetpack_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_jetpack_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_media.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_media.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_media_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_media_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_media_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_media_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_media_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_media_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_plain.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_plain_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_plain_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_plain_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_plain_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_plain_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_plain_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_mochitest_vg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_mochitest_vg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_not_accelerated.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_not_accelerated_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_not_accelerated_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_not_accelerated_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_not_accelerated_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_not_accelerated_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_not_accelerated_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_reftest_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_reftest_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_reftests.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_reftests_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_reftests_e10s_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_web_platform_tests_reftests_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_web_platform_tests_reftests_opt.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_xpcshell.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_xpcshell.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_xpcshell_dbg.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_xpcshell_dbg.yml
rename from testing/taskcluster/tasks/tests/fx_linux64_xpcshell_opt.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_linux64_xpcshell_opt.yml
rename from testing/taskcluster/tasks/tests/fx_test_base.yml
rename to taskcluster/ci/legacy/tasks/tests/fx_test_base.yml
rename from testing/taskcluster/tasks/tests/harness_marionette.yml
rename to taskcluster/ci/legacy/tasks/tests/harness_marionette.yml
--- a/testing/taskcluster/tasks/tests/harness_marionette.yml
+++ b/taskcluster/ci/legacy/tasks/tests/harness_marionette.yml
@@ -12,17 +12,17 @@ task:
     description: 'Marionette harness unit test'
 
   payload:
     command:
       - --tests=testing/marionette/harness/marionette/tests/harness_unit
       # Avoid overwriting /home/workspace/build/src
       - --work-dir=mozharness_workspace
     env:
-      JOB_SCRIPT: 'testing/taskcluster/scripts/tester/harness-test-linux.sh'
+      JOB_SCRIPT: 'taskcluster/scripts/tester/harness-test-linux.sh'
       MOZHARNESS_SCRIPT: >
           testing/mozharness/scripts/marionette_harness_tests.py
     artifacts:
       'public/logs/':
         type: directory
         path: '/home/worker/workspace/mozharness_workspace/upload/logs/'
         expires: '{{#from_now}}1 year{{/from_now}}'
   extra:
rename from testing/taskcluster/tasks/tests/mozharness-gecko.yml
rename to taskcluster/ci/legacy/tasks/tests/mozharness-gecko.yml
rename from testing/taskcluster/tasks/tests/mozlint-flake8.yml
rename to taskcluster/ci/legacy/tasks/tests/mozlint-flake8.yml
rename from testing/taskcluster/tasks/tests/mulet_build_test.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_build_test.yml
rename from testing/taskcluster/tasks/tests/mulet_build_unit.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_build_unit.yml
rename from testing/taskcluster/tasks/tests/mulet_gaia_js_integration_tests.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_gaia_js_integration_tests.yml
rename from testing/taskcluster/tasks/tests/mulet_gaia_unit.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_gaia_unit.yml
rename from testing/taskcluster/tasks/tests/mulet_gaia_unit_oop.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_gaia_unit_oop.yml
rename from testing/taskcluster/tasks/tests/mulet_linter.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_linter.yml
rename from testing/taskcluster/tasks/tests/mulet_mochitests.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_mochitests.yml
rename from testing/taskcluster/tasks/tests/mulet_reftests.yml
rename to taskcluster/ci/legacy/tasks/tests/mulet_reftests.yml
--- a/taskcluster/docs/index.rst
+++ b/taskcluster/docs/index.rst
@@ -12,9 +12,10 @@ than you might suppose!  This implementa
  * "Try" pushes, with special means to select a subset of the graph for execution
  * Optimization -- skipping tasks that have already been performed
 
 .. toctree::
 
     taskgraph
     parameters
     attributes
+    yaml-templates
     old
new file mode 100644
--- /dev/null
+++ b/taskcluster/docs/yaml-templates.rst
@@ -0,0 +1,45 @@
+Task Definition YAML Templates
+==============================
+
+Many kinds of tasks are described using YAML files.  These files allow some
+limited forms of inheritance and template substitution as well as the usual
+YAML features, as described below.
+
+Please use these features sparingly.  In many cases, it is better to add a
+feature to the implementation of a task kind rather than add complexity to the
+YAML files.
+
+Inheritance
+-----------
+
+One YAML file can "inherit" from another by including a top-level ``$inherits``
+key.  That key specifies the parent file in ``from``, and optionally a
+collection of variables in ``variables``.  For example:
+
+.. code-block:: yaml
+
+    $inherits:
+      from: 'tasks/builds/base_linux32.yml'
+      variables:
+        build_name: 'linux32'
+        build_type: 'dbg'
+
+Inheritance proceeds as follows: First, the child document has its template
+substitutions performed and is parsed as YAML.  Then, the parent document is
+parsed, with substitutions specified by ``variables`` added to the template
+substitutions.  Finally, the child document is merged with the parent.
+
+To merge two JSON objects (dictionaries), each value is merged individually.
+Lists are merged by concatenating the lists from the parent and child
+documents.  Atomic values (strings, numbers, etc.) are merged by preferring the
+child document's value.
+
+Substitution
+------------
+
+Each document is expanded using the PyStache template engine before it is
+parsed as YAML.  The parameters for this expansion are specific to the task
+kind.
+
+Simple value substitution looks like ``{{variable}}``.  Function calls look
+like ``{{#function}}argument{{/function}}``.
--- a/taskcluster/mach_commands.py
+++ b/taskcluster/mach_commands.py
@@ -15,16 +15,18 @@ from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
     SubCommand,
 )
 
 from mozbuild.base import MachCommandBase
 
+ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{}/artifacts/{}'
+
 
 class ShowTaskGraphSubCommand(SubCommand):
     """A SubCommand with TaskGraph-specific arguments"""
 
     def __call__(self, func):
         after = SubCommand.__call__(self, func)
         args = [
             CommandArgument('--root', '-r', default='taskcluster/ci',
@@ -198,8 +200,35 @@ class MachCommands(MachCommandBase):
         for label in taskgraph.graph.visit_postorder():
             print(label)
 
     def show_taskgraph_json(self, taskgraph):
         # JSON output is a sequence of JSON objects, rather than a single object, so
         # disassemble the dictionary
         for task in taskgraph.to_json().itervalues():
             print(json.dumps(task))
+
+
+@CommandProvider
+class LoadImage(object):
+    @Command('taskcluster-load-image', category="ci",
+        description="Load a pre-built Docker image")
+    @CommandArgument('--task-id',
+        help="Load the image at public/image.tar in this task, rather than "
+             "searching the index")
+    @CommandArgument('image_name', nargs='?',
+        help="Load the image of this name based on the current contents of the tree "
+             "(as built for mozilla-central or mozilla-inbound)")
+    def load_image(self, image_name, task_id):
+        from taskgraph.docker import load_image_by_name, load_image_by_task_id
+        if not image_name and not task_id:
+            print("Specify either IMAGE-NAME or TASK-ID")
+            sys.exit(1)
+        try:
+            if task_id:
+                ok = load_image_by_task_id(task_id)
+            else:
+                ok = load_image_by_name(image_name)
+            if not ok:
+                sys.exit(1)
+        except Exception as e:
+            traceback.print_exc()
+            sys.exit(1)
rename from testing/taskcluster/scripts/builder/build-emulator-x86.sh
rename to taskcluster/scripts/builder/build-emulator-x86.sh
rename from testing/taskcluster/scripts/builder/build-emulator.sh
rename to taskcluster/scripts/builder/build-emulator.sh
rename from testing/taskcluster/scripts/builder/build-haz-linux.sh
rename to taskcluster/scripts/builder/build-haz-linux.sh
rename from testing/taskcluster/scripts/builder/build-linux.sh
rename to taskcluster/scripts/builder/build-linux.sh
rename from testing/taskcluster/scripts/builder/build-mulet-haz-linux.sh
rename to taskcluster/scripts/builder/build-mulet-haz-linux.sh
rename from testing/taskcluster/scripts/builder/build-mulet-linux.sh
rename to taskcluster/scripts/builder/build-mulet-linux.sh
rename from testing/taskcluster/scripts/builder/build-simulator.sh
rename to taskcluster/scripts/builder/build-simulator.sh
rename from testing/taskcluster/scripts/builder/build-sm-package.sh
rename to taskcluster/scripts/builder/build-sm-package.sh
rename from testing/taskcluster/scripts/builder/build-sm.sh
rename to taskcluster/scripts/builder/build-sm.sh
rename from testing/taskcluster/scripts/builder/desktop-setup.sh
rename to taskcluster/scripts/builder/desktop-setup.sh
rename from testing/taskcluster/scripts/builder/gaia_props.py
rename to taskcluster/scripts/builder/gaia_props.py
rename from testing/taskcluster/scripts/builder/get-objdir.py
rename to taskcluster/scripts/builder/get-objdir.py
rename from testing/taskcluster/scripts/builder/hazard-analysis.sh
rename to taskcluster/scripts/builder/hazard-analysis.sh
rename from testing/taskcluster/scripts/builder/install-packages.sh
rename to taskcluster/scripts/builder/install-packages.sh
rename from testing/taskcluster/scripts/builder/pull-gaia.sh
rename to taskcluster/scripts/builder/pull-gaia.sh
rename from testing/taskcluster/scripts/builder/setup-ccache.sh
rename to taskcluster/scripts/builder/setup-ccache.sh
rename from testing/taskcluster/scripts/builder/sm-tooltool-config.sh
rename to taskcluster/scripts/builder/sm-tooltool-config.sh
rename from testing/taskcluster/scripts/copy.sh
rename to taskcluster/scripts/copy.sh
rename from testing/taskcluster/scripts/misc/build-cctools.sh
rename to taskcluster/scripts/misc/build-cctools.sh
rename from testing/taskcluster/scripts/misc/build-clang-linux.sh
rename to taskcluster/scripts/misc/build-clang-linux.sh
rename from testing/taskcluster/scripts/misc/build-gcc-linux.sh
rename to taskcluster/scripts/misc/build-gcc-linux.sh
rename from testing/taskcluster/scripts/misc/minidump_stackwalk.sh
rename to taskcluster/scripts/misc/minidump_stackwalk.sh
rename from testing/taskcluster/scripts/misc/repackage-jdk-centos.sh
rename to taskcluster/scripts/misc/repackage-jdk-centos.sh
rename from testing/taskcluster/scripts/phone-builder/build-dolphin.sh
rename to taskcluster/scripts/phone-builder/build-dolphin.sh
rename from testing/taskcluster/scripts/phone-builder/build-phone-ota.sh
rename to taskcluster/scripts/phone-builder/build-phone-ota.sh
rename from testing/taskcluster/scripts/phone-builder/build-phone.sh
rename to taskcluster/scripts/phone-builder/build-phone.sh
rename from testing/taskcluster/scripts/phone-builder/post-build.sh
rename to taskcluster/scripts/phone-builder/post-build.sh
rename from testing/taskcluster/scripts/phone-builder/pre-build.sh
rename to taskcluster/scripts/phone-builder/pre-build.sh
rename from testing/taskcluster/scripts/tester/harness-test-linux.sh
rename to taskcluster/scripts/tester/harness-test-linux.sh
rename from testing/taskcluster/scripts/tester/test-b2g.sh
rename to taskcluster/scripts/tester/test-b2g.sh
rename from testing/taskcluster/scripts/tester/test-linux.sh
rename to taskcluster/scripts/tester/test-linux.sh
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/docker.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import json
+import os
+import subprocess
+import tarfile
+import urllib2
+
+from taskgraph.util import docker
+
+GECKO = os.path.realpath(os.path.join(__file__, '..', '..', '..'))
+INDEX_URL = 'https://index.taskcluster.net/v1/task/docker.images.v1.{}.{}.hash.{}'
+ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{}/artifacts/{}'
+
+
+def load_image_by_name(image_name):
+    context_path = os.path.join(GECKO, 'testing', 'docker', image_name)
+    context_hash = docker.generate_context_hash(context_path)
+
+    image_index_url = INDEX_URL.format('mozilla-central', image_name, context_hash)
+    print("Fetching", image_index_url)
+    task = json.load(urllib2.urlopen(image_index_url))
+
+    return load_image_by_task_id(task['taskId'])
+
+
+def load_image_by_task_id(task_id):
+    # because we need to read this file twice (and one read is not all the way
+    # through), it is difficult to stream it.  So we download to disk and then
+    # read it back.
+    filename = 'temp-docker-image.tar'
+
+    artifact_url = ARTIFACT_URL.format(task_id, 'public/image.tar')
+    print("Downloading", artifact_url)
+    subprocess.check_call(['curl', '-#', '-L', '-o', filename, artifact_url])
+
+    print("Determining image name")
+    tf = tarfile.open(filename)
+    repositories = json.load(tf.extractfile('repositories'))
+    name = repositories.keys()[0]
+    tag = repositories[name].keys()[0]
+    name = '{}:{}'.format(name, tag)
+    print("Image name:", name)
+
+    print("Loading image into docker")
+    try:
+        subprocess.check_call(['docker', 'load', '-i', filename])
+    except subprocess.CalledProcessError:
+        print("*** `docker load` failed.  You may avoid re-downloading that tarball by fixing the")
+        print("*** problem and running `docker load < {}`.".format(filename))
+        raise
+
+    print("Deleting temporary file")
+    os.unlink(filename)
+
+    print("The requested docker image is now available as", name)
+    print("Try: docker run -ti --rm {} bash".format(name))
--- a/taskcluster/taskgraph/kind/docker_image.py
+++ b/taskcluster/taskgraph/kind/docker_image.py
@@ -9,21 +9,22 @@ import json
 import os
 import urllib2
 import hashlib
 import tarfile
 import time
 
 from . import base
 from ..types import Task
-from taskgraph.util import docker_image
-import taskcluster_graph.transform.routes as routes_transform
-import taskcluster_graph.transform.treeherder as treeherder_transform
-from taskcluster_graph.templates import Templates
-from taskcluster_graph.from_now import (
+from taskgraph.util.docker import (
+    docker_image,
+    generate_context_hash
+)
+from taskgraph.util.templates import Templates
+from taskgraph.util.time import (
     json_time_from_now,
     current_json_time,
 )
 
 logger = logging.getLogger(__name__)
 GECKO = os.path.realpath(os.path.join(__file__, '..', '..', '..', '..'))
 ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{}/artifacts/{}'
 INDEX_URL = 'https://index.taskcluster.net/v1/task/{}'
@@ -55,17 +56,17 @@ class DockerImageKind(base.Kind):
             'source': '{repo}file/{rev}/testing/taskcluster/tasks/image.yml'
                     .format(repo=params['head_repository'], rev=params['head_rev']),
         }
 
         tasks = []
         templates = Templates(self.path)
         for image_name in self.config['images']:
             context_path = os.path.join('testing', 'docker', image_name)
-            context_hash = self.generate_context_hash(context_path)
+            context_hash = generate_context_hash(context_path)
 
             image_parameters = dict(parameters)
             image_parameters['context_hash'] = context_hash
             image_parameters['context_path'] = context_path
             image_parameters['artifact_path'] = 'public/image.tar'
             image_parameters['image_name'] = image_name
 
             image_artifact_path = "public/decision_task/image_contexts/{}/context.tar.gz".format(image_name)
@@ -129,34 +130,8 @@ class DockerImageKind(base.Kind):
     def create_context_tar(self, context_dir, destination, image_name):
         'Creates a tar file of a particular context directory.'
         destination = os.path.abspath(destination)
         if not os.path.exists(os.path.dirname(destination)):
             os.makedirs(os.path.dirname(destination))
 
         with tarfile.open(destination, 'w:gz') as tar:
             tar.add(context_dir, arcname=image_name)
-
-    def generate_context_hash(self, image_path):
-        '''Generates a sha256 hash for context directory used to build an image.
-
-        Contents of the directory are sorted alphabetically, contents of each file is hashed,
-        and then a hash is created for both the file hashes as well as their paths.
-
-        This ensures that hashs are consistent and also change based on if file locations
-        within the context directory change.
-        '''
-        context_hash = hashlib.sha256()
-        files = []
-
-        for dirpath, dirnames, filenames in os.walk(os.path.join(GECKO, image_path)):
-            for filename in filenames:
-                files.append(os.path.join(dirpath, filename))
-
-        for filename in sorted(files):
-            relative_filename = filename.replace(GECKO, '')
-            with open(filename, 'rb') as f:
-                file_hash = hashlib.sha256()
-                data = f.read()
-                file_hash.update(data)
-                context_hash.update(file_hash.hexdigest() + '\t' + relative_filename + '\n')
-
-        return context_hash.hexdigest()
--- a/taskcluster/taskgraph/kind/legacy.py
+++ b/taskcluster/taskgraph/kind/legacy.py
@@ -1,83 +1,285 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
-import time
-import os
-import sys
+import copy
 import json
-import copy
+import logging
+import os
 import re
-import logging
+import sys
+import time
+from collections import defaultdict, namedtuple
 
 from . import base
 from ..types import Task
 from functools import partial
 from mozpack.path import match as mozpackmatch
 from slugid import nice as slugid
-from taskcluster_graph.mach_util import (
-    merge_dicts,
-    gaia_info,
-    configure_dependent_task,
-    set_interactive_task,
-    remove_caches_from_task,
-    query_vcs_info
-)
-import taskcluster_graph.transform.routes as routes_transform
-import taskcluster_graph.transform.treeherder as treeherder_transform
-from taskcluster_graph.commit_parser import parse_commit
-from taskcluster_graph.from_now import (
+from taskgraph.util.legacy_commit_parser import parse_commit
+from taskgraph.util.time import (
     json_time_from_now,
     current_json_time,
 )
-from taskcluster_graph.templates import Templates
-import taskcluster_graph.build_task
-from taskgraph.util import docker_image
+from taskgraph.util.templates import Templates
+from taskgraph.util.docker import docker_image
 
+
+ROOT = os.path.dirname(os.path.realpath(__file__))
+GECKO = os.path.realpath(os.path.join(ROOT, '..', '..', '..'))
 # TASKID_PLACEHOLDER is the "internal" form of a taskid; it is substituted with
 # actual taskIds at the very last minute, in get_task_definition
 TASKID_PLACEHOLDER = 'TaskLabel=={}'
 
 DEFINE_TASK = 'queue:define-task:aws-provisioner-v1/{}'
 DEFAULT_TRY = 'try: -b do -p all -u all -t all'
 DEFAULT_JOB_PATH = os.path.join(
     'tasks', 'branches', 'base_jobs.yml'
 )
 
+TREEHERDER_ROUTE_PREFIX = 'tc-treeherder-stage'
+TREEHERDER_ROUTES = {
+    'staging': 'tc-treeherder-stage',
+    'production': 'tc-treeherder'
+}
+
 # time after which a try build's results will expire
 TRY_EXPIRATION = "14 days"
 
 logger = logging.getLogger(__name__)
 
 def mklabel():
     return TASKID_PLACEHOLDER.format(slugid())
 
-# monkey-patch mklabel into image_builder, as well
-from taskcluster_graph import image_builder
-image_builder.mklabel = mklabel
+def merge_dicts(*dicts):
+    merged_dict = {}
+    for dictionary in dicts:
+        merged_dict.update(dictionary)
+    return merged_dict
+
+def gaia_info():
+    '''Fetch details from in tree gaia.json (which links this version of
+    gecko->gaia) and construct the usual base/head/ref/rev pairing...'''
+    gaia = json.load(open(os.path.join(GECKO, 'b2g', 'config', 'gaia.json')))
+
+    if gaia['git'] is None or \
+       gaia['git']['remote'] == '' or \
+       gaia['git']['git_revision'] == '' or \
+       gaia['git']['branch'] == '':
+
+       # Just use the hg params...
+       return {
+         'gaia_base_repository': 'https://hg.mozilla.org/{}'.format(gaia['repo_path']),
+         'gaia_head_repository': 'https://hg.mozilla.org/{}'.format(gaia['repo_path']),
+         'gaia_ref': gaia['revision'],
+         'gaia_rev': gaia['revision']
+       }
+
+    else:
+        # Use git
+        return {
+            'gaia_base_repository': gaia['git']['remote'],
+            'gaia_head_repository': gaia['git']['remote'],
+            'gaia_rev': gaia['git']['git_revision'],
+            'gaia_ref': gaia['git']['branch'],
+        }
+
+def configure_dependent_task(task_path, parameters, taskid, templates, build_treeherder_config):
+    """Configure a build dependent task. This is shared between post-build and test tasks.
+
+    :param task_path: location to the task yaml
+    :param parameters: parameters to load the template
+    :param taskid: taskid of the dependent task
+    :param templates: reference to the template builder
+    :param build_treeherder_config: parent treeherder config
+    :return: the configured task
+    """
+    task = templates.load(task_path, parameters)
+    task['taskId'] = taskid
+
+    if 'requires' not in task:
+        task['requires'] = []
+
+    task['requires'].append(parameters['build_slugid'])
+
+    if 'treeherder' not in task['task']['extra']:
+        task['task']['extra']['treeherder'] = {}
+
+    # Copy over any treeherder configuration from the build so
+    # tests show up under the same platform...
+    treeherder_config = task['task']['extra']['treeherder']
+
+    treeherder_config['collection'] = \
+        build_treeherder_config.get('collection', {})
+
+    treeherder_config['build'] = \
+        build_treeherder_config.get('build', {})
+
+    treeherder_config['machine'] = \
+        build_treeherder_config.get('machine', {})
+
+    if 'routes' not in task['task']:
+        task['task']['routes'] = []
+
+    if 'scopes' not in task['task']:
+        task['task']['scopes'] = []
+
+    return task
+
+def set_interactive_task(task, interactive):
+    r"""Make the task interactive.
+
+    :param task: task definition.
+    :param interactive: True if the task should be interactive.
+    """
+    if not interactive:
+        return
+
+    payload = task["task"]["payload"]
+    if "features" not in payload:
+        payload["features"] = {}
+    payload["features"]["interactive"] = True
+
+def remove_caches_from_task(task):
+    r"""Remove all caches but tc-vcs from the task.
+
+    :param task: task definition.
+    """
+    whitelist = [
+        re.compile("^level-[123]-.*-tc-vcs(-public-sources)?$"),
+        re.compile("^tooltool-cache$"),
+    ]
+    try:
+        caches = task["task"]["payload"]["cache"]
+        for cache in caches.keys():
+            if not any(pat.match(cache) for pat in whitelist):
+                caches.pop(cache)
+    except KeyError:
+        pass
+
+def query_vcs_info(repository, revision):
+    """Query the pushdate and pushid of a repository/revision.
+
+    This is intended to be used on hg.mozilla.org/mozilla-central and
+    similar. It may or may not work for other hg repositories.
+    """
+    if not repository or not revision:
+        logger.warning('cannot query vcs info because vcs info not provided')
+        return None
+
+    VCSInfo = namedtuple('VCSInfo', ['pushid', 'pushdate', 'changesets'])
+
+    try:
+        import requests
+        url = '%s/json-automationrelevance/%s' % (repository.rstrip('/'),
+                                                  revision)
+        logger.debug("Querying version control for metadata: %s", url)
+        contents = requests.get(url).json()
+
+        changesets = []
+        for c in contents['changesets']:
+            changesets.append({k: c[k] for k in ('desc', 'files', 'node')})
+
+        pushid = contents['changesets'][-1]['pushid']
+        pushdate = contents['changesets'][-1]['pushdate'][0]
+
+        return VCSInfo(pushid, pushdate, changesets)
+
+    except Exception:
+        logger.exception("Error querying VCS info for '%s' revision '%s'",
+                repository, revision)
+        return None
+
 
 def set_expiration(task, timestamp):
     task_def = task['task']
     task_def['expires'] = timestamp
     if task_def.get('deadline', timestamp) > timestamp:
         task_def['deadline'] = timestamp
 
     try:
         artifacts = task_def['payload']['artifacts']
     except KeyError:
         return
 
     for artifact in artifacts.values():
         artifact['expires'] = timestamp
 
+def add_treeherder_revision_info(task, revision, revision_hash):
+    # Only add treeherder information if task.extra.treeherder is present
+    if 'extra' not in task and 'treeherder' not in task.extra:
+        return
 
+    task['extra']['treeherder']['revision'] = revision
+    task['extra']['treeherder']['revision_hash'] = revision_hash
+
+
+def decorate_task_treeherder_routes(task, suffix):
+    """Decorate the given task with treeherder routes.
+
+    Uses task.extra.treeherderEnv if available otherwise defaults to only
+    staging.
+
+    :param dict task: task definition.
+    :param str suffix: The project/revision_hash portion of the route.
+    """
+
+    if 'extra' not in task:
+        return
+
+    if 'routes' not in task:
+        task['routes'] = []
+
+    treeheder_env = task['extra'].get('treeherderEnv', ['staging'])
+
+    for env in treeheder_env:
+        task['routes'].append('{}.{}'.format(TREEHERDER_ROUTES[env], suffix))
+
+def decorate_task_json_routes(task, json_routes, parameters):
+    """Decorate the given task with routes.json routes.
+
+    :param dict task: task definition.
+    :param json_routes: the list of routes to use from routes.json
+    :param parameters: dictionary of parameters to use in route templates
+    """
+    routes = task.get('routes', [])
+    for route in json_routes:
+        routes.append(route.format(**parameters))
+
+    task['routes'] = routes
+
+class BuildTaskValidationException(Exception):
+    pass
+
+def validate_build_task(task):
+    '''The build tasks have some required fields in extra this function ensures
+    they are there. '''
+    if 'task' not in task:
+        raise BuildTaskValidationException('must have task field')
+
+    task_def = task['task']
+
+    if 'extra' not in task_def:
+        raise BuildTaskValidationException('build task must have task.extra props')
+
+    if 'locations' not in task_def['extra']:
+        raise BuildTaskValidationException('task.extra.locations missing')
+
+    locations = task_def['extra']['locations']
+
+    if 'build' not in locations:
+        raise BuildTaskValidationException('task.extra.locations.build missing')
+
+    if 'tests' not in locations and 'test_packages' not in locations:
+        raise BuildTaskValidationException('task.extra.locations.tests or '
+                                           'task.extra.locations.tests_packages missing')
 
 class LegacyKind(base.Kind):
     """
     This kind generates a full task graph from the old YAML files in
     `testing/taskcluster/tasks`.  The tasks already have dependency links.
 
     The existing task-graph generation generates slugids for tasks during task
     generation, so this kind labels tasks using those slugids, with a prefix of
@@ -154,19 +356,19 @@ class LegacyKind(base.Kind):
 
         # Task graph we are generating for taskcluster...
         graph = {
             'tasks': [],
             'scopes': set(),
         }
 
         if params['revision_hash']:
-            for env in routes_transform.TREEHERDER_ROUTES:
+            for env in TREEHERDER_ROUTES:
                 route = 'queue:route:{}.{}'.format(
-                    routes_transform.TREEHERDER_ROUTES[env],
+                    TREEHERDER_ROUTES[env],
                     treeherder_route)
                 graph['scopes'].add(route)
 
         graph['metadata'] = {
             'source': '{repo}file/{rev}/testing/taskcluster/mach_commands.py'.format(repo=params['head_repository'], rev=params['head_rev']),
             'owner': params['owner'],
             # TODO: Add full mach commands to this example?
             'description': 'Task graph generated via ./mach taskcluster-graph',
@@ -230,27 +432,27 @@ class LegacyKind(base.Kind):
             set_interactive_task(build_task, interactive)
 
             # try builds don't use cache
             if project == "try":
                 remove_caches_from_task(build_task)
                 set_expiration(build_task, json_time_from_now(TRY_EXPIRATION))
 
             if params['revision_hash']:
-                treeherder_transform.add_treeherder_revision_info(build_task['task'],
-                                                                  params['head_rev'],
-                                                                  params['revision_hash'])
-                routes_transform.decorate_task_treeherder_routes(build_task['task'],
-                                                                 treeherder_route)
-                routes_transform.decorate_task_json_routes(build_task['task'],
-                                                           json_routes,
-                                                           build_parameters)
+                add_treeherder_revision_info(build_task['task'],
+                                             params['head_rev'],
+                                             params['revision_hash'])
+                decorate_task_treeherder_routes(build_task['task'],
+                                                treeherder_route)
+                decorate_task_json_routes(build_task['task'],
+                                          json_routes,
+                                          build_parameters)
 
             # Ensure each build graph is valid after construction.
-            taskcluster_graph.build_task.validate(build_task)
+            validate_build_task(build_task)
             attributes = build_task['attributes'] = {'kind':'legacy', 'legacy_kind': 'build'}
             if 'build_name' in build:
                 attributes['build_platform'] = build['build_name']
             if 'build_type' in task_extra:
                 attributes['build_type'] = {'dbg': 'debug'}.get(task_extra['build_type'],
                                                                 task_extra['build_type'])
             if build.get('is_job'):
                 attributes['job'] = build['build_name']
@@ -306,19 +508,19 @@ class LegacyKind(base.Kind):
                 post_parameters = merge_dicts(build_parameters,
                                               post_build.get('additional-parameters', {}))
                 post_task = configure_dependent_task(post_build['task'],
                                                      post_parameters,
                                                      mklabel(),
                                                      templates,
                                                      build_treeherder_config)
                 set_interactive_task(post_task, interactive)
-                treeherder_transform.add_treeherder_revision_info(post_task['task'],
-                                                                  params['head_rev'],
-                                                                  params['revision_hash'])
+                add_treeherder_revision_info(post_task['task'],
+                                             params['head_rev'],
+                                             params['revision_hash'])
 
                 if project == "try":
                     set_expiration(post_task, json_time_from_now(TRY_EXPIRATION))
 
                 post_task['attributes'] = attributes.copy()
                 post_task['attributes']['legacy_kind'] = 'post_build'
                 post_task['attributes']['post_build'] = post_build['job_flag']
                 graph['tasks'].append(post_task)
@@ -357,20 +559,20 @@ class LegacyKind(base.Kind):
                     test_task = configure_dependent_task(test['task'],
                                                          test_parameters,
                                                          mklabel(),
                                                          templates,
                                                          build_treeherder_config)
                     set_interactive_task(test_task, interactive)
 
                     if params['revision_hash']:
-                        treeherder_transform.add_treeherder_revision_info(test_task['task'],
-                                                                          params['head_rev'],
-                                                                          params['revision_hash'])
-                        routes_transform.decorate_task_treeherder_routes(
+                        add_treeherder_revision_info(test_task['task'],
+                                                     params['head_rev'],
+                                                     params['revision_hash'])
+                        decorate_task_treeherder_routes(
                             test_task['task'],
                             treeherder_route
                         )
 
                     if project == "try":
                         set_expiration(test_task, json_time_from_now(TRY_EXPIRATION))
 
                     test_task['attributes'] = attributes.copy()
--- a/taskcluster/taskgraph/test/test_kind_docker_image.py
+++ b/taskcluster/taskgraph/test/test_kind_docker_image.py
@@ -29,26 +29,10 @@ class TestDockerImageKind(unittest.TestC
 
     def test_create_context_tar(self):
         image_dir = os.path.join(docker_image.GECKO, 'testing', 'docker', 'image_builder')
         tarball = tempfile.mkstemp()[1]
         self.kind.create_context_tar(image_dir, tarball, 'image_builder')
         self.failUnless(os.path.exists(tarball))
         os.unlink(tarball)
 
-    def test_generate_context_hash(self):
-        tmpdir = tempfile.mkdtemp()
-        old_GECKO = docker_image.GECKO
-        docker_image.GECKO = tmpdir
-        try:
-            os.makedirs(os.path.join(tmpdir, 'docker', 'my-image'))
-            with open(os.path.join(tmpdir, 'docker', 'my-image', 'Dockerfile'), "w") as f:
-                f.write("FROM node\nADD a-file\n")
-            with open(os.path.join(tmpdir, 'docker', 'my-image', 'a-file'), "w") as f:
-                f.write("data\n")
-            self.assertEqual(self.kind.generate_context_hash('docker/my-image'),
-                    '781143fcc6cc72c9024b058665265cb6bae3fb8031cad7227dd169ffbfced434')
-        finally:
-            docker_image.GECKO = old_GECKO
-            shutil.rmtree(tmpdir)
-
 if __name__ == '__main__':
     main()
--- a/taskcluster/taskgraph/test/test_kind_legacy.py
+++ b/taskcluster/taskgraph/test/test_kind_legacy.py
@@ -1,24 +1,47 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import unittest
 
-from ..kind.legacy import LegacyKind, TASKID_PLACEHOLDER
+from ..kind.legacy import (
+    LegacyKind,
+    TASKID_PLACEHOLDER,
+    validate_build_task,
+    BuildTaskValidationException
+)
 from ..types import Task
 from mozunit import main
 
 
 class TestLegacyKind(unittest.TestCase):
     # NOTE: much of LegacyKind is copy-pasted from the old legacy code, which
     # is emphatically *not* designed for testing, so this test class does not
     # attempt to test the entire class.
 
     def setUp(self):
         self.kind = LegacyKind('/root', {})
 
 
+class TestValidateBuildTask(unittest.TestCase):
+
+    def test_validate_missing_extra(self):
+        with self.assertRaises(BuildTaskValidationException):
+            validate_build_task({})
+
+    def test_validate_valid(self):
+        with self.assertRaises(BuildTaskValidationException):
+            validate_build_task({
+                'extra': {
+                    'locations': {
+                        'build': '',
+                        'tests': ''
+                    }
+                }
+            })
+
+
 if __name__ == '__main__':
     main()
rename from taskcluster/taskgraph/test/test_util.py
rename to taskcluster/taskgraph/test/test_util_docker.py
--- a/taskcluster/taskgraph/test/test_util.py
+++ b/taskcluster/taskgraph/test/test_util_docker.py
@@ -1,27 +1,46 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
+import os
+import shutil
+import tempfile
 import unittest
 
-from ..util import docker_image, DOCKER_ROOT
+from ..util import docker
 from mozunit import main, MockedOpen
 
 
-class TestDockerImage(unittest.TestCase):
+class TestDocker(unittest.TestCase):
+
+    def test_generate_context_hash(self):
+        tmpdir = tempfile.mkdtemp()
+        old_GECKO = docker.GECKO
+        docker.GECKO = tmpdir
+        try:
+            os.makedirs(os.path.join(tmpdir, 'docker', 'my-image'))
+            with open(os.path.join(tmpdir, 'docker', 'my-image', 'Dockerfile'), "w") as f:
+                f.write("FROM node\nADD a-file\n")
+            with open(os.path.join(tmpdir, 'docker', 'my-image', 'a-file'), "w") as f:
+                f.write("data\n")
+            self.assertEqual(docker.generate_context_hash('docker/my-image'),
+                    '781143fcc6cc72c9024b058665265cb6bae3fb8031cad7227dd169ffbfced434')
+        finally:
+            docker.GECKO = old_GECKO
+            shutil.rmtree(tmpdir)
 
     def test_docker_image_explicit_registry(self):
         files = {}
-        files["{}/myimage/REGISTRY".format(DOCKER_ROOT)] = "cool-images"
-        files["{}/myimage/VERSION".format(DOCKER_ROOT)] = "1.2.3"
+        files["{}/myimage/REGISTRY".format(docker.DOCKER_ROOT)] = "cool-images"
+        files["{}/myimage/VERSION".format(docker.DOCKER_ROOT)] = "1.2.3"
         with MockedOpen(files):
-            self.assertEqual(docker_image('myimage'), "cool-images/myimage:1.2.3")
+            self.assertEqual(docker.docker_image('myimage'), "cool-images/myimage:1.2.3")
 
     def test_docker_image_default_registry(self):
         files = {}
-        files["{}/REGISTRY".format(DOCKER_ROOT)] = "mozilla"
-        files["{}/myimage/VERSION".format(DOCKER_ROOT)] = "1.2.3"
+        files["{}/REGISTRY".format(docker.DOCKER_ROOT)] = "mozilla"
+        files["{}/myimage/VERSION".format(docker.DOCKER_ROOT)] = "1.2.3"
         with MockedOpen(files):
-            self.assertEqual(docker_image('myimage'), "mozilla/myimage:1.2.3")
+            self.assertEqual(docker.docker_image('myimage'), "mozilla/myimage:1.2.3")
rename from testing/taskcluster/tests/test_commit_parser.py
rename to taskcluster/taskgraph/test/test_util_legacy_commit_parser.py
--- a/testing/taskcluster/tests/test_commit_parser.py
+++ b/taskcluster/taskgraph/test/test_util_legacy_commit_parser.py
@@ -1,19 +1,20 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import unittest
 import mozunit
-from taskcluster_graph.commit_parser import (
+from taskgraph.util.legacy_commit_parser import (
     parse_commit,
-    normalize_test_list
+    normalize_test_list,
+    parse_test_opts
 )
 
 class TestCommitParser(unittest.TestCase):
 
     def test_normalize_test_list_none(self):
         self.assertEqual(
             normalize_test_list({}, ['woot'], 'none'), []
         )
@@ -109,17 +110,18 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/linux',
                 'dependents': [],
                 'additional-parameters': {},
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'post-build': [],
-                'interactive': False
+                'interactive': False,
+                'when': {}
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
     def test_flag_aliasing(self):
         commit = 'try: -b o -p magic-alias -u none -t none'
@@ -149,17 +151,18 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/linux',
                 'dependents': [],
                 'additional-parameters': {},
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'interactive': False,
-                'post-build': []
+                'post-build': [],
+                'when': {},
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
     def test_try_flag_in_middle_of_commit(self):
         '''
@@ -190,17 +193,18 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/linux',
                 'dependents': [],
                 'additional-parameters': {},
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'interactive': False,
-                'post-build': []
+                'post-build': [],
+                'when': {}
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
     def test_try_flags_not_specified(self):
         '''
@@ -261,17 +265,18 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/linux',
                 'dependents': [],
                 'post-build': [],
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'interactive': False,
-                'additional-parameters': {}
+                'additional-parameters': {},
+                'when': {}
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
     def test_some_test_tasks_restricted(self):
         '''
@@ -310,31 +315,34 @@ class TestCommitParser(unittest.TestCase
             {
                 'task': 'task/linux-debug',
                 'dependents': [],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'linux',
                 'build_type': 'debug',
                 'interactive': False,
+                'when': {},
             },
             {
                 'task': 'task/linux',
                 'dependents': [{
                     'allowed_build_tasks': {
                         'task/linux': {
-                            'task':'task/web-platform-tests'
+                            'task':'task/web-platform-tests',
+                            'unittest_try_name':'web-platform-tests'
                         }
                     }
                 }],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'interactive': False,
+                'when': {},
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
 
     def test_specific_test_platforms(self):
@@ -396,60 +404,67 @@ class TestCommitParser(unittest.TestCase
             {
                 'task': 'task/linux',
                 'dependents': [],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'interactive': False,
+                'when': {},
             },
             {
                 'task': 'task/linux-debug',
                 'dependents': [],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'linux',
                 'build_type': 'debug',
                 'interactive': False,
+                'when': {},
             },
             {
                 'task': 'task/win32',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/win32': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     },
                     {
                         'allowed_build_tasks': {
                             'task/linux-debug': {
                                 'task': 'task/mochitest',
+                                'unittest_try_name': 'mochitest',
                             },
                             'task/win32': {
                                 'task': 'task/mochitest',
+                                'unittest_try_name': 'mochitest',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'win32',
                 'build_type': 'opt',
                 'interactive': False,
+                'when': {},
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
-        self.assertEqual(expected, result)
+        self.assertEqual(sorted(expected), sorted(result))
 
     def test_specific_test_platforms_with_specific_platform(self):
         '''
         This test cases covers the platform specific test exclusion options.
         '''
         commit = 'try: -b od -p win32 -u mochitest[windows] -t none'
         jobs = {
             'flags': {
@@ -503,28 +518,31 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/win32',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux-debug': {
                                 'task': 'task/mochitest',
+                                'unittest_try_name': 'mochitest',
                             },
                             'task/win32': {
                                 'task': 'task/mochitest',
+                                'unittest_try_name': 'mochitest',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'win32',
                 'build_type': 'opt',
                 'interactive': False,
+                'when': {}
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
     def test_specific_chunks(self):
         '''
@@ -564,26 +582,28 @@ class TestCommitParser(unittest.TestCase
             {
                 'task': 'task/linux',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/mochitest',
                                 'chunks': 5,
-                                'only_chunks': set([1, 2])
+                                'only_chunks': set([1, 2]),
+                                'unittest_try_name': 'mochitest',
                             },
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'post-build': [],
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'interactive': False,
+                'when': {},
             }
         ]
         result, triggers = parse_commit(commit, jobs)
         self.assertEqual(expected, result)
 
     def test_commit_with_builds_and_tests(self):
         '''
         This test covers the broad case of a commit which has both builds and
@@ -640,91 +660,107 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/linux',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {}
             },
             {
                 'task': 'task/linux-debug',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {}
             },
             {
                 'task': 'task/linux64',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {}
             },
             {
                 'task': 'task/linux64-debug',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {}
             }
         ]
 
@@ -785,113 +821,183 @@ class TestCommitParser(unittest.TestCase
         expected = [
             {
                 'task': 'task/linux',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'build_name': 'linux',
                 'build_type': 'opt',
                 'post-build': [],
-                'interactive': False
+                'interactive': False,
+                'when': {}
             },
             {
                 'task': 'task/linux-debug',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'build_name': 'linux',
                 'build_type': 'debug',
                 'post-build': [],
-                'interactive': False
+                'interactive': False,
+                'when': {}
             },
             {
                 'task': 'task/linux64',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'build_name': 'linux64',
                 'build_type': 'opt',
                 'post-build': [],
-                'interactive': False
+                'interactive': False,
+                'when': {}
             },
             {
                 'task': 'task/linux64-debug',
                 'dependents': [
                     {
                         'allowed_build_tasks': {
                             'task/linux': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             },
                             'task/linux64-debug': {
                                 'task': 'task/web-platform-tests',
+                                'unittest_try_name': 'web-platform-tests',
                             }
                         }
                     }
                 ],
                 'additional-parameters': {},
                 'build_name': 'linux64',
                 'build_type': 'debug',
                 'post-build': [],
-                'interactive': False
+                'interactive': False,
+                'when': {}
             }
         ]
 
         result, triggers = parse_commit(commit, jobs)
-        self.assertEqual(expected, result)
+        self.assertEqual(sorted(expected), sorted(result))
+
+
+class TryTestParserTest(unittest.TestCase):
+
+    def test_parse_opts_valid(self):
+        self.assertEquals(
+            parse_test_opts('all[Mulet Linux]'),
+            [{ 'test': 'all', 'platforms': ['Mulet Linux'] }]
+        )
+
+        self.assertEquals(
+            parse_test_opts('all[Amazing, Foobar woot,yeah]'),
+            [{ 'test': 'all', 'platforms': ['Amazing', 'Foobar woot', 'yeah'] }]
+        )
+
+        self.assertEquals(
+            parse_test_opts('a,b, c'),
+            [
+                { 'test': 'a' },
+                { 'test': 'b' },
+                { 'test': 'c' },
+            ]
+        )
+        self.assertEquals(
+            parse_test_opts('woot, bar[b], baz, qux[ z ],a'),
+            [
+                { 'test': 'woot' },
+                { 'test': 'bar', 'platforms': ['b'] },
+                { 'test': 'baz' },
+                { 'test': 'qux', 'platforms': ['z'] },
+                { 'test': 'a' }
+            ]
+        )
+
+        self.assertEquals(
+            parse_test_opts('mochitest-3[Ubuntu,10.6,10.8,Windows XP,Windows 7,Windows 8]'),
+            [
+                {
+                    'test': 'mochitest-3',
+                    'platforms': [
+                        'Ubuntu', '10.6', '10.8', 'Windows XP', 'Windows 7', 'Windows 8'
+                    ]
+                }
+            ]
+        )
+
+        self.assertEquals(
+            parse_test_opts(''),
+            []
+        )
 
 
 if __name__ == '__main__':
     mozunit.main()
rename from testing/taskcluster/tests/test_templates.py
rename to taskcluster/taskgraph/test/test_util_templates.py
--- a/testing/taskcluster/tests/test_templates.py
+++ b/taskcluster/taskgraph/test/test_util_templates.py
@@ -1,23 +1,124 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
 import os
 
 import unittest
 import mozunit
-from taskcluster_graph.templates import (
+import textwrap
+from taskgraph.util.templates import (
     Templates,
     TemplatesException
 )
 
+files = {}
+files['/fixtures/circular.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: 'circular_ref.yml'
+      variables:
+        woot: 'inherit'
+    """)
+
+files['/fixtures/inherit.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: 'templates.yml'
+      variables:
+        woot: 'inherit'
+    """)
+
+files['/fixtures/extend_child.yml'] = textwrap.dedent("""\
+    list: ['1', '2', '3']
+    was_list: ['1']
+    obj:
+      level: 1
+      deeper:
+        woot: 'bar'
+        list: ['baz']
+    """)
+
+files['/fixtures/circular_ref.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: 'circular.yml'
+    """)
+
+files['/fixtures/child_pass.yml'] = textwrap.dedent("""\
+    values:
+      - {{a}}
+      - {{b}}
+      - {{c}}
+    """)
+
+files['/fixtures/inherit_pass.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: 'child_pass.yml'
+      variables:
+        a: 'a'
+        b: 'b'
+        c: 'c'
+    """)
+
+files['/fixtures/deep/2.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: deep/1.yml
+
+    """)
+
+files['/fixtures/deep/3.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: deep/2.yml
+
+    """)
+
+files['/fixtures/deep/4.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: deep/3.yml
+    """)
+
+files['/fixtures/deep/1.yml'] = textwrap.dedent("""\
+    variable: {{value}}
+    """)
+
+files['/fixtures/simple.yml'] = textwrap.dedent("""\
+    is_simple: true
+    """)
+
+files['/fixtures/templates.yml'] = textwrap.dedent("""\
+    content: 'content'
+    variable: '{{woot}}'
+    """)
+
+files['/fixtures/extend_parent.yml'] = textwrap.dedent("""\
+    $inherits:
+      from: 'extend_child.yml'
+
+    list: ['4']
+    was_list:
+      replaced: true
+    obj:
+      level: 2
+      from_parent: true