Merge mozilla-inbound to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Sat, 21 Jul 2018 00:42:01 +0300
changeset 482708 6eec814dea78
parent 482599 d6a5e8aea651 (current diff)
parent 482707 1f10db43a17e (diff)
child 482713 028d311f0394
child 482728 558782eeafe1
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
6eec814dea78 / 63.0a1 / 20180720220116 / files
nightly linux64
6eec814dea78 / 63.0a1 / 20180720220116 / files
nightly win32
6eec814dea78 / 63.0a1 / 20180720220116 / files
nightly win64
6eec814dea78 / 63.0a1 / 20180720220116 / files
nightly mac
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
browser/components/payments/res/containers/payment-method-picker.js
dom/media/test/test_can_play_type_mpeg.html
testing/web-platform/meta/bluetooth/idl/idlharness.tentative.window.js.ini
testing/web-platform/meta/content-security-policy/frame-src/frame-src-redirect.html.ini
testing/web-platform/meta/content-security-policy/frame-src/frame-src-self-unique-origin.html.ini
testing/web-platform/meta/content-security-policy/img-src/img-src-self-unique-origin.html.ini
testing/web-platform/meta/generic-sensor/idlharness.https.html.ini
testing/web-platform/meta/mediacapture-streams/MediaDevices-IDL-all.html.ini
testing/web-platform/meta/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html.ini
testing/web-platform/meta/mediacapture-streams/MediaStreamTrack-idl.https.html.ini
testing/web-platform/meta/workers/baseurl/alpha/sharedworker.html.ini
testing/web-platform/tests/2dcontext/best-practices/.gitkeep
testing/web-platform/tests/2dcontext/building-paths/.gitkeep
testing/web-platform/tests/2dcontext/compositing/.gitkeep
testing/web-platform/tests/2dcontext/conformance-requirements/.gitkeep
testing/web-platform/tests/2dcontext/drawing-images-to-the-canvas/.gitkeep
testing/web-platform/tests/2dcontext/drawing-model/.gitkeep
testing/web-platform/tests/2dcontext/drawing-paths-to-the-canvas/.gitkeep
testing/web-platform/tests/2dcontext/drawing-rectangles-to-the-canvas/.gitkeep
testing/web-platform/tests/2dcontext/drawing-text-to-the-canvas/.gitkeep
testing/web-platform/tests/2dcontext/drawingstyle-objects/.gitkeep
testing/web-platform/tests/2dcontext/examples/.gitkeep
testing/web-platform/tests/2dcontext/fill-and-stroke-styles/.gitkeep
testing/web-platform/tests/2dcontext/hit-regions/.gitkeep
testing/web-platform/tests/2dcontext/line-styles/.gitkeep
testing/web-platform/tests/2dcontext/path-objects/.gitkeep
testing/web-platform/tests/2dcontext/pixel-manipulation/.gitkeep
testing/web-platform/tests/2dcontext/shadows/.gitkeep
testing/web-platform/tests/2dcontext/text-styles/.gitkeep
testing/web-platform/tests/2dcontext/the-canvas-state/.gitkeep
testing/web-platform/tests/2dcontext/transformations/.gitkeep
testing/web-platform/tests/bluetooth/idl/idlharness.tentative.window.js
testing/web-platform/tests/fetch/http-cache/resources/http-cache.py
testing/web-platform/tests/generic-sensor/idlharness.https.html
testing/web-platform/tests/html/browsers/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/aborting-a-document-load/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/history-traversal/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/navigating-across-documents/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-html/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-media/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-multipart-x-mixed-replace/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-plugin/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-text/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-ua-inline/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/read-xml/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/scroll-to-fragid/.gitkeep
testing/web-platform/tests/html/browsers/browsing-the-web/unloading-documents/.gitkeep
testing/web-platform/tests/html/browsers/history/.gitkeep
testing/web-platform/tests/html/browsers/history/history-notes/.gitkeep
testing/web-platform/tests/html/browsers/history/the-history-interface/.gitkeep
testing/web-platform/tests/html/browsers/history/the-location-interface/.gitkeep
testing/web-platform/tests/html/browsers/history/the-session-history-of-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/offline/.gitkeep
testing/web-platform/tests/html/browsers/offline/appcache/.gitkeep
testing/web-platform/tests/html/browsers/offline/application-cache-api/.gitkeep
testing/web-platform/tests/html/browsers/offline/browser-state/.gitkeep
testing/web-platform/tests/html/browsers/offline/changestonetworkingmodel/.gitkeep
testing/web-platform/tests/html/browsers/offline/disk-space/.gitkeep
testing/web-platform/tests/html/browsers/offline/downloading-or-updating-an-application-cache/.gitkeep
testing/web-platform/tests/html/browsers/offline/expiring-application-caches/.gitkeep
testing/web-platform/tests/html/browsers/offline/introduction-4/.gitkeep
testing/web-platform/tests/html/browsers/offline/manifests/.gitkeep
testing/web-platform/tests/html/browsers/offline/the-application-cache-selection-algorithm/.gitkeep
testing/web-platform/tests/html/browsers/sandboxing/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/accessing-other-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/browser-interface-elements/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/closing-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/garbage-collection-and-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/named-access-on-the-window-object/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/security-window/.gitkeep
testing/web-platform/tests/html/browsers/the-window-object/the-windowproxy-object/.gitkeep
testing/web-platform/tests/html/browsers/windows/.gitkeep
testing/web-platform/tests/html/browsers/windows/auxiliary-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/windows/browsing-context-names/.gitkeep
testing/web-platform/tests/html/browsers/windows/groupings-of-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/windows/secondary-browsing-contexts/.gitkeep
testing/web-platform/tests/html/browsers/windows/security-nav/.gitkeep
testing/web-platform/tests/html/dom/.gitkeep
testing/web-platform/tests/html/dom/META.yml
testing/web-platform/tests/html/dom/documents/.gitkeep
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/.gitkeep
testing/web-platform/tests/html/dom/documents/loading-xml-documents/.gitkeep
testing/web-platform/tests/html/dom/documents/resource-metadata-management/.gitkeep
testing/web-platform/tests/html/dom/documents/security-document/.gitkeep
testing/web-platform/tests/html/dom/documents/the-document-object/.gitkeep
testing/web-platform/tests/html/dom/dynamic-markup-insertion/.gitkeep
testing/web-platform/tests/html/dom/dynamic-markup-insertion/closing-the-input-stream/.gitkeep
testing/web-platform/tests/html/dom/dynamic-markup-insertion/document-write/.gitkeep
testing/web-platform/tests/html/dom/dynamic-markup-insertion/document-writeln/.gitkeep
testing/web-platform/tests/html/dom/dynamic-markup-insertion/opening-the-input-stream/.gitkeep
testing/web-platform/tests/html/dom/elements/.gitkeep
testing/web-platform/tests/html/dom/elements/content-models/.gitkeep
testing/web-platform/tests/html/dom/elements/element-definitions/.gitkeep
testing/web-platform/tests/html/dom/elements/elements-in-the-dom/.gitkeep
testing/web-platform/tests/html/dom/elements/global-attributes/.gitkeep
testing/web-platform/tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/.gitkeep
testing/web-platform/tests/html/dom/elements/semantics-0/.gitkeep
testing/web-platform/tests/html/dom/elements/wai-aria/.gitkeep
testing/web-platform/tests/html/dom/interactions-with-xpath-and-xslt/.gitkeep
testing/web-platform/tests/html/editing/.gitkeep
testing/web-platform/tests/html/editing/META.yml
testing/web-platform/tests/html/editing/activation/.gitkeep
testing/web-platform/tests/html/editing/assigning-keyboard-shortcuts/.gitkeep
testing/web-platform/tests/html/editing/assigning-keyboard-shortcuts/introduction-6/.gitkeep
testing/web-platform/tests/html/editing/assigning-keyboard-shortcuts/processing-model-4/.gitkeep
testing/web-platform/tests/html/editing/assigning-keyboard-shortcuts/the-accesskey-attribute/.gitkeep
testing/web-platform/tests/html/editing/editing-0/.gitkeep
testing/web-platform/tests/html/editing/editing-0/best-practices-for-in-page-editors/.gitkeep
testing/web-platform/tests/html/editing/editing-0/contenteditable/.gitkeep
testing/web-platform/tests/html/editing/editing-0/editing-apis/.gitkeep
testing/web-platform/tests/html/editing/editing-0/making-entire-documents-editable-the-designmode-idl-attribute/.gitkeep
testing/web-platform/tests/html/editing/editing-0/spelling-and-grammar-checking/.gitkeep
testing/web-platform/tests/html/editing/focus/.gitkeep
testing/web-platform/tests/html/editing/focus/document-level-focus-apis/.gitkeep
testing/web-platform/tests/html/editing/focus/element-level-focus-apis/.gitkeep
testing/web-platform/tests/html/editing/focus/focus-management/.gitkeep
testing/web-platform/tests/html/editing/focus/sequential-focus-navigation-and-the-tabindex-attribute/.gitkeep
testing/web-platform/tests/html/editing/inert-subtrees/.gitkeep
testing/web-platform/tests/html/editing/inert-subtrees/the-inert-attribute/.gitkeep
testing/web-platform/tests/html/editing/the-hidden-attribute/.gitkeep
testing/web-platform/tests/html/iana/.gitkeep
testing/web-platform/tests/html/iana/application-x-www-form-urlencoded/.gitkeep
testing/web-platform/tests/html/iana/application-xhtml-xml/.gitkeep
testing/web-platform/tests/html/iana/multipart-x-mixed-replace/.gitkeep
testing/web-platform/tests/html/iana/ping-to/.gitkeep
testing/web-platform/tests/html/iana/text-cache-manifest/.gitkeep
testing/web-platform/tests/html/iana/text-html/.gitkeep
testing/web-platform/tests/html/iana/web-scheme-prefix/.gitkeep
testing/web-platform/tests/html/infrastructure/.gitkeep
testing/web-platform/tests/html/infrastructure/META.yml
testing/web-platform/tests/html/infrastructure/case-sensitivity-and-string-comparison/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/collections/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/domstringmap/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/garbage-collection/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/reflecting-content-attributes-in-idl-attributes/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/safe-passing-of-structured-data/.gitkeep
testing/web-platform/tests/html/infrastructure/common-dom-interfaces/transferable-objects/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/boolean-attributes/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/colors/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/comma-separated-tokens/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/common-parser-idioms/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/dates-and-times/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/keywords-and-enumerated-attributes/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/mq/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/numbers/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/space-separated-tokens/.gitkeep
testing/web-platform/tests/html/infrastructure/common-microsyntaxes/syntax-references/.gitkeep
testing/web-platform/tests/html/infrastructure/conformance-requirements/.gitkeep
testing/web-platform/tests/html/infrastructure/conformance-requirements/conformance-classes/.gitkeep
testing/web-platform/tests/html/infrastructure/conformance-requirements/dependencies/.gitkeep
testing/web-platform/tests/html/infrastructure/conformance-requirements/extensibility/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/content-type-sniffing/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/cors-enabled-fetch/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/cors-settings-attributes/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/encrypted-http-and-related-security-concerns/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/extracting-character-encodings-from-meta-elements/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/processing-model/.gitkeep
testing/web-platform/tests/html/infrastructure/fetching-resources/terminology-1/.gitkeep
testing/web-platform/tests/html/infrastructure/namespaces/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/character-encodings/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/dom-trees/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/plugins/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/resources/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/scripting-0/.gitkeep
testing/web-platform/tests/html/infrastructure/terminology/xml/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/base-urls/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/dynamic-changes-to-base-urls/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/interfaces-for-url-manipulation/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/parsing-urls/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/resolving-urls/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/terminology-0/.gitkeep
testing/web-platform/tests/html/infrastructure/urls/url-manipulation-and-creation/.gitkeep
testing/web-platform/tests/html/infrastructure/utf-8/.gitkeep
testing/web-platform/tests/html/introduction/.gitkeep
testing/web-platform/tests/html/introduction/a-quick-introduction-to-html/.gitkeep
testing/web-platform/tests/html/introduction/a-quick-introduction-to-html/common-pitfalls-to-avoid-when-using-the-scripting-apis/.gitkeep
testing/web-platform/tests/html/introduction/a-quick-introduction-to-html/writing-secure-applications-with-html/.gitkeep
testing/web-platform/tests/html/introduction/audience/.gitkeep
testing/web-platform/tests/html/introduction/background/.gitkeep
testing/web-platform/tests/html/introduction/conformance-requirements-for-authors/.gitkeep
testing/web-platform/tests/html/introduction/conformance-requirements-for-authors/presentational-markup/.gitkeep
testing/web-platform/tests/html/introduction/conformance-requirements-for-authors/restrictions-on-content-models-and-on-attribute-values/.gitkeep
testing/web-platform/tests/html/introduction/conformance-requirements-for-authors/syntax-errors/.gitkeep
testing/web-platform/tests/html/introduction/design-notes/.gitkeep
testing/web-platform/tests/html/introduction/design-notes/compliance-with-other-specifications/.gitkeep
testing/web-platform/tests/html/introduction/design-notes/serializability-of-script-execution/.gitkeep
testing/web-platform/tests/html/introduction/fingerprint/.gitkeep
testing/web-platform/tests/html/introduction/history-0/.gitkeep
testing/web-platform/tests/html/introduction/html-vs-xhtml/.gitkeep
testing/web-platform/tests/html/introduction/scope/.gitkeep
testing/web-platform/tests/html/introduction/structure-of-this-specification/.gitkeep
testing/web-platform/tests/html/introduction/structure-of-this-specification/how-to-read-this-specification/.gitkeep
testing/web-platform/tests/html/introduction/structure-of-this-specification/typographic-conventions/.gitkeep
testing/web-platform/tests/html/introduction/suggested-reading/.gitkeep
testing/web-platform/tests/html/obsolete/.gitkeep
testing/web-platform/tests/html/obsolete/non-conforming-features/.gitkeep
testing/web-platform/tests/html/obsolete/obsolete-but-conforming-features/.gitkeep
testing/web-platform/tests/html/obsolete/obsolete-but-conforming-features/warnings-for-obsolete-but-conforming-features/.gitkeep
testing/web-platform/tests/html/obsolete/requirements-for-implementations/.gitkeep
testing/web-platform/tests/html/obsolete/requirements-for-implementations/frames/.gitkeep
testing/web-platform/tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/.gitkeep
testing/web-platform/tests/html/obsolete/requirements-for-implementations/the-applet-element/.gitkeep
testing/web-platform/tests/html/obsolete/requirements-for-implementations/the-marquee-element-0/.gitkeep
testing/web-platform/tests/html/rendering/.gitkeep
testing/web-platform/tests/html/rendering/bindings/.gitkeep
testing/web-platform/tests/html/rendering/bindings/introduction-9/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-details-element-0/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-a-button/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-a-checkbox-and-radio-button-widgets/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-a-color-well/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-a-file-upload-control/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-a-range-control/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-a-text-entry-widget/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-input-element-as-domain-specific-widgets/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-marquee-element/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-meter-element-0/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-progress-element-0/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-select-element-0/.gitkeep
testing/web-platform/tests/html/rendering/bindings/the-textarea-element-0/.gitkeep
testing/web-platform/tests/html/rendering/frames-and-framesets/.gitkeep
testing/web-platform/tests/html/rendering/interactive-media/.gitkeep
testing/web-platform/tests/html/rendering/interactive-media/editing-hosts/.gitkeep
testing/web-platform/tests/html/rendering/interactive-media/links-forms-and-navigation/.gitkeep
testing/web-platform/tests/html/rendering/interactive-media/text-rendered-in-native-user-interfaces/.gitkeep
testing/web-platform/tests/html/rendering/interactive-media/the-title-attribute-0/.gitkeep
testing/web-platform/tests/html/rendering/introduction-8/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/bidirectional-text/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/flow-content-0/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/form-controls/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/hidden-elements/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/lists/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/phrasing-content-0/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/quotes/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/sections-and-headings/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/tables/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/the-fieldset-element-0/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/the-hr-element-0/.gitkeep
testing/web-platform/tests/html/rendering/non-replaced-elements/the-page/.gitkeep
testing/web-platform/tests/html/rendering/print-media/.gitkeep
testing/web-platform/tests/html/rendering/replaced-elements/.gitkeep
testing/web-platform/tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/.gitkeep
testing/web-platform/tests/html/rendering/replaced-elements/embedded-content-rendering-rules/.gitkeep
testing/web-platform/tests/html/rendering/replaced-elements/image-maps-0/.gitkeep
testing/web-platform/tests/html/rendering/replaced-elements/images/.gitkeep
testing/web-platform/tests/html/rendering/replaced-elements/toolbars-0/.gitkeep
testing/web-platform/tests/html/rendering/the-css-user-agent-style-sheet-and-presentational-hints/.gitkeep
testing/web-platform/tests/html/rendering/unstyled-xml-documents/.gitkeep
testing/web-platform/tests/html/semantics/.gitkeep
testing/web-platform/tests/html/semantics/META.yml
testing/web-platform/tests/html/semantics/common-idioms/.gitkeep
testing/web-platform/tests/html/semantics/common-idioms/conversations/.gitkeep
testing/web-platform/tests/html/semantics/common-idioms/footnotes/.gitkeep
testing/web-platform/tests/html/semantics/common-idioms/rel-up/.gitkeep
testing/web-platform/tests/html/semantics/common-idioms/tag-clouds/.gitkeep
testing/web-platform/tests/html/semantics/common-idioms/the-main-part-of-the-content/.gitkeep
testing/web-platform/tests/html/semantics/disabled-elements/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/styling/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/the-base-element/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/the-head-element/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/the-link-element/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/the-meta-element/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/the-style-element/.gitkeep
testing/web-platform/tests/html/semantics/document-metadata/the-title-element/.gitkeep
testing/web-platform/tests/html/semantics/edits/.gitkeep
testing/web-platform/tests/html/semantics/edits/attributes-common-to-ins-and-del-elements/.gitkeep
testing/web-platform/tests/html/semantics/edits/edits-and-lists/.gitkeep
testing/web-platform/tests/html/semantics/edits/edits-and-paragraphs/.gitkeep
testing/web-platform/tests/html/semantics/edits/edits-and-tables/.gitkeep
testing/web-platform/tests/html/semantics/edits/the-del-element/.gitkeep
testing/web-platform/tests/html/semantics/edits/the-ins-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/dimension-attributes/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/image-maps/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/mathml/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/media-elements/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/svg/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-area-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-audio-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-canvas-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-embed-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-img-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-map-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-object-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-param-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-source-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-track-element/.gitkeep
testing/web-platform/tests/html/semantics/embedded-content/the-video-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/.gitkeep
testing/web-platform/tests/html/semantics/forms/attributes-common-to-form-controls/.gitkeep
testing/web-platform/tests/html/semantics/forms/categories/.gitkeep
testing/web-platform/tests/html/semantics/forms/constraints/.gitkeep
testing/web-platform/tests/html/semantics/forms/form-control-infrastructure/.gitkeep
testing/web-platform/tests/html/semantics/forms/form-submission-0/.gitkeep
testing/web-platform/tests/html/semantics/forms/introduction-1/.gitkeep
testing/web-platform/tests/html/semantics/forms/resetting-a-form/.gitkeep
testing/web-platform/tests/html/semantics/forms/textfieldselection/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-button-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-datalist-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-fieldset-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-form-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-input-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-label-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-legend-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-meter-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-optgroup-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-option-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-output-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-select-element/.gitkeep
testing/web-platform/tests/html/semantics/forms/the-textarea-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-blockquote-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-dd-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-div-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-dl-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-dt-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-figcaption-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-figure-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-hr-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-p-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-pre-element/.gitkeep
testing/web-platform/tests/html/semantics/grouping-content/the-ul-element/.gitkeep
testing/web-platform/tests/html/semantics/interactive-elements/.gitkeep
testing/web-platform/tests/html/semantics/interactive-elements/commands/.gitkeep
testing/web-platform/tests/html/semantics/interactive-elements/the-details-element/.gitkeep
testing/web-platform/tests/html/semantics/interactive-elements/the-menu-element/.gitkeep
testing/web-platform/tests/html/semantics/interactive-elements/the-summary-element/.gitkeep
testing/web-platform/tests/html/semantics/links/.gitkeep
testing/web-platform/tests/html/semantics/links/downloading-resources/.gitkeep
testing/web-platform/tests/html/semantics/links/following-hyperlinks/.gitkeep
testing/web-platform/tests/html/semantics/links/introduction-3/.gitkeep
testing/web-platform/tests/html/semantics/links/links-created-by-a-and-area-elements/.gitkeep
testing/web-platform/tests/html/semantics/links/linktypes/.gitkeep
testing/web-platform/tests/html/semantics/scripting-1/.gitkeep
testing/web-platform/tests/html/semantics/scripting-1/the-noscript-element/.gitkeep
testing/web-platform/tests/html/semantics/scripting-1/the-script-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/.gitkeep
testing/web-platform/tests/html/semantics/sections/headings-and-sections/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-address-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-article-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-aside-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-body-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-footer-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-h1-h2-h3-h4-h5-and-h6-elements/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-header-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-hgroup-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-nav-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/the-section-element/.gitkeep
testing/web-platform/tests/html/semantics/sections/usage-summary-0/.gitkeep
testing/web-platform/tests/html/semantics/selectors/.gitkeep
testing/web-platform/tests/html/semantics/selectors/case-sensitivity/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/attributes-common-to-td-and-th-elements/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/examples/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/processing-model-1/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-caption-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-col-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-colgroup-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-table-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-tbody-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-td-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-tfoot-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-th-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-thead-element/.gitkeep
testing/web-platform/tests/html/semantics/tabular-data/the-tr-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-a-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-abbr-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-b-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-bdi-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-bdo-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-br-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-cite-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-code-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-dfn-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-em-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-i-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-kbd-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-mark-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-q-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-rp-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-rt-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-ruby-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-s-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-samp-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-small-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-span-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-strong-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-sub-and-sup-elements/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-time-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-u-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/the-var-element/.gitkeep
testing/web-platform/tests/html/semantics/text-level-semantics/usage-summary/.gitkeep
testing/web-platform/tests/html/semantics/the-root-element/.gitkeep
testing/web-platform/tests/html/semantics/the-root-element/the-html-element/.gitkeep
testing/web-platform/tests/html/syntax/.gitkeep
testing/web-platform/tests/html/syntax/parsing-html-fragments/.gitkeep
testing/web-platform/tests/html/syntax/parsing/.gitkeep
testing/web-platform/tests/html/syntax/serializing-html-fragments/.gitkeep
testing/web-platform/tests/html/syntax/writing/.gitkeep
testing/web-platform/tests/html/syntax/writing/cdata-sections/.gitkeep
testing/web-platform/tests/html/syntax/writing/character-references/.gitkeep
testing/web-platform/tests/html/syntax/writing/comments/.gitkeep
testing/web-platform/tests/html/syntax/writing/elements-0/.gitkeep
testing/web-platform/tests/html/syntax/writing/text/.gitkeep
testing/web-platform/tests/html/syntax/writing/the-doctype/.gitkeep
testing/web-platform/tests/html/the-xhtml-syntax/.gitkeep
testing/web-platform/tests/html/the-xhtml-syntax/parsing-xhtml-documents/.gitkeep
testing/web-platform/tests/html/the-xhtml-syntax/parsing-xhtml-fragments/.gitkeep
testing/web-platform/tests/html/the-xhtml-syntax/serializing-xhtml-fragments/.gitkeep
testing/web-platform/tests/html/the-xhtml-syntax/writing-xhtml-documents/.gitkeep
testing/web-platform/tests/html/webappapis/.gitkeep
testing/web-platform/tests/html/webappapis/atob/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/enabling-and-disabling-scripting/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/event-loops/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/events/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/introduction-5/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/javascript-protocol/.gitkeep
testing/web-platform/tests/html/webappapis/scripting/processing-model-2/.gitkeep
testing/web-platform/tests/html/webappapis/system-state-and-capabilities/.gitkeep
testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-external-interface/.gitkeep
testing/web-platform/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/.gitkeep
testing/web-platform/tests/html/webappapis/timers/.gitkeep
testing/web-platform/tests/html/webappapis/user-prompts/.gitkeep
testing/web-platform/tests/html/webappapis/user-prompts/dialogs-implemented-using-separate-documents/.gitkeep
testing/web-platform/tests/html/webappapis/user-prompts/printing/.gitkeep
testing/web-platform/tests/html/webappapis/user-prompts/simple-dialogs/.gitkeep
testing/web-platform/tests/interfaces/mediacapture-main.idl
testing/web-platform/tests/interfaces/sensors.idl
testing/web-platform/tests/interfaces/webappsec-subresource-integrity.idl
testing/web-platform/tests/mediacapture-streams/MediaDevices-IDL-all.html
testing/web-platform/tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
testing/web-platform/tests/mediacapture-streams/MediaStreamTrack-idl.https.html
testing/web-platform/tests/navigation-timing/idlharness.html
testing/web-platform/tests/workers/baseurl/alpha/importScripts.html
testing/web-platform/tests/workers/baseurl/alpha/sharedworker.html
testing/web-platform/tests/workers/baseurl/alpha/worker.html
testing/web-platform/tests/workers/baseurl/alpha/xhr.html
--- a/accessible/aom/AccessibleNode.cpp
+++ b/accessible/aom/AccessibleNode.cpp
@@ -37,17 +37,19 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Ac
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AccessibleNode)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AccessibleNode)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AccessibleNode)
 
-AccessibleNode::AccessibleNode(nsINode* aNode) : mDOMNode(aNode)
+AccessibleNode::AccessibleNode(nsINode* aNode) :
+    mBooleanProperties(0),
+    mDOMNode(aNode)
 {
   nsAccessibilityService* accService = GetOrCreateAccService();
   if (!accService) {
     return;
   }
 
   DocAccessible* doc = accService->GetDocAccessible(mDOMNode->OwnerDoc());
   if (doc) {
--- a/accessible/aom/AccessibleNode.h
+++ b/accessible/aom/AccessibleNode.h
@@ -5,30 +5,51 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef A11Y_AOM_ACCESSIBLENODE_H
 #define A11Y_AOM_ACCESSIBLENODE_H
 
 #include "nsWrapperCache.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/Nullable.h"
 
 class nsINode;
 
 namespace mozilla {
 
 namespace a11y {
   class Accessible;
 }
 
 namespace dom {
 
 class DOMStringList;
 struct ParentObject;
 
+#define ANODE_ENUM(name) \
+    e##name,
+
+#define ANODE_FUNC(typeName, type, name)                    \
+  dom::Nullable<type> Get##name()                           \
+  {                                                         \
+    return GetProperty(AOM##typeName##Property::e##name);   \
+  }                                                         \
+                                                            \
+  void Set##name(const dom::Nullable<type>& a##name)        \
+  {                                                         \
+    SetProperty(AOM##typeName##Property::e##name, a##name); \
+  }                                                         \
+
+#define ANODE_PROPS(typeName, type, ...)                     \
+  enum class AOM##typeName##Property {                       \
+    MOZ_FOR_EACH(ANODE_ENUM, (), (__VA_ARGS__))              \
+  };                                                         \
+  MOZ_FOR_EACH(ANODE_FUNC, (typeName, type,), (__VA_ARGS__)) \
+
 class AccessibleNode : public nsISupports,
                        public nsWrapperCache
 {
 public:
   explicit AccessibleNode(nsINode* aNode);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS;
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AccessibleNode);
@@ -44,21 +65,62 @@ public:
   bool Is(const Sequence<nsString>& aFlavors);
   bool Has(const Sequence<nsString>& aAttributes);
   void Get(JSContext* cx, const nsAString& aAttribute,
            JS::MutableHandle<JS::Value> aValue,
            ErrorResult& aRv);
 
   static bool IsAOMEnabled(JSContext*, JSObject*);
 
+  ANODE_PROPS(Boolean, bool,
+    Atomic,
+    Busy,
+    Disabled,
+    Expanded,
+    Hidden,
+    Modal,
+    Multiline,
+    Multiselectable,
+    ReadOnly,
+    Required,
+    Selected
+  )
+
 protected:
   AccessibleNode(const AccessibleNode& aCopy) = delete;
   AccessibleNode& operator=(const AccessibleNode& aCopy) = delete;
   virtual ~AccessibleNode();
 
+  dom::Nullable<bool> GetProperty(AOMBooleanProperty aProperty)
+  {
+    int num = static_cast<int>(aProperty);
+    if (mBooleanProperties & (1U << (2 * num))) {
+      bool data = static_cast<bool>(mBooleanProperties & (1U << (2 * num + 1)));
+      return dom::Nullable<bool>(data);
+    }
+    return dom::Nullable<bool>();
+  }
+
+  void SetProperty(AOMBooleanProperty aProperty,
+                   const dom::Nullable<bool>& aValue)
+  {
+    int num = static_cast<int>(aProperty);
+    if (aValue.IsNull()) {
+      mBooleanProperties &= ~(1U << (2 * num));
+    } else {
+      mBooleanProperties |= (1U << (2 * num));
+      mBooleanProperties = (aValue.Value() ? mBooleanProperties | (1U << (2 * num + 1))
+                                           : mBooleanProperties & ~(1U << (2 * num + 1)));
+    }
+  }
+
+  // The 2k'th bit indicates whether the k'th boolean property is used(1) or not(0)
+  // and 2k+1'th bit contains the property's value(1:true, 0:false)
+  uint32_t mBooleanProperties;
+
   RefPtr<a11y::Accessible> mIntl;
   RefPtr<nsINode> mDOMNode;
   RefPtr<dom::DOMStringList> mStates;
 };
 
 } // dom
 } // mozilla
 
--- a/accessible/tests/mochitest/aom/test_general.html
+++ b/accessible/tests/mochitest/aom/test_general.html
@@ -36,16 +36,26 @@
     return new Promise((resolve) => {
       let iframe = document.createElement("iframe");
       iframe.src = `data:text/html,<html><body>hey</body></html>`;
       iframe.onload = () => resolve(iframe.contentDocument);
       document.body.appendChild(iframe);
     });
   }
 
+  function testBoolProp(anode, prop) {
+    is(anode[prop], null, `anode.${prop} should be null`);
+    anode[prop] = true;
+    is(anode[prop], true, `anode.${prop} was assigned true`);
+    anode[prop] = false;
+    is(anode[prop], false, `anode.${prop} was assigned false`);
+    anode[prop] = null;
+    is(anode[prop], null, `anode.${prop} was assigned null`);
+  }
+
   // Check that the WebIDL is as expected.
   function checkImplementation(ifrDoc) {
     let anode = ifrDoc.accessibleNode;
     ok(anode, "DOM document has accessible node");
 
     is(anode.role, "document", "correct role of a document accessible node");
     is(anode.DOMNode, ifrDoc, "correct DOM Node of a document accessible node");
 
@@ -96,16 +106,23 @@
     }
 
     is(anode.attributes.length, attrs.length, "correct number of attributes");
     for (let i = 0; i < attrs.length; i++) {
       ok(attrs.includes(anode.attributes[i]),
          `${anode.attributes[i]} attribute is expected and found`);
     }
 
+    const boolProps = ["atomic", "busy", "disabled", "expanded", "hidden", "modal",
+                       "multiline", "multiselectable", "readOnly", "required", "selected"];
+
+    for (const boolProp of boolProps) {
+      testBoolProp(anode, boolProp);
+    }
+
     // Check if an AccessibleNode is properly cached.
     let node = ifrDoc.createElement("div");
     anode = node.accessibleNode;
     is(anode, node.accessibleNode, "an AccessibleNode is properly cached");
 
     // Adopting node to another document doesn't change .accessibleNode
     let anotherDoc = document.implementation.createDocument("", "", null);
     let adopted_node = anotherDoc.adoptNode(node);
--- a/browser/components/extensions/ExtensionPopups.jsm
+++ b/browser/components/extensions/ExtensionPopups.jsm
@@ -73,16 +73,17 @@ class BasePopup {
     this.blockParser = blockParser;
 
     extension.callOnClose(this);
 
     this.contentReady = new Promise(resolve => {
       this._resolveContentReady = resolve;
     });
 
+    this.window.addEventListener("unload", this);
     this.viewNode.addEventListener(this.DESTROY_EVENT, this);
     this.panel.addEventListener("popuppositioned", this, {once: true, capture: true});
 
     this.browser = null;
     this.browserLoaded = new Promise((resolve, reject) => {
       this.browserLoadedDeferred = {resolve, reject};
     });
     this.browserReady = this.createBrowser(viewNode, popupURL);
@@ -96,16 +97,18 @@ class BasePopup {
 
   close() {
     this.closePopup();
   }
 
   destroy() {
     this.extension.forgetOnClose(this);
 
+    this.window.removeEventListener("unload", this);
+
     this.destroyed = true;
     this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
     // Ignore unhandled rejections if the "attach" method is not called.
     this.browserLoaded.catch(() => {});
 
     BasePopup.instances.get(this.window).delete(this.extension);
 
     return this.browserReady.then(() => {
@@ -207,16 +210,17 @@ class BasePopup {
       case "Extension:DOMWindowClose":
         this.closePopup();
         break;
     }
   }
 
   handleEvent(event) {
     switch (event.type) {
+      case "unload":
       case this.DESTROY_EVENT:
         if (!this.destroyed) {
           this.destroy();
         }
         break;
       case "popuppositioned":
         if (!this.destroyed) {
           this.browserLoaded.then(() => {
@@ -476,16 +480,19 @@ class ViewPopup extends BasePopup {
    * @param {Element} viewNode
    *        The node to attach the browser to.
    * @returns {Promise<boolean>}
    *        Resolves when the browser is ready. Resolves to `false` if the
    *        browser was destroyed before it was fully loaded, and the popup
    *        should be closed, or `true` otherwise.
    */
   async attach(viewNode) {
+    this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
+    this.panel.removeEventListener("popuppositioned", this, {once: true, capture: true});
+
     this.viewNode = viewNode;
     this.viewNode.addEventListener(this.DESTROY_EVENT, this);
     this.viewNode.setAttribute("closemenu", "none");
 
     this.panel.addEventListener("popuppositioned", this, {once: true, capture: true});
     if (this.extension.remote) {
       this.panel.setAttribute("remote", "true");
     }
--- a/browser/components/payments/res/components/rich-select.css
+++ b/browser/components/payments/res/components/rich-select.css
@@ -1,14 +1,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/. */
 
 rich-select {
-  display: inline-block;
+  border: 1px solid #0C0C0D33;
+  display: block;
+  margin: 14px 0;
   position: relative;
 }
 
 /* Focusing on the underlying select element outlines the outer
 rich-select wrapper making it appear like rich-select is focused. */
 rich-select:focus-within {
   outline: 1px dotted;
 }
--- a/browser/components/payments/res/containers/address-picker.js
+++ b/browser/components/payments/res/containers/address-picker.js
@@ -1,55 +1,35 @@
 /* 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 AddressOption from "../components/address-option.js";
-import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
-import RichSelect from "../components/rich-select.js";
+import RichPicker from "./rich-picker.js";
 import paymentRequest from "../paymentRequest.js";
 
 /**
  * <address-picker></address-picker>
  * Container around add/edit links and <rich-select> with
  * <address-option> listening to savedAddresses & tempAddresses.
  */
 
-export default class AddressPicker extends PaymentStateSubscriberMixin(HTMLElement) {
+export default class AddressPicker extends RichPicker {
   static get observedAttributes() {
-    return ["address-fields"];
+    return RichPicker.observedAttributes.concat(["address-fields"]);
   }
 
   constructor() {
     super();
-    this.dropdown = new RichSelect();
-    this.dropdown.addEventListener("change", this);
     this.dropdown.setAttribute("option-type", "address-option");
-    this.addLink = document.createElement("a");
-    this.addLink.className = "add-link";
-    this.addLink.href = "javascript:void(0)";
-    this.addLink.textContent = this.dataset.addLinkLabel;
-    this.addLink.addEventListener("click", this);
-    this.editLink = document.createElement("a");
-    this.editLink.className = "edit-link";
-    this.editLink.href = "javascript:void(0)";
-    this.editLink.textContent = this.dataset.editLinkLabel;
-    this.editLink.addEventListener("click", this);
-  }
-
-  connectedCallback() {
-    this.appendChild(this.dropdown);
-    this.appendChild(this.addLink);
-    this.append(" ");
-    this.appendChild(this.editLink);
-    super.connectedCallback();
   }
 
   attributeChangedCallback(name, oldValue, newValue) {
-    if (oldValue !== newValue) {
+    super.attributeChangedCallback(name, oldValue, newValue);
+    if (name == "address-fields" && oldValue !== newValue) {
       this.render(this.requestStore.getState());
     }
   }
 
   /**
    * De-dupe and filter addresses for the given set of fields that will be visible
    *
    * @param {object} addresses
--- a/browser/components/payments/res/containers/payment-dialog.js
+++ b/browser/components/payments/res/containers/payment-dialog.js
@@ -40,17 +40,16 @@ export default class PaymentDialog exten
     this._payButton.addEventListener("click", this);
 
     this._viewAllButton = contents.querySelector("#view-all");
     this._viewAllButton.addEventListener("click", this);
 
     this._mainContainer = contents.getElementById("main-container");
     this._orderDetailsOverlay = contents.querySelector("#order-details-overlay");
 
-    this._shippingTypeLabel = contents.querySelector("#shipping-type-label");
     this._shippingAddressPicker = contents.querySelector("address-picker.shipping-related");
     this._shippingRelatedEls = contents.querySelectorAll(".shipping-related");
     this._payerRelatedEls = contents.querySelectorAll(".payer-related");
     this._payerAddressPicker = contents.querySelector("address-picker.payer-related");
 
     this._header = contents.querySelector("header");
 
     this._errorText = contents.querySelector("#error-text");
@@ -247,16 +246,18 @@ export default class PaymentDialog exten
     let additionalItems = this._getAdditionalDisplayItems(state);
     this._viewAllButton.hidden = !displayItems.length && !additionalItems.length;
 
     let shippingType = state.request.paymentOptions.shippingType || "shipping";
     this._shippingAddressPicker.dataset.addAddressTitle =
       this.dataset[shippingType + "AddressTitleAdd"];
     this._shippingAddressPicker.dataset.editAddressTitle =
       this.dataset[shippingType + "AddressTitleEdit"];
+    let addressPickerLabel = this._shippingAddressPicker.dataset[shippingType + "AddressLabel"];
+    this._shippingAddressPicker.setAttribute("label", addressPickerLabel);
 
     let totalItem = paymentRequest.getTotalItem(state);
     let totalAmountEl = this.querySelector("#total > currency-amount");
     totalAmountEl.value = totalItem.amount.value;
     totalAmountEl.currency = totalItem.amount.currency;
 
     // Show the total header on the address and basic card pages only during
     // on-boarding(FTU) and on the payment summary page.
@@ -289,19 +290,16 @@ export default class PaymentDialog exten
       }
       this._payerAddressPicker.setAttribute("address-fields", [...fieldNames].join(" "));
     } else {
       this._payerAddressPicker.removeAttribute("address-fields");
     }
     this._payerAddressPicker.dataset.addAddressTitle = this.dataset.payerTitleAdd;
     this._payerAddressPicker.dataset.editAddressTitle = this.dataset.payerTitleEdit;
 
-    this._shippingTypeLabel.querySelector("label").textContent =
-      this._shippingTypeLabel.dataset[shippingType + "AddressLabel"];
-
     this._renderPayButton(state);
 
     for (let page of this._mainContainer.querySelectorAll(":scope > .page")) {
       page.hidden = state.page.id != page.id;
     }
 
     let {
       changesPrevented,
--- a/browser/components/payments/res/containers/payment-method-picker.js
+++ b/browser/components/payments/res/containers/payment-method-picker.js
@@ -1,55 +1,37 @@
 /* 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 BasicCardOption from "../components/basic-card-option.js";
-import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
-import RichSelect from "../components/rich-select.js";
+import RichPicker from "./rich-picker.js";
 import paymentRequest from "../paymentRequest.js";
 
 /**
  * <payment-method-picker></payment-method-picker>
  * Container around add/edit links and <rich-select> with
  * <basic-card-option> listening to savedBasicCards.
  */
 
-export default class PaymentMethodPicker extends PaymentStateSubscriberMixin(HTMLElement) {
+export default class PaymentMethodPicker extends RichPicker {
   constructor() {
     super();
-    this.dropdown = new RichSelect();
-    this.dropdown.addEventListener("change", this);
     this.dropdown.setAttribute("option-type", "basic-card-option");
-    this.spacerText = document.createTextNode(" ");
     this.securityCodeInput = document.createElement("input");
     this.securityCodeInput.autocomplete = "off";
+    this.securityCodeInput.placeholder = "CVV"; /* XXX Bug 1473772 */
     this.securityCodeInput.size = 3;
     this.securityCodeInput.classList.add("security-code");
     this.securityCodeInput.addEventListener("change", this);
-    this.addLink = document.createElement("a");
-    this.addLink.className = "add-link";
-    this.addLink.href = "javascript:void(0)";
-    this.addLink.textContent = this.dataset.addLinkLabel;
-    this.addLink.addEventListener("click", this);
-    this.editLink = document.createElement("a");
-    this.editLink.className = "edit-link";
-    this.editLink.href = "javascript:void(0)";
-    this.editLink.textContent = this.dataset.editLinkLabel;
-    this.editLink.addEventListener("click", this);
   }
 
   connectedCallback() {
-    this.appendChild(this.dropdown);
-    this.appendChild(this.spacerText);
-    this.appendChild(this.securityCodeInput);
-    this.appendChild(this.addLink);
-    this.append(" ");
-    this.appendChild(this.editLink);
     super.connectedCallback();
+    this.dropdown.after(this.securityCodeInput);
   }
 
   render(state) {
     let basicCards = paymentRequest.getBasicCards(state);
     let desiredOptions = [];
     for (let [guid, basicCard] of Object.entries(basicCards)) {
       let optionEl = this.dropdown.getOptionByValue(guid);
       if (!optionEl) {
new file mode 100644
--- /dev/null
+++ b/browser/components/payments/res/containers/rich-picker.css
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+.rich-picker {
+  display: grid;
+  grid-template-columns: 5fr auto auto;
+  grid-template-areas:
+    "label    edit     add"
+    "dropdown dropdown dropdown";
+}
+
+.rich-picker > label {
+  color: #0c0c0d;
+  font-weight: 700;
+  grid-area: label;
+}
+
+.rich-picker > .add-link,
+.rich-picker > .edit-link {
+  padding: 0 8px;
+}
+
+.rich-picker > .add-link {
+  grid-area: add;
+}
+
+.rich-picker > .edit-link {
+  grid-area: edit;
+  border-right: 1px solid #0C0C0D33;
+}
+
+.rich-picker > rich-select {
+  grid-area: dropdown;
+}
+
+/* Payment Method Picker */
+payment-method-picker.rich-picker {
+  grid-template-columns: 20fr 1fr auto auto;
+  grid-template-areas:
+    "label    spacer edit add"
+    "dropdown cvv    cvv  cvv";
+}
+
+payment-method-picker > input {
+  border: 1px solid #0C0C0D33;
+  border-left: none;
+  grid-area: cvv;
+  margin: 14px 0; /* Has to be same as rich-select */
+  padding: 8px;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/payments/res/containers/rich-picker.js
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
+import RichSelect from "../components/rich-select.js";
+
+export default class RichPicker extends PaymentStateSubscriberMixin(HTMLElement) {
+  static get observedAttributes() {
+    return ["label"];
+  }
+
+  constructor() {
+    super();
+    this.classList.add("rich-picker");
+
+    this.dropdown = new RichSelect();
+    this.dropdown.addEventListener("change", this);
+    this.dropdown.popupBox.id = "select-" + Math.floor(Math.random() * 1000000);
+
+    this.labelElement = document.createElement("label");
+    this.labelElement.setAttribute("for", this.dropdown.popupBox.id);
+
+    this.addLink = document.createElement("a");
+    this.addLink.className = "add-link";
+    this.addLink.href = "javascript:void(0)";
+    this.addLink.textContent = this.dataset.addLinkLabel;
+    this.addLink.addEventListener("click", this);
+
+    this.editLink = document.createElement("a");
+    this.editLink.className = "edit-link";
+    this.editLink.href = "javascript:void(0)";
+    this.editLink.textContent = this.dataset.editLinkLabel;
+    this.editLink.addEventListener("click", this);
+  }
+
+  connectedCallback() {
+    // The document order, by default, controls tab order so keep that in mind if changing this.
+    this.appendChild(this.labelElement);
+    this.appendChild(this.dropdown);
+    this.appendChild(this.editLink);
+    this.appendChild(this.addLink);
+    super.connectedCallback();
+  }
+
+  attributeChangedCallback(name, oldValue, newValue) {
+    if (name == "label") {
+      this.labelElement.textContent = newValue;
+    }
+  }
+}
--- a/browser/components/payments/res/containers/shipping-option-picker.js
+++ b/browser/components/payments/res/containers/shipping-option-picker.js
@@ -1,36 +1,31 @@
 /* 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 PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
-import RichSelect from "../components/rich-select.js";
+import RichPicker from "./rich-picker.js";
 import ShippingOption from "../components/shipping-option.js";
 
 /**
  * <shipping-option-picker></shipping-option-picker>
  * Container around <rich-select> with
  * <option> listening to shippingOptions.
  */
 
-export default class ShippingOptionPicker extends PaymentStateSubscriberMixin(HTMLElement) {
+export default class ShippingOptionPicker extends RichPicker {
   constructor() {
     super();
-    this.dropdown = new RichSelect();
-    this.dropdown.addEventListener("change", this);
     this.dropdown.setAttribute("option-type", "shipping-option");
   }
 
-  connectedCallback() {
-    this.appendChild(this.dropdown);
-    super.connectedCallback();
-  }
+  render(state) {
+    this.addLink.hidden = true;
+    this.editLink.hidden = true;
 
-  render(state) {
     let {shippingOptions} = state.request.paymentDetails;
     let desiredOptions = [];
     for (let option of shippingOptions) {
       let optionEl = this.dropdown.getOptionByValue(option.id);
       if (!optionEl) {
         optionEl = document.createElement("option");
         optionEl.value = option.id;
       }
--- a/browser/components/payments/res/paymentRequest.css
+++ b/browser/components/payments/res/paymentRequest.css
@@ -50,16 +50,17 @@ payment-dialog > header {
   padding-top: 19px;
 }
 
 #main-container {
   display: flex;
   grid-area: main;
   position: relative;
   max-height: 100%;
+  padding-top: 18px;
 }
 
 .page {
   display: flex;
   flex-direction: column;
   height: 100%;
   position: relative;
   width: 100%;
--- a/browser/components/payments/res/paymentRequest.xhtml
+++ b/browser/components/payments/res/paymentRequest.xhtml
@@ -68,16 +68,17 @@
   <link rel="stylesheet" href="components/rich-select.css"/>
   <link rel="stylesheet" href="components/address-option.css"/>
   <link rel="stylesheet" href="components/basic-card-option.css"/>
   <link rel="stylesheet" href="components/shipping-option.css"/>
   <link rel="stylesheet" href="components/payment-details-item.css"/>
   <link rel="stylesheet" href="containers/address-form.css"/>
   <link rel="stylesheet" href="containers/basic-card-form.css"/>
   <link rel="stylesheet" href="containers/order-details.css"/>
+  <link rel="stylesheet" href="containers/rich-picker.css"/>
 
   <script src="unprivileged-fallbacks.js"></script>
 
   <script src="formautofill/autofillEditForms.js"></script>
 
   <script type="module" src="containers/payment-dialog.js"></script>
   <script type="module" src="paymentRequest.js"></script>
 
@@ -91,39 +92,34 @@
         <button id="view-all" class="closed">&viewAllItems;</button>
       </div>
     </header>
 
     <div id="main-container">
       <payment-request-page id="payment-summary">
         <div class="page-body">
           <div id="error-text"></div>
-
-          <div class="shipping-related"
-               id="shipping-type-label"
-               data-shipping-address-label="&shippingAddressLabel;"
-               data-delivery-address-label="&deliveryAddressLabel;"
-               data-persist-checkbox-label="&addressPage.persistCheckbox.label;"
-               data-pickup-address-label="&pickupAddressLabel;"><label></label></div>
           <address-picker class="shipping-related"
                           data-add-link-label="&address.addLink.label;"
                           data-edit-link-label="&address.editLink.label;"
+                          data-shipping-address-label="&shippingAddressLabel;"
+                          data-delivery-address-label="&deliveryAddressLabel;"
+                          data-pickup-address-label="&pickupAddressLabel;"
                           selected-state-key="selectedShippingAddress"></address-picker>
 
-          <div class="shipping-related"><label>&shippingOptionsLabel;</label></div>
-          <shipping-option-picker class="shipping-related"></shipping-option-picker>
+          <shipping-option-picker class="shipping-related"
+                                  label="&shippingOptionsLabel;"></shipping-option-picker>
 
-          <div><label>&paymentMethodsLabel;</label></div>
           <payment-method-picker selected-state-key="selectedPaymentCard"
                                  data-add-link-label="&basicCard.addLink.label;"
-                                 data-edit-link-label="&basicCard.editLink.label;">
+                                 data-edit-link-label="&basicCard.editLink.label;"
+                                 label="&paymentMethodsLabel;">
           </payment-method-picker>
-
-          <div class="payer-related"><label>&payerLabel;</label></div>
           <address-picker class="payer-related"
+                          label="&payerLabel;"
                           data-add-link-label="&payer.addLink.label;"
                           data-edit-link-label="&payer.editLink.label;"
                           selected-state-key="selectedPayerAddress"></address-picker>
           <div id="error-text"></div>
         </div>
 
         <footer>
           <button id="cancel">&cancelPaymentButton.label;</button>
--- a/browser/components/payments/test/browser/browser_request_shipping.js
+++ b/browser/components/payments/test/browser/browser_request_shipping.js
@@ -30,20 +30,20 @@ add_task(async function test_request_shi
         }
       );
 
       await spawnPaymentDialogTask(frame, async ([aShippingKey, aShippingString]) => {
         let shippingOptionPicker = content.document.querySelector("shipping-option-picker");
         ok(content.isVisible(shippingOptionPicker),
            "shipping-option-picker should be visible");
         const addressSelector = "address-picker[selected-state-key='selectedShippingAddress']";
-        let shippingAddress = content.document.querySelector(addressSelector);
-        ok(content.isVisible(shippingAddress),
+        let shippingAddressPicker = content.document.querySelector(addressSelector);
+        ok(content.isVisible(shippingAddressPicker),
            "shipping address picker should be visible");
-        let shippingOption = content.document.querySelector("#shipping-type-label");
+        let shippingOption = shippingAddressPicker.querySelector("label");
         is(shippingOption.textContent, aShippingString,
            "Label should be match shipping type: " + aShippingKey);
       }, [shippingKey, shippingString]);
 
       spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
 
       await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
     }
--- a/browser/components/payments/test/mochitest/test_payment_dialog.html
+++ b/browser/components/payments/test/mochitest/test_payment_dialog.html
@@ -11,16 +11,17 @@ Test the payment-dialog custom element
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script src="sinon-2.3.2.js"></script>
   <script src="payments_common.js"></script>
   <script src="../../res/vendor/custom-elements.min.js"></script>
   <script src="../../res/unprivileged-fallbacks.js"></script>
 
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <link rel="stylesheet" type="text/css" href="../../res/paymentRequest.css"/>
+  <link rel="stylesheet" type="text/css" href="../../res/containers/rich-picker.css"/>
 </head>
 <body>
   <p id="display">
     <iframe id="templateFrame" src="../../res/paymentRequest.xhtml" width="0" height="0"></iframe>
   </p>
 <div id="content" style="display: none">
 
 </div>
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/win64/nightly-asan-reporter
@@ -0,0 +1,28 @@
+MOZ_AUTOMATION_L10N_CHECK=0
+
+ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
+MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
+
+. "$topsrcdir/build/mozconfig.win-common"
+. "$topsrcdir/browser/config/mozconfigs/common"
+
+ac_add_options --disable-debug
+ac_add_options --enable-optimize="-O2 -gline-tables-only"
+ac_add_options --enable-address-sanitizer-reporter
+
+. "$topsrcdir/build/win64/mozconfig.vs-latest"
+
+. "$topsrcdir/build/win64/mozconfig.asan"
+
+export MOZ_PKG_SPECIAL=asan-reporter
+
+# Need this to add source information into platform.ini
+export MOZILLA_OFFICIAL=1
+
+# Enable Telemetry
+# The channel reported by Telemetry here will be "nightly-asan" as specified
+# in the respective override pref (toolkit.telemetry.overrideUpdateChannel),
+# while the build otherwise identifies as "nightly" to receive its updates.
+export MOZ_TELEMETRY_REPORTING=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/themes/shared/aboutNetError.css
+++ b/browser/themes/shared/aboutNetError.css
@@ -3,16 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 @import url("chrome://browser/skin/error-pages.css");
 
 :root {
   --exception-button-container-background: #F5F5F7;
 }
 
+body.certerror {
+  justify-content: normal;
+}
+
 body.captiveportal .title {
   background-image: url("wifi.svg");
 }
 
 body.certerror .title {
   background-image: url("cert-error.svg");
 }
 
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 72
+Version 73
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-71...release-72
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-72...release-73
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.4.1
 - react-dom @16.4.1
 - webpack @3.11.0
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -2716,32 +2716,36 @@ html[dir="rtl"] .editor-mount {
 
 :not(.empty-line):not(.new-breakpoint)
   > .CodeMirror-gutter-wrapper:hover
   > .CodeMirror-linenumber {
   height: 13px;
   color: var(--theme-body-color);
   /* Add 1px offset to the background to match it
     with the actual breakpoint image dimensions */
-  background: linear-gradient(to bottom, transparent 1px, var(--gutter-hover-background-color) 0);
+  background: linear-gradient(
+    to bottom,
+    transparent 1px,
+    var(--gutter-hover-background-color) 0
+  );
 }
 
 :not(.empty-line):not(.new-breakpoint)
   > .CodeMirror-gutter-wrapper:hover
   > .CodeMirror-linenumber::after {
-    content: '';
-    position: absolute;
-    top: 1px;
-    height: 12px;
-    width: 9px;
-    background-color: var(--gutter-hover-background-color);
-    mask: url("chrome://devtools/skin/images/debugger/breakpoint.svg") no-repeat;
-    mask-size: auto 12px;
-    mask-position: right;
-  }
+  content: "";
+  position: absolute;
+  top: 1px;
+  height: 12px;
+  width: 9px;
+  background-color: var(--gutter-hover-background-color);
+  mask: url("chrome://devtools/skin/images/debugger/breakpoint.svg") no-repeat;
+  mask-size: auto 12px;
+  mask-position: right;
+}
 
 .editor-wrapper .breakpoints {
   position: absolute;
   top: 0;
   left: 0;
 }
 
 .function-search {
@@ -2781,18 +2785,18 @@ html[dir="rtl"] .editor-mount {
   padding: 0px 5px;
   margin: 0px 4px;
   border-radius: 5px;
   border-color: blue;
   border: 1px solid #00b6ff;
 }
 
 .editor .breakpoint {
-    position: absolute;
-    right: -2px;
+  position: absolute;
+  right: -2px;
 }
 
 .editor.new-breakpoint.folding-enabled svg {
   right: -16px;
 }
 
 .new-breakpoint.has-condition svg {
   fill: var(--theme-graphs-yellow);
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -22777,16 +22777,17 @@ function parseSourceScopes(sourceId) {
 
 function buildScopeList(ast, sourceId) {
   const { global, lexical } = createGlobalScope(ast, sourceId);
 
   const state = {
     sourceId,
     freeVariables: new Map(),
     freeVariableStack: [],
+    inType: null,
     scope: lexical,
     scopeStack: [],
     declarationBindingIds: new Set()
   };
   t.traverse(ast, scopeCollectionVisitor, state);
 
   for (const [key, freeVariables] of state.freeVariables) {
     let binding = global.bindings[key];
@@ -22903,16 +22904,18 @@ function parseDeclarator(declaratorId, t
   } else if (isNode(declaratorId, "ArrayPattern")) {
     declaratorId.elements.forEach(item => {
       parseDeclarator(item, targetScope, type, locationType, declaration, state);
     });
   } else if (isNode(declaratorId, "AssignmentPattern")) {
     parseDeclarator(declaratorId.left, targetScope, type, locationType, declaration, state);
   } else if (isNode(declaratorId, "RestElement")) {
     parseDeclarator(declaratorId.argument, targetScope, type, locationType, declaration, state);
+  } else if (t.isTSParameterProperty(declaratorId)) {
+    parseDeclarator(declaratorId.parameter, targetScope, type, locationType, declaration, state);
   }
 }
 
 function isLetOrConst(node) {
   return node.kind === "let" || node.kind === "const";
 }
 
 function hasLexicalDeclaration(node, parent) {
@@ -22952,16 +22955,20 @@ function createGlobalScope(ast, sourceId
 
 const scopeCollectionVisitor = {
   // eslint-disable-next-line complexity
   enter(node, ancestors, state) {
     state.scopeStack.push(state.scope);
 
     const parentNode = ancestors.length === 0 ? null : ancestors[ancestors.length - 1].node;
 
+    if (state.inType) {
+      return;
+    }
+
     if (t.isProgram(node)) {
       const scope = pushTempScope(state, "module", "Module", {
         start: fromBabelLocation(node.loc.start, state.sourceId),
         end: fromBabelLocation(node.loc.end, state.sourceId)
       });
       scope.bindings.this = {
         type: "implicit",
         refs: []
@@ -23122,16 +23129,20 @@ const scopeCollectionVisitor = {
     !t.isForStatement(parentNode, { init: node }) || !t.isForXStatement(parentNode, { left: node }))) {
       // Finds right lexical environment
       const hoistAt = !isLetOrConst(node) ? getVarScope(state.scope) : state.scope;
       node.declarations.forEach(declarator => {
         parseDeclarator(declarator.id, hoistAt, node.kind, node.kind, node, state);
       });
     } else if (t.isImportDeclaration(node) && (!node.importKind || node.importKind === "value")) {
       node.specifiers.forEach(spec => {
+        if (spec.importKind && spec.importKind !== "value") {
+          return;
+        }
+
         if (t.isImportNamespaceSpecifier(spec)) {
           state.declarationBindingIds.add(spec.local);
 
           state.scope.bindings[spec.local.name] = {
             // Imported namespaces aren't live import bindings, they are
             // just normal const bindings.
             type: "const",
             refs: [{
@@ -23171,20 +23182,39 @@ const scopeCollectionVisitor = {
           start: fromBabelLocation(node.id.loc.start, state.sourceId),
           end: fromBabelLocation(node.id.loc.end, state.sourceId),
           declaration: {
             start: fromBabelLocation(node.loc.start, state.sourceId),
             end: fromBabelLocation(node.loc.end, state.sourceId)
           }
         }]
       };
+    } else if (t.isTSModuleDeclaration(node)) {
+      state.declarationBindingIds.add(node.id);
+      state.scope.bindings[node.id.name] = {
+        type: "const",
+        refs: [{
+          type: "ts-namespace-decl",
+          start: fromBabelLocation(node.id.loc.start, state.sourceId),
+          end: fromBabelLocation(node.id.loc.end, state.sourceId),
+          declaration: {
+            start: fromBabelLocation(node.loc.start, state.sourceId),
+            end: fromBabelLocation(node.loc.end, state.sourceId)
+          }
+        }]
+      };
+    } else if (t.isTSModuleBlock(node)) {
+      pushTempScope(state, "block", "TypeScript Namespace", {
+        start: fromBabelLocation(node.loc.start, state.sourceId),
+        end: fromBabelLocation(node.loc.end, state.sourceId)
+      });
     } else if (t.isIdentifier(node) && t.isReferenced(node, parentNode) &&
     // Babel doesn't cover this in 'isReferenced' yet, but it should
     // eventually.
-    !t.isTSEnumMember(parentNode, { id: node }) &&
+    !t.isTSEnumMember(parentNode, { id: node }) && !t.isTSModuleDeclaration(parentNode, { id: node }) &&
     // isReferenced above fails to see `var { foo } = ...` as a non-reference
     // because the direct parent is not enough to know that the pattern is
     // used within a variable declaration.
     !state.declarationBindingIds.has(node)) {
       let freeVariables = state.freeVariables.get(node.name);
       if (!freeVariables) {
         freeVariables = [];
         state.freeVariables.set(node.name, freeVariables);
@@ -23236,16 +23266,28 @@ const scopeCollectionVisitor = {
         refs: []
       };
     } else if (t.isSwitchStatement(node) && hasLexicalDeclaration(node, parentNode)) {
       pushTempScope(state, "block", "Switch", {
         start: fromBabelLocation(node.loc.start, state.sourceId),
         end: fromBabelLocation(node.loc.end, state.sourceId)
       });
     }
+
+    if (
+    // In general Flow expressions are deleted, so they can't contain
+    // runtime bindings, but typecasts are the one exception there.
+    t.isFlow(node) && !t.isTypeCastExpression(node) ||
+    // In general TS items are deleted, but TS has a few wrapper node
+    // types that can contain general JS expressions.
+    node.type.startsWith("TS") && !t.isTSTypeAssertion(node) && !t.isTSAsExpression(node) && !t.isTSNonNullExpression(node) && !t.isTSModuleDeclaration(node) && !t.isTSModuleBlock(node) && !t.isTSParameterProperty(node) && !t.isTSExportAssignment(node)) {
+      // Flag this node as a root "type" node. All items inside of this
+      // will be skipped entirely.
+      state.inType = node;
+    }
   },
   exit(node, ancestors, state) {
     const currentScope = state.scope;
     const parentScope = state.scopeStack.pop();
     if (!parentScope) {
       throw new Error("Assertion failure - unsynchronized pop");
     }
     state.scope = parentScope;
@@ -23277,16 +23319,20 @@ const scopeCollectionVisitor = {
         if (!refs) {
           refs = [];
           parentFreeVariables.set(key, refs);
         }
 
         refs.push(...value);
       }
     }
+
+    if (state.inType === node) {
+      state.inType = null;
+    }
   }
 };
 
 function isOpeningJSXIdentifier(node, ancestors) {
   if (!t.isJSXIdentifier(node)) {
     return false;
   }
 
@@ -24865,24 +24911,17 @@ function onEnter(node, ancestors, state)
 
   if (t.isClassProperty(node)) {
     return addBreakPoint(state, startLocation);
   }
 
   if (t.isFunction(node)) {
     const { line, column } = node.loc.end;
     addBreakPoint(state, startLocation);
-    return addStopPoint(state, { line, column: column - 1 });
-  }
-
-  if (t.isProgram(node)) {
-    const lastStatement = node.body[node.body.length - 1];
-    if (lastStatement) {
-      return addStopPoint(state, lastStatement.loc.end);
-    }
+    return addEmptyPoint(state, { line, column: column - 1 });
   }
 
   if (!hasPoint(state, startLocation) && inStepExpression(parentNode)) {
     return addEmptyPoint(state, startLocation);
   }
 }
 
 function hasPoint(state, { line, column }) {
--- a/devtools/client/debugger/new/src/actions/breakpoints.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints.js
@@ -11,16 +11,17 @@ exports.enableBreakpoint = enableBreakpo
 exports.disableBreakpoint = disableBreakpoint;
 exports.toggleAllBreakpoints = toggleAllBreakpoints;
 exports.toggleBreakpoints = toggleBreakpoints;
 exports.removeAllBreakpoints = removeAllBreakpoints;
 exports.removeBreakpoints = removeBreakpoints;
 exports.remapBreakpoints = remapBreakpoints;
 exports.setBreakpointCondition = setBreakpointCondition;
 exports.toggleBreakpoint = toggleBreakpoint;
+exports.toggleBreakpointsAtLine = toggleBreakpointsAtLine;
 exports.addOrToggleDisabledBreakpoint = addOrToggleDisabledBreakpoint;
 exports.toggleDisabledBreakpoint = toggleDisabledBreakpoint;
 
 var _promise = require("./utils/middleware/promise");
 
 var _selectors = require("../selectors/index");
 
 var _breakpoint = require("../utils/breakpoint/index");
@@ -433,16 +434,50 @@ function toggleBreakpoint(line, column) 
       sourceId: selectedSource.id,
       sourceUrl: selectedSource.url,
       line: line,
       column: column
     }));
   };
 }
 
+function toggleBreakpointsAtLine(line, column) {
+  return ({
+    dispatch,
+    getState,
+    client,
+    sourceMaps
+  }) => {
+    const state = getState();
+    const selectedSource = (0, _selectors.getSelectedSource)(state);
+
+    if (!line || !selectedSource) {
+      return;
+    }
+
+    const bps = (0, _selectors.getBreakpointsAtLine)(state, line);
+    const isEmptyLine = (0, _ast.isEmptyLineInSource)(state, line, selectedSource.id);
+
+    if (isEmptyLine) {
+      return;
+    }
+
+    if (bps.size === 0) {
+      return dispatch(addBreakpoint({
+        sourceId: selectedSource.id,
+        sourceUrl: selectedSource.url,
+        line,
+        column
+      }));
+    }
+
+    return Promise.all(bps.map(bp => dispatch(removeBreakpoint(bp.location))));
+  };
+}
+
 function addOrToggleDisabledBreakpoint(line, column) {
   return ({
     dispatch,
     getState,
     client,
     sourceMaps
   }) => {
     const selectedSource = (0, _selectors.getSelectedSource)(getState());
--- a/devtools/client/debugger/new/src/actions/pause/paused.js
+++ b/devtools/client/debugger/new/src/actions/pause/paused.js
@@ -53,17 +53,17 @@ function paused(pauseInfo) {
   }) {
     const {
       frames,
       why,
       loadedObjects
     } = pauseInfo;
     const topFrame = frames.length > 0 ? frames[0] : null;
 
-    if (topFrame && why.type == "resumeLimit") {
+    if (topFrame && !why.frameFinished && why.type == "resumeLimit") {
       const mappedFrame = await (0, _mapFrames.updateFrameLocation)(topFrame, sourceMaps);
       const source = await getOriginalSourceForFrame(getState(), mappedFrame); // Ensure that the original file has loaded if there is one.
 
       await dispatch((0, _loadSourceText.loadSourceText)(source));
 
       if ((0, _pause.shouldStep)(mappedFrame, getState(), sourceMaps)) {
         dispatch((0, _commands.command)("stepOver"));
         return;
--- a/devtools/client/debugger/new/src/components/Editor/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/index.js
@@ -159,17 +159,17 @@ class Editor extends _react.PureComponen
     };
 
     this.onGutterClick = (cm, line, gutter, ev) => {
       const {
         selectedSource,
         conditionalPanelLine,
         closeConditionalPanel,
         addOrToggleDisabledBreakpoint,
-        toggleBreakpoint,
+        toggleBreakpointsAtLine,
         continueToHere
       } = this.props; // ignore right clicks in the gutter
 
       if (ev.ctrlKey && ev.button === 0 || ev.which === 3 || selectedSource && selectedSource.isBlackBoxed || !selectedSource) {
         return;
       }
 
       if (conditionalPanelLine) {
@@ -185,17 +185,17 @@ class Editor extends _react.PureComponen
       if (ev.altKey) {
         return continueToHere(sourceLine);
       }
 
       if (ev.shiftKey) {
         return addOrToggleDisabledBreakpoint(sourceLine);
       }
 
-      return toggleBreakpoint(sourceLine);
+      return toggleBreakpointsAtLine(sourceLine);
     };
 
     this.onGutterContextMenu = event => {
       event.stopPropagation();
       event.preventDefault();
       return this.props.setContextMenu("Gutter", event);
     };
 
@@ -628,12 +628,13 @@ const mapStateToProps = state => {
 };
 
 exports.default = (0, _reactRedux.connect)(mapStateToProps, {
   openConditionalPanel: _actions2.default.openConditionalPanel,
   closeConditionalPanel: _actions2.default.closeConditionalPanel,
   setContextMenu: _actions2.default.setContextMenu,
   continueToHere: _actions2.default.continueToHere,
   toggleBreakpoint: _actions2.default.toggleBreakpoint,
+  toggleBreakpointsAtLine: _actions2.default.toggleBreakpointsAtLine,
   addOrToggleDisabledBreakpoint: _actions2.default.addOrToggleDisabledBreakpoint,
   jumpToMappedLocation: _actions2.default.jumpToMappedLocation,
   traverseResults: _actions2.default.traverseResults
 })(Editor);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/selectors/breakpointAtLocation.js
+++ b/devtools/client/debugger/new/src/selectors/breakpointAtLocation.js
@@ -1,14 +1,15 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getBreakpointAtLocation = getBreakpointAtLocation;
+exports.getBreakpointsAtLine = getBreakpointsAtLine;
 
 var _sources = require("../reducers/sources");
 
 var _breakpoints = require("../reducers/breakpoints");
 
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
@@ -65,9 +66,15 @@ function findBreakpointAtLocation(breakp
  * user clicks in the gutter or on a token.
  */
 
 
 function getBreakpointAtLocation(state, location) {
   const selectedSource = (0, _sources.getSelectedSource)(state);
   const breakpoints = getBreakpointsForSource(state, selectedSource);
   return findBreakpointAtLocation(breakpoints, selectedSource, location);
+}
+
+function getBreakpointsAtLine(state, line) {
+  const selectedSource = (0, _sources.getSelectedSource)(state);
+  const breakpoints = getBreakpointsForSource(state, selectedSource);
+  return breakpoints.filter(breakpoint => getLocation(breakpoint, selectedSource).line === line);
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/selectors/index.js
+++ b/devtools/client/debugger/new/src/selectors/index.js
@@ -193,16 +193,22 @@ Object.defineProperty(exports, "getQuick
 var _breakpointAtLocation = require("./breakpointAtLocation");
 
 Object.defineProperty(exports, "getBreakpointAtLocation", {
   enumerable: true,
   get: function () {
     return _breakpointAtLocation.getBreakpointAtLocation;
   }
 });
+Object.defineProperty(exports, "getBreakpointsAtLine", {
+  enumerable: true,
+  get: function () {
+    return _breakpointAtLocation.getBreakpointsAtLine;
+  }
+});
 
 var _visibleBreakpoints = require("./visibleBreakpoints");
 
 Object.defineProperty(exports, "getVisibleBreakpoints", {
   enumerable: true,
   get: function () {
     return _visibleBreakpoints.getVisibleBreakpoints;
   }
--- a/devtools/client/debugger/new/src/utils/pause/mapScopes/index.js
+++ b/devtools/client/debugger/new/src/utils/pause/mapScopes/index.js
@@ -94,17 +94,17 @@ function isReliableScope(scope) {
 
       if (binding.value && typeof binding.value === "object" && (binding.value.type === "unscoped" || binding.value.type === "unmapped")) {
         unknownBindings += 1;
       }
     }
   } // As determined by fair dice roll.
 
 
-  return totalBindings === 0 || unknownBindings / totalBindings < 0.1;
+  return totalBindings === 0 || unknownBindings / totalBindings < 0.25;
 }
 
 function batchScopeMappings(originalAstScopes, source, sourceMaps) {
   const precalculatedRanges = new Map();
   const precalculatedLocations = new Map(); // Explicitly dispatch all of the sourcemap requests synchronously up front so
   // that they will be batched into a single request for the worker to process.
 
   for (const item of originalAstScopes) {
--- a/devtools/client/debugger/new/src/workers/parser/getScopes/visitor.js
+++ b/devtools/client/debugger/new/src/workers/parser/getScopes/visitor.js
@@ -43,16 +43,17 @@ function buildScopeList(ast, sourceId) {
   const {
     global,
     lexical
   } = createGlobalScope(ast, sourceId);
   const state = {
     sourceId,
     freeVariables: new Map(),
     freeVariableStack: [],
+    inType: null,
     scope: lexical,
     scopeStack: [],
     declarationBindingIds: new Set()
   };
   t.traverse(ast, scopeCollectionVisitor, state);
 
   for (const [key, freeVariables] of state.freeVariables) {
     let binding = global.bindings[key];
@@ -177,16 +178,18 @@ function parseDeclarator(declaratorId, t
   } else if (isNode(declaratorId, "ArrayPattern")) {
     declaratorId.elements.forEach(item => {
       parseDeclarator(item, targetScope, type, locationType, declaration, state);
     });
   } else if (isNode(declaratorId, "AssignmentPattern")) {
     parseDeclarator(declaratorId.left, targetScope, type, locationType, declaration, state);
   } else if (isNode(declaratorId, "RestElement")) {
     parseDeclarator(declaratorId.argument, targetScope, type, locationType, declaration, state);
+  } else if (t.isTSParameterProperty(declaratorId)) {
+    parseDeclarator(declaratorId.parameter, targetScope, type, locationType, declaration, state);
   }
 }
 
 function isLetOrConst(node) {
   return node.kind === "let" || node.kind === "const";
 }
 
 function hasLexicalDeclaration(node, parent) {
@@ -226,16 +229,20 @@ function createGlobalScope(ast, sourceId
 }
 
 const scopeCollectionVisitor = {
   // eslint-disable-next-line complexity
   enter(node, ancestors, state) {
     state.scopeStack.push(state.scope);
     const parentNode = ancestors.length === 0 ? null : ancestors[ancestors.length - 1].node;
 
+    if (state.inType) {
+      return;
+    }
+
     if (t.isProgram(node)) {
       const scope = pushTempScope(state, "module", "Module", {
         start: fromBabelLocation(node.loc.start, state.sourceId),
         end: fromBabelLocation(node.loc.end, state.sourceId)
       });
       scope.bindings.this = {
         type: "implicit",
         refs: []
@@ -399,16 +406,20 @@ const scopeCollectionVisitor = {
     }))) {
       // Finds right lexical environment
       const hoistAt = !isLetOrConst(node) ? getVarScope(state.scope) : state.scope;
       node.declarations.forEach(declarator => {
         parseDeclarator(declarator.id, hoistAt, node.kind, node.kind, node, state);
       });
     } else if (t.isImportDeclaration(node) && (!node.importKind || node.importKind === "value")) {
       node.specifiers.forEach(spec => {
+        if (spec.importKind && spec.importKind !== "value") {
+          return;
+        }
+
         if (t.isImportNamespaceSpecifier(spec)) {
           state.declarationBindingIds.add(spec.local);
           state.scope.bindings[spec.local.name] = {
             // Imported namespaces aren't live import bindings, they are
             // just normal const bindings.
             type: "const",
             refs: [{
               type: "import-ns-decl",
@@ -446,20 +457,41 @@ const scopeCollectionVisitor = {
           start: fromBabelLocation(node.id.loc.start, state.sourceId),
           end: fromBabelLocation(node.id.loc.end, state.sourceId),
           declaration: {
             start: fromBabelLocation(node.loc.start, state.sourceId),
             end: fromBabelLocation(node.loc.end, state.sourceId)
           }
         }]
       };
+    } else if (t.isTSModuleDeclaration(node)) {
+      state.declarationBindingIds.add(node.id);
+      state.scope.bindings[node.id.name] = {
+        type: "const",
+        refs: [{
+          type: "ts-namespace-decl",
+          start: fromBabelLocation(node.id.loc.start, state.sourceId),
+          end: fromBabelLocation(node.id.loc.end, state.sourceId),
+          declaration: {
+            start: fromBabelLocation(node.loc.start, state.sourceId),
+            end: fromBabelLocation(node.loc.end, state.sourceId)
+          }
+        }]
+      };
+    } else if (t.isTSModuleBlock(node)) {
+      pushTempScope(state, "block", "TypeScript Namespace", {
+        start: fromBabelLocation(node.loc.start, state.sourceId),
+        end: fromBabelLocation(node.loc.end, state.sourceId)
+      });
     } else if (t.isIdentifier(node) && t.isReferenced(node, parentNode) && // Babel doesn't cover this in 'isReferenced' yet, but it should
     // eventually.
     !t.isTSEnumMember(parentNode, {
       id: node
+    }) && !t.isTSModuleDeclaration(parentNode, {
+      id: node
     }) && // isReferenced above fails to see `var { foo } = ...` as a non-reference
     // because the direct parent is not enough to know that the pattern is
     // used within a variable declaration.
     !state.declarationBindingIds.has(node)) {
       let freeVariables = state.freeVariables.get(node.name);
 
       if (!freeVariables) {
         freeVariables = [];
@@ -516,16 +548,26 @@ const scopeCollectionVisitor = {
         refs: []
       };
     } else if (t.isSwitchStatement(node) && hasLexicalDeclaration(node, parentNode)) {
       pushTempScope(state, "block", "Switch", {
         start: fromBabelLocation(node.loc.start, state.sourceId),
         end: fromBabelLocation(node.loc.end, state.sourceId)
       });
     }
+
+    if ( // In general Flow expressions are deleted, so they can't contain
+    // runtime bindings, but typecasts are the one exception there.
+    t.isFlow(node) && !t.isTypeCastExpression(node) || // In general TS items are deleted, but TS has a few wrapper node
+    // types that can contain general JS expressions.
+    node.type.startsWith("TS") && !t.isTSTypeAssertion(node) && !t.isTSAsExpression(node) && !t.isTSNonNullExpression(node) && !t.isTSModuleDeclaration(node) && !t.isTSModuleBlock(node) && !t.isTSParameterProperty(node) && !t.isTSExportAssignment(node)) {
+      // Flag this node as a root "type" node. All items inside of this
+      // will be skipped entirely.
+      state.inType = node;
+    }
   },
 
   exit(node, ancestors, state) {
     const currentScope = state.scope;
     const parentScope = state.scopeStack.pop();
 
     if (!parentScope) {
       throw new Error("Assertion failure - unsynchronized pop");
@@ -559,16 +601,20 @@ const scopeCollectionVisitor = {
         if (!refs) {
           refs = [];
           parentFreeVariables.set(key, refs);
         }
 
         refs.push(...value);
       }
     }
+
+    if (state.inType === node) {
+      state.inType = null;
+    }
   }
 
 };
 
 function isOpeningJSXIdentifier(node, ancestors) {
   if (!t.isJSXIdentifier(node)) {
     return false;
   }
--- a/devtools/client/debugger/new/src/workers/parser/pausePoints.js
+++ b/devtools/client/debugger/new/src/workers/parser/pausePoints.js
@@ -138,30 +138,22 @@ function onEnter(node, ancestors, state)
   }
 
   if (t.isFunction(node)) {
     const {
       line,
       column
     } = node.loc.end;
     addBreakPoint(state, startLocation);
-    return addStopPoint(state, {
+    return addEmptyPoint(state, {
       line,
       column: column - 1
     });
   }
 
-  if (t.isProgram(node)) {
-    const lastStatement = node.body[node.body.length - 1];
-
-    if (lastStatement) {
-      return addStopPoint(state, lastStatement.loc.end);
-    }
-  }
-
   if (!hasPoint(state, startLocation) && inStepExpression(parentNode)) {
     return addEmptyPoint(state, startLocation);
   }
 }
 
 function hasPoint(state, {
   line,
   column
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -6,16 +6,18 @@ support-files =
   head.js
   helpers.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/shared/test/shared-head.js
   !/devtools/client/shared/test/telemetry-test-helpers.js
   examples/sourcemapped/polyfill-bundle.js
   examples/sourcemapped/fixtures/typescript-classes/output.js
   examples/sourcemapped/fixtures/typescript-classes/output.js.map
+  examples/sourcemapped/fixtures/babel-bindings-with-flow/output.js
+  examples/sourcemapped/fixtures/babel-bindings-with-flow/output.js.map
   examples/sourcemapped/fixtures/babel-eval-maps/output.js
   examples/sourcemapped/fixtures/babel-eval-maps/output.js.map
   examples/sourcemapped/fixtures/babel-for-of/output.js
   examples/sourcemapped/fixtures/babel-for-of/output.js.map
   examples/sourcemapped/fixtures/babel-line-start-bindings-es6/output.js
   examples/sourcemapped/fixtures/babel-line-start-bindings-es6/output.js.map
   examples/sourcemapped/fixtures/babel-shadowed-vars/output.js
   examples/sourcemapped/fixtures/babel-shadowed-vars/output.js.map
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js
@@ -11,11 +11,11 @@ async function removeBreakpoint(dbg) {
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
   await selectSource(dbg, "simple2");
   await waitForSelectedSource(dbg, "simple2");
 
   await addBreakpoint(dbg, "simple2", 3);
   await removeBreakpoint(dbg);
 
-  await waitForState(dbg, state => dbg.selectors.getBreakpoints(state).size == 0)
+  await waitForState(dbg, state => dbg.selectors.getBreakpoints(state).size == 0);
   ok("successfully removed the breakpoint")
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
@@ -41,9 +41,17 @@ add_task(async function() {
   is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
   assertEditorBreakpoint(dbg, 4, true);
 
   // Make sure clicking at the same place removes the icon.
   clickGutter(dbg, 4);
   await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
   is(getBreakpoints(getState()).size, 0, "No breakpoints exist");
   assertEditorBreakpoint(dbg, 4, false);
+
+  // Ensure that clicking the gutter removes all breakpoints on a given line
+  await addBreakpoint(dbg, source, 4, 0);
+  await addBreakpoint(dbg, source, 4, 1);
+  await addBreakpoint(dbg, source, 4, 2);
+  clickGutter(dbg, 4);
+  await waitForState(dbg, state => dbg.selectors.getBreakpoints(state).size == 0);
+  assertEditorBreakpoint(dbg, 4, false);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-returnvalues.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-returnvalues.js
@@ -9,17 +9,16 @@ function getValue(dbg, index) {
 async function testReturnValue(dbg, val) {
   invokeInTab("return_something", val);
   await waitForPaused(dbg);
 
   // "Step in" 3 times to get to the point where the debugger can
   // see the return value.
   await stepIn(dbg);
   await stepIn(dbg);
-  await stepIn(dbg);
 
   is(getLabel(dbg, 1), "return_something", "check for return_something");
 
   // We don't show "undefined" but we do show other falsy values.
   let label = getLabel(dbg, 2);
   if (val === "undefined") {
     ok(label !== "<return>", "do not show <return> for undefined");
   } else {
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
@@ -23,16 +23,24 @@ async function breakpointScopes(dbg, fix
   ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
 }
 
 add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("doc-sourcemapped.html");
 
+  await breakpointScopes(dbg, "babel-bindings-with-flow", { line: 9, column: 2 }, [
+    "root",
+    ["value", '"a-named"'],
+    "Module",
+    ["aNamed", "Getter"],
+    "root()",
+  ]);
+
   await breakpointScopes(dbg, "typescript-classes", { line: 50, column: 2 }, [
     "Module",
     "AnotherThing()",
     "AppComponent()",
     "decoratorFactory()",
     "def()",
     "ExportedOther()",
     "ExpressionClass:Foo()",
@@ -264,21 +272,27 @@ add_task(async function() {
       // making us use the first, optimized-out binding. Given that imports
       // are almost never the last thing in a file though, this is probably not
       // a huge deal for now.
       ["aDefault", "(optimized away)"],
       ["root", "(optimized away)"],
       ["val", "(optimized away)"]
     ]
   );
+
   await breakpointScopes(
     dbg,
     "babel-flowtype-bindings",
-    { line: 8, column: 2 },
-    ["Module", ["aConst", '"a-const"'], "root()"]
+    { line: 9, column: 2 },
+    [
+      "Module",
+      ["aConst", '"a-const"'],
+      ["Four", "Getter"],
+      "root()"
+    ]
   );
 
   await breakpointScopes(dbg, "babel-switches", { line: 7, column: 6 }, [
     "Switch",
     ["val", "2"],
     "Function Body",
     ["val", "1"],
     "Module",
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
@@ -84,12 +84,11 @@ add_task(async function() {
 
   await dbg.actions.jumpToMappedSelectedLocation();
   await stepOver(dbg);
   assertPausedLocation(dbg);
   assertDebugLine(dbg, 71);
 
   await dbg.actions.jumpToMappedSelectedLocation();
   await stepOut(dbg);
-  await stepOut(dbg);
   assertPausedLocation(dbg);
   assertDebugLine(dbg, 16);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
@@ -19,11 +19,11 @@ add_task(async function test() {
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
 
-  assertDebugLine(dbg, 42264);
+  assertDebugLine(dbg, 42309);
   assertPausedLocation(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/examples/doc-sourcemapped.html
+++ b/devtools/client/debugger/new/test/mochitest/examples/doc-sourcemapped.html
@@ -8,16 +8,18 @@
     <script src="sourcemapped/polyfill-bundle.js"></script>
   </head>
   <body>
     <!-- INJECTED-START -->
     <!--
       Content generated by examples/sourcemapped/webpack.config.js.
       Run "yarn build" to update.
     -->
+    <script src="sourcemapped/fixtures/babel-bindings-with-flow/output.js"></script>
+    <button onclick="babelBindingsWithFlow()">Run babel-bindings-with-flow</button>
     <script src="sourcemapped/fixtures/babel-classes/output.js"></script>
     <button onclick="babelClasses()">Run babel-classes</button>
     <script src="sourcemapped/fixtures/babel-commonjs/output.js"></script>
     <button onclick="babelCommonjs()">Run babel-commonjs</button>
     <script src="sourcemapped/fixtures/babel-eval-maps/output.js"></script>
     <button onclick="babelEvalMaps()">Run babel-eval-maps</button>
     <script src="sourcemapped/fixtures/babel-flowtype-bindings/output.js"></script>
     <button onclick="babelFlowtypeBindings()">Run babel-flowtype-bindings</button>
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-bindings-with-flow/input.js
@@ -0,0 +1,10 @@
+// Webpack doesn't map import declarations well, so doing this forces binding
+// processing to only process the binding being cast when searching for
+// matches. That way we can properly test if the flow cast causes problems.
+import { aNamed } from "./src/mod";
+
+export default function root() {
+  var value = (aNamed: Array<string>);
+
+  console.log("pause here", root, value);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-bindings-with-flow/output.js
@@ -0,0 +1,96 @@
+var babelBindingsWithFlow =
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
+/* harmony export (immutable) */ __webpack_exports__["default"] = root;
+/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_mod__ = __webpack_require__(1);
+// Webpack doesn't map import declarations well, so doing this forces binding
+// processing to only process the binding being cast when searching for
+// matches. That way we can properly test if the flow cast causes problems.
+
+
+function root() {
+  var value = __WEBPACK_IMPORTED_MODULE_0__src_mod__["a" /* aNamed */];
+
+  console.log("pause here", root, value);
+}
+
+/***/ }),
+/* 1 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return aNamed; });
+var aNamed = "a-named";
+
+/***/ })
+/******/ ])["default"];
+//# sourceMappingURL=output.js.map
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-bindings-with-flow/output.js.map
@@ -0,0 +1,1 @@
+{"version":3,"sources":["webpack:///webpack/bootstrap 0a6829f83ea66e8a6df4","webpack:///./fixtures/babel-bindings-with-flow/input.js","webpack:///./fixtures/babel-bindings-with-flow/src/mod.js"],"names":["root","value","console","log","aNamed"],"mappings":";;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;AC7DA;AAAA;AACA;AACA;AACA;;AAEe,SAASA,IAAT,GAAgB;AAC7B,MAAIC,QAAS,wDAAb;;AAEAC,UAAQC,GAAR,CAAY,YAAZ,EAA0BH,IAA1B,EAAgCC,KAAhC;AACD,C;;;;;;;;ACTM,IAAMG,SAAS,SAAf,C","file":"fixtures/babel-bindings-with-flow/output.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 0a6829f83ea66e8a6df4","// Webpack doesn't map import declarations well, so doing this forces binding\n// processing to only process the binding being cast when searching for\n// matches. That way we can properly test if the flow cast causes problems.\nimport { aNamed } from \"./src/mod\";\n\nexport default function root() {\n  var value = (aNamed: Array<string>);\n\n  console.log(\"pause here\", root, value);\n}\n\n\n\n// WEBPACK FOOTER //\n// ./fixtures/babel-bindings-with-flow/input.js","export const aNamed = \"a-named\";\n\n\n\n// WEBPACK FOOTER //\n// ./fixtures/babel-bindings-with-flow/src/mod.js"],"sourceRoot":""}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-bindings-with-flow/src/mod.js
@@ -0,0 +1,1 @@
+export const aNamed = "a-named";
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/input.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/input.js
@@ -1,9 +1,10 @@
 import type { One, Two, Three } from "./src/mod";
+import { Four, type Five, typeof Six } from "./src/mod";
 
 type Other = {};
 
 const aConst = "a-const";
 
 export default function root() {
-  console.log("pause here", aConst, root);
+  console.log("pause here", aConst, Four, root);
 }
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/output.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/output.js
@@ -66,19 +66,30 @@ var babelFlowtypeBindings =
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
 /* harmony export (immutable) */ __webpack_exports__["default"] = root;
+/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_mod__ = __webpack_require__(1);
+
 
 
 var aConst = "a-const";
 
 function root() {
-  console.log("pause here", aConst, root);
+  console.log("pause here", aConst, __WEBPACK_IMPORTED_MODULE_0__src_mod__["a" /* Four */], root);
 }
 
+/***/ }),
+/* 1 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Four; });
+/* unused harmony default export */ var _unused_webpack_default_export = ("a-default");
+var Four = "one";
+
 /***/ })
 /******/ ])["default"];
 //# sourceMappingURL=output.js.map
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/output.js.map
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/output.js.map
@@ -1,1 +1,1 @@
-{"version":3,"sources":["webpack:///webpack/bootstrap 8c9635f8ac6ac3fe46a1","webpack:///./fixtures/babel-flowtype-bindings/input.js"],"names":["aConst","root","console","log"],"mappings":";;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;ACzDA,IAAMA,SAAS,SAAf;;AAEe,SAASC,IAAT,GAAgB;AAC7BC,UAAQC,GAAR,CAAY,YAAZ,EAA0BH,MAA1B,EAAkCC,IAAlC;AACD,C","file":"fixtures/babel-flowtype-bindings/output.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 8c9635f8ac6ac3fe46a1","import type { One, Two, Three } from \"./src/mod\";\n\ntype Other = {};\n\nconst aConst = \"a-const\";\n\nexport default function root() {\n  console.log(\"pause here\", aConst, root);\n}\n\n\n\n// WEBPACK FOOTER //\n// ./fixtures/babel-flowtype-bindings/input.js"],"sourceRoot":""}
\ No newline at end of file
+{"version":3,"sources":["webpack:///webpack/bootstrap 17b7f597c5958d1b689d","webpack:///./fixtures/babel-flowtype-bindings/input.js","webpack:///./fixtures/babel-flowtype-bindings/src/mod.js"],"names":["aConst","root","console","log","Four"],"mappings":";;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;AC5DA;;AAIA,IAAMA,SAAS,SAAf;;AAEe,SAASC,IAAT,GAAgB;AAC7BC,UAAQC,GAAR,CAAY,YAAZ,EAA0BH,MAA1B,EAAkC,sDAAlC,EAAwCC,IAAxC;AACD,C;;;;;;;;ACTD,0EAAe,WAAf;AACO,IAAMG,OAAO,KAAb,C","file":"fixtures/babel-flowtype-bindings/output.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 17b7f597c5958d1b689d","import type { One, Two, Three } from \"./src/mod\";\nimport { Four, type Five, typeof Six } from \"./src/mod\";\n\ntype Other = {};\n\nconst aConst = \"a-const\";\n\nexport default function root() {\n  console.log(\"pause here\", aConst, Four, root);\n}\n\n\n\n// WEBPACK FOOTER //\n// ./fixtures/babel-flowtype-bindings/input.js","export default \"a-default\";\nexport const Four = \"one\";\n\n\n\n// WEBPACK FOOTER //\n// ./fixtures/babel-flowtype-bindings/src/mod.js"],"sourceRoot":""}
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/src/mod.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemapped/fixtures/babel-flowtype-bindings/src/mod.js
@@ -1,1 +1,2 @@
 export default "a-default";
+export const Four = "one";
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -339,22 +339,19 @@ nsIContent::GetLang() const
   }
 
   return nullptr;
 }
 
 already_AddRefed<nsIURI>
 nsIContent::GetBaseURI(bool aTryUseXHRDocBaseURI) const
 {
-  if (IsInAnonymousSubtree() && IsAnonymousContentInSVGUseSubtree()) {
-    nsIContent* bindingParent = GetBindingParent();
-    MOZ_ASSERT(bindingParent);
-    SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
+  if (SVGUseElement* use = GetContainingSVGUseShadowHost()) {
     // XXX Ignore xml:base as we are removing it.
-    if (URLExtraData* data = useElement->GetContentURLData()) {
+    if (URLExtraData* data = use->GetContentURLData()) {
       return do_AddRef(data->BaseURI());
     }
   }
 
   nsIDocument* doc = OwnerDoc();
   // Start with document base
   nsCOMPtr<nsIURI> base = doc->GetBaseURI(aTryUseXHRDocBaseURI);
 
@@ -414,37 +411,31 @@ nsIContent::GetBaseURI(bool aTryUseXHRDo
   }
 
   return base.forget();
 }
 
 nsIURI*
 nsIContent::GetBaseURIForStyleAttr() const
 {
-  if (IsInAnonymousSubtree() && IsAnonymousContentInSVGUseSubtree()) {
-    nsIContent* bindingParent = GetBindingParent();
-    MOZ_ASSERT(bindingParent);
-    SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
-    if (URLExtraData* data = useElement->GetContentURLData()) {
+  if (SVGUseElement* use = GetContainingSVGUseShadowHost()) {
+    if (URLExtraData* data = use->GetContentURLData()) {
       return data->BaseURI();
     }
   }
   // This also ignores the case that SVG inside XBL binding.
   // But it is probably fine.
   return OwnerDoc()->GetDocBaseURI();
 }
 
 already_AddRefed<URLExtraData>
 nsIContent::GetURLDataForStyleAttr(nsIPrincipal* aSubjectPrincipal) const
 {
-  if (IsInAnonymousSubtree() && IsAnonymousContentInSVGUseSubtree()) {
-    nsIContent* bindingParent = GetBindingParent();
-    MOZ_ASSERT(bindingParent);
-    SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
-    if (URLExtraData* data = useElement->GetContentURLData()) {
+  if (SVGUseElement* use = GetContainingSVGUseShadowHost()) {
+    if (URLExtraData* data = use->GetContentURLData()) {
       return do_AddRef(data);
     }
   }
   if (aSubjectPrincipal && aSubjectPrincipal != NodePrincipal()) {
     // TODO: Cache this?
     return MakeAndAddRef<URLExtraData>(OwnerDoc()->GetDocBaseURI(),
                                        OwnerDoc()->GetDocumentURI(),
                                        aSubjectPrincipal);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -60,16 +60,17 @@
 #include "mozilla/EventStateManager.h"
 
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/FramingChecker.h"
 #include "mozilla/dom/HTMLSharedElement.h"
+#include "mozilla/dom/SVGUseElement.h"
 #include "nsGenericHTMLElement.h"
 #include "mozilla/dom/CDATASection.h"
 #include "mozilla/dom/ProcessingInstruction.h"
 #include "nsDOMString.h"
 #include "nsNodeUtils.h"
 #include "nsLayoutUtils.h" // for GetFrameForPoint
 #include "nsIFrame.h"
 #include "nsITabChild.h"
@@ -7416,31 +7417,31 @@ nsIDocument::FlushPendingNotifications(m
   if (nsIPresShell* shell = GetShell()) {
     shell->FlushPendingNotifications(aFlush);
   }
 }
 
 static bool
 Copy(nsIDocument* aDocument, void* aData)
 {
-  nsTArray<nsCOMPtr<nsIDocument> >* resources =
-    static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
+  auto* resources = static_cast<nsTArray<nsCOMPtr<nsIDocument>>*>(aData);
   resources->AppendElement(aDocument);
   return true;
 }
 
 void
 nsIDocument::FlushExternalResources(FlushType aType)
 {
   NS_ASSERTION(aType >= FlushType::Style,
     "should only need to flush for style or higher in external resources");
   if (GetDisplayDocument()) {
     return;
   }
-  nsTArray<nsCOMPtr<nsIDocument> > resources;
+
+  nsTArray<nsCOMPtr<nsIDocument>> resources;
   EnumerateExternalResources(Copy, &resources);
 
   for (uint32_t i = 0; i < resources.Length(); i++) {
     resources[i]->FlushPendingNotifications(aType);
   }
 }
 
 void
@@ -9735,16 +9736,53 @@ nsIDocument::GetPlugins(nsTArray<nsIObje
   aPlugins.SetCapacity(aPlugins.Length() + mPlugins.Count());
   for (auto iter = mPlugins.ConstIter(); !iter.Done(); iter.Next()) {
     aPlugins.AppendElement(iter.Get()->GetKey());
   }
   EnumerateSubDocuments(AllSubDocumentPluginEnum, &aPlugins);
 }
 
 void
+nsIDocument::ScheduleSVGUseElementShadowTreeUpdate(SVGUseElement& aUseElement)
+{
+  MOZ_ASSERT(aUseElement.IsInComposedDoc());
+
+  mSVGUseElementsNeedingShadowTreeUpdate.PutEntry(&aUseElement);
+
+  if (nsIPresShell* shell = GetShell()) {
+    shell->EnsureStyleFlush();
+  }
+}
+
+void
+nsIDocument::DoUpdateSVGUseElementShadowTrees()
+{
+  MOZ_ASSERT(!mSVGUseElementsNeedingShadowTreeUpdate.IsEmpty());
+  nsTArray<RefPtr<SVGUseElement>> useElementsToUpdate;
+
+  do {
+    useElementsToUpdate.Clear();
+    useElementsToUpdate.SetCapacity(mSVGUseElementsNeedingShadowTreeUpdate.Count());
+
+    {
+      for (auto iter = mSVGUseElementsNeedingShadowTreeUpdate.ConstIter();
+           !iter.Done();
+           iter.Next()) {
+        useElementsToUpdate.AppendElement(iter.Get()->GetKey());
+      }
+      mSVGUseElementsNeedingShadowTreeUpdate.Clear();
+    }
+
+    for (auto& useElement : useElementsToUpdate) {
+      useElement->UpdateShadowTree();
+    }
+  } while (!mSVGUseElementsNeedingShadowTreeUpdate.IsEmpty());
+}
+
+void
 nsIDocument::NotifyMediaFeatureValuesChanged()
 {
   for (auto iter = mResponsiveContent.ConstIter(); !iter.Done();
        iter.Next()) {
     RefPtr<HTMLImageElement> imageElement = iter.Get()->GetKey();
     imageElement->MediaFeatureValuesChanged();
   }
 }
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2585,18 +2585,17 @@ nsFocusManager::GetSelectionLocation(nsI
           // Yes, indeed we were at the end of the last node
           nsCOMPtr<nsIFrameEnumerator> frameTraversal;
           nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
                                              presContext, startFrame,
                                              eLeaf,
                                              false, // aVisual
                                              false, // aLockInScrollView
                                              true,  // aFollowOOFs
-                                             false, // aSkipPopupChecks
-                                             false  // aSkipShadow
+                                             false // aSkipPopupChecks
                                              );
           NS_ENSURE_SUCCESS(rv, rv);
 
           nsIFrame *newCaretFrame = nullptr;
           nsCOMPtr<nsIContent> newCaretContent = startContent;
           bool endOfSelectionInStartNode(startContent == endContent);
           do {
             // Continue getting the next frame until the primary content for the frame
@@ -3318,18 +3317,17 @@ nsFocusManager::GetNextTabbableContentIn
           nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
                                              iterContent->OwnerDoc()->
                                                GetShell()->GetPresContext(),
                                              frame,
                                              ePreOrder,
                                              false, // aVisual
                                              false, // aLockInScrollView
                                              true, // aFollowOOFs
-                                             true,  // aSkipPopupChecks
-                                             false // aSkipShadow
+                                             true  // aSkipPopupChecks
                                              );
           if (NS_SUCCEEDED(rv)) {
             nsIFrame* frame =
               static_cast<nsIFrame*>(frameTraversal->CurrentItem());
             while (frame) {
               int32_t tabIndex;
               frame->IsFocusable(&tabIndex, 0);
               if (tabIndex >= 0 &&
@@ -3450,16 +3448,34 @@ nsFocusManager::GetNextTabbableContentIn
     }
 
     startContent = owner;
   }
 
   return nullptr;
 }
 
+static nsIContent*
+GetTopLevelHost(nsIContent* aContent)
+{
+  nsIContent* topLevelhost = nullptr;
+  while (aContent) {
+    if (HTMLSlotElement* slot = aContent->GetAssignedSlot()) {
+      aContent = slot;
+    } else if (ShadowRoot* shadowRoot = aContent->GetContainingShadow()) {
+      aContent = shadowRoot->Host();
+      topLevelhost = aContent;
+    } else {
+      aContent = aContent->GetParent();
+    }
+  }
+
+  return topLevelhost;
+}
+
 nsresult
 nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell,
                                        nsIContent* aRootContent,
                                        nsIContent* aOriginalStartContent,
                                        nsIContent* aStartContent,
                                        bool aForward,
                                        int32_t aCurrentTabIndex,
                                        bool aIgnoreTabIndex,
@@ -3467,16 +3483,18 @@ nsFocusManager::GetNextTabbableContent(n
                                        nsIContent** aResultContent)
 {
   *aResultContent = nullptr;
 
   nsCOMPtr<nsIContent> startContent = aStartContent;
   if (!startContent)
     return NS_OK;
 
+  nsIContent* currentTopLevelHost = GetTopLevelHost(aStartContent);
+
   LOGCONTENTNAVIGATION("GetNextTabbable: %s", aStartContent);
   LOGFOCUSNAVIGATION(("  tabindex: %d", aCurrentTabIndex));
 
   if (nsDocument::IsShadowDOMEnabled(aRootContent)) {
     // If aStartContent is a shadow host or slot in forward navigation,
     // search in scope owned by aStartContent
     if (aForward && IsHostOrSlot(aStartContent)) {
       nsIContent* contentToFocus =
@@ -3546,18 +3564,17 @@ nsFocusManager::GetNextTabbableContent(n
     // ignore these boundaries.
     nsCOMPtr<nsIFrameEnumerator> frameTraversal;
     nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
                                        presContext, startFrame,
                                        ePreOrder,
                                        false, // aVisual
                                        false, // aLockInScrollView
                                        true,  // aFollowOOFs
-                                       aForDocumentNavigation,  // aSkipPopupChecks
-                                       nsDocument::IsShadowDOMEnabled(aRootContent) // aSkipShadow
+                                       aForDocumentNavigation  // aSkipPopupChecks
                                        );
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (iterStartContent == aRootContent) {
       if (!aForward) {
         frameTraversal->Last();
       } else if (aRootContent->IsFocusable()) {
         frameTraversal->Next();
@@ -3572,17 +3589,39 @@ nsFocusManager::GetNextTabbableContent(n
         frameTraversal->Next();
       else
         frameTraversal->Prev();
     }
 
     // Walk frames to find something tabbable matching mCurrentTabIndex
     nsIFrame* frame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
     while (frame) {
+      // Try to find the topmost Shadow DOM host, since we want to
+      // skip Shadow DOM in frame traversal.
       nsIContent* currentContent = frame->GetContent();
+      nsIContent* oldTopLevelHost = currentTopLevelHost;
+      nsIContent* topLevel = GetTopLevelHost(currentContent);
+      currentTopLevelHost = topLevel;
+      if (topLevel) {
+        if (topLevel == oldTopLevelHost) {
+          // We're within Shadow DOM, continue.
+          do {
+            if (aForward) {
+              frameTraversal->Next();
+            } else {
+              frameTraversal->Prev();
+            }
+            frame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
+            // For the usage of GetPrevContinuation, see the comment
+            // at the end of while (frame) loop.
+          } while (frame && frame->GetPrevContinuation());
+          continue;
+        }
+        currentContent = topLevel;
+      }
 
       // For document navigation, check if this element is an open panel. Since
       // panels aren't focusable (tabIndex would be -1), we'll just assume that
       // for document navigation, the tabIndex is 0.
       if (aForDocumentNavigation && currentContent && (aCurrentTabIndex == 0) &&
           currentContent->IsXULElement(nsGkAtoms::panel)) {
         nsMenuPopupFrame* popupFrame = do_QueryFrame(frame);
         // Check if the panel is open. Closed panels are ignored since you can't
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -175,16 +175,17 @@ enum class OrientationType : uint8_t;
 class ProcessingInstruction;
 class Promise;
 class ScriptLoader;
 class Selection;
 class ServiceWorkerDescriptor;
 class StyleSheetList;
 class SVGDocument;
 class SVGSVGElement;
+class SVGUseElement;
 class Touch;
 class TouchList;
 class TreeWalker;
 class XPathEvaluator;
 class XPathExpression;
 class XPathNSResolver;
 class XPathResult;
 class XULDocument;
@@ -1903,16 +1904,25 @@ public:
   /**
    * Calls FlushPendingNotifications on any external resources this document
    * has. If this document has no external resources or is an external resource
    * itself this does nothing. This should only be called with
    * aType >= FlushType::Style.
    */
   void FlushExternalResources(mozilla::FlushType aType);
 
+  // Triggers an update of <svg:use> element shadow trees.
+  void UpdateSVGUseElementShadowTrees()
+  {
+    if (mSVGUseElementsNeedingShadowTreeUpdate.IsEmpty()) {
+      return;
+    }
+    DoUpdateSVGUseElementShadowTrees();
+  }
+
   nsBindingManager* BindingManager() const
   {
     return mNodeInfoManager->GetBindingManager();
   }
 
   /**
    * Only to be used inside Gecko, you can't really do anything with the
    * pointer outside Gecko anyway.
@@ -2904,23 +2914,34 @@ public:
   // Removes an element from mResponsiveContent when the element is
   // removed from the tree.
   void RemoveResponsiveContent(mozilla::dom::HTMLImageElement* aContent)
   {
     MOZ_ASSERT(aContent);
     mResponsiveContent.RemoveEntry(aContent);
   }
 
+  void ScheduleSVGUseElementShadowTreeUpdate(mozilla::dom::SVGUseElement&);
+  void UnscheduleSVGUseElementShadowTreeUpdate(mozilla::dom::SVGUseElement& aElement)
+  {
+    mSVGUseElementsNeedingShadowTreeUpdate.RemoveEntry(&aElement);
+  }
+
+  bool SVGUseElementNeedsShadowTreeUpdate(mozilla::dom::SVGUseElement& aElement) const
+  {
+    return mSVGUseElementsNeedingShadowTreeUpdate.GetEntry(&aElement);
+  }
+
+  using ShadowRootSet = nsTHashtable<nsPtrHashKey<mozilla::dom::ShadowRoot>>;
+
   void AddComposedDocShadowRoot(mozilla::dom::ShadowRoot& aShadowRoot)
   {
     mComposedShadowRoots.PutEntry(&aShadowRoot);
   }
 
-  using ShadowRootSet = nsTHashtable<nsPtrHashKey<mozilla::dom::ShadowRoot>>;
-
   void RemoveComposedDocShadowRoot(mozilla::dom::ShadowRoot& aShadowRoot)
   {
     mComposedShadowRoots.RemoveEntry(&aShadowRoot);
   }
 
   // If you're considering using this, you probably want to use
   // ShadowRoot::IsComposedDocParticipant instead. This is just for
   // sanity-checking.
@@ -3536,16 +3557,18 @@ public:
    * nearest non-anonymous ancestor in this document.
    * Returns null if there is no such element.
    */
   nsIContent* GetContentInThisDocument(nsIFrame* aFrame) const;
 
   void ReportShadowDOMUsage();
 
 protected:
+  void DoUpdateSVGUseElementShadowTrees();
+
   already_AddRefed<nsIPrincipal> MaybeDowngradePrincipal(nsIPrincipal* aPrincipal);
 
   void EnsureOnloadBlocker();
 
   void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);
 
   // Returns true if the scheme for the url for this document is "about".
   bool IsAboutPage() const;
@@ -3751,16 +3774,23 @@ protected:
   // Tracking for images in the document.
   RefPtr<mozilla::dom::ImageTracker> mImageTracker;
 
   // A hashtable of ShadowRoots belonging to the composed doc.
   //
   // See ShadowRoot::SetIsComposedDocParticipant.
   ShadowRootSet mComposedShadowRoots;
 
+  using SVGUseElementSet =
+    nsTHashtable<nsPtrHashKey<mozilla::dom::SVGUseElement>>;
+
+  // The set of <svg:use> elements that need a shadow tree reclone because the
+  // tree they map to has changed.
+  SVGUseElementSet mSVGUseElementsNeedingShadowTreeUpdate;
+
   // The set of all object, embed, video/audio elements or
   // nsIObjectLoadingContent or nsIDocumentActivity for which this is the owner
   // document. (They might not be in the document.)
   //
   // These are non-owning pointers, the elements are responsible for removing
   // themselves when they go away.
   nsAutoPtr<nsTHashtable<nsPtrHashKey<nsISupports> > > mActivityObservers;
 
@@ -4595,18 +4625,18 @@ nsINode::OwnerDocAsNode() const
 // (because this header does not include nsIContent) and we can't put it in
 // nsIContent.h, because the definition of nsIContent::IsInAnonymousSubtree is
 // in nsIContentInlines.h.  And then we get include hell from people trying to
 // call nsINode::GetParentObject but not including nsIContentInlines.h and with
 // no really good way to include it.
 template<typename T>
 inline bool ShouldUseXBLScope(const T* aNode)
 {
-  return aNode->IsInAnonymousSubtree() &&
-         !aNode->IsAnonymousContentInSVGUseSubtree();
+  // TODO(emilio): Is the <svg:use> shadow tree check needed now?
+  return aNode->IsInAnonymousSubtree() && !aNode->IsInSVGUseShadowTree();
 }
 
 inline mozilla::dom::ParentObject
 nsINode::GetParentObject() const
 {
   mozilla::dom::ParentObject p(OwnerDoc());
     // Note that mUseXBLScope is a no-op for chrome, and other places where we
     // don't use XBL scopes.
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -28,16 +28,17 @@
 #include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/L10nUtilsBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/SVGUseElement.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsAttrValueOrString.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
@@ -511,23 +512,21 @@ operator<<(std::ostream& aStream, const 
 
     curr = curr->GetParentNode();
   }
 
   NS_ConvertUTF16toUTF8 str(elemDesc);
   return aStream << str.get();
 }
 
-bool
-nsINode::IsAnonymousContentInSVGUseSubtree() const
+SVGUseElement*
+nsINode::DoGetContainingSVGUseShadowHost() const
 {
-  MOZ_ASSERT(IsInAnonymousSubtree());
-  nsIContent* parent = AsContent()->GetBindingParent();
-  // Watch out for parentless native-anonymous subtrees.
-  return parent && parent->IsSVGElement(nsGkAtoms::use);
+  MOZ_ASSERT(IsInShadowTree());
+  return SVGUseElement::FromNode(AsContent()->GetContainingShadowHost());
 }
 
 void
 nsINode::GetNodeValueInternal(nsAString& aNodeValue)
 {
   SetDOMStringToNull(aNodeValue);
 }
 
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -81,16 +81,17 @@ class DOMQuad;
 class DOMRectReadOnly;
 class Element;
 class EventHandlerNonNull;
 class L10nCallback;
 template<typename T> class Optional;
 class OwningNodeOrString;
 class Promise;
 template<typename> class Sequence;
+class SVGUseElement;
 class Text;
 class TextOrElementOrDocument;
 struct DOMPointInit;
 struct GetRootNodeOptions;
 enum class CallerType : uint32_t;
 } // namespace dom
 } // namespace mozilla
 
@@ -1225,18 +1226,28 @@ public:
     return false;
 #else
     return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
 #endif
   }
 
   bool IsInAnonymousSubtree() const;
 
-  // Note: This asserts |IsInAnonymousSubtree()|.
-  bool IsAnonymousContentInSVGUseSubtree() const;
+  bool IsInSVGUseShadowTree() const
+  {
+    return !!GetContainingSVGUseShadowHost();
+  }
+
+  mozilla::dom::SVGUseElement* GetContainingSVGUseShadowHost() const
+  {
+    if (!IsInShadowTree()) {
+      return nullptr;
+    }
+    return DoGetContainingSVGUseShadowHost();
+  }
 
   // True for native anonymous content and for XBL content if the binding
   // has chromeOnlyContent="true".
   bool ChromeOnlyAccess() const
   {
     return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_CHROME_ONLY_ACCESS);
   }
 
@@ -1397,16 +1408,18 @@ public:
    * anonymous tree.
    */
   bool Contains(const nsINode* aOther) const;
 
   bool UnoptimizableCCNode() const;
 
 private:
 
+  mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const;
+
   nsIDocument* GetComposedDocInternal() const;
 
   nsIContent* GetNextNodeImpl(const nsINode* aRoot,
                               const bool aSkipChildren) const
   {
     // Can't use nsContentUtils::ContentIsDescendantOf here, since we
     // can't include it here.
 #ifdef DEBUG
--- a/dom/base/nsIStyleSheetLinkingElement.h
+++ b/dom/base/nsIStyleSheetLinkingElement.h
@@ -152,22 +152,19 @@ public:
    */
   virtual void InitStyleLinkElement(bool aDontLoadStyle) = 0;
 
   /**
    * Tells this element to update the stylesheet.
    *
    * @param aObserver    observer to notify once the stylesheet is loaded.
    *                     This will be passed to the CSSLoader
-   * @param aForceUpdate whether we wand to force the update, flushing the
-   *                     cached version if any.
    */
   virtual mozilla::Result<Update, nsresult>
-    UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                     ForceUpdate = ForceUpdate::No) = 0;
+    UpdateStyleSheet(nsICSSLoaderObserver* aObserver) = 0;
 
   /**
    * Tells this element whether to update the stylesheet when the
    * element's properties change.
    *
    * @param aEnableUpdates update on changes or not.
    */
   virtual void SetEnableUpdates(bool aEnableUpdates) = 0;
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -258,30 +258,19 @@ uint32_t nsStyleLinkElement::ParseLinkTy
   if (inString) {
     nsContentUtils::ASCIIToLower(Substring(start, current), subString);
     linkMask |= ToLinkMask(subString);
   }
   return linkMask;
 }
 
 Result<nsStyleLinkElement::Update, nsresult>
-nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                                     ForceUpdate aForceUpdate)
+nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver)
 {
-  if (aForceUpdate == ForceUpdate::Yes) {
-    // We remove this stylesheet from the cache to load a new version.
-    nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
-    nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
-      thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
-    if (doc && doc->CSSLoader()->GetEnabled() &&
-        mStyleSheet && !mStyleSheet->IsInline()) {
-      doc->CSSLoader()->ObsoleteSheet(mStyleSheet->GetOriginalURI());
-    }
-  }
-  return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aForceUpdate);
+  return DoUpdateStyleSheet(nullptr, nullptr, aObserver, ForceUpdate::No);
 }
 
 Result<nsStyleLinkElement::Update, nsresult>
 nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument* aOldDocument,
                                              ShadowRoot* aOldShadowRoot,
                                              ForceUpdate aForceUpdate)
 {
   return DoUpdateStyleSheet(
@@ -293,18 +282,17 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
                                        ShadowRoot* aOldShadowRoot,
                                        nsICSSLoaderObserver* aObserver,
                                        ForceUpdate aForceUpdate)
 {
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
   // All instances of nsStyleLinkElement should implement nsIContent.
   MOZ_ASSERT(thisContent);
 
-  if (thisContent->IsInAnonymousSubtree() &&
-      thisContent->IsAnonymousContentInSVGUseSubtree()) {
+  if (thisContent->IsInSVGUseShadowTree()) {
     // Stylesheets in <use>-cloned subtrees are disabled until we figure out
     // how they should behave.
     return Update { };
   }
 
   if (mStyleSheet && (aOldDocument || aOldShadowRoot)) {
     MOZ_ASSERT(!(aOldDocument && aOldShadowRoot),
                "ShadowRoot content is never in document, thus "
--- a/dom/base/nsStyleLinkElement.h
+++ b/dom/base/nsStyleLinkElement.h
@@ -43,17 +43,17 @@ public:
   mozilla::StyleSheet* GetSheet() const { return mStyleSheet; }
 
   // nsIStyleSheetLinkingElement
   void SetStyleSheet(mozilla::StyleSheet* aStyleSheet) override;
   mozilla::StyleSheet* GetStyleSheet() override;
   void InitStyleLinkElement(bool aDontLoadStyle) override;
 
   mozilla::Result<Update, nsresult>
-    UpdateStyleSheet(nsICSSLoaderObserver*, ForceUpdate) override;
+    UpdateStyleSheet(nsICSSLoaderObserver*) override;
 
   void SetEnableUpdates(bool aEnableUpdates) override;
   void GetCharset(nsAString& aCharset) override;
 
   void OverrideBaseURI(nsIURI* aNewBaseURI) override;
   void SetLineNumber(uint32_t aLineNumber) override;
   uint32_t GetLineNumber() override;
   void SetColumnNumber(uint32_t aColumnNumber) override;
--- a/dom/base/test/file_bug1453693.html
+++ b/dom/base/test/file_bug1453693.html
@@ -215,23 +215,58 @@
         opener.is(lastFocusTarget, input11, "[nested shadow] Should have focused input element. (7)");
 
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, button, "[nested shadow] Should have focused button element. (8)");
 
         // Back to beginning, outside of Shadow DOM.
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (2)");
+
+        host.remove();
+      }
+
+      function testTabbingThroughDisplayContentsHost() {
+        opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (1)");
+
+        var host = document.createElement("div");
+        host.id = "host";
+        host.setAttribute("style", "display: contents; border: 1px solid black;");
+        document.body.appendChild(host);
+
+        var sr0 = host.attachShadow({mode: "open"});
+        sr0.innerHTML = "<input id='shadowInput1'><input id='shadowInput2'>";
+        var shadowInput1 = sr0.getElementById("shadowInput1");
+        shadowInput1.onfocus = focusLogger;
+        var shadowInput2 = sr0.getElementById("shadowInput2");
+        shadowInput2.onfocus = focusLogger;
+
+        document.body.offsetLeft;
+
+        synthesizeKey("KEY_Tab");
+        opener.is(lastFocusTarget, shadowInput1, "Should have focused input element. (1)");
+
+        synthesizeKey("KEY_Tab");
+        opener.is(lastFocusTarget, shadowInput2, "Should have focused input element. (2)");
+
+        // Backwards
+        synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(lastFocusTarget, shadowInput1, "Should have focused input element. (3)");
+
+        // Back to beginning, outside of Shadow DOM.
+        synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (2)");
       }
 
       function runTest() {
 
         testTabbingThroughShadowDOMWithTabIndexes();
         testTabbingThroughSimpleShadowDOM();
         testTabbingThroughNestedShadowDOM();
+        testTabbingThroughDisplayContentsHost();
 
         opener.didRunTests();
         window.close();
       }
 
       function init() {
         SimpleTest.waitForFocus(runTest);
       }
--- a/dom/base/test/test_warning_for_blocked_cross_site_request.html
+++ b/dom/base/test/test_warning_for_blocked_cross_site_request.html
@@ -22,21 +22,23 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var tests = {
   font : {
     uri_test : "font_bad",
-    result : null
+    result : null,
+    category: "CORSMissingAllowOrigin",
   },
   xhr : {
     uri_test : "http://invalid",
-    result : null
+    result : null,
+    category: "CORSAllowOriginNotMatchingOrigin"
   },
 }
 
 function testsComplete() {
   for (var testName in tests) {
     var test = tests[testName];
     if (test.result == null)
       return false;
@@ -45,24 +47,26 @@ function testsComplete() {
 }
 
 SpecialPowers.registerConsoleListener(function CORSMsgListener(aMsg) {
   if (!/Cross-Origin Request Blocked/.test(aMsg.message))
     return;
 
   for (var testName in tests) {
     var test = tests[testName];
+    var category = test.category;
     if (test.result != null)
       continue;
 
     var testRegexp = new RegExp(test.uri_test);
     if (testRegexp.test(aMsg.message)) {
       test.result = true;
       ok(true, "Got \"Cross-site request blocked\" warning message for " + testName);
-      ok(aMsg.category == "CORS", "Got warning message with category \"" + aMsg.category + "\", expected \"CORS\"");
+      ok(aMsg.category == category,
+         "Got warning message with category \"" + aMsg.category + "\", expected \"" + category + "\"");
       // Got the message we wanted - make sure it is destined for a valid inner window
       ok(aMsg.windowID != 0, "Valid (non-zero) windowID for the cross-site request blocked message.");
       break;
     }
   }
 
   if (testsComplete()) {
     SimpleTest.executeSoon(cleanup);
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -1743,17 +1743,18 @@ HTMLFormElement::GetActionURL(nsIURI** a
 
     const char16_t* params[] = { reportSpec.get(), reportScheme.get() };
     CSP_LogLocalizedStr("upgradeInsecureRequest",
                         params, ArrayLength(params),
                         EmptyString(), // aSourceFile
                         EmptyString(), // aScriptSample
                         0, // aLineNumber
                         0, // aColumnNumber
-                        nsIScriptError::warningFlag, "CSP",
+                        nsIScriptError::warningFlag,
+                        NS_LITERAL_CSTRING("upgradeInsecureRequest"),
                         document->InnerWindowID(),
                         !!document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId);
   }
 
   //
   // Assign to the output
   //
   actionURL.forget(aActionURL);
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -238,18 +238,30 @@ already_AddRefed<SharedThreadPool> GetMe
     default:
       MOZ_FALLTHROUGH_ASSERT("Unexpected MediaThreadType");
     case MediaThreadType::PLAYBACK:
       name = "MediaPlayback";
       break;
   }
 
   static const uint32_t kMediaThreadPoolDefaultCount = 4;
-  return SharedThreadPool::
+  RefPtr<SharedThreadPool> pool = SharedThreadPool::
     Get(nsDependentCString(name), kMediaThreadPoolDefaultCount);
+
+  // Ensure a larger stack for platform decoder threads
+  if (aType == MediaThreadType::PLATFORM_DECODER) {
+    const uint32_t minStackSize = 512*1024;
+    uint32_t stackSize;
+    MOZ_ALWAYS_SUCCEEDS(pool->GetThreadStackSize(&stackSize));
+    if (stackSize < minStackSize) {
+      MOZ_ALWAYS_SUCCEEDS(pool->SetThreadStackSize(minStackSize));
+    }
+  }
+
+  return already_AddRefed<SharedThreadPool>(pool.forget());
 }
 
 bool
 ExtractVPXCodecDetails(const nsAString& aCodec,
                        uint8_t& aProfile,
                        uint8_t& aLevel,
                        uint8_t& aBitDepth)
 {
--- a/dom/security/FramingChecker.cpp
+++ b/dom/security/FramingChecker.cpp
@@ -191,17 +191,18 @@ ShouldIgnoreFrameOptions(nsIChannel* aCh
                                u"frame-ancestors" };
   CSP_LogLocalizedStr("IgnoringSrcBecauseOfDirective",
                       params, ArrayLength(params),
                       EmptyString(), // no sourcefile
                       EmptyString(), // no scriptsample
                       0,             // no linenumber
                       0,             // no columnnumber
                       nsIScriptError::warningFlag,
-                      "CSP", innerWindowID,
+                      NS_LITERAL_CSTRING("IgnoringSrcBecauseOfDirective"),
+                      innerWindowID,
                       privateWindow);
 
   return true;
 }
 
 // Check if X-Frame-Options permits this document to be loaded as a subdocument.
 // This will iterate through and check any number of X-Frame-Options policies
 // in the request (comma-separated in a header, multiple headers, etc).
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -772,16 +772,17 @@ nsCSPContext::EnsureEventTarget(nsIEvent
 
 struct ConsoleMsgQueueElem {
   nsString      mMsg;
   nsString      mSourceName;
   nsString      mSourceLine;
   uint32_t      mLineNumber;
   uint32_t      mColumnNumber;
   uint32_t      mSeverityFlag;
+  nsCString     mCategory;
 };
 
 void
 nsCSPContext::flushConsoleMessages()
 {
   bool privateWindow = false;
 
   // should flush messages even if doc is not available
@@ -792,55 +793,61 @@ nsCSPContext::flushConsoleMessages()
   }
 
   mQueueUpMessages = false;
 
   for (uint32_t i = 0; i < mConsoleMsgQueue.Length(); i++) {
     ConsoleMsgQueueElem &elem = mConsoleMsgQueue[i];
     CSP_LogMessage(elem.mMsg, elem.mSourceName, elem.mSourceLine,
                    elem.mLineNumber, elem.mColumnNumber,
-                   elem.mSeverityFlag, "CSP", mInnerWindowID,
+                   elem.mSeverityFlag, elem.mCategory, mInnerWindowID,
                    privateWindow);
   }
   mConsoleMsgQueue.Clear();
 }
 
 void
 nsCSPContext::logToConsole(const char* aName,
                            const char16_t** aParams,
                            uint32_t aParamsLength,
                            const nsAString& aSourceName,
                            const nsAString& aSourceLine,
                            uint32_t aLineNumber,
                            uint32_t aColumnNumber,
                            uint32_t aSeverityFlag)
 {
+  // we are passing aName as the category so we can link to the
+  // appropriate MDN docs depending on the specific error.
+  nsDependentCString category(aName);
+
   // let's check if we have to queue up console messages
   if (mQueueUpMessages) {
     nsAutoString msg;
     CSP_GetLocalizedStr(aName, aParams, aParamsLength, msg);
     ConsoleMsgQueueElem &elem = *mConsoleMsgQueue.AppendElement();
     elem.mMsg = msg;
     elem.mSourceName = PromiseFlatString(aSourceName);
     elem.mSourceLine = PromiseFlatString(aSourceLine);
     elem.mLineNumber = aLineNumber;
     elem.mColumnNumber = aColumnNumber;
     elem.mSeverityFlag = aSeverityFlag;
+    elem.mCategory = category;
     return;
   }
 
   bool privateWindow = false;
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
   if (doc) {
     privateWindow = !!doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId;
   }
 
+
   CSP_LogLocalizedStr(aName, aParams, aParamsLength, aSourceName,
                       aSourceLine, aLineNumber, aColumnNumber,
-                      aSeverityFlag, "CSP", mInnerWindowID, privateWindow);
+                      aSeverityFlag, category, mInnerWindowID, privateWindow);
 }
 
 /**
  * Strip URI for reporting according to:
  * http://www.w3.org/TR/CSP/#violation-reports
  *
  * @param aURI
  *        The uri to be stripped for reporting
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -124,17 +124,17 @@ CSP_LogStrMessage(const nsAString& aMsg)
 
 void
 CSP_LogMessage(const nsAString& aMessage,
                const nsAString& aSourceName,
                const nsAString& aSourceLine,
                uint32_t aLineNumber,
                uint32_t aColumnNumber,
                uint32_t aFlags,
-               const char *aCategory,
+               const nsACString& aCategory,
                uint64_t aInnerWindowID,
                bool aFromPrivateWindow)
 {
   nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
 
   nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
 
   if (!console || !error) {
@@ -153,30 +153,35 @@ CSP_LogMessage(const nsAString& aMessage
   // E.g. 'aSourceLine' might be: 'onclick attribute on DIV element'.
   // In such cases we append 'aSourceLine' directly to the error message.
   if (!aSourceLine.IsEmpty()) {
     cspMsg.AppendLiteral(u" Source: ");
     cspMsg.Append(aSourceLine);
     cspMsg.AppendLiteral(u".");
   }
 
+  // Since we are leveraging csp errors as the category names which
+  // we pass to devtools, we should prepend them with "CSP_" to
+  // allow easy distincution in devtools code. e.g.
+  // upgradeInsecureRequest -> CSP_upgradeInsecureRequest
+  nsCString category("CSP_");
+  category.Append(aCategory);
+
   nsresult rv;
   if (aInnerWindowID > 0) {
-    nsCString catStr;
-    catStr.AssignASCII(aCategory);
     rv = error->InitWithWindowID(cspMsg, aSourceName,
                                  aSourceLine, aLineNumber,
                                  aColumnNumber, aFlags,
-                                 catStr, aInnerWindowID);
+                                 category, aInnerWindowID);
   }
   else {
     rv = error->Init(cspMsg, aSourceName,
                      aSourceLine, aLineNumber,
                      aColumnNumber, aFlags,
-                     aCategory, aFromPrivateWindow);
+                     category.get(), aFromPrivateWindow);
   }
   if (NS_FAILED(rv)) {
     return;
   }
   console->LogMessage(error);
 }
 
 /**
@@ -186,17 +191,17 @@ void
 CSP_LogLocalizedStr(const char* aName,
                     const char16_t** aParams,
                     uint32_t aLength,
                     const nsAString& aSourceName,
                     const nsAString& aSourceLine,
                     uint32_t aLineNumber,
                     uint32_t aColumnNumber,
                     uint32_t aFlags,
-                    const char* aCategory,
+                    const nsACString& aCategory,
                     uint64_t aInnerWindowID,
                     bool aFromPrivateWindow)
 {
   nsAutoString logMsg;
   CSP_GetLocalizedStr(aName, aParams, aLength, logMsg);
   CSP_LogMessage(logMsg, aSourceName, aSourceLine,
                  aLineNumber, aColumnNumber, aFlags,
                  aCategory, aInnerWindowID, aFromPrivateWindow);
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -28,34 +28,34 @@ namespace dom {
 void CSP_LogLocalizedStr(const char* aName,
                          const char16_t** aParams,
                          uint32_t aLength,
                          const nsAString& aSourceName,
                          const nsAString& aSourceLine,
                          uint32_t aLineNumber,
                          uint32_t aColumnNumber,
                          uint32_t aFlags,
-                         const char* aCategory,
+                         const nsACString& aCategory,
                          uint64_t aInnerWindowID,
                          bool aFromPrivateWindow);
 
 void CSP_GetLocalizedStr(const char* aName,
                          const char16_t** aParams,
                          uint32_t aLength,
                          nsAString& outResult);
 
 void CSP_LogStrMessage(const nsAString& aMsg);
 
 void CSP_LogMessage(const nsAString& aMessage,
                     const nsAString& aSourceName,
                     const nsAString& aSourceLine,
                     uint32_t aLineNumber,
                     uint32_t aColumnNumber,
                     uint32_t aFlags,
-                    const char* aCategory,
+                    const nsACString& aCategory,
                     uint64_t aInnerWindowID,
                     bool aFromPrivateWindow);
 
 
 /* =============== Constant and Type Definitions ================== */
 
 #define INLINE_STYLE_VIOLATION_OBSERVER_TOPIC        "violated base restriction: Inline Stylesheets will not apply"
 #define INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC       "violated base restriction: Inline Scripts will not execute"
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -798,17 +798,18 @@ nsMixedContentBlocker::ShouldLoad(bool a
 
     const char16_t* params[] = { reportSpec.get()};
     CSP_LogLocalizedStr("blockAllMixedContent",
                         params, ArrayLength(params),
                         EmptyString(), // aSourceFile
                         EmptyString(), // aScriptSample
                         0, // aLineNumber
                         0, // aColumnNumber
-                        nsIScriptError::errorFlag, "CSP",
+                        nsIScriptError::errorFlag,
+                        NS_LITERAL_CSTRING("blockAllMixedContent"),
                         document->InnerWindowID(),
                         !!document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId);
     *aDecision = REJECT_REQUEST;
     return NS_OK;
   }
 
   // Determine if the rootDoc is https and if the user decided to allow Mixed Content
   bool rootHasSecureConnection = false;
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -450,41 +450,26 @@ nsSMILCSSValueType::Interpolate(const ns
   const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
   MOZ_ASSERT(endWrapper, "expecting non-null endpoint");
   return InterpolateForServo(startWrapper,
                              *endWrapper,
                              aUnitDistance,
                              aResult);
 }
 
-// Helper function to extract presContext
-static nsPresContext*
-GetPresContextForElement(Element* aElem)
-{
-  nsIDocument* doc = aElem->GetUncomposedDoc();
-  if (!doc) {
-    // This can happen if we process certain types of restyles mid-sample
-    // and remove anonymous animated content from the document as a result.
-    // See bug 534975.
-    return nullptr;
-  }
-  return doc->GetPresContext();
-}
-
-
 static ServoAnimationValues
 ValueFromStringHelper(nsCSSPropertyID aPropID,
                       Element* aTargetElement,
                       nsPresContext* aPresContext,
                       ComputedStyle* aComputedStyle,
                       const nsAString& aString)
 {
   ServoAnimationValues result;
 
-  nsIDocument* doc = aTargetElement->GetUncomposedDoc();
+  nsIDocument* doc = aTargetElement->GetComposedDoc();
   if (!doc) {
     return result;
   }
 
   // Parse property
   ServoCSSParser::ParsingEnvironment env =
     ServoCSSParser::GetParsingEnvironment(doc);
   RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
@@ -507,23 +492,24 @@ ValueFromStringHelper(nsCSSPropertyID aP
 void
 nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
                                     Element* aTargetElement,
                                     const nsAString& aString,
                                     nsSMILValue& aValue,
                                     bool* aIsContextSensitive)
 {
   MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed");
-  nsPresContext* presContext = GetPresContextForElement(aTargetElement);
+  nsPresContext* presContext =
+    nsContentUtils::GetContextForContent(aTargetElement);
   if (!presContext) {
     NS_WARNING("Not parsing animation value; unable to get PresContext");
     return;
   }
 
-  nsIDocument* doc = aTargetElement->GetUncomposedDoc();
+  nsIDocument* doc = aTargetElement->GetComposedDoc();
   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                 doc->NodePrincipal(),
                                                 nullptr,
                                                 doc->GetDocumentURI(),
                                                 0, 0, aString, nullptr)) {
     return;
   }
 
@@ -551,17 +537,17 @@ nsSMILCSSValueType::ValueFromString(nsCS
 // static
 nsSMILValue
 nsSMILCSSValueType::ValueFromAnimationValue(nsCSSPropertyID aPropID,
                                             Element* aTargetElement,
                                             const AnimationValue& aValue)
 {
   nsSMILValue result;
 
-  nsIDocument* doc = aTargetElement->GetUncomposedDoc();
+  nsIDocument* doc = aTargetElement->GetComposedDoc();
   // We'd like to avoid serializing |aValue| if possible, and since the
   // string passed to CSPAllowsInlineStyle is only used for reporting violations
   // and an intermediate CSS value is not likely to be particularly useful
   // in that case, we just use a generic placeholder string instead.
   static const nsLiteralString kPlaceholderText =
     NS_LITERAL_STRING("[SVG animation of CSS]");
   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                 doc->NodePrincipal(),
--- a/dom/smil/nsSMILTimeValueSpec.cpp
+++ b/dom/smil/nsSMILTimeValueSpec.cpp
@@ -91,17 +91,17 @@ nsSMILTimeValueSpec::ResolveReferences(n
   if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE && !IsEventBased())
     return;
 
   MOZ_ASSERT(aContextNode,
              "null context node for resolving timing references against");
 
   // If we're not bound to the document yet, don't worry, we'll get called again
   // when that happens
-  if (!aContextNode->IsInUncomposedDoc())
+  if (!aContextNode->IsInComposedDoc())
     return;
 
   // Hold ref to the old element so that it isn't destroyed in between resetting
   // the referenced element and using the pointer to update the referenced
   // element.
   RefPtr<Element> oldReferencedElement = mReferencedElement.get();
 
   if (mParams.mDependentElemID) {
--- a/dom/smil/nsSMILTimedElement.cpp
+++ b/dom/smil/nsSMILTimedElement.cpp
@@ -98,17 +98,17 @@ namespace
     }
 
     NS_IMETHOD Run() override
     {
       InternalSMILTimeEvent event(true, mMsg);
       event.mDetail = mDetail;
 
       nsPresContext* context = nullptr;
-      nsIDocument* doc = mTarget->GetUncomposedDoc();
+      nsIDocument* doc = mTarget->GetComposedDoc();
       if (doc) {
         context = doc->GetPresContext();
       }
 
       return EventDispatcher::Dispatch(mTarget, context, &event);
     }
   };
 } // namespace
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -67,17 +67,20 @@ SVGAnimationElement::GetTargetElementCon
       HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
     return mHrefTarget.get();
   }
   MOZ_ASSERT(!mHrefTarget.get(),
              "We shouldn't have a href target "
              "if we don't have an xlink:href or href attribute");
 
   // No "href" or "xlink:href" attribute --> I should target my parent.
-  return GetFlattenedTreeParentElement();
+  //
+  // Note that we want to use GetParentElement instead of the flattened tree to
+  // allow <use><animate>, for example.
+  return GetParentElement();
 }
 
 bool
 SVGAnimationElement::GetTargetAttributeName(int32_t *aNamespaceID,
                                             nsAtom **aLocalName) const
 {
   const nsAttrValue* nameAttr
     = mAttrsAndChildren.GetAttr(nsGkAtoms::attributeName);
@@ -163,28 +166,19 @@ SVGAnimationElement::BindToTree(nsIDocum
 {
   MOZ_ASSERT(!mHrefTarget.get(),
              "Shouldn't have href-target yet (or it should've been cleared)");
   nsresult rv = SVGAnimationElementBase::BindToTree(aDocument, aParent,
                                                     aBindingParent,
                                                     aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv,rv);
 
-  // XXXdholbert is GetCtx (as a check for SVG parent) still needed here?
-  if (!GetCtx()) {
-    // No use proceeding. We don't have an SVG parent (yet) so we won't be able
-    // to register ourselves etc. Maybe next time we'll have more luck.
-    // (This sort of situation will arise a lot when trees are being constructed
-    // piece by piece via script)
-    return NS_OK;
-  }
-
   // Add myself to the animation controller's master set of animation elements.
-  if (aDocument) {
-    nsSMILAnimationController *controller = aDocument->GetAnimationController();
+  if (nsIDocument* doc = GetComposedDoc()) {
+    nsSMILAnimationController* controller = doc->GetAnimationController();
     if (controller) {
       controller->RegisterAnimationElement(this);
     }
     const nsAttrValue* href =
       HasAttr(kNameSpaceID_None, nsGkAtoms::href)
       ? mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_None)
       : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
     if (href) {
@@ -203,17 +197,17 @@ SVGAnimationElement::BindToTree(nsIDocum
   AnimationNeedsResample();
 
   return NS_OK;
 }
 
 void
 SVGAnimationElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
-  nsSMILAnimationController *controller = OwnerDoc()->GetAnimationController();
+  nsSMILAnimationController* controller = OwnerDoc()->GetAnimationController();
   if (controller) {
     controller->UnregisterAnimationElement(this);
   }
 
   mHrefTarget.Unlink();
   mTimedElement.DissolveReferences();
 
   AnimationNeedsResample();
@@ -309,17 +303,17 @@ SVGAnimationElement::AfterSetAttr(int32_
       if (xlinkHref) {
         UpdateHrefTarget(this, xlinkHref->GetStringValue());
       }
     } else if (!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
       mHrefTarget.Unlink();
       AnimationTargetChanged();
     } // else: we unset xlink:href, but we still have href attribute, so keep
       // mHrefTarget linking to href.
-  } else if (IsInUncomposedDoc() &&
+  } else if (IsInComposedDoc() &&
              !(aNamespaceID == kNameSpaceID_XLink &&
                HasAttr(kNameSpaceID_None, nsGkAtoms::href))) {
     // Note: "href" takes priority over xlink:href. So if "xlink:href" is being
     // set here, we only let that update our target if "href" is *unset*.
     MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
                "Expected href attribute to be string type");
     UpdateHrefTarget(this, aValue->GetStringValue());
   } // else: we're not yet in a document -- we'll update the target on
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -36,23 +36,23 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::SVGPreserveAspectRatio_Binding;
 using namespace mozilla::gfx;
 
 SVGSVGElement*
 SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
 {
-  nsIContent *element = nullptr;
-  nsIContent *ancestor = aSVGElement->GetFlattenedTreeParent();
+  Element* element = nullptr;
+  Element* ancestor = aSVGElement->GetParentElementCrossingShadowRoot();
 
   while (ancestor && ancestor->IsSVGElement() &&
                      !ancestor->IsSVGElement(nsGkAtoms::foreignObject)) {
     element = ancestor;
-    ancestor = element->GetFlattenedTreeParent();
+    ancestor = element->GetParentElementCrossingShadowRoot();
   }
 
   if (element && element->IsSVGElement(nsGkAtoms::svg)) {
     return static_cast<SVGSVGElement*>(element);
   }
   return nullptr;
 }
 
--- a/dom/svg/SVGUseElement.cpp
+++ b/dom/svg/SVGUseElement.cpp
@@ -77,16 +77,20 @@ SVGUseElement::SVGUseElement(already_Add
   : SVGUseElementBase(aNodeInfo)
   , mReferencedElementTracker(this)
 {
 }
 
 SVGUseElement::~SVGUseElement()
 {
   UnlinkSource();
+  MOZ_DIAGNOSTIC_ASSERT(
+    !OwnerDoc()->SVGUseElementNeedsShadowTreeUpdate(*this),
+    "Dying without unbinding?"
+  );
 }
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 nsresult
 SVGUseElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                      bool aPreallocateChildren) const
@@ -104,16 +108,36 @@ SVGUseElement::Clone(mozilla::dom::NodeI
 
   if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
     kungFuDeathGrip.swap(*aResult);
   }
 
   return NS_FAILED(rv1) ? rv1 : rv2;
 }
 
+nsresult
+SVGUseElement::BindToTree(nsIDocument* aDocument,
+                          nsIContent* aParent,
+                          nsIContent* aBindingParent,
+                          bool aCompileEventHandlers)
+{
+  nsresult rv = SVGUseElementBase::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  TriggerReclone();
+  return NS_OK;
+}
+
+void
+SVGUseElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+  SVGUseElementBase::UnbindFromTree(aDeep, aNullParent);
+  OwnerDoc()->UnscheduleSVGUseElementShadowTreeUpdate(*this);
+}
+
 already_AddRefed<SVGAnimatedString>
 SVGUseElement::Href()
 {
   return mStringAttributes[HREF].IsExplicitlySet()
          ? mStringAttributes[HREF].ToDOMAnimatedString(this)
          : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
 }
 
@@ -199,162 +223,184 @@ void
 SVGUseElement::NodeWillBeDestroyed(const nsINode *aNode)
 {
   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
   UnlinkSource();
 }
 
 //----------------------------------------------------------------------
 
-already_AddRefed<nsIContent>
-SVGUseElement::CreateAnonymousContent()
+void
+SVGUseElement::UpdateShadowTree()
 {
+  MOZ_ASSERT(IsInComposedDoc());
+
   if (mReferencedElementTracker.get()) {
     mReferencedElementTracker.get()->RemoveMutationObserver(this);
   }
 
   LookupHref();
-  nsIContent* targetContent = mReferencedElementTracker.get();
-  if (!targetContent)
-    return nullptr;
+
+  RefPtr<ShadowRoot> shadow = GetShadowRoot();
+  if (!shadow) {
+    shadow = AttachShadowWithoutNameChecks(ShadowRootMode::Closed);
+  }
+  MOZ_ASSERT(shadow);
+
+  Element* targetElement = mReferencedElementTracker.get();
+  RefPtr<Element> newElement;
+
+  auto UpdateShadowTree = mozilla::MakeScopeExit([&]() {
+    nsIContent* firstChild = shadow->GetFirstChild();
+    if (firstChild) {
+      MOZ_ASSERT(!firstChild->GetNextSibling());
+      shadow->RemoveChildNode(firstChild, /* aNotify = */ true);
+    }
+
+    if (newElement) {
+      shadow->AppendChildTo(newElement, /* aNotify = */ true);
+    }
+  });
 
   // make sure target is valid type for <use>
   // QIable nsSVGGraphicsElement would eliminate enumerating all elements
-  if (!targetContent->IsAnyOfSVGElements(nsGkAtoms::svg,
+  if (!targetElement ||
+      !targetElement->IsAnyOfSVGElements(nsGkAtoms::svg,
                                          nsGkAtoms::symbol,
                                          nsGkAtoms::g,
                                          nsGkAtoms::path,
                                          nsGkAtoms::text,
                                          nsGkAtoms::rect,
                                          nsGkAtoms::circle,
                                          nsGkAtoms::ellipse,
                                          nsGkAtoms::line,
                                          nsGkAtoms::polyline,
                                          nsGkAtoms::polygon,
                                          nsGkAtoms::image,
-                                         nsGkAtoms::use))
-    return nullptr;
+                                         nsGkAtoms::use)) {
+    return;
+  }
 
   // circular loop detection
 
   // check 1 - check if we're a document descendent of the target
-  if (nsContentUtils::ContentIsDescendantOf(this, targetContent))
-    return nullptr;
+  if (nsContentUtils::ContentIsShadowIncludingDescendantOf(this, targetElement)) {
+    return;
+  }
 
   // check 2 - check if we're a clone, and if we already exist in the hierarchy
-  if (GetParent() && mOriginal) {
-    for (nsCOMPtr<nsIContent> content = GetParent();
-         content;
-         content = content->GetParent()) {
-      if (content->IsSVGElement(nsGkAtoms::use) &&
-          static_cast<SVGUseElement*>(content.get())->mOriginal == mOriginal) {
-        return nullptr;
+  if (mOriginal) {
+    for (nsINode* parent = GetParentOrHostNode();
+         parent;
+         parent = parent->GetParentOrHostNode()) {
+      SVGUseElement* use = SVGUseElement::FromNode(*parent);
+      if (use && use->mOriginal == mOriginal) {
+        return;
       }
     }
   }
 
-  nsNodeInfoManager* nodeInfoManager =
-    targetContent->OwnerDoc() == OwnerDoc() ?
-      nullptr : OwnerDoc()->NodeInfoManager();
-  nsCOMPtr<nsINode> newnode =
-    nsNodeUtils::Clone(targetContent, true, nodeInfoManager, nullptr,
-                       IgnoreErrors());
-  nsCOMPtr<nsIContent> newcontent = do_QueryInterface(newnode);
+  nsCOMPtr<nsIURI> baseURI = targetElement->GetBaseURI();
+  if (!baseURI) {
+    return;
+  }
+
+  {
+    nsNodeInfoManager* nodeInfoManager =
+      targetElement->OwnerDoc() == OwnerDoc()
+        ? nullptr
+        : OwnerDoc()->NodeInfoManager();
 
-  if (!newcontent)
-    return nullptr;
+    nsCOMPtr<nsINode> newNode =
+      nsNodeUtils::Clone(targetElement, true, nodeInfoManager, nullptr,
+                         IgnoreErrors());
+    if (!newNode) {
+      return;
+    }
 
-  if (newcontent->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
-    nsSVGElement *newElement = static_cast<nsSVGElement*>(newcontent.get());
+    MOZ_ASSERT(newNode->IsElement());
+    newElement = newNode.forget().downcast<Element>();
+  }
 
+  if (newElement->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
+    auto* newSVGElement = static_cast<nsSVGElement*>(newElement.get());
     if (mLengthAttributes[ATTR_WIDTH].IsExplicitlySet())
-      newElement->SetLength(nsGkAtoms::width, mLengthAttributes[ATTR_WIDTH]);
+      newSVGElement->SetLength(nsGkAtoms::width, mLengthAttributes[ATTR_WIDTH]);
     if (mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet())
-      newElement->SetLength(nsGkAtoms::height, mLengthAttributes[ATTR_HEIGHT]);
+      newSVGElement->SetLength(nsGkAtoms::height, mLengthAttributes[ATTR_HEIGHT]);
   }
 
   // Store the base URI
-  nsCOMPtr<nsIURI> baseURI = targetContent->GetBaseURI();
-  if (!baseURI) {
-    return nullptr;
-  }
   mContentURLData = new URLExtraData(baseURI.forget(),
                                      do_AddRef(OwnerDoc()->GetDocumentURI()),
                                      do_AddRef(NodePrincipal()));
 
-  targetContent->AddMutationObserver(this);
-
-#ifdef DEBUG
-  // Our anonymous clone can get restyled by various things
-  // (e.g. SMIL).  Reconstructing its frame is OK, though, because
-  // it's going to be our _only_ child in the frame tree, so can't get
-  // mis-ordered with anything.
-  newcontent->SetProperty(nsGkAtoms::restylableAnonymousNode,
-                          reinterpret_cast<void*>(true));
-#endif // DEBUG
-
-  return newcontent.forget();
+  targetElement->AddMutationObserver(this);
 }
 
 nsIURI*
 SVGUseElement::GetSourceDocURI()
 {
-  nsIContent* targetContent = mReferencedElementTracker.get();
-  if (!targetContent)
+  nsIContent* targetElement = mReferencedElementTracker.get();
+  if (!targetElement) {
     return nullptr;
+  }
 
-  return targetContent->OwnerDoc()->GetDocumentURI();
+  return targetElement->OwnerDoc()->GetDocumentURI();
+}
+
+static nsINode*
+GetClonedChild(const SVGUseElement& aUseElement)
+{
+  const ShadowRoot* shadow = aUseElement.GetShadowRoot();
+  return shadow ? shadow->GetFirstChild() : nullptr;
 }
 
 bool
 SVGUseElement::OurWidthAndHeightAreUsed() const
 {
-  auto* frame = GetFrame();
-  if (!frame || !frame->GetContentClone()) {
-    return false;
-  }
-  return frame->GetContentClone()->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol);
+  nsINode* clonedChild = GetClonedChild(*this);
+  return clonedChild &&
+    clonedChild->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol);
 }
 
 //----------------------------------------------------------------------
 // implementation helpers
 
 void
 SVGUseElement::SyncWidthOrHeight(nsAtom* aName)
 {
   NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
                "The clue is in the function name");
   NS_ASSERTION(OurWidthAndHeightAreUsed(), "Don't call this");
 
-  auto* frame = GetFrame();
-  nsIContent* clone = frame ? frame->GetContentClone() : nullptr;
-
-  if (OurWidthAndHeightAreUsed()) {
-    auto* target = static_cast<nsSVGElement*>(clone);
-    uint32_t index = *sLengthInfo[ATTR_WIDTH].mName == aName ? ATTR_WIDTH : ATTR_HEIGHT;
+  if (!OurWidthAndHeightAreUsed()) {
+    return;
+  }
 
-    if (mLengthAttributes[index].IsExplicitlySet()) {
-      target->SetLength(aName, mLengthAttributes[index]);
-      return;
-    }
-    if (clone->IsSVGElement(nsGkAtoms::svg)) {
-      // Our width/height attribute is now no longer explicitly set, so we
-      // need to revert the clone's width/height to the width/height of the
-      // content that's being cloned.
-      TriggerReclone();
-      return;
-    }
-    // Our width/height attribute is now no longer explicitly set, so we
-    // need to set the value to 100%
-    nsSVGLength2 length;
-    length.Init(SVGContentUtils::XY, 0xff,
-                100, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE);
-    target->SetLength(aName, length);
+  auto* target = nsSVGElement::FromNode(GetClonedChild(*this));
+  uint32_t index = *sLengthInfo[ATTR_WIDTH].mName == aName ? ATTR_WIDTH : ATTR_HEIGHT;
+
+  if (mLengthAttributes[index].IsExplicitlySet()) {
+    target->SetLength(aName, mLengthAttributes[index]);
     return;
   }
+  if (target->IsSVGElement(nsGkAtoms::svg)) {
+    // Our width/height attribute is now no longer explicitly set, so we
+    // need to revert the clone's width/height to the width/height of the
+    // content that's being cloned.
+    TriggerReclone();
+    return;
+  }
+  // Our width/height attribute is now no longer explicitly set, so we
+  // need to set the value to 100%
+  nsSVGLength2 length;
+  length.Init(SVGContentUtils::XY, 0xff,
+              100, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE);
+  target->SetLength(aName, length);
 }
 
 void
 SVGUseElement::LookupHref()
 {
   nsAutoString href;
   if (mStringAttributes[HREF].IsExplicitlySet()) {
     mStringAttributes[HREF].GetAnimValue(href, this);
@@ -376,23 +422,19 @@ SVGUseElement::LookupHref()
   nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
                                             GetComposedDoc(), baseURI);
   mReferencedElementTracker.Reset(this, targetURI);
 }
 
 void
 SVGUseElement::TriggerReclone()
 {
-  nsIDocument *doc = GetComposedDoc();
-  if (!doc)
-    return;
-  nsIPresShell *presShell = doc->GetShell();
-  if (!presShell)
-    return;
-  presShell->PostRecreateFramesFor(this);
+  if (nsIDocument* doc = GetComposedDoc()) {
+    doc->ScheduleSVGUseElementShadowTreeUpdate(*this);
+  }
 }
 
 void
 SVGUseElement::UnlinkSource()
 {
   if (mReferencedElementTracker.get()) {
     mReferencedElementTracker.get()->RemoveMutationObserver(this);
   }
--- a/dom/svg/SVGUseElement.h
+++ b/dom/svg/SVGUseElement.h
@@ -39,31 +39,36 @@ class SVGUseElement final : public SVGUs
 protected:
   friend nsresult (::NS_NewSVGUseElement(nsIContent **aResult,
                                          already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGUseElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual ~SVGUseElement();
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
+  NS_IMPL_FROMNODE_WITH_TAG(SVGUseElement, kNameSpaceID_SVG, use)
+
+  nsresult BindToTree(nsIDocument* aDocument,
+                      nsIContent* aParent,
+                      nsIContent* aBindingParent,
+                      bool aCompileEventHandlers) override;
+  void UnbindFromTree(bool aDeep = true,
+                      bool aNullParent = true) override;
+
   // interfaces:
-
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGUseElement, SVGUseElementBase)
 
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
-  // for nsSVGUseFrame's nsIAnonymousContentCreator implementation.
-  already_AddRefed<nsIContent> CreateAnonymousContent();
-
   // nsSVGElement specializations:
   virtual gfxMatrix PrependLocalTransformsTo(
     const gfxMatrix &aMatrix,
     SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual bool HasValidDimensions() const override;
 
   // nsIContent interface
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
@@ -75,37 +80,44 @@ public:
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
 
   nsIURI* GetSourceDocURI();
   URLExtraData* GetContentURLData() const { return mContentURLData; }
 
+  // Updates the internal shadow tree to be an up-to-date clone of the
+  // referenced element.
+  void UpdateShadowTree();
+
 protected:
   /**
    * Helper that provides a reference to the element with the ID that is
    * referenced by the 'use' element's 'href' attribute, and that will update
    * the 'use' element if the element that that ID identifies changes to a
    * different element (or none).
    */
   class ElementTracker final : public IDTracker {
   public:
     explicit ElementTracker(SVGUseElement* aOwningUseElement)
       : mOwningUseElement(aOwningUseElement)
     {}
-  protected:
-    virtual void ElementChanged(Element* aFrom, Element* aTo) override {
+
+  private:
+
+    void ElementChanged(Element* aFrom, Element* aTo) override
+    {
       IDTracker::ElementChanged(aFrom, aTo);
       if (aFrom) {
         aFrom->RemoveMutationObserver(mOwningUseElement);
       }
       mOwningUseElement->TriggerReclone();
     }
-  private:
+
     SVGUseElement* mOwningUseElement;
   };
 
   nsSVGUseFrame* GetFrame() const;
 
   virtual LengthAttributesInfo GetLengthInfo() override;
   virtual StringAttributesInfo GetStringInfo() override;
 
@@ -124,16 +136,16 @@ protected:
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 
   enum { HREF, XLINK_HREF };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 
   nsCOMPtr<nsIContent> mOriginal; // if we've been cloned, our "real" copy
-  ElementTracker       mReferencedElementTracker;
+  ElementTracker mReferencedElementTracker;
   RefPtr<URLExtraData> mContentURLData; // URL data for its anonymous content
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGUseElement_h
--- a/dom/webidl/AccessibleNode.webidl
+++ b/dom/webidl/AccessibleNode.webidl
@@ -12,9 +12,26 @@ interface AccessibleNode {
   [Frozen, Cached, Pure]
   readonly attribute sequence<DOMString> attributes;
   readonly attribute Node? DOMNode;
 
   boolean is(DOMString... states);
   boolean has(DOMString... attributes);
   [Throws]
   any get(DOMString attribute);
+
+  // Accessible properties
+  attribute boolean? modal;
+  attribute boolean? multiline;
+  attribute boolean? multiselectable;
+  attribute boolean? readOnly;
+  attribute boolean? required;
+
+  // Accessible states
+  attribute boolean? disabled;
+  attribute boolean? expanded;
+  attribute boolean? hidden;
+  attribute boolean? selected;
+
+  // Live regions
+  attribute boolean? atomic;
+  attribute boolean? busy;
 };
--- a/dom/websocket/WebSocket.cpp
+++ b/dom/websocket/WebSocket.cpp
@@ -1719,17 +1719,18 @@ WebSocketImpl::Init(JSContext* aCx,
 
     const char16_t* params[] = { reportSpec.get(), u"wss" };
     CSP_LogLocalizedStr("upgradeInsecureRequest",
                         params, ArrayLength(params),
                         EmptyString(), // aSourceFile
                         EmptyString(), // aScriptSample
                         0, // aLineNumber
                         0, // aColumnNumber
-                        nsIScriptError::warningFlag, "CSP",
+                        nsIScriptError::warningFlag,
+                        NS_LITERAL_CSTRING("upgradeInsecureRequest"),
                         mInnerWindowID,
                         mPrivateBrowsing);
   }
 
   // Don't allow https:// to open ws://
   if (!mIsServerSide && !mSecure &&
       !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
                             false)) {
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -171,47 +171,51 @@ typedef uintptr_t SyncHandle;
  * kinds of buffer and texture clients to create.
  */
 struct TextureFactoryIdentifier
 {
   LayersBackend mParentBackend;
   GeckoProcessType mParentProcessType;
   int32_t mMaxTextureSize;
   bool mCompositorUseANGLE;
+  bool mCompositorUseDComp;
   bool mSupportsTextureBlitting;
   bool mSupportsPartialUploads;
   bool mSupportsComponentAlpha;
   bool mUsingAdvancedLayers;
   SyncHandle mSyncHandle;
 
   explicit TextureFactoryIdentifier(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
                                     GeckoProcessType aParentProcessType = GeckoProcessType_Default,
                                     int32_t aMaxTextureSize = 4096,
                                     bool aCompositorUseANGLE = false,
+                                    bool aCompositorUseDComp = false,
                                     bool aSupportsTextureBlitting = false,
                                     bool aSupportsPartialUploads = false,
                                     bool aSupportsComponentAlpha = true,
                                     SyncHandle aSyncHandle = 0)
     : mParentBackend(aLayersBackend)
     , mParentProcessType(aParentProcessType)
     , mMaxTextureSize(aMaxTextureSize)
     , mCompositorUseANGLE(aCompositorUseANGLE)
+    , mCompositorUseDComp(aCompositorUseDComp)
     , mSupportsTextureBlitting(aSupportsTextureBlitting)
     , mSupportsPartialUploads(aSupportsPartialUploads)
     , mSupportsComponentAlpha(aSupportsComponentAlpha)
     , mUsingAdvancedLayers(false)
     , mSyncHandle(aSyncHandle)
   {}
 
   bool operator==(const TextureFactoryIdentifier& aOther) const {
     return
       mParentBackend == aOther.mParentBackend &&
       mParentProcessType == aOther.mParentProcessType &&
       mMaxTextureSize == aOther.mMaxTextureSize &&
       mCompositorUseANGLE == aOther.mCompositorUseANGLE &&
+      mCompositorUseDComp == aOther.mCompositorUseDComp &&
       mSupportsTextureBlitting == aOther.mSupportsTextureBlitting &&
       mSupportsPartialUploads == aOther.mSupportsPartialUploads &&
       mSupportsComponentAlpha == aOther.mSupportsComponentAlpha &&
       mSyncHandle == aOther.mSyncHandle;
   }
 };
 
 /**
--- a/gfx/layers/ipc/KnowsCompositor.h
+++ b/gfx/layers/ipc/KnowsCompositor.h
@@ -108,16 +108,21 @@ public:
            (GetCompositorBackendType() == layers::LayersBackend::LAYERS_WR && GetCompositorUseANGLE());
   }
 
   bool GetCompositorUseANGLE() const
   {
     return mTextureFactoryIdentifier.mCompositorUseANGLE;
   }
 
+  bool GetCompositorUseDComp() const
+  {
+    return mTextureFactoryIdentifier.mCompositorUseDComp;
+  }
+
   const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
   {
     return mTextureFactoryIdentifier;
   }
 
   bool DeviceCanReset() const
   {
     return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC;
--- a/gfx/layers/ipc/LayersMessageUtils.h
+++ b/gfx/layers/ipc/LayersMessageUtils.h
@@ -331,29 +331,31 @@ struct ParamTraits<mozilla::layers::Text
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mParentBackend);
     WriteParam(aMsg, aParam.mParentProcessType);
     WriteParam(aMsg, aParam.mMaxTextureSize);
     WriteParam(aMsg, aParam.mCompositorUseANGLE);
+    WriteParam(aMsg, aParam.mCompositorUseDComp);
     WriteParam(aMsg, aParam.mSupportsTextureBlitting);
     WriteParam(aMsg, aParam.mSupportsPartialUploads);
     WriteParam(aMsg, aParam.mSupportsComponentAlpha);
     WriteParam(aMsg, aParam.mUsingAdvancedLayers);
     WriteParam(aMsg, aParam.mSyncHandle);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool result = ReadParam(aMsg, aIter, &aResult->mParentBackend) &&
                   ReadParam(aMsg, aIter, &aResult->mParentProcessType) &&
                   ReadParam(aMsg, aIter, &aResult->mMaxTextureSize) &&
                   ReadParam(aMsg, aIter, &aResult->mCompositorUseANGLE) &&
+                  ReadParam(aMsg, aIter, &aResult->mCompositorUseDComp) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
                   ReadParam(aMsg, aIter, &aResult->mUsingAdvancedLayers) &&
                   ReadParam(aMsg, aIter, &aResult->mSyncHandle);
     return result;
   }
 };
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1855,16 +1855,17 @@ TextureFactoryIdentifier
 WebRenderBridgeParent::GetTextureFactoryIdentifier()
 {
   MOZ_ASSERT(mApi);
 
   return TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
                                   XRE_GetProcessType(),
                                   mApi->GetMaxTextureSize(),
                                   mApi->GetUseANGLE(),
+                                  mApi->GetUseDComp(),
                                   false,
                                   false,
                                   false,
                                   mApi->GetSyncHandle());
 }
 
 wr::Epoch
 WebRenderBridgeParent::GetNextWrEpoch()
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -610,17 +610,20 @@ void
 WebRenderLayerManager::FlushRendering()
 {
   CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
   if (!cBridge) {
     return;
   }
   MOZ_ASSERT(mWidget);
 
-  if (mWidget->SynchronouslyRepaintOnResize() || gfxPrefs::LayersForceSynchronousResize()) {
+  // When DirectComposition and compositor window are used, we do not need to do sync FlushRendering.
+  if (WrBridge()->GetCompositorUseDComp()) {
+    cBridge->SendFlushRenderingAsync();
+  } else if (mWidget->SynchronouslyRepaintOnResize() || gfxPrefs::LayersForceSynchronousResize()) {
     cBridge->SendFlushRendering();
   } else {
     cBridge->SendFlushRenderingAsync();
   }
 }
 
 void
 WebRenderLayerManager::WaitOnTransactionProcessed()
--- a/gfx/webrender_bindings/RenderCompositor.h
+++ b/gfx/webrender_bindings/RenderCompositor.h
@@ -39,16 +39,18 @@ public:
   virtual void EndFrame() = 0;
   virtual void Pause() = 0;
   virtual bool Resume() = 0;
 
   virtual gl::GLContext* gl() const { return nullptr; }
 
   virtual bool UseANGLE() const { return false; }
 
+  virtual bool UseDComp() const { return false; }
+
   virtual LayoutDeviceIntSize GetBufferSize() = 0;
 
   widget::CompositorWidget* GetWidget() const { return mWidget; }
 
   layers::SyncObjectHost* GetSyncObject() const { return mSyncObject.get(); }
 
 protected:
   RefPtr<widget::CompositorWidget> mWidget;
--- a/gfx/webrender_bindings/RenderCompositorANGLE.h
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.h
@@ -37,16 +37,18 @@ public:
   void EndFrame() override;
   void Pause() override;
   bool Resume() override;
 
   gl::GLContext* gl() const override { return mGL; }
 
   bool UseANGLE() const override { return true; }
 
+  bool UseDComp() const override { return !!mCompositionDevice; }
+
   LayoutDeviceIntSize GetBufferSize() override;
 
 protected:
   void InsertPresentWaitQuery();
   void WaitForPreviousPresentQuery();
   bool ResizeBufferIfNeeded();
   void DestroyEGLSurface();
   ID3D11Device* GetDeviceOfEGLDisplay();
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -26,23 +26,25 @@ using layers::Stringify;
 
 class NewRenderer : public RendererEvent
 {
 public:
   NewRenderer(wr::DocumentHandle** aDocHandle,
               layers::CompositorBridgeParent* aBridge,
               uint32_t* aMaxTextureSize,
               bool* aUseANGLE,
+              bool* aUseDComp,
               RefPtr<widget::CompositorWidget>&& aWidget,
               layers::SynchronousTask* aTask,
               LayoutDeviceIntSize aSize,
               layers::SyncHandle* aHandle)
     : mDocHandle(aDocHandle)
     , mMaxTextureSize(aMaxTextureSize)
     , mUseANGLE(aUseANGLE)
+    , mUseDComp(aUseDComp)
     , mBridge(aBridge)
     , mCompositorWidget(std::move(aWidget))
     , mTask(aTask)
     , mSize(aSize)
     , mSyncHandle(aHandle)
   {
     MOZ_COUNT_CTOR(NewRenderer);
   }
@@ -58,16 +60,17 @@ public:
 
     UniquePtr<RenderCompositor> compositor = RenderCompositor::Create(std::move(mCompositorWidget));
     if (!compositor) {
       // RenderCompositor::Create puts a message into gfxCriticalNote if it is nullptr
       return;
     }
 
     *mUseANGLE = compositor->UseANGLE();
+    *mUseDComp = compositor->UseDComp();
 
     wr::Renderer* wrRenderer = nullptr;
     if (!wr_window_new(aWindowId, mSize.width, mSize.height, compositor->gl(),
                        aRenderThread.ThreadPool().Raw(),
                        mDocHandle, &wrRenderer,
                        mMaxTextureSize)) {
       // wr_window_new puts a message into gfxCriticalNote if it returns false
       return;
@@ -97,16 +100,17 @@ public:
 
     aRenderThread.AddRenderer(aWindowId, std::move(renderer));
   }
 
 private:
   wr::DocumentHandle** mDocHandle;
   uint32_t* mMaxTextureSize;
   bool* mUseANGLE;
+  bool* mUseDComp;
   layers::CompositorBridgeParent* mBridge;
   RefPtr<widget::CompositorWidget> mCompositorWidget;
   layers::SynchronousTask* mTask;
   LayoutDeviceIntSize mSize;
   layers::SyncHandle* mSyncHandle;
 };
 
 class RemoveRenderer : public RendererEvent
@@ -266,43 +270,44 @@ WebRenderAPI::Create(layers::CompositorB
   MOZ_ASSERT(aBridge);
   MOZ_ASSERT(aWidget);
   static_assert(sizeof(size_t) == sizeof(uintptr_t),
       "The FFI bindings assume size_t is the same size as uintptr_t!");
 
   wr::DocumentHandle* docHandle = nullptr;
   uint32_t maxTextureSize = 0;
   bool useANGLE = false;
+  bool useDComp = false;
   layers::SyncHandle syncHandle = 0;
 
   // Dispatch a synchronous task because the DocumentHandle object needs to be created
   // on the render thread. If need be we could delay waiting on this task until
   // the next time we need to access the DocumentHandle object.
   layers::SynchronousTask task("Create Renderer");
-  auto event = MakeUnique<NewRenderer>(&docHandle, aBridge, &maxTextureSize, &useANGLE,
+  auto event = MakeUnique<NewRenderer>(&docHandle, aBridge, &maxTextureSize, &useANGLE, &useDComp,
                                        std::move(aWidget), &task, aSize,
                                        &syncHandle);
   RenderThread::Get()->RunEvent(aWindowId, std::move(event));
 
   task.Wait();
 
   if (!docHandle) {
     return nullptr;
   }
 
-  return RefPtr<WebRenderAPI>(new WebRenderAPI(docHandle, aWindowId, maxTextureSize, useANGLE, syncHandle)).forget();
+  return RefPtr<WebRenderAPI>(new WebRenderAPI(docHandle, aWindowId, maxTextureSize, useANGLE, useDComp, syncHandle)).forget();
 }
 
 already_AddRefed<WebRenderAPI>
 WebRenderAPI::Clone()
 {
   wr::DocumentHandle* docHandle = nullptr;
   wr_api_clone(mDocHandle, &docHandle);
 
-  RefPtr<WebRenderAPI> renderApi = new WebRenderAPI(docHandle, mId, mMaxTextureSize, mUseANGLE, mSyncHandle);
+  RefPtr<WebRenderAPI> renderApi = new WebRenderAPI(docHandle, mId, mMaxTextureSize, mUseANGLE, mUseDComp, mSyncHandle);
   renderApi->mRootApi = this; // Hold root api
   renderApi->mRootDocumentApi = this;
   return renderApi.forget();
 }
 
 already_AddRefed<WebRenderAPI>
 WebRenderAPI::CreateDocument(LayoutDeviceIntSize aSize, int8_t aLayerIndex)
 {
@@ -311,16 +316,17 @@ WebRenderAPI::CreateDocument(LayoutDevic
   wrSize.height = aSize.height;
   wr::DocumentHandle* newDoc;
 
   wr_api_create_document(mDocHandle, &newDoc, wrSize, aLayerIndex);
 
   RefPtr<WebRenderAPI> api(new WebRenderAPI(newDoc, mId,
                                             mMaxTextureSize,
                                             mUseANGLE,
+                                            mUseDComp,
                                             mSyncHandle));
   api->mRootApi = this;
   return api.forget();
 }
 
 wr::WrIdNamespace
 WebRenderAPI::GetNamespace() {
   return wr_api_get_namespace(mDocHandle);
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -200,37 +200,40 @@ public:
   bool Resume();
 
   void WakeSceneBuilder();
   void FlushSceneBuilder();
 
   wr::WrIdNamespace GetNamespace();
   uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
   bool GetUseANGLE() const { return mUseANGLE; }
+  bool GetUseDComp() const { return mUseDComp; }
   layers::SyncHandle GetSyncHandle() const { return mSyncHandle; }
 
   void Capture();
 
 protected:
-  WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId, uint32_t aMaxTextureSize, bool aUseANGLE, layers::SyncHandle aSyncHandle)
+  WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId, uint32_t aMaxTextureSize, bool aUseANGLE, bool aUseDComp, layers::SyncHandle aSyncHandle)
     : mDocHandle(aHandle)
     , mId(aId)
     , mMaxTextureSize(aMaxTextureSize)
     , mUseANGLE(aUseANGLE)
+    , mUseDComp(aUseDComp)
     , mSyncHandle(aSyncHandle)
   {}
 
   ~WebRenderAPI();
   // Should be used only for shutdown handling
   void WaitFlushed();
 
   wr::DocumentHandle* mDocHandle;
   wr::WindowId mId;
   uint32_t mMaxTextureSize;
   bool mUseANGLE;
+  bool mUseDComp;
   layers::SyncHandle mSyncHandle;
 
   // We maintain alive the root api to know when to shut the render backend down,
   // and the root api for the document to know when to delete the document.
   // mRootApi is null for the api object that owns the channel (and is responsible
   // for shutting it down), and mRootDocumentApi is null for the api object owning
   // (and responsible for destroying) a given document.
   // All api objects in the same window use the same channel, and some api objects
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -125,16 +125,77 @@ enum BuiltinThenableJobSlots {
 enum PromiseAllDataHolderSlots {
     PromiseAllDataHolderSlot_Promise = 0,
     PromiseAllDataHolderSlot_RemainingElements,
     PromiseAllDataHolderSlot_ValuesArray,
     PromiseAllDataHolderSlot_ResolveFunction,
     PromiseAllDataHolderSlots,
 };
 
+struct PromiseCapability {
+    JSObject* promise = nullptr;
+    JSObject* resolve = nullptr;
+    JSObject* reject = nullptr;
+
+    PromiseCapability() = default;
+
+    static void trace(PromiseCapability* self, JSTracer* trc) { self->trace(trc); }
+    void trace(JSTracer* trc);
+};
+
+void
+PromiseCapability::trace(JSTracer* trc)
+{
+    if (promise)
+        TraceRoot(trc, &promise, "PromiseCapability::promise");
+    if (resolve)
+        TraceRoot(trc, &resolve, "PromiseCapability::resolve");
+    if (reject)
+        TraceRoot(trc, &reject, "PromiseCapability::reject");
+}
+
+namespace js {
+
+template <typename Wrapper>
+class WrappedPtrOperations<PromiseCapability, Wrapper>
+{
+    const PromiseCapability& capability() const { return static_cast<const Wrapper*>(this)->get(); }
+
+  public:
+    HandleObject promise() const {
+        return HandleObject::fromMarkedLocation(&capability().promise);
+    }
+    HandleObject resolve() const {
+        return HandleObject::fromMarkedLocation(&capability().resolve);
+    }
+    HandleObject reject() const {
+        return HandleObject::fromMarkedLocation(&capability().reject);
+    }
+};
+
+template <typename Wrapper>
+class MutableWrappedPtrOperations<PromiseCapability, Wrapper>
+    : public WrappedPtrOperations<PromiseCapability, Wrapper>
+{
+    PromiseCapability& capability() { return static_cast<Wrapper*>(this)->get(); }
+
+  public:
+    MutableHandleObject promise() {
+        return MutableHandleObject::fromMarkedLocation(&capability().promise);
+    }
+    MutableHandleObject resolve() {
+        return MutableHandleObject::fromMarkedLocation(&capability().resolve);
+    }
+    MutableHandleObject reject() {
+        return MutableHandleObject::fromMarkedLocation(&capability().reject);
+    }
+};
+
+} // namespace js
+
 class PromiseAllDataHolder : public NativeObject
 {
   public:
     static const Class class_;
     JSObject* promiseObj() { return &getFixedSlot(PromiseAllDataHolderSlot_Promise).toObject(); }
     JSObject* resolveObj() {
         return &getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObject();
     }
@@ -160,17 +221,17 @@ const Class PromiseAllDataHolder::class_
     "PromiseAllDataHolder",
     JSCLASS_HAS_RESERVED_SLOTS(PromiseAllDataHolderSlots)
 };
 
 static PromiseAllDataHolder*
 NewPromiseAllDataHolder(JSContext* cx, HandleObject resultPromise, HandleValue valuesArray,
                         HandleObject resolve)
 {
-    Rooted<PromiseAllDataHolder*> dataHolder(cx, NewObjectWithClassProto<PromiseAllDataHolder>(cx));
+    PromiseAllDataHolder* dataHolder = NewBuiltinClassInstance<PromiseAllDataHolder>(cx);
     if (!dataHolder)
         return nullptr;
 
     assertSameCompartment(cx, resultPromise);
     assertSameCompartment(cx, valuesArray);
     assertSameCompartment(cx, resolve);
 
     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_Promise, ObjectValue(*resultPromise));
@@ -201,17 +262,17 @@ class PromiseDebugInfo : public NativeOb
         Slot_ResolutionTime,
         Slot_Id,
         SlotCount
     };
 
   public:
     static const Class class_;
     static PromiseDebugInfo* create(JSContext* cx, Handle<PromiseObject*> promise) {
-        Rooted<PromiseDebugInfo*> debugInfo(cx, NewObjectWithClassProto<PromiseDebugInfo>(cx));
+        Rooted<PromiseDebugInfo*> debugInfo(cx, NewBuiltinClassInstance<PromiseDebugInfo>(cx));
         if (!debugInfo)
             return nullptr;
 
         RootedObject stack(cx);
         if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
             return nullptr;
         debugInfo->setFixedSlot(Slot_AllocationSite, ObjectOrNullValue(stack));
         debugInfo->setFixedSlot(Slot_ResolutionSite, NullValue());
@@ -364,31 +425,37 @@ static MOZ_MUST_USE bool RunResolutionFu
                                                HandleValue result, ResolutionMode mode,
                                                HandleObject promiseObj);
 
 // ES2016, 25.4.1.1.1, Steps 1.a-b.
 // Extracting all of this internal spec algorithm into a helper function would
 // be tedious, so the check in step 1 and the entirety of step 2 aren't
 // included.
 static bool
-AbruptRejectPromise(JSContext *cx, CallArgs& args, HandleObject promiseObj, HandleObject reject)
+AbruptRejectPromise(JSContext* cx, CallArgs& args, HandleObject promiseObj, HandleObject reject)
 {
     // Step 1.a.
     RootedValue reason(cx);
     if (!MaybeGetAndClearException(cx, &reason))
         return false;
 
     if (!RunResolutionFunction(cx, reject, reason, RejectMode, promiseObj))
         return false;
 
     // Step 1.b.
     args.rval().setObject(*promiseObj);
     return true;
 }
 
+static bool
+AbruptRejectPromise(JSContext* cx, CallArgs& args, Handle<PromiseCapability> capability)
+{
+    return AbruptRejectPromise(cx, args, capability.promise(), capability.reject());
+}
+
 enum ReactionRecordSlots {
     // The promise for which this record provides a reaction handler.
     // Matches the [[Capability]].[[Promise]] field from the spec.
     //
     // The slot value is either an object, but not necessarily a built-in
     // Promise object, or null. The latter case is only possible for async
     // generator functions, in which case the REACTION_FLAG_ASYNC_GENERATOR
     // flag must be set.
@@ -397,18 +464,24 @@ enum ReactionRecordSlots {
     // The [[Handler]] field(s) of a PromiseReaction record. We create a
     // single reaction record for fulfillment and rejection, therefore our
     // PromiseReaction implementation needs two [[Handler]] fields.
     //
     // The slot value is either a callable object, an integer constant from
     // the |PromiseHandler| enum, or null. If the value is null, either the
     // REACTION_FLAG_DEBUGGER_DUMMY or the
     // REACTION_FLAG_DEFAULT_RESOLVING_HANDLER flag must be set.
+    //
+    // After setting the target state for a PromiseReaction, the slot of the
+    // no longer used handler gets reused to store the argument of the active
+    // handler.
     ReactionRecordSlot_OnFulfilled,
+    ReactionRecordSlot_OnRejectedArg = ReactionRecordSlot_OnFulfilled,
     ReactionRecordSlot_OnRejected,
+    ReactionRecordSlot_OnFulfilledArg = ReactionRecordSlot_OnRejected,
 
     // The functions to resolve or reject the promise. Matches the
     // [[Capability]].[[Resolve]] and [[Capability]].[[Reject]] fields from
     // the spec.
     //
     // The slot values are either callable objects or null, but the latter
     // case is only allowed if the promise is either a built-in Promise object
     // or null.
@@ -416,69 +489,83 @@ enum ReactionRecordSlots {
     ReactionRecordSlot_Reject,
 
     // The incumbent global for this reaction record. Can be null.
     ReactionRecordSlot_IncumbentGlobalObject,
 
     // Bitmask of the REACTION_FLAG values.
     ReactionRecordSlot_Flags,
 
-    // Argument when calling the function stored in OnFulfilled or OnRejected.
-    ReactionRecordSlot_HandlerArg,
-
     // Additional slot to store extra data for specific reaction record types.
     //
     // - When the REACTION_FLAG_ASYNC_GENERATOR flag is set, this slot store
     //   the async generator function for this promise reaction.
     // - When the REACTION_FLAG_DEFAULT_RESOLVING_HANDLER flag is set, this
     //   slot stores the promise to resolve when conceptually "calling" the
     //   OnFulfilled or OnRejected handlers.
     ReactionRecordSlot_GeneratorOrPromiseToResolve,
 
     ReactionRecordSlots,
 };
 
 // ES2016, 25.4.1.2.
 class PromiseReactionRecord : public NativeObject
 {
-  static constexpr size_t REACTION_FLAG_RESOLVED = 0x1;
-  static constexpr size_t REACTION_FLAG_FULFILLED = 0x2;
-  static constexpr size_t REACTION_FLAG_DEFAULT_RESOLVING_HANDLER = 0x4;
-  static constexpr size_t REACTION_FLAG_ASYNC_FUNCTION = 0x8;
-  static constexpr size_t REACTION_FLAG_ASYNC_GENERATOR = 0x10;
-  static constexpr size_t REACTION_FLAG_DEBUGGER_DUMMY = 0x20;
-
-  void setFlagOnInitialState(size_t flag) {
-      int32_t flags = this->flags();
-      MOZ_ASSERT(flags == 0, "Can't modify with non-default flags");
-      flags |= flag;
-      setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
-  }
+    static constexpr uint32_t REACTION_FLAG_RESOLVED = 0x1;
+    static constexpr uint32_t REACTION_FLAG_FULFILLED = 0x2;
+    static constexpr uint32_t REACTION_FLAG_DEFAULT_RESOLVING_HANDLER = 0x4;
+    static constexpr uint32_t REACTION_FLAG_ASYNC_FUNCTION = 0x8;
+    static constexpr uint32_t REACTION_FLAG_ASYNC_GENERATOR = 0x10;
+    static constexpr uint32_t REACTION_FLAG_DEBUGGER_DUMMY = 0x20;
+
+    void setFlagOnInitialState(uint32_t flag) {
+        int32_t flags = this->flags();
+        MOZ_ASSERT(flags == 0, "Can't modify with non-default flags");
+        flags |= flag;
+        setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
+    }
+
+    uint32_t handlerSlot() {
+        MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
+        return targetState() == JS::PromiseState::Fulfilled
+               ? ReactionRecordSlot_OnFulfilled
+               : ReactionRecordSlot_OnRejected;
+    }
+
+    uint32_t handlerArgSlot() {
+        MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
+        return targetState() == JS::PromiseState::Fulfilled
+               ? ReactionRecordSlot_OnFulfilledArg
+               : ReactionRecordSlot_OnRejectedArg;
+    }
 
   public:
     static const Class class_;
 
     JSObject* promise() { return getFixedSlot(ReactionRecordSlot_Promise).toObjectOrNull(); }
     int32_t flags() { return getFixedSlot(ReactionRecordSlot_Flags).toInt32(); }
     JS::PromiseState targetState() {
         int32_t flags = this->flags();
         if (!(flags & REACTION_FLAG_RESOLVED))
             return JS::PromiseState::Pending;
         return flags & REACTION_FLAG_FULFILLED
                ? JS::PromiseState::Fulfilled
                : JS::PromiseState::Rejected;
     }
-    void setTargetState(JS::PromiseState state) {
+    void setTargetStateAndHandlerArg(JS::PromiseState state, const Value& arg) {
+        MOZ_ASSERT(targetState() == JS::PromiseState::Pending);
+        MOZ_ASSERT(state != JS::PromiseState::Pending, "Can't revert a reaction to pending.");
+
         int32_t flags = this->flags();
-        MOZ_ASSERT(!(flags & REACTION_FLAG_RESOLVED));
-        MOZ_ASSERT(state != JS::PromiseState::Pending, "Can't revert a reaction to pending.");
         flags |= REACTION_FLAG_RESOLVED;
         if (state == JS::PromiseState::Fulfilled)
             flags |= REACTION_FLAG_FULFILLED;
+
         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
+        setFixedSlot(handlerArgSlot(), arg);
     }
     void setIsDefaultResolvingHandler(PromiseObject* promiseToResolve) {
         setFlagOnInitialState(REACTION_FLAG_DEFAULT_RESOLVING_HANDLER);
         setFixedSlot(ReactionRecordSlot_GeneratorOrPromiseToResolve, ObjectValue(*promiseToResolve));
     }
     bool isDefaultResolvingHandler() {
         int32_t flags = this->flags();
         return flags & REACTION_FLAG_DEFAULT_RESOLVING_HANDLER;
@@ -512,31 +599,26 @@ class PromiseReactionRecord : public Nat
         setFlagOnInitialState(REACTION_FLAG_DEBUGGER_DUMMY);
     }
     bool isDebuggerDummy() {
         int32_t flags = this->flags();
         return flags & REACTION_FLAG_DEBUGGER_DUMMY;
     }
     Value handler() {
         MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
-        uint32_t slot = targetState() == JS::PromiseState::Fulfilled
-                        ? ReactionRecordSlot_OnFulfilled
-                        : ReactionRecordSlot_OnRejected;
-        return getFixedSlot(slot);
+        return getFixedSlot(handlerSlot());
     }
     Value handlerArg() {
         MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
-        return getFixedSlot(ReactionRecordSlot_HandlerArg);
+        return getFixedSlot(handlerArgSlot());
     }
-    void setHandlerArg(Value& arg) {
-        MOZ_ASSERT(targetState() == JS::PromiseState::Pending);
-        setFixedSlot(ReactionRecordSlot_HandlerArg, arg);
-    }
-    JSObject* incumbentGlobalObject() {
-        return getFixedSlot(ReactionRecordSlot_IncumbentGlobalObject).toObjectOrNull();
+    JSObject* getAndClearIncumbentGlobalObject() {
+        JSObject* obj = getFixedSlot(ReactionRecordSlot_IncumbentGlobalObject).toObjectOrNull();
+        setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject, UndefinedValue());
+        return obj;
     }
 };
 
 const Class PromiseReactionRecord::class_ = {
     "PromiseReactionRecord",
     JSCLASS_HAS_RESERVED_SLOTS(ReactionRecordSlots)
 };
 
@@ -596,46 +678,53 @@ IsSettledMaybeWrappedPromise(JSObject* p
         // Caller needs to handle dead wrappers.
         if (JS_IsDeadWrapper(promise))
             return false;
     }
 
     return promise->as<PromiseObject>().state() != JS::PromiseState::Pending;
 }
 
-static MOZ_MUST_USE bool RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
-                                                   HandleValue reason);
+// ES2016, 25.4.1.7.
+static MOZ_MUST_USE bool
+RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue reason);
+
+// ES2016, 25.4.1.7.
+static MOZ_MUST_USE bool
+RejectPromiseInternal(JSContext* cx, Handle<PromiseObject*> promise, HandleValue reason);
 
 // ES2016, 25.4.1.3.1.
 static bool
 RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedFunction reject(cx, &args.callee().as<JSFunction>());
-    RootedValue reasonVal(cx, args.get(0));
+    JSFunction* reject = &args.callee().as<JSFunction>();
+    HandleValue reasonVal = args.get(0);
 
     // Steps 1-2.
-    RootedValue promiseVal(cx, reject->getExtendedSlot(RejectFunctionSlot_Promise));
+    const Value& promiseVal = reject->getExtendedSlot(RejectFunctionSlot_Promise);
 
     // Steps 3-4.
     // If the Promise isn't available anymore, it has been resolved and the
     // reference to it removed to make it eligible for collection.
     if (promiseVal.isUndefined()) {
         args.rval().setUndefined();
         return true;
     }
 
+    // Store the promise value in |promise| before ClearResolutionFunctionSlots
+    // removes the reference.
+    RootedObject promise(cx, &promiseVal.toObject());
+
     // Step 5.
     // Here, we only remove the Promise reference from the resolution
     // functions. Actually marking it as fulfilled/rejected happens later.
     ClearResolutionFunctionSlots(reject);
 
-    RootedObject promise(cx, &promiseVal.toObject());
-
     // In some cases the Promise reference on the resolution function won't
     // have been removed during resolution, so we need to check that here,
     // too.
     if (IsSettledMaybeWrappedPromise(promise)) {
         args.rval().setUndefined();
         return true;
     }
 
@@ -661,16 +750,17 @@ static MOZ_MUST_USE bool EnqueuePromiseR
 static bool Promise_then(JSContext* cx, unsigned argc, Value* vp);
 static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
                               HandleValue onRejected, MutableHandleValue rval, bool rvalUsed);
 
 // ES2016, 25.4.1.3.2, steps 6-13.
 static MOZ_MUST_USE bool
 ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resolutionVal)
 {
+    assertSameCompartment(cx, promise, resolutionVal);
     MOZ_ASSERT(!IsSettledMaybeWrappedPromise(promise));
 
     // Step 7 (reordered).
     if (!resolutionVal.isObject())
         return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
 
     RootedObject resolution(cx, &resolutionVal.toObject());
 
@@ -710,30 +800,26 @@ ResolvePromiseInternal(JSContext* cx, Ha
         return RejectMaybeWrappedPromise(cx, promise, error);
 
     // Step 10 (implicit).
 
     // Step 11.
     if (!IsCallable(thenVal))
         return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
 
-    // If the resolution object is a built-in Promise object, possibly from a
-    // different realm in the same compartment, and the `then` property is the
-    // original Promise.prototype.then function from the current realm, we
-    // skip storing/calling it.
-    // And additionally require that |promise| itself is also a built-in
-    // Promise object from the same compartment, so the fast path doesn't need
-    // to cope with wrappers.
+    // If the resolution object is a built-in Promise object and the
+    // `then` property is the original Promise.prototype.then function
+    // from the current realm, we skip storing/calling it.
+    // Additionally we require that |promise| itself is also a built-in
+    // Promise object, so the fast path doesn't need to cope with wrappers.
     bool isBuiltinThen = false;
     if (resolution->is<PromiseObject>() &&
-        resolution->as<PromiseObject>().compartment() == cx->compartment() &&
+        promise->is<PromiseObject>() &&
         IsNativeFunction(thenVal, Promise_then) &&
-        thenVal.toObject().as<JSFunction>().realm() == cx->realm() &&
-        promise->is<PromiseObject>() &&
-        promise->as<PromiseObject>().compartment() == cx->compartment())
+        thenVal.toObject().as<JSFunction>().realm() == cx->realm())
     {
         isBuiltinThen = true;
     }
 
     // Step 12.
     if (!isBuiltinThen) {
         RootedValue promiseVal(cx, ObjectValue(*promise));
         if (!EnqueuePromiseResolveThenableJob(cx, promiseVal, resolutionVal, thenVal))
@@ -748,18 +834,18 @@ ResolvePromiseInternal(JSContext* cx, Ha
 }
 
 // ES2016, 25.4.1.3.2.
 static bool
 ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedFunction resolve(cx, &args.callee().as<JSFunction>());
-    RootedValue resolutionVal(cx, args.get(0));
+    JSFunction* resolve = &args.callee().as<JSFunction>();
+    HandleValue resolutionVal = args.get(0);
 
     // Steps 3-4 (reordered).
     // We use the reference to the reject function as a signal for whether
     // the resolve or reject function was already called, at which point
     // the references on each of the functions are cleared.
     if (!resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction).isObject()) {
         args.rval().setUndefined();
         return true;
@@ -812,52 +898,49 @@ EnqueuePromiseReactionJob(JSContext* cx,
     // compartment, where the job creation should take place anyway.
     Rooted<PromiseReactionRecord*> reaction(cx);
     RootedValue handlerArg(cx, handlerArg_);
     mozilla::Maybe<AutoRealm> ar;
     if (!IsProxy(reactionObj)) {
         MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
         reaction = &reactionObj->as<PromiseReactionRecord>();
     } else {
-        if (JS_IsDeadWrapper(UncheckedUnwrap(reactionObj))) {
+        JSObject* unwrappedReactionObj = UncheckedUnwrap(reactionObj);
+        if (JS_IsDeadWrapper(unwrappedReactionObj)) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
         }
-        reaction = &UncheckedUnwrap(reactionObj)->as<PromiseReactionRecord>();
+        reaction = &unwrappedReactionObj->as<PromiseReactionRecord>();
         MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
         ar.emplace(cx, reaction);
-        if (!reaction->compartment()->wrap(cx, &handlerArg))
+        if (!cx->compartment()->wrap(cx, &handlerArg))
             return false;
     }
 
     // Must not enqueue a reaction job more than once.
     MOZ_ASSERT(reaction->targetState() == JS::PromiseState::Pending);
 
     assertSameCompartment(cx, handlerArg);
-    reaction->setHandlerArg(handlerArg.get());
+    reaction->setTargetStateAndHandlerArg(targetState, handlerArg);
 
     RootedValue reactionVal(cx, ObjectValue(*reaction));
-
-    reaction->setTargetState(targetState);
     RootedValue handler(cx, reaction->handler());
 
     // If we have a handler callback, we enter that handler's compartment so
     // that the promise reaction job function is created in that compartment.
     // That guarantees that the embedding ends up with the right entry global.
     // This is relevant for some html APIs like fetch that derive information
     // from said global.
     mozilla::Maybe<AutoRealm> ar2;
     if (handler.isObject()) {
-        RootedObject handlerObj(cx, &handler.toObject());
-
         // The unwrapping has to be unchecked because we specifically want to
         // be able to use handlers with wrappers that would only allow calls.
         // E.g., it's ok to have a handler from a chrome compartment in a
         // reaction to a content compartment's Promise instance.
-        handlerObj = UncheckedUnwrap(handlerObj);
+        JSObject* handlerObj = UncheckedUnwrap(&handler.toObject());
         MOZ_ASSERT(handlerObj);
         ar2.emplace(cx, handlerObj);
 
         // We need to wrap the reaction to store it on the job function.
         if (!cx->compartment()->wrap(cx, &reactionVal))
             return false;
     }
 
@@ -889,18 +972,17 @@ EnqueuePromiseReactionJob(JSContext* cx,
             return false;
     }
 
     // Using objectFromIncumbentGlobal, we can derive the incumbent global by
     // unwrapping and then getting the global. This is very convoluted, but
     // much better than having to store the original global as a private value
     // because we couldn't wrap it to store it as a normal JS value.
     RootedObject global(cx);
-    RootedObject objectFromIncumbentGlobal(cx, reaction->incumbentGlobalObject());
-    if (objectFromIncumbentGlobal) {
+    if (JSObject* objectFromIncumbentGlobal = reaction->getAndClearIncumbentGlobalObject()) {
         objectFromIncumbentGlobal = CheckedUnwrap(objectFromIncumbentGlobal);
         MOZ_ASSERT(objectFromIncumbentGlobal);
         global = &objectFromIncumbentGlobal->nonCCWGlobal();
     }
 
     // Note: the global we pass here might be from a different compartment
     // than job and promise. While it's somewhat unusual to pass objects
     // from multiple compartments, in this case we specifically need the
@@ -950,34 +1032,42 @@ ResolvePromise(JSContext* cx, Handle<Pro
     // Step 7 of FulfillPromise.
     // Step 8 of RejectPromise.
     if (reactionsVal.isObject())
         return TriggerPromiseReactions(cx, reactionsVal, state, valueOrReason);
 
     return true;
 }
 
+// ES2016, 25.4.1.7.
+static MOZ_MUST_USE bool
+RejectPromiseInternal(JSContext* cx, Handle<PromiseObject*> promise, HandleValue reason)
+{
+    return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected);
+}
+
 // ES2016, 25.4.1.4.
 static MOZ_MUST_USE bool
 FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue value_)
 {
     Rooted<PromiseObject*> promise(cx);
     RootedValue value(cx, value_);
 
     mozilla::Maybe<AutoRealm> ar;
     if (!IsProxy(promiseObj)) {
         promise = &promiseObj->as<PromiseObject>();
     } else {
-        if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
+        JSObject* unwrappedPromiseObj = UncheckedUnwrap(promiseObj);
+        if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
         }
-        promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
+        promise = &unwrappedPromiseObj->as<PromiseObject>();
         ar.emplace(cx, promise);
-        if (!promise->compartment()->wrap(cx, &value))
+        if (!cx->compartment()->wrap(cx, &value))
             return false;
     }
 
     return ResolvePromise(cx, promise, value, JS::PromiseState::Fulfilled);
 }
 
 static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp);
 static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);
@@ -1025,18 +1115,17 @@ CreatePromiseWithDefaultResolutionFuncti
     // Steps 9-10 (Not applicable).
 
     // Step 11.
     return promise;
 }
 
 // ES2016, 25.4.1.5.
 static MOZ_MUST_USE bool
-NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
-                     MutableHandleObject resolve, MutableHandleObject reject,
+NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandle<PromiseCapability> capability,
                      bool canOmitResolutionFunctions)
 {
     RootedValue cVal(cx, ObjectValue(*C));
 
     // Steps 1-2.
     if (!IsConstructor(C)) {
         ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, cVal, nullptr);
         return false;
@@ -1051,22 +1140,27 @@ NewPromiseCapability(JSContext* cx, Hand
     // pass the reject (and resolve, in the race case) function to thenables
     // in the list passed to all/race, which (potentially) means exposing them
     // to content.
     //
     // For Promise.all and Promise.race we can only optimize away the creation
     // of the GetCapabilitiesExecutor function, and directly allocate the
     // result promise instead of invoking the Promise constructor.
     if (IsNativeFunction(cVal, PromiseConstructor)) {
-        if (canOmitResolutionFunctions)
-            promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx));
-        else
-            promise.set(CreatePromiseWithDefaultResolutionFunctions(cx, resolve, reject));
+        PromiseObject* promise;
+        if (canOmitResolutionFunctions) {
+            promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
+        } else {
+            promise = CreatePromiseWithDefaultResolutionFunctions(cx, capability.resolve(),
+                                                                  capability.reject());
+        }
         if (!promise)
             return false;
+
+        capability.promise().set(promise);
         return true;
     }
 
     // Step 3 (omitted).
 
     // Step 4.
     HandlePropertyName funName = cx->names().empty;
     RootedFunction executor(cx, NewNativeFunction(cx, GetCapabilitiesExecutor, 2, funName,
@@ -1074,49 +1168,49 @@ NewPromiseCapability(JSContext* cx, Hand
     if (!executor)
         return false;
 
     // Step 5 (omitted).
 
     // Step 6.
     FixedConstructArgs<1> cargs(cx);
     cargs[0].setObject(*executor);
-    if (!Construct(cx, cVal, cargs, cVal, promise))
+    if (!Construct(cx, cVal, cargs, cVal, capability.promise()))
         return false;
 
     // Step 7.
-    RootedValue resolveVal(cx, executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve));
+    const Value& resolveVal = executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve);
     if (!IsCallable(resolveVal)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                   JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE);
         return false;
     }
 
     // Step 8.
-    RootedValue rejectVal(cx, executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject));
+    const Value& rejectVal = executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject);
     if (!IsCallable(rejectVal)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                   JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE);
         return false;
     }
 
     // Step 9 (well, the equivalent for all of promiseCapabilities' fields.)
-    resolve.set(&resolveVal.toObject());
-    reject.set(&rejectVal.toObject());
+    capability.resolve().set(&resolveVal.toObject());
+    capability.reject().set(&rejectVal.toObject());
 
     // Step 10.
     return true;
 }
 
 // ES2016, 25.4.1.5.1.
 static bool
 GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedFunction F(cx, &args.callee().as<JSFunction>());
+    JSFunction* F = &args.callee().as<JSFunction>();
 
     // Steps 1-2 (implicit).
 
     // Steps 3-4.
     if (!F->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve).isUndefined() ||
         !F->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject).isUndefined())
     {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
@@ -1141,36 +1235,37 @@ RejectMaybeWrappedPromise(JSContext *cx,
 {
     Rooted<PromiseObject*> promise(cx);
     RootedValue reason(cx, reason_);
 
     mozilla::Maybe<AutoRealm> ar;
     if (!IsProxy(promiseObj)) {
         promise = &promiseObj->as<PromiseObject>();
     } else {
-        if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
+        JSObject* unwrappedPromiseObj = UncheckedUnwrap(promiseObj);
+        if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
         }
-        promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
+        promise = &unwrappedPromiseObj->as<PromiseObject>();
         ar.emplace(cx, promise);
 
         // The rejection reason might've been created in a compartment with higher
         // privileges than the Promise's. In that case, object-type rejection
         // values might be wrapped into a wrapper that throws whenever the
         // Promise's reaction handler wants to do anything useful with it. To
         // avoid that situation, we synthesize a generic error that doesn't
         // expose any privileged information but can safely be used in the
         // rejection handler.
-        if (!promise->compartment()->wrap(cx, &reason))
+        if (!cx->compartment()->wrap(cx, &reason))
             return false;
         if (reason.isObject() && !CheckedUnwrap(&reason.toObject())) {
             // Report the existing reason, so we don't just drop it on the
             // floor.
-            RootedObject realReason(cx, UncheckedUnwrap(&reason.toObject()));
+            JSObject* realReason = UncheckedUnwrap(&reason.toObject());
             RootedValue realReasonVal(cx, ObjectValue(*realReason));
             Rooted<GlobalObject*> realGlobal(cx, &realReason->nonCCWGlobal());
             ReportErrorToGlobal(cx, realGlobal, realReasonVal);
 
             // Async stacks are only properly adopted if there's at least one
             // interpreter frame active right now. If a thenable job with a
             // throwing `then` function got us here, that'll not be the case,
             // so we add one by throwing the error from self-hosted code.
@@ -1185,32 +1280,31 @@ RejectMaybeWrappedPromise(JSContext *cx,
 // ES2016, 25.4.1.8.
 static MOZ_MUST_USE bool
 TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal, JS::PromiseState state,
                         HandleValue valueOrReason)
 {
     MOZ_ASSERT(state == JS::PromiseState::Fulfilled || state == JS::PromiseState::Rejected);
 
     RootedObject reactions(cx, &reactionsVal.toObject());
-    RootedObject reaction(cx);
 
     if (reactions->is<PromiseReactionRecord>() ||
         IsWrapper(reactions) ||
         JS_IsDeadWrapper(reactions))
     {
         return EnqueuePromiseReactionJob(cx, reactions, valueOrReason, state);
     }
 
-    RootedNativeObject reactionsList(cx, &reactions->as<NativeObject>());
-    size_t reactionsCount = reactionsList->getDenseInitializedLength();
+    HandleNativeObject reactionsList = reactions.as<NativeObject>();
+    uint32_t reactionsCount = reactionsList->getDenseInitializedLength();
     MOZ_ASSERT(reactionsCount > 1, "Reactions list should be created lazily");
 
-    RootedValue reactionVal(cx);
-    for (size_t i = 0; i < reactionsCount; i++) {
-        reactionVal = reactionsList->getDenseElement(i);
+    RootedObject reaction(cx);
+    for (uint32_t i = 0; i < reactionsCount; i++) {
+        const Value& reactionVal = reactionsList->getDenseElement(i);
         MOZ_RELEASE_ASSERT(reactionVal.isObject());
         reaction = &reactionVal.toObject();
         if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
             return false;
     }
 
     return true;
 }
@@ -1236,29 +1330,29 @@ DefaultResolvingPromiseReactionJob(JSCon
     if (promiseToResolve->state() == JS::PromiseState::Pending) {
         RootedValue argument(cx, reaction->handlerArg());
 
         // Step 6.
         bool ok;
         if (reaction->targetState() == JS::PromiseState::Fulfilled)
             ok = ResolvePromiseInternal(cx, promiseToResolve, argument);
         else
-            ok = RejectMaybeWrappedPromise(cx, promiseToResolve, argument);
+            ok = RejectPromiseInternal(cx, promiseToResolve, argument);
 
         if (!ok) {
             resolutionMode = RejectMode;
             if (!MaybeGetAndClearException(cx, &handlerResult))
                 return false;
         }
     }
 
     // Steps 7-9.
-    size_t hookSlot = resolutionMode == RejectMode
-                      ? ReactionRecordSlot_Reject
-                      : ReactionRecordSlot_Resolve;
+    uint32_t hookSlot = resolutionMode == RejectMode
+                        ? ReactionRecordSlot_Reject
+                        : ReactionRecordSlot_Resolve;
     RootedObject callee(cx, reaction->getFixedSlot(hookSlot).toObjectOrNull());
     RootedObject promiseObj(cx, reaction->promise());
     if (!RunResolutionFunction(cx, callee, handlerResult, resolutionMode, promiseObj))
         return false;
 
     rval.setUndefined();
     return true;
 }
@@ -1377,17 +1471,17 @@ PromiseReactionJob(JSContext* cx, unsign
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
         }
         MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
         ar.emplace(cx, reactionObj);
     }
 
     // Steps 1-2.
-    Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
+    Handle<PromiseReactionRecord*> reaction = reactionObj.as<PromiseReactionRecord>();
     if (reaction->isDefaultResolvingHandler())
         return DefaultResolvingPromiseReactionJob(cx, reaction, args.rval());
     if (reaction->isAsyncFunction())
         return AsyncFunctionPromiseReactionJob(cx, reaction, args.rval());
     if (reaction->isAsyncGenerator())
         return AsyncGeneratorPromiseReactionJob(cx, reaction, args.rval());
     if (reaction->isDebuggerDummy())
         return true;
@@ -1412,40 +1506,38 @@ PromiseReactionJob(JSContext* cx, unsign
             resolutionMode = RejectMode;
             handlerResult = argument;
         } else {
             MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone ||
                        handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone);
 
             bool done = handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone;
             // Async Iteration proposal 11.1.3.2.5 step 1.
-            RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
+            JSObject* resultObj = CreateIterResultObject(cx, argument, done);
             if (!resultObj)
                 return false;
 
             handlerResult = ObjectValue(*resultObj);
         }
     } else {
         MOZ_ASSERT(handlerVal.isObject());
         MOZ_ASSERT(IsCallable(handlerVal));
 
         // Step 6.
-        FixedInvokeArgs<1> args2(cx);
-        args2[0].set(argument);
-        if (!Call(cx, handlerVal, UndefinedHandleValue, args2, &handlerResult)) {
+        if (!Call(cx, handlerVal, UndefinedHandleValue, argument, &handlerResult)) {
             resolutionMode = RejectMode;
             if (!MaybeGetAndClearException(cx, &handlerResult))
                 return false;
         }
     }
 
     // Steps 7-9.
-    size_t hookSlot = resolutionMode == RejectMode
-                      ? ReactionRecordSlot_Reject
-                      : ReactionRecordSlot_Resolve;
+    uint32_t hookSlot = resolutionMode == RejectMode
+                        ? ReactionRecordSlot_Reject
+                        : ReactionRecordSlot_Resolve;
     RootedObject callee(cx, reaction->getFixedSlot(hookSlot).toObjectOrNull());
     RootedObject promiseObj(cx, reaction->promise());
     if (!RunResolutionFunction(cx, callee, handlerResult, resolutionMode, promiseObj))
         return false;
 
     args.rval().setUndefined();
     return true;
 }
@@ -1494,21 +1586,18 @@ PromiseResolveThenableJob(JSContext* cx,
     RootedValue rval(cx);
     if (Call(cx, then, thenable, args2, &rval))
         return true;
 
     // Steps 3-4.
     if (!MaybeGetAndClearException(cx, &rval))
         return false;
 
-    FixedInvokeArgs<1> rejectArgs(cx);
-    rejectArgs[0].set(rval);
-
     RootedValue rejectVal(cx, ObjectValue(*rejectFn));
-    return Call(cx, rejectVal, UndefinedHandleValue, rejectArgs, &rval);
+    return Call(cx, rejectVal, UndefinedHandleValue, rval, &rval);
 }
 
 static MOZ_MUST_USE bool
 OriginalPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise,
                                          Handle<PromiseObject*> promiseToResolve);
 
 /**
  * Specialization of PromiseResolveThenableJob when the `thenable` is a
@@ -1553,17 +1642,17 @@ PromiseResolveBuiltinThenableJob(JSConte
     // Testing functions allow to directly settle a promise without going
     // through the resolving functions. In that case the normal bookkeeping to
     // ensure only pending promises can be resolved doesn't apply and we need
     // to manually check for already settled promises. The exception is simply
     // dropped when this case happens.
     if (promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
         return true;
 
-    return RejectMaybeWrappedPromise(cx, promise, exception);
+    return RejectPromiseInternal(cx, promise.as<PromiseObject>(), exception);
 }
 
 /**
  * Tells the embedding to enqueue a Promise resolve thenable job, based on
  * three parameters:
  * promiseToResolve_ - The promise to resolve, obviously.
  * thenable_ - The thenable to resolve the Promise with.
  * thenVal - The `then` function to invoke with the `thenable` as the receiver.
@@ -1579,52 +1668,52 @@ EnqueuePromiseResolveThenableJob(JSConte
     // We enter the `then` callable's compartment so that the job function is
     // created in that compartment.
     // That guarantees that the embedding ends up with the right entry global.
     // This is relevant for some html APIs like fetch that derive information
     // from said global.
     RootedObject then(cx, CheckedUnwrap(&thenVal.toObject()));
     AutoRealm ar(cx, then);
 
+    // Wrap the `promiseToResolve` and `thenable` arguments.
+    if (!cx->compartment()->wrap(cx, &promiseToResolve))
+        return false;
+
+    MOZ_ASSERT(thenable.isObject());
+    if (!cx->compartment()->wrap(cx, &thenable))
+        return false;
+
     HandlePropertyName funName = cx->names().empty;
     RootedFunction job(cx, NewNativeFunction(cx, PromiseResolveThenableJob, 0, funName,
                                              gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
     if (!job)
         return false;
 
     // Store the `then` function on the callback.
     job->setExtendedSlot(ThenableJobSlot_Handler, ObjectValue(*then));
 
     // Create a dense array to hold the data needed for the reaction job to
     // work.
     // The layout is described in the ThenableJobDataIndices enum.
     RootedArrayObject data(cx, NewDenseFullyAllocatedArray(cx, ThenableJobDataLength));
-    if (!data ||
-        data->ensureDenseElements(cx, 0, ThenableJobDataLength) != DenseElementResult::Success)
-    {
+    if (!data)
         return false;
-    }
-
-    // Wrap and set the `promiseToResolve` argument.
-    if (!cx->compartment()->wrap(cx, &promiseToResolve))
-        return false;
-    data->setDenseElement(ThenableJobDataIndex_Promise, promiseToResolve);
+
+    // Set the `promiseToResolve` and `thenable` arguments.
+    data->setDenseInitializedLength(ThenableJobDataLength);
+    data->initDenseElement(ThenableJobDataIndex_Promise, promiseToResolve);
+    data->initDenseElement(ThenableJobDataIndex_Thenable, thenable);
+
+    // Store the data array on the reaction job.
+    job->setExtendedSlot(ThenableJobSlot_JobData, ObjectValue(*data));
+
     // At this point the promise is guaranteed to be wrapped into the job's
     // compartment.
     RootedObject promise(cx, &promiseToResolve.toObject());
 
-    // Wrap and set the `thenable` argument.
-    MOZ_ASSERT(thenable.isObject());
-    if (!cx->compartment()->wrap(cx, &thenable))
-        return false;
-    data->setDenseElement(ThenableJobDataIndex_Thenable, thenable);
-
-    // Store the data array on the reaction job.
-    job->setExtendedSlot(ThenableJobSlot_JobData, ObjectValue(*data));
-
     RootedObject incumbentGlobal(cx, cx->runtime()->getIncumbentGlobal(cx));
     return cx->runtime()->enqueuePromiseJob(cx, job, promise, incumbentGlobal);
 }
 
 /**
  * Tells the embedding to enqueue a Promise resolve thenable built-in job,
  * based on two parameters:
  * promiseToResolve - The promise to resolve, obviously.
@@ -1655,20 +1744,16 @@ EnqueuePromiseResolveThenableBuiltinJob(
 static MOZ_MUST_USE bool
 AddDummyPromiseReactionForDebugger(JSContext* cx, Handle<PromiseObject*> promise,
                                    HandleObject dependentPromise);
 
 static MOZ_MUST_USE bool
 AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise,
                    Handle<PromiseReactionRecord*> reaction);
 
-static MOZ_MUST_USE bool
-BlockOnPromise(JSContext* cx, HandleValue promise, HandleObject blockedPromise,
-               HandleValue onFulfilled, HandleValue onRejected, bool onFulfilledReturnsUndefined);
-
 static JSFunction*
 GetResolveFunctionFromReject(JSFunction* reject)
 {
     MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction);
     Value resolveFunVal = reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction);
     MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction));
     return &resolveFunVal.toObject().as<JSFunction>();
 }
@@ -1787,17 +1872,17 @@ PromiseConstructor(JSContext* cx, unsign
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     if (!ThrowIfNotConstructing(cx, args, "Promise"))
         return false;
 
     // Step 2.
-    RootedValue executorVal(cx, args.get(0));
+    HandleValue executorVal = args.get(0);
     if (!IsCallable(executorVal))
         return ReportIsNotFunction(cx, executorVal);
     RootedObject executor(cx, &executorVal.toObject());
 
     // Steps 3-10.
     RootedObject newTarget(cx, &args.newTarget().toObject());
 
     // If the constructor is called via an Xray wrapper, then the newTarget
@@ -1834,17 +1919,17 @@ PromiseConstructor(JSContext* cx, unsign
         JSObject* unwrappedNewTarget = CheckedUnwrap(newTarget);
         MOZ_ASSERT(unwrappedNewTarget);
         MOZ_ASSERT(unwrappedNewTarget != newTarget);
 
         newTarget = unwrappedNewTarget;
         {
             AutoRealm ar(cx, newTarget);
             Handle<GlobalObject*> global = cx->global();
-            RootedObject promiseCtor(cx, GlobalObject::getOrCreatePromiseConstructor(cx, global));
+            JSFunction* promiseCtor = GlobalObject::getOrCreatePromiseConstructor(cx, global);
             if (!promiseCtor)
                 return false;
 
             // Promise subclasses don't get the special Xray treatment, so
             // we only need to do the complex wrapping and unwrapping scheme
             // described above for instances of Promise itself.
             if (newTarget == promiseCtor) {
                 needsWrapping = true;
@@ -1883,18 +1968,20 @@ PromiseObject::create(JSContext* cx, Han
     RootedObject usedProto(cx, proto);
     // If the proto is wrapped, that means the current function is running
     // with a different compartment active from the one the Promise instance
     // is to be created in.
     // See the comment in PromiseConstructor for details.
     if (needsWrapping) {
         MOZ_ASSERT(proto);
         usedProto = CheckedUnwrap(proto);
-        if (!usedProto)
+        if (!usedProto) {
+            ReportAccessDenied(cx);
             return nullptr;
+        }
     }
 
 
     // Steps 3-7.
     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, usedProto, needsWrapping,
                                                                    false));
     if (!promise)
         return nullptr;
@@ -1924,36 +2011,31 @@ PromiseObject::create(JSContext* cx, Han
     } else {
         promise->initFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*rejectFn));
     }
 
     // Step 9.
     bool success;
     {
         FixedInvokeArgs<2> args(cx);
-
         args[0].setObject(*resolveFn);
         args[1].setObject(*rejectFn);
 
         RootedValue calleeOrRval(cx, ObjectValue(*executor));
         success = Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval);
     }
 
     // Step 10.
     if (!success) {
         RootedValue exceptionVal(cx);
         if (!MaybeGetAndClearException(cx, &exceptionVal))
             return nullptr;
 
-        FixedInvokeArgs<1> args(cx);
-
-        args[0].set(exceptionVal);
-
         RootedValue calleeOrRval(cx, ObjectValue(*rejectFn));
-        if (!Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval))
+        if (!Call(cx, calleeOrRval, UndefinedHandleValue, exceptionVal, &calleeOrRval))
             return nullptr;
     }
 
     // Let the Debugger know about this Promise.
     Debugger::onNewPromise(cx, promise);
 
     // Step 11.
     return promise;
@@ -1962,88 +2044,93 @@ PromiseObject::create(JSContext* cx, Han
 // ES2016, 25.4.3.1. skipping creation of resolution functions and executor
 // function invocation.
 /* static */ PromiseObject*
 PromiseObject::createSkippingExecutor(JSContext* cx)
 {
     return CreatePromiseObjectWithoutResolutionFunctions(cx);
 }
 
-static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator,
-                                           HandleObject C, HandleObject promiseObj,
-                                           HandleObject resolve, HandleObject reject,
-                                           bool* done);
+class MOZ_STACK_CLASS PromiseForOfIterator : public JS::ForOfIterator {
+  public:
+    using JS::ForOfIterator::ForOfIterator;
+
+    bool isOptimizedDenseArrayIteration() {
+        MOZ_ASSERT(valueIsIterable());
+        return index != NOT_ARRAY && IsPackedArray(iterator);
+    }
+};
+
+static MOZ_MUST_USE bool
+PerformPromiseAll(JSContext *cx, PromiseForOfIterator& iterator, HandleObject C,
+                  Handle<PromiseCapability> resultCapability, bool* done);
 
 // ES2016, 25.4.4.1.
 static bool
 Promise_static_all(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedValue iterable(cx, args.get(0));
+    HandleValue iterable = args.get(0);
 
     // Step 2 (reordered).
-    RootedValue CVal(cx, args.thisv());
+    HandleValue CVal = args.thisv();
     if (!CVal.isObject()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
                                   "Receiver of Promise.all call");
         return false;
     }
 
     // Step 1.
     RootedObject C(cx, &CVal.toObject());
 
     // Step 3.
-    RootedObject resultPromise(cx);
-    RootedObject resolve(cx);
-    RootedObject reject(cx);
-    if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
+    Rooted<PromiseCapability> promiseCapability(cx);
+    if (!NewPromiseCapability(cx, C, &promiseCapability, false))
         return false;
 
     // Steps 4-5.
-    JS::ForOfIterator iter(cx);
+    PromiseForOfIterator iter(cx);
     if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
-        return AbruptRejectPromise(cx, args, resultPromise, reject);
+        return AbruptRejectPromise(cx, args, promiseCapability);
 
     if (!iter.valueIsIterable()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
                                   "Argument of Promise.all");
-        return AbruptRejectPromise(cx, args, resultPromise, reject);
+        return AbruptRejectPromise(cx, args, promiseCapability);
     }
 
     // Step 6 (implicit).
 
     // Step 7.
     bool done;
-    bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject, &done);
+    bool result = PerformPromiseAll(cx, iter, C, promiseCapability, &done);
 
     // Step 8.
     if (!result) {
         // Step 8.a.
         if (!done)
             iter.closeThrow();
 
         // Step 8.b.
-        return AbruptRejectPromise(cx, args, resultPromise, reject);
+        return AbruptRejectPromise(cx, args, promiseCapability);
     }
 
     // Step 9.
-    args.rval().setObject(*resultPromise);
+    args.rval().setObject(*promiseCapability.promise());
     return true;
 }
 
-static MOZ_MUST_USE bool PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
-                                            HandleValue onFulfilled_, HandleValue onRejected_,
-                                            HandleObject resultPromise,
-                                            HandleObject resolve, HandleObject reject);
+static MOZ_MUST_USE bool
+PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
+                   HandleValue onRejected_, Handle<PromiseCapability> resultCapability);
 
 static MOZ_MUST_USE bool
 PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise,
                                         Handle<PromiseObject*> promiseToResolve,
-                                        HandleObject resultPromise, HandleObject resolve,
-                                        HandleObject reject);
+                                        Handle<PromiseCapability> resultCapability);
 
 static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp);
 
 // Unforgeable version of ES2016, 25.4.4.1.
 MOZ_MUST_USE JSObject*
 js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
 {
 #ifdef DEBUG
@@ -2057,49 +2144,49 @@ js::GetWaitForAllPromise(JSContext* cx, 
     // Step 1.
     RootedObject C(cx, GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
     if (!C)
         return nullptr;
 
     // Step 2 (omitted).
 
     // Step 3.
-    RootedObject resultPromise(cx);
-    RootedObject resolve(cx);
-    RootedObject reject(cx);
-    if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
+    Rooted<PromiseCapability> resultCapability(cx);
+    if (!NewPromiseCapability(cx, C, &resultCapability, false))
         return nullptr;
 
     // Steps 4-6 (omitted).
 
     // Step 7.
     // Implemented as an inlined, simplied version of ES2016 25.4.4.1.1, PerformPromiseAll.
     {
         uint32_t promiseCount = promises.length();
         // Sub-steps 1-2 (omitted).
 
         // Sub-step 3.
         RootedNativeObject valuesArray(cx, NewDenseFullyAllocatedArray(cx, promiseCount));
         if (!valuesArray)
             return nullptr;
-        if (valuesArray->ensureDenseElements(cx, 0, promiseCount) != DenseElementResult::Success)
-            return nullptr;
+        valuesArray->ensureDenseInitializedLength(cx, 0, promiseCount);
 
         // Sub-step 4.
         // Create our data holder that holds all the things shared across
         // every step of the iterator.  In particular, this holds the
         // remainingElementsCount (as an integer reserved slot), the array of
         // values, and the resolve function from our PromiseCapability.
         RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
-        Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, resultPromise,
-                                                                             valuesArrayVal,
-                                                                             resolve));
+        Rooted<PromiseAllDataHolder*> dataHolder(cx);
+        dataHolder = NewPromiseAllDataHolder(cx, resultCapability.promise(), valuesArrayVal,
+                                             resultCapability.resolve());
         if (!dataHolder)
             return nullptr;
-        RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
+
+        // Call PerformPromiseThen with resolve and reject set to nullptr.
+        Rooted<PromiseCapability> resultCapabilityWithoutResolving(cx);
+        resultCapabilityWithoutResolving.promise().set(resultCapability.promise());
 
         // Sub-step 5 (inline in loop-header below).
 
         // Sub-step 6.
         for (uint32_t index = 0; index < promiseCount; index++) {
             // Steps a-c (omitted).
             // Step d (implemented after the loop).
             // Steps e-g (omitted).
@@ -2114,61 +2201,62 @@ js::GetWaitForAllPromise(JSContext* cx, 
             RootedFunction resolveFunc(cx, NewNativeFunction(cx, PromiseAllResolveElementFunction,
                                                              1, nullptr,
                                                              gc::AllocKind::FUNCTION_EXTENDED,
                                                              GenericObject));
             if (!resolveFunc)
                 return nullptr;
 
             // Steps k-o.
-            resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, dataHolderVal);
+            resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data,
+                                         ObjectValue(*dataHolder));
             resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex,
                                          Int32Value(index));
 
             // Step p.
             dataHolder->increaseRemainingCount();
 
             // Step q, very roughly.
             RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
-            RootedValue rejectFunVal(cx, ObjectValue(*reject));
+            RootedValue rejectFunVal(cx, ObjectValue(*resultCapability.reject()));
             Rooted<PromiseObject*> nextPromise(cx);
 
             // GetWaitForAllPromise is used internally only and must not
             // trigger content-observable effects when registering a reaction.
             // It's also meant to work on wrapped Promises, potentially from
             // compartments with principals inaccessible from the current
             // compartment. To make that work, it unwraps promises with
             // UncheckedUnwrap,
             nextPromise = &UncheckedUnwrap(nextPromiseObj)->as<PromiseObject>();
 
             if (!PerformPromiseThen(cx, nextPromise, resolveFunVal, rejectFunVal,
-                                    resultPromise, nullptr, nullptr))
+                                    resultCapabilityWithoutResolving))
             {
                 return nullptr;
             }
 
             // Step r (inline in loop-header).
         }
 
         // Sub-step d.i (implicit).
         // Sub-step d.ii.
         int32_t remainingCount = dataHolder->decreaseRemainingCount();
 
         // Sub-step d.iii-iv.
         if (remainingCount == 0) {
             RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
-            if (!ResolvePromiseInternal(cx, resultPromise, valuesArrayVal))
+            if (!ResolvePromiseInternal(cx, resultCapability.promise(), valuesArrayVal))
                 return nullptr;
         }
     }
 
     // Step 8 (omitted).
 
     // Step 9.
-    return resultPromise;
+    return resultCapability.promise();
 }
 
 static MOZ_MUST_USE bool
 RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue result,
                       ResolutionMode mode, HandleObject promiseObj)
 {
     // The absence of a resolve/reject function can mean that, as an
     // optimization, those weren't created. In that case, a flag is set on
@@ -2177,54 +2265,310 @@ RunResolutionFunction(JSContext *cx, Han
     // subclass constructor passes null/undefined to `super()`.)
     // There are also reactions where the Promise itself is missing. For
     // those, there's nothing left to do here.
     assertSameCompartment(cx, resolutionFun);
     assertSameCompartment(cx, result);
     assertSameCompartment(cx, promiseObj);
     if (resolutionFun) {
         RootedValue calleeOrRval(cx, ObjectValue(*resolutionFun));
-        FixedInvokeArgs<1> resolveArgs(cx);
-        resolveArgs[0].set(result);
-        return Call(cx, calleeOrRval, UndefinedHandleValue, resolveArgs, &calleeOrRval);
+        return Call(cx, calleeOrRval, UndefinedHandleValue, result, &calleeOrRval);
     }
 
     if (!promiseObj)
         return true;
 
-    Rooted<PromiseObject*> promise(cx, &promiseObj->as<PromiseObject>());
+    Handle<PromiseObject*> promise = promiseObj.as<PromiseObject>();
     if (promise->state() != JS::PromiseState::Pending)
         return true;
 
     if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS))
         return true;
 
     if (mode == ResolveMode)
         return ResolvePromiseInternal(cx, promise, result);
 
-    return RejectMaybeWrappedPromise(cx, promiseObj, result);
+    return RejectPromiseInternal(cx, promise, result);
+}
+
+static MOZ_MUST_USE JSObject*
+CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
+                              ResolutionMode mode);
+
+static bool
+IsPromiseSpecies(JSContext* cx, JSFunction* species);
+
+// ES2019 draft rev dd269df67d37409a6f2099a842b8f5c75ee6fc24
+// 25.6.4.1.1 Runtime Semantics: PerformPromiseAll, step 6.
+// 25.6.4.3.1 Runtime Semantics: PerformPromiseRace, step 3.
+template <typename T>
+static MOZ_MUST_USE bool
+CommonPerformPromiseAllRace(JSContext *cx, PromiseForOfIterator& iterator, HandleObject C,
+                            Handle<PromiseCapability> resultCapability, bool* done,
+                            bool resolveReturnsUndefined, T getResolveFun)
+{
+    RootedObject promiseCtor(cx, GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
+    if (!promiseCtor)
+        return false;
+
+    // Optimized dense array iteration ensures no side-effects take place
+    // during the iteration.
+    bool iterationMayHaveSideEffects = !iterator.isOptimizedDenseArrayIteration();
+
+    // Try to optimize when the Promise object is in its default state, seeded
+    // with |C == promiseCtor| because we can only perform this optimization
+    // for the builtin Promise constructor.
+    bool isDefaultPromiseState = C == promiseCtor;
+    bool validatePromiseState = true;
+
+    PromiseLookup& promiseLookup = cx->realm()->promiseLookup;
+
+    RootedValue CVal(cx, ObjectValue(*C));
+    HandleObject resultPromise = resultCapability.promise();
+    RootedValue resolveFunVal(cx);
+    RootedValue rejectFunVal(cx, ObjectValue(*resultCapability.reject()));
+
+    // We're reusing rooted variables in the loop below, so we don't need to
+    // declare a gazillion different rooted variables here. Rooted variables
+    // which are reused include "Or" in their name.
+    RootedValue nextValueOrNextPromise(cx);
+    RootedObject nextPromiseObj(cx);
+    RootedValue resolveOrThen(cx);
+    RootedObject thenSpeciesOrBlockedPromise(cx);
+    Rooted<PromiseCapability> thenCapability(cx);
+
+    while (true) {
+        // Steps a-c, e-g.
+        RootedValue& nextValue = nextValueOrNextPromise;
+        if (!iterator.next(&nextValue, done)) {
+            // Steps b, f.
+            *done = true;
+
+            // Steps c, g.
+            return false;
+        }
+
+        // Step d.
+        if (*done)
+            return true;
+
+        // Set to false when we can skip the [[Get]] for "then" and instead
+        // use the built-in Promise.prototype.then function.
+        bool getThen = true;
+
+        if (isDefaultPromiseState && validatePromiseState)
+            isDefaultPromiseState = promiseLookup.isDefaultPromiseState(cx);
+
+        RootedValue& nextPromise = nextValueOrNextPromise;
+        if (isDefaultPromiseState) {
+            PromiseObject* nextValuePromise = nullptr;
+            if (nextValue.isObject() && nextValue.toObject().is<PromiseObject>())
+                nextValuePromise = &nextValue.toObject().as<PromiseObject>();
+
+            if (nextValuePromise &&
+                promiseLookup.isDefaultInstanceWhenPromiseStateIsSane(cx, nextValuePromise))
+            {
+                // The below steps don't produce any side-effects, so we can
+                // skip the Promise state revalidation in the next iteration
+                // when the iterator itself also doesn't produce any
+                // side-effects.
+                validatePromiseState = iterationMayHaveSideEffects;
+
+                // 25.6.4.1.1, step 6.i.
+                // 25.6.4.3.1, step 3.h.
+                // Promise.resolve is a no-op for the default case.
+                MOZ_ASSERT(&nextPromise.toObject() == nextValuePromise);
+
+                // `nextPromise` uses the built-in `then` function.
+                getThen = false;
+            } else {
+                // Need to revalidate the Promise state in the next iteration,
+                // because CommonStaticResolveRejectImpl may have modified it.
+                validatePromiseState = true;
+
+                // 25.6.4.1.1, step 6.i.
+                // 25.6.4.3.1, step 3.h.
+                // Inline the call to Promise.resolve.
+                JSObject* res = CommonStaticResolveRejectImpl(cx, CVal, nextValue, ResolveMode);
+                if (!res)
+                    return false;
+
+                nextPromise.setObject(*res);
+            }
+        } else {
+            // 25.6.4.1.1, step 6.i.
+            // 25.6.4.3.1, step 3.h.
+            // Sadly, because someone could have overridden
+            // "resolve" on the canonical Promise constructor.
+            RootedValue& staticResolve = resolveOrThen;
+            if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
+                return false;
+
+            if (!Call(cx, staticResolve, CVal, nextValue, &nextPromise))
+                return false;
+        }
+
+        // Get the resolve function for this iteration.
+        // 25.6.4.1.1, steps 6.j-q.
+        JSObject* resolveFun = getResolveFun();
+        if (!resolveFun)
+            return false;
+        resolveFunVal.setObject(*resolveFun);
+
+        // Call |nextPromise.then| with the provided hooks and add
+        // |resultPromise| to the list of dependent promises.
+        //
+        // If |nextPromise.then| is the original |Promise.prototype.then|
+        // function and the call to |nextPromise.then| would use the original
+        // |Promise| constructor to create the resulting promise, we skip the
+        // call to |nextPromise.then| and thus creating a new promise that
+        // would not be observable by content.
+
+        // 25.6.4.1.1, step 6.r.
+        // 25.6.4.3.1, step 3.i.
+        nextPromiseObj = ToObject(cx, nextPromise);
+        if (!nextPromiseObj)
+            return false;
+
+        RootedValue& thenVal = resolveOrThen;
+        bool isBuiltinThen;
+        if (getThen) {
+            // We don't use the Promise lookup cache here, because this code
+            // is only called when we had a lookup cache miss, so it's likely
+            // we'd get another cache miss when trying to use the cache here.
+            if (!GetProperty(cx, nextPromiseObj, nextPromise, cx->names().then, &thenVal))
+                return false;
+
+            // |nextPromise| is an unwrapped Promise, and |then| is the
+            // original |Promise.prototype.then|, inline it here.
+            isBuiltinThen = nextPromiseObj->is<PromiseObject>() &&
+                            IsNativeFunction(thenVal, Promise_then);
+        } else {
+            isBuiltinThen = true;
+        }
+
+        // By default, the blocked promise is added as an extra entry to the
+        // rejected promises list.
+        bool addToDependent = true;
+
+        if (isBuiltinThen) {
+            MOZ_ASSERT(nextPromise.isObject());
+            MOZ_ASSERT(&nextPromise.toObject() == nextPromiseObj);
+
+            // 25.6.5.4, step 3.
+            RootedObject& thenSpecies = thenSpeciesOrBlockedPromise;
+            if (getThen) {
+                thenSpecies = SpeciesConstructor(cx, nextPromiseObj, JSProto_Promise,
+                                                 IsPromiseSpecies);
+                if (!thenSpecies)
+                    return false;
+            } else {
+                thenSpecies = promiseCtor;
+            }
+
+            // The fast path here and the one in NewPromiseCapability may not
+            // set the resolve and reject handlers, so we need to clear the
+            // fields in case they were set in the previous iteration.
+            thenCapability.resolve().set(nullptr);
+            thenCapability.reject().set(nullptr);
+
+            // Skip the creation of a built-in Promise object if:
+            // 1. `thenSpecies` is the built-in Promise constructor.
+            // 2. `resolveFun` doesn't return an object, which ensures no
+            //    side-effects take place in ResolvePromiseInternal.
+            // 3. The result promise is a built-in Promise object.
+            // 4. The result promise doesn't use the default resolving
+            //    functions, which in turn means RunResolutionFunction when
+            //    called from PromiseRectionJob won't try to resolve the
+            //    promise.
+            if (thenSpecies == promiseCtor &&
+                resolveReturnsUndefined &&
+                resultPromise->is<PromiseObject>() &&
+                !PromiseHasAnyFlag(resultPromise->as<PromiseObject>(),
+                                   PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS))
+            {
+                thenCapability.promise().set(resultPromise);
+                addToDependent = false;
+            } else {
+                // 25.6.5.4, step 4.
+                if (!NewPromiseCapability(cx, thenSpecies, &thenCapability, true))
+                    return false;
+            }
+
+            // 25.6.5.4, step 5.
+            Handle<PromiseObject*> promise = nextPromiseObj.as<PromiseObject>();
+            if (!PerformPromiseThen(cx, promise, resolveFunVal, rejectFunVal, thenCapability))
+                return false;
+        } else {
+            // Optimization failed, do the normal call.
+            RootedValue& ignored = thenVal;
+            if (!Call(cx, thenVal, nextPromise, resolveFunVal, rejectFunVal, &ignored))
+                return false;
+
+            // In case the value to depend on isn't an object at all, there's
+            // nothing more to do here: we can only add reactions to Promise
+            // objects (potentially after unwrapping them), and non-object
+            // values can't be Promise objects. This can happen if Promise.all
+            // is called on an object with a `resolve` method that returns
+            // primitives.
+            if (!nextPromise.isObject())
+                addToDependent = false;
+        }
+
+        // Adds |resultPromise| to the list of dependent promises.
+        if (addToDependent) {
+            // The object created by the |promise.then| call or the inlined
+            // version of it above is visible to content (either because
+            // |promise.then| was overridden by content and could leak it,
+            // or because a constructor other than the original value of
+            // |Promise| was used to create it). To have both that object and
+            // |resultPromise| show up as dependent promises in the debugger,
+            // add a dummy reaction to the list of reject reactions that
+            // contains |resultPromise|, but otherwise does nothing.
+            RootedObject& blockedPromise = thenSpeciesOrBlockedPromise;
+            blockedPromise = resultPromise;
+
+            mozilla::Maybe<AutoRealm> ar;
+            if (IsProxy(nextPromiseObj)) {
+                nextPromiseObj = CheckedUnwrap(nextPromiseObj);
+                if (!nextPromiseObj) {
+                    ReportAccessDenied(cx);
+                    return false;
+                }
+                if (JS_IsDeadWrapper(nextPromiseObj)) {
+                    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+                    return false;
+                }
+                ar.emplace(cx, nextPromiseObj);
+                if (!cx->compartment()->wrap(cx, &blockedPromise))
+                    return false;
+            }
+
+            // If either the object to depend on or the object that gets
+            // blocked isn't a, maybe-wrapped, Promise instance, we ignore it.
+            // All this does is lose some small amount of debug information in
+            // scenarios that are highly unlikely to occur in useful code.
+            if (nextPromiseObj->is<PromiseObject>() && resultPromise->is<PromiseObject>()) {
+                Handle<PromiseObject*> promise = nextPromiseObj.as<PromiseObject>();
+                if (!AddDummyPromiseReactionForDebugger(cx, promise, blockedPromise))
+                    return false;
+            }
+        }
+    }
 }
 
 // ES2016, 25.4.4.1.1.
 static MOZ_MUST_USE bool
-PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
-                  HandleObject promiseObj, HandleObject resolve, HandleObject reject,
-                  bool* done)
+PerformPromiseAll(JSContext *cx, PromiseForOfIterator& iterator, HandleObject C,
+                  Handle<PromiseCapability> resultCapability, bool* done)
 {
     *done = false;
 
-    RootedObject unwrappedPromiseObj(cx);
-    if (IsWrapper(promiseObj)) {
-        unwrappedPromiseObj = CheckedUnwrap(promiseObj);
-        MOZ_ASSERT(unwrappedPromiseObj);
-    }
-
     // Step 1.
     MOZ_ASSERT(C->isConstructor());
-    RootedValue CVal(cx, ObjectValue(*C));
 
     // Step 2 (omitted).
 
     // Step 3.
     // We have to be very careful about which compartments we create things in
     // here.  In particular, we have to maintain the invariant that anything
     // stored in a reserved slot is same-compartment with the object whose
     // reserved slot it's in.  But we want to create the values array in the
@@ -2238,139 +2582,117 @@ PerformPromiseAll(JSContext *cx, JS::For
     // and the data holder in our current compartment.  Store a
     // cross-compartment wrapper to the values array in the holder.  This
     // should be OK because the only things we hand the
     // PromiseAllResolveElement function to are the "then" calls we do and in
     // the case when the Promise's compartment is not the current compartment
     // those are happening over Xrays anyway, which means they get the
     // canonical "then" function and content can't see our
     // PromiseAllResolveElement.
-    RootedObject valuesArray(cx);
-    if (unwrappedPromiseObj) {
-        JSAutoRealm ar(cx, unwrappedPromiseObj);
-        valuesArray = NewDenseFullyAllocatedArray(cx, 0);
+    RootedArrayObject valuesArray(cx);
+    RootedValue valuesArrayVal(cx);
+    if (IsWrapper(resultCapability.promise())) {
+        JSObject* unwrappedPromiseObj = CheckedUnwrap(resultCapability.promise());
+        MOZ_ASSERT(unwrappedPromiseObj);
+
+        {
+            AutoRealm ar(cx, unwrappedPromiseObj);
+            valuesArray = NewDenseEmptyArray(cx);
+            if (!valuesArray)
+                return false;
+        }
+
+        valuesArrayVal.setObject(*valuesArray);
+        if (!cx->compartment()->wrap(cx, &valuesArrayVal))
+            return false;
     } else {
-        valuesArray = NewDenseFullyAllocatedArray(cx, 0);
+        valuesArray = NewDenseEmptyArray(cx);
+        if (!valuesArray)
+            return false;
+
+        valuesArrayVal.setObject(*valuesArray);
     }
-    if (!valuesArray)
-        return false;
-
-    RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
-    if (!cx->compartment()->wrap(cx, &valuesArrayVal))
-        return false;
 
     // Step 4.
     // Create our data holder that holds all the things shared across
     // every step of the iterator.  In particular, this holds the
     // remainingElementsCount (as an integer reserved slot), the array of
     // values, and the resolve function from our PromiseCapability.
-    Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, promiseObj,
-                                                                         valuesArrayVal, resolve));
+    Rooted<PromiseAllDataHolder*> dataHolder(cx);
+    dataHolder = NewPromiseAllDataHolder(cx, resultCapability.promise(), valuesArrayVal,
+                                         resultCapability.resolve());
     if (!dataHolder)
         return false;
-    RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
 
     // Step 5.
     uint32_t index = 0;
 
-    // Step 6.
-    RootedValue nextValue(cx);
-    RootedId indexId(cx);
-    RootedValue rejectFunVal(cx, ObjectValue(*reject));
-
-    while (true) {
-        // Steps a-c, e-g.
-        if (!iterator.next(&nextValue, done)) {
-            // Steps b, f.
-            *done = true;
-
-            // Steps c, g.
-            return false;
-        }
-
-        // Step d.
-        if (*done) {
-            // Step d.i (implicit).
-
-            // Step d.ii.
-            int32_t remainingCount = dataHolder->decreaseRemainingCount();
-
-            // Steps d.iii-iv.
-            if (remainingCount == 0) {
-                return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode,
-                                             promiseObj);
-            }
-
-            // We're all set for now!
-            return true;
-        }
-
-        // Step h.
-        { // Scope for the JSAutoRealm we need to work with valuesArray.  We
+    auto getResolve = [cx, &valuesArray, &dataHolder, &index]() -> JSObject* {
+        // Step 6.h.
+        { // Scope for the AutoRealm we need to work with valuesArray.  We
             // mostly do this for performance; we could go ahead and do the define via
             // a cross-compartment proxy instead...
-            JSAutoRealm ar(cx, valuesArray);
-            indexId = INT_TO_JSID(index);
-            if (!DefineDataProperty(cx, valuesArray, indexId, UndefinedHandleValue))
-                return false;
+            AutoRealm ar(cx, valuesArray);
+
+            if (!NewbornArrayPush(cx, valuesArray, UndefinedValue()))
+                return nullptr;
         }
 
-        // Step i.
-        // Sadly, because someone could have overridden
-        // "resolve" on the canonical Promise constructor.
-        RootedValue nextPromise(cx);
-        RootedValue staticResolve(cx);
-        if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
-            return false;
-
-        FixedInvokeArgs<1> resolveArgs(cx);
-        resolveArgs[0].set(nextValue);
-        if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
-            return false;
-
-        // Step j.
-        RootedFunction resolveFunc(cx, NewNativeFunction(cx, PromiseAllResolveElementFunction,
-                                                         1, nullptr,
-                                                         gc::AllocKind::FUNCTION_EXTENDED,
-                                                         GenericObject));
+        // Steps 6.j-k.
+        JSFunction* resolveFunc = NewNativeFunction(cx, PromiseAllResolveElementFunction, 1,
+                                                    nullptr,gc::AllocKind::FUNCTION_EXTENDED,
+                                                    GenericObject);
         if (!resolveFunc)
-            return false;
-
-        // Steps k,m,n.
-        resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, dataHolderVal);
-
-        // Step l.
+            return nullptr;
+
+        // Steps 6.l, 6.n-p.
+        resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data,
+                                     ObjectValue(*dataHolder));
+
+        // Step 6.m.
         resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex,
                                      Int32Value(index));
 
-        // Steps o-p.
+        // Step 6.q.
         dataHolder->increaseRemainingCount();
 
-        // Step q.
-        RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
-        if (!BlockOnPromise(cx, nextPromise, promiseObj, resolveFunVal, rejectFunVal, true))
-            return false;
-
-        // Step r.
+        // Step 6.s.
         index++;
         MOZ_ASSERT(index > 0);
+
+        return resolveFunc;
+    };
+
+    // Step 6.
+    if (!CommonPerformPromiseAllRace(cx, iterator, C, resultCapability, done, true, getResolve))
+        return false;
+
+    // Step 6.d.ii.
+    int32_t remainingCount = dataHolder->decreaseRemainingCount();
+
+    // Steps 6.d.iii-iv.
+    if (remainingCount == 0) {
+        return RunResolutionFunction(cx, resultCapability.resolve(), valuesArrayVal, ResolveMode,
+                                     resultCapability.promise());
     }
+
+    return true;
 }
 
 // ES2016, 25.4.4.1.2.
 static bool
 PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedFunction resolve(cx, &args.callee().as<JSFunction>());
+    JSFunction* resolve = &args.callee().as<JSFunction>();
     RootedValue xVal(cx, args.get(0));
 
     // Step 1.
-    RootedValue dataVal(cx, resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_Data));
+    const Value& dataVal = resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_Data);
 
     // Step 2.
     // We use the existence of the data holder as a signal for whether the
     // Promise was already resolved. Upon resolution, it's reset to
     // `undefined`.
     if (dataVal.isUndefined()) {
         args.rval().setUndefined();
         return true;
@@ -2383,38 +2705,37 @@ PromiseAllResolveElementFunction(JSConte
 
     // Step 4.
     int32_t index = resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex)
                     .toInt32();
 
     // Step 5.
     RootedValue valuesVal(cx, data->valuesArray());
     RootedObject valuesObj(cx, &valuesVal.toObject());
-    bool valuesListIsWrapped = false;
-    if (IsWrapper(valuesObj)) {
-        valuesListIsWrapped = true;
+    if (IsProxy(valuesObj)) {
         // See comment for PerformPromiseAll, step 3 for why we unwrap here.
         valuesObj = UncheckedUnwrap(valuesObj);
+
+        if (JS_IsDeadWrapper(valuesObj)) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+            return false;
+        }
+
+        AutoRealm ar(cx, valuesObj);
+        if (!cx->compartment()->wrap(cx, &xVal))
+            return false;
     }
-    if (JS_IsDeadWrapper(valuesObj)) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
-        return false;
-    }
-    RootedNativeObject values(cx, &valuesObj->as<NativeObject>());
+    HandleNativeObject values = valuesObj.as<NativeObject>();
 
     // Step 6 (moved under step 10).
     // Step 7 (moved to step 9).
 
     // Step 8.
     // The index is guaranteed to be initialized to `undefined`.
-    if (valuesListIsWrapped) {
-        AutoRealm ar(cx, values);
-        if (!cx->compartment()->wrap(cx, &xVal))
-            return false;
-    }
+    MOZ_ASSERT(values->getDenseElement(index).isUndefined());
     values->setDenseElement(index, xVal);
 
     // Steps 7,9.
     uint32_t remainingCount = data->decreaseRemainingCount();
 
     // Step 10.
     if (remainingCount == 0) {
         // Step 10.a. (Omitted, happened in PerformPromiseAll.)
@@ -2427,137 +2748,100 @@ PromiseAllResolveElementFunction(JSConte
             return false;
     }
 
     // Step 11.
     args.rval().setUndefined();
     return true;
 }
 
-static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator,
-                                            HandleObject C, HandleObject promiseObj,
-                                            HandleObject resolve, HandleObject reject,
-                                            bool* done);
+static MOZ_MUST_USE bool
+PerformPromiseRace(JSContext *cx, PromiseForOfIterator& iterator, HandleObject C,
+                   Handle<PromiseCapability> resultCapability, bool* done);
 
 // ES2016, 25.4.4.3.
 static bool
 Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedValue iterable(cx, args.get(0));
+    HandleValue iterable = args.get(0);
 
     // Step 2 (reordered).
-    RootedValue CVal(cx, args.thisv());
+    HandleValue CVal = args.thisv();
     if (!CVal.isObject()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
                                   "Receiver of Promise.race call");
         return false;
     }
 
     // Step 1.
     RootedObject C(cx, &CVal.toObject());
 
     // Step 3.
-    RootedObject resultPromise(cx);
-    RootedObject resolve(cx);
-    RootedObject reject(cx);
-    if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
+    Rooted<PromiseCapability> promiseCapability(cx);
+    if (!NewPromiseCapability(cx, C, &promiseCapability, false))
         return false;
 
     // Steps 4-5.
-    JS::ForOfIterator iter(cx);
+    PromiseForOfIterator iter(cx);
     if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
-        return AbruptRejectPromise(cx, args, resultPromise, reject);
+        return AbruptRejectPromise(cx, args, promiseCapability);
 
     if (!iter.valueIsIterable()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
                                   "Argument of Promise.race");
-        return AbruptRejectPromise(cx, args, resultPromise, reject);
+        return AbruptRejectPromise(cx, args, promiseCapability);
     }
 
     // Step 6 (implicit).
 
     // Step 7.
     bool done;
-    bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject, &done);
+    bool result = PerformPromiseRace(cx, iter, C, promiseCapability, &done);
 
     // Step 8.
     if (!result) {
         // Step 8.a.
         if (!done)
             iter.closeThrow();
 
         // Step 8.b.
-        return AbruptRejectPromise(cx, args, resultPromise, reject);
+        return AbruptRejectPromise(cx, args, promiseCapability);
     }
 
     // Step 9.
-    args.rval().setObject(*resultPromise);
+    args.rval().setObject(*promiseCapability.promise());
     return true;
 }
 
 // ES2016, 25.4.4.3.1.
 static MOZ_MUST_USE bool
-PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
-                   HandleObject promiseObj, HandleObject resolve, HandleObject reject,
-                   bool* done)
+PerformPromiseRace(JSContext *cx, PromiseForOfIterator& iterator, HandleObject C,
+                   Handle<PromiseCapability> resultCapability, bool* done)
 {
     *done = false;
+
+    // Step 1.
     MOZ_ASSERT(C->isConstructor());
-    RootedValue CVal(cx, ObjectValue(*C));
+
+    // Step 2 (omitted).
 
     // BlockOnPromise fast path requires the passed onFulfilled function
     // doesn't return an object value, because otherwise the skipped promise
     // creation is detectable due to missing property lookups.
-    bool isDefaultResolveFn = IsNativeFunction(resolve, ResolvePromiseFunction);
-
-    RootedValue nextValue(cx);
-    RootedValue resolveFunVal(cx, ObjectValue(*resolve));
-    RootedValue rejectFunVal(cx, ObjectValue(*reject));
-
-    while (true) {
-        // Steps a-c, e-g.
-        if (!iterator.next(&nextValue, done)) {
-            // Steps b, f.
-            *done = true;
-
-            // Steps c, g.
-            return false;
-        }
-
-        // Step d.
-        if (*done) {
-            // Step d.i (implicit).
-
-            // Step d.ii.
-            return true;
-        }
-
-        // Step h.
-        // Sadly, because someone could have overridden
-        // "resolve" on the canonical Promise constructor.
-        RootedValue nextPromise(cx);
-        RootedValue staticResolve(cx);
-        if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
-            return false;
-
-        FixedInvokeArgs<1> resolveArgs(cx);
-        resolveArgs[0].set(nextValue);
-        if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
-            return false;
-
-        // Step i.
-        if (!BlockOnPromise(cx, nextPromise, promiseObj, resolveFunVal, rejectFunVal,
-                            isDefaultResolveFn))
-        {
-            return false;
-        }
-    }
-
-    MOZ_ASSERT_UNREACHABLE("Shouldn't reach the end of PerformPromiseRace");
+    bool isDefaultResolveFn = IsNativeFunction(resultCapability.resolve(),
+                                               ResolvePromiseFunction);
+
+    auto getResolve = [&resultCapability]() -> JSObject* {
+        return resultCapability.resolve();
+    };
+
+    // Step 3.
+    return CommonPerformPromiseAllRace(cx, iterator, C, resultCapability, done,
+                                       isDefaultResolveFn, getResolve);
 }
 
 
 // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5.
 static MOZ_MUST_USE JSObject*
 CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
                               ResolutionMode mode)
 {
@@ -2580,106 +2864,104 @@ CommonStaticResolveRejectImpl(JSContext*
         } else if (IsWrapper(xObj)) {
             // Treat instances of Promise from other compartments as Promises
             // here, too.
             // It's important to do the GetProperty for the `constructor`
             // below through the wrapper, because wrappers can change the
             // outcome, so instead of unwrapping and then performing the
             // GetProperty, just check here and then operate on the original
             // object again.
-            RootedObject unwrappedObject(cx, CheckedUnwrap(xObj));
+            JSObject* unwrappedObject = CheckedUnwrap(xObj);
             if (unwrappedObject && unwrappedObject->is<PromiseObject>())
                 isPromise = true;
         }
         if (isPromise) {
             RootedValue ctorVal(cx);
             if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
                 return nullptr;
             if (ctorVal == thisVal)
                 return xObj;
         }
     }
 
     // Step 4 of Resolve, 3 of Reject.
-    RootedObject promise(cx);
-    RootedObject resolveFun(cx);
-    RootedObject rejectFun(cx);
-    if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
+    Rooted<PromiseCapability> capability(cx);
+    if (!NewPromiseCapability(cx, C, &capability, true))
         return nullptr;
 
     // Step 5 of Resolve, 4 of Reject.
-    if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode,
-                               promise))
+    if (!RunResolutionFunction(cx, mode == ResolveMode ? capability.resolve() : capability.reject(),
+                               argVal, mode, capability.promise()))
     {
         return nullptr;
     }
 
     // Step 6 of Resolve, 4 of Reject.
-    return promise;
+    return capability.promise();
 }
 
 MOZ_MUST_USE JSObject*
 js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value)
 {
     RootedValue C(cx, ObjectValue(*constructor));
     return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode);
 }
 
 /**
  * ES2016, 25.4.4.4, Promise.reject.
  */
 static bool
 Promise_reject(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedValue thisVal(cx, args.thisv());
-    RootedValue argVal(cx, args.get(0));
+    HandleValue thisVal = args.thisv();
+    HandleValue argVal = args.get(0);
     JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode);
     if (!result)
         return false;
     args.rval().setObject(*result);
     return true;
 }
 
 /**
  * Unforgeable version of ES2016, 25.4.4.4, Promise.reject.
  */
 /* static */ JSObject*
 PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
 {
-    RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
+    JSObject* promiseCtor = JS::GetPromiseConstructor(cx);
     if (!promiseCtor)
         return nullptr;
     RootedValue cVal(cx, ObjectValue(*promiseCtor));
     return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode);
 }
 
 /**
  * ES2016, 25.4.4.5, Promise.resolve.
  */
 static bool
 Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedValue thisVal(cx, args.thisv());
-    RootedValue argVal(cx, args.get(0));
+    HandleValue thisVal = args.thisv();
+    HandleValue argVal = args.get(0);
     JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode);
     if (!result)
         return false;
     args.rval().setObject(*result);
     return true;
 }
 
 /**
  * Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
  */
 /* static */ JSObject*
 PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
 {
-    RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
+    JSObject* promiseCtor = JS::GetPromiseConstructor(cx);
     if (!promiseCtor)
         return nullptr;
     RootedValue cVal(cx, ObjectValue(*promiseCtor));
     return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
 }
 
 /**
  * ES2016, 25.4.4.6 get Promise [ @@species ]
@@ -2696,28 +2978,32 @@ Promise_static_species(JSContext* cx, un
 
 // ES2016, 25.4.5.1, implemented in Promise.js.
 
 enum class IncumbentGlobalObject {
     Yes, No
 };
 
 static PromiseReactionRecord*
-NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfilled,
-                  HandleValue onRejected, HandleObject resolve, HandleObject reject,
+NewReactionRecord(JSContext* cx, Handle<PromiseCapability> resultCapability,
+                  HandleValue onFulfilled, HandleValue onRejected,
                   IncumbentGlobalObject incumbentGlobalObjectOption)
 {
     // Either of the following conditions must be met:
-    //   * resultPromise is a PromiseObject
-    //   * resolve and reject are callable
+    //   * resultCapability.promise is a PromiseObject
+    //   * resultCapability.resolve and resultCapability.resolve are callable
     // except for Async Generator, there resultPromise can be nullptr.
-    MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), resolve);
-    MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), IsCallable(resolve));
-    MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), reject);
-    MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), IsCallable(reject));
+#ifdef DEBUG
+    if (resultCapability.promise() && !resultCapability.promise()->is<PromiseObject>()) {
+        MOZ_ASSERT(resultCapability.resolve());
+        MOZ_ASSERT(IsCallable(resultCapability.resolve()));
+        MOZ_ASSERT(resultCapability.reject());
+        MOZ_ASSERT(IsCallable(resultCapability.reject()));
+    }
+#endif
 
     // Ensure the onFulfilled handler has the expected type.
     MOZ_ASSERT(onFulfilled.isInt32() || onFulfilled.isObjectOrNull());
     MOZ_ASSERT_IF(onFulfilled.isObject(), IsCallable(onFulfilled));
     MOZ_ASSERT_IF(onFulfilled.isInt32(),
                   0 <= onFulfilled.toInt32() && onFulfilled.toInt32() < PromiseHandlerLimit);
 
     // Ensure the onRejected handler has the expected type.
@@ -2730,62 +3016,64 @@ NewReactionRecord(JSContext* cx, HandleO
     MOZ_ASSERT(onFulfilled.isNull() == onRejected.isNull());
 
     RootedObject incumbentGlobalObject(cx);
     if (incumbentGlobalObjectOption == IncumbentGlobalObject::Yes) {
         if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobalObject))
             return nullptr;
     }
 
-    Rooted<PromiseReactionRecord*> reaction(cx, NewObjectWithClassProto<PromiseReactionRecord>(cx));
+    PromiseReactionRecord* reaction = NewBuiltinClassInstance<PromiseReactionRecord>(cx);
     if (!reaction)
         return nullptr;
 
-    assertSameCompartment(cx, resultPromise);
+    assertSameCompartment(cx, resultCapability.promise());
     assertSameCompartment(cx, onFulfilled);
     assertSameCompartment(cx, onRejected);
-    assertSameCompartment(cx, resolve);
-    assertSameCompartment(cx, reject);
+    assertSameCompartment(cx, resultCapability.resolve());
+    assertSameCompartment(cx, resultCapability.reject());
     assertSameCompartment(cx, incumbentGlobalObject);
 
-    reaction->setFixedSlot(ReactionRecordSlot_Promise, ObjectOrNullValue(resultPromise));
+    reaction->setFixedSlot(ReactionRecordSlot_Promise,
+                           ObjectOrNullValue(resultCapability.promise()));
     reaction->setFixedSlot(ReactionRecordSlot_Flags, Int32Value(0));
     reaction->setFixedSlot(ReactionRecordSlot_OnFulfilled, onFulfilled);
     reaction->setFixedSlot(ReactionRecordSlot_OnRejected, onRejected);
-    reaction->setFixedSlot(ReactionRecordSlot_Resolve, ObjectOrNullValue(resolve));
-    reaction->setFixedSlot(ReactionRecordSlot_Reject, ObjectOrNullValue(reject));
+    reaction->setFixedSlot(ReactionRecordSlot_Resolve,
+                           ObjectOrNullValue(resultCapability.resolve()));
+    reaction->setFixedSlot(ReactionRecordSlot_Reject,
+                           ObjectOrNullValue(resultCapability.reject()));
     reaction->setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject,
                            ObjectOrNullValue(incumbentGlobalObject));
 
     return reaction;
 }
 
 static bool
 IsPromiseSpecies(JSContext* cx, JSFunction* species)
 {
     return species->maybeNative() == Promise_static_species;
 }
 
 static bool
 PromiseThenNewPromiseCapability(JSContext* cx, HandleObject promiseObj,
                                 CreateDependentPromise createDependent,
-                                MutableHandleObject resultPromise,
-                                MutableHandleObject resolve, MutableHandleObject reject)
+                                MutableHandle<PromiseCapability> resultCapability)
 {
     if (createDependent != CreateDependentPromise::Never) {
         // Step 3.
         RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
         if (!C)
             return false;
 
         if (createDependent == CreateDependentPromise::Always ||
             !IsNativeFunction(C, PromiseConstructor))
         {
             // Step 4.
-            if (!NewPromiseCapability(cx, C, resultPromise, resolve, reject, true))
+            if (!NewPromiseCapability(cx, C, resultCapability, true))
                 return false;
         }
     }
 
     return true;
 }
 
 // ES2016, 25.4.5.3., steps 3-5.
@@ -2796,52 +3084,83 @@ js::OriginalPromiseThen(JSContext* cx, H
 {
     RootedObject promiseObj(cx, promise);
     if (promise->compartment() != cx->compartment()) {
         if (!cx->compartment()->wrap(cx, &promiseObj))
             return false;
     }
 
     // Steps 3-4.
-    RootedObject resultPromise(cx);
-    RootedObject resolve(cx);
-    RootedObject reject(cx);
-    if (!PromiseThenNewPromiseCapability(cx, promiseObj, createDependent, &resultPromise,
-                                         &resolve, &reject))
-    {
+    Rooted<PromiseCapability> resultCapability(cx);
+    if (!PromiseThenNewPromiseCapability(cx, promiseObj, createDependent, &resultCapability))
         return false;
-    }
 
     // Step 5.
-    if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, resolve, reject))
+    if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultCapability))
         return false;
 
-    dependent.set(resultPromise);
+    dependent.set(resultCapability.promise());
     return true;
 }
 
 static MOZ_MUST_USE bool
 OriginalPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise,
                                          Handle<PromiseObject*> promiseToResolve)
 {
     assertSameCompartment(cx, promise);
 
     // Steps 3-4.
-    RootedObject resultPromise(cx);
-    RootedObject resolve(cx);
-    RootedObject reject(cx);
+    Rooted<PromiseCapability> resultCapability(cx);
     if (!PromiseThenNewPromiseCapability(cx, promise, CreateDependentPromise::SkipIfCtorUnobservable,
-                                         &resultPromise, &resolve, &reject))
+                                         &resultCapability))
     {
         return false;
     }
 
     // Step 5.
-    return PerformPromiseThenWithoutSettleHandlers(cx, promise, promiseToResolve, resultPromise,
-                                                   resolve, reject);
+    return PerformPromiseThenWithoutSettleHandlers(cx, promise, promiseToResolve, resultCapability);
+}
+
+static bool
+CanCallOriginalPromiseThenBuiltin(JSContext* cx, HandleValue promise)
+{
+    return promise.isObject() &&
+           promise.toObject().is<PromiseObject>() &&
+           cx->realm()->promiseLookup.isDefaultInstance(cx, &promise.toObject().as<PromiseObject>());
+}
+
+// ES2016, 25.4.5.3., steps 3-5.
+static bool
+OriginalPromiseThenBuiltin(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
+                           HandleValue onRejected, MutableHandleValue rval, bool rvalUsed)
+{
+    assertSameCompartment(cx, promiseVal, onFulfilled, onRejected);
+    MOZ_ASSERT(CanCallOriginalPromiseThenBuiltin(cx, promiseVal));
+
+    Rooted<PromiseObject*> promise(cx, &promiseVal.toObject().as<PromiseObject>());
+
+    // Steps 3-4.
+    Rooted<PromiseCapability> resultCapability(cx);
+    if (rvalUsed) {
+        PromiseObject* resultPromise = CreatePromiseObjectWithoutResolutionFunctions(cx);
+        if (!resultPromise)
+            return false;
+
+        resultCapability.promise().set(resultPromise);
+    }
+
+    // Step 5.
+    if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultCapability))
+        return false;
+
+    if (rvalUsed)
+        rval.setObject(*resultCapability.promise());
+    else
+        rval.setUndefined();
+    return true;
 }
 
 static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
                                                         Handle<PromiseObject*> promise,
                                                         Handle<PromiseReactionRecord*> reaction);
 
 // Some async/await functions are implemented here instead of
 // js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
@@ -2871,17 +3190,17 @@ js::IsPromiseForAsync(JSObject* promise)
 MOZ_MUST_USE bool
 js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
 {
     // Step 3.f.
     RootedValue exc(cx);
     if (!MaybeGetAndClearException(cx, &exc))
         return false;
 
-    if (!RejectMaybeWrappedPromise(cx, resultPromise, exc))
+    if (!RejectPromiseInternal(cx, resultPromise, exc))
         return false;
 
     // Step 3.g.
     return true;
 }
 
 // ES 2018 draft 25.5.5.2 steps 3.d-e, 3.g.
 MOZ_MUST_USE bool
@@ -2910,19 +3229,20 @@ InternalAwait(JSContext* cx, HandleValue
     if (!promise)
         return false;
 
     // Step 3.
     if (!ResolvePromiseInternal(cx, promise, value))
         return false;
 
     // Step 7-8.
-    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
+    Rooted<PromiseCapability> resultCapability(cx);
+    resultCapability.promise().set(resultPromise);
+    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultCapability,
                                                                   onFulfilled, onRejected,
-                                                                  nullptr, nullptr,
                                                                   IncumbentGlobalObject::Yes));
     if (!reaction)
         return false;
 
     // Step 6.
     extraStep(reaction);
 
     // Step 9.
@@ -2962,64 +3282,63 @@ js::AsyncGeneratorAwait(JSContext* cx, H
 
 // Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
 // Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
 // Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
 bool
 js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
 {
     // Step 1.
-    RootedValue thisVal(cx, args.thisv());
+    HandleValue thisVal = args.thisv();
 
     // Step 2.
-    RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
+    Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
     if (!resultPromise)
         return false;
 
     // Step 3.
     if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
         // NB: See https://github.com/tc39/proposal-async-iteration/issues/105
         // for why this check shouldn't be necessary as long as we can ensure
         // the Async-from-Sync iterator can't be accessed directly by user
         // code.
 
         // Step 3.a.
         RootedValue badGeneratorError(cx);
         if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
             return false;
 
         // Step 3.b.
-        if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
+        if (!RejectPromiseInternal(cx, resultPromise, badGeneratorError))
             return false;
 
         // Step 3.c.
         args.rval().setObject(*resultPromise);
         return true;
     }
 
     Rooted<AsyncFromSyncIteratorObject*> asyncIter(
         cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
 
     // Step 4.
     RootedObject iter(cx, asyncIter->iterator());
 
-    RootedValue resultVal(cx);
     RootedValue func(cx);
     if (completionKind == CompletionKind::Normal) {
         // 11.1.3.2.1 steps 5-6 (partially).
         func.set(asyncIter->nextMethod());
     } else if (completionKind == CompletionKind::Return) {
         // 11.1.3.2.2 steps 5-6.
         if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
         // Step 7.
         if (func.isNullOrUndefined()) {
             // Step 7.a.
-            RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
+            JSObject* resultObj = CreateIterResultObject(cx, args.get(0), true);
             if (!resultObj)
                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
             RootedValue resultVal(cx, ObjectValue(*resultObj));
 
             // Step 7.b.
             if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
@@ -3032,31 +3351,30 @@ js::AsyncFromSyncIteratorMethod(JSContex
         // 11.1.3.2.3 steps 5-6.
         MOZ_ASSERT(completionKind == CompletionKind::Throw);
         if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
         // Step 7.
         if (func.isNullOrUndefined()) {
             // Step 7.a.
-            if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
+            if (!RejectPromiseInternal(cx, resultPromise, args.get(0)))
                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
             // Step 7.b.
             args.rval().setObject(*resultPromise);
             return true;
         }
     }
 
     // 11.1.3.2.1 steps 5-6 (partially).
     // 11.1.3.2.2, 11.1.3.2.3 steps 8-9.
     RootedValue iterVal(cx, ObjectValue(*iter));
-    FixedInvokeArgs<1> args2(cx);
-    args2[0].set(args.get(0));
-    if (!js::Call(cx, func, iterVal, args2, &resultVal))
+    RootedValue resultVal(cx);
+    if (!Call(cx, func, iterVal, args.get(0), &resultVal))
         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
     // 11.1.3.2.1 steps 5-6 (partially).
     // 11.1.3.2.2, 11.1.3.2.3 steps 10.
     if (!resultVal.isObject()) {
         CheckIsObjectKind kind;
         switch (completionKind) {
           case CompletionKind::Normal:
@@ -3150,55 +3468,55 @@ AsyncGeneratorResumeNext(JSContext* cx, 
             HandleValue exception = valueOrException;
 
             // Step 1 (implicit).
 
             // Steps 2-3.
             MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
 
             // Step 4.
-            Rooted<AsyncGeneratorRequest*> request(
-                cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
+            AsyncGeneratorRequest* request =
+                AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj);
             if (!request)
                 return false;
 
             // Step 5.
-            RootedObject resultPromise(cx, request->promise());
+            Rooted<PromiseObject*> resultPromise(cx, request->promise());
 
             asyncGenObj->cacheRequest(request);
 
             // Step 6.
-            if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
+            if (!RejectPromiseInternal(cx, resultPromise, exception))
                 return false;
 
             // Steps 7-8.
             break;
           }
           case ResumeNextKind::Resolve: {
             // 11.4.3.3 AsyncGeneratorResolve ( generator, value, done )
             HandleValue value = valueOrException;
 
             // Step 1 (implicit).
 
             // Steps 2-3.
             MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
 
             // Step 4.
-            Rooted<AsyncGeneratorRequest*> request(
-                cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
+            AsyncGeneratorRequest* request =
+                AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj);
             if (!request)
                 return false;
 
             // Step 5.
-            RootedObject resultPromise(cx, request->promise());
+            Rooted<PromiseObject*> resultPromise(cx, request->promise());
 
             asyncGenObj->cacheRequest(request);
 
             // Step 6.
-            RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
+            JSObject* resultObj = CreateIterResultObject(cx, value, done);
             if (!resultObj)
                 return false;
 
             RootedValue resultValue(cx, ObjectValue(*resultObj));
 
             // Step 7.
             if (!ResolvePromiseInternal(cx, resultPromise, resultValue))
                 return false;
@@ -3316,29 +3634,29 @@ AsyncGeneratorResumeNext(JSContext* cx, 
 MOZ_MUST_USE bool
 js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
                           CompletionKind completionKind, HandleValue completionValue,
                           MutableHandleValue result)
 {
     // Step 1 (implicit).
 
     // Step 2.
-    RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
+    Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
     if (!resultPromise)
         return false;
 
     // Step 3.
     if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) {
         // Step 3.a.
         RootedValue badGeneratorError(cx);
         if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError))
             return false;
 
         // Step 3.b.
-        if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
+        if (!RejectPromiseInternal(cx, resultPromise, badGeneratorError))
             return false;
 
         // Step 3.c.
         result.setObject(*resultPromise);
         return true;
     }
 
     Rooted<AsyncGeneratorObject*> asyncGenObj(
@@ -3367,31 +3685,35 @@ js::AsyncGeneratorEnqueue(JSContext* cx,
     return true;
 }
 
 static bool
 Promise_catch_impl(JSContext* cx, unsigned argc, Value* vp, bool rvalUsed)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
+    HandleValue thisVal = args.thisv();
+    HandleValue onFulfilled = UndefinedHandleValue;
+    HandleValue onRejected = args.get(0);
+
+    // Fast path when the default Promise state is intact.
+    if (CanCallOriginalPromiseThenBuiltin(cx, thisVal)) {
+        return OriginalPromiseThenBuiltin(cx, thisVal, onFulfilled, onRejected, args.rval(),
+                                          rvalUsed);
+    }
+
     // Step 1.
     RootedValue thenVal(cx);
-    if (!GetProperty(cx, args.thisv(), cx->names().then, &thenVal))
+    if (!GetProperty(cx, thisVal, cx->names().then, &thenVal))
         return false;
 
-    if (IsNativeFunction(thenVal, &Promise_then)) {
-        return Promise_then_impl(cx, args.thisv(), UndefinedHandleValue, args.get(0),
-                                 args.rval(), rvalUsed);
-    }
-
-    FixedInvokeArgs<2> iargs(cx);
-    iargs[0].setUndefined();
-    iargs[1].set(args.get(0));
-
-    return Call(cx, thenVal, args.thisv(), iargs, args.rval());
+    if (IsNativeFunction(thenVal, &Promise_then))
+        return Promise_then_impl(cx, thisVal, onFulfilled, onRejected, args.rval(), rvalUsed);
+
+    return Call(cx, thenVal, thisVal, UndefinedHandleValue, onRejected, args.rval());
 }
 
 static MOZ_ALWAYS_INLINE bool
 IsPromiseThenOrCatchRetValImplicitlyUsed(JSContext* cx)
 {
     // The returned promise of Promise#then and Promise#catch contains
     // stack info if async stack is enabled.  Even if their return value is not
     // used explicitly in the script, the stack info is observable in devtools
@@ -3437,24 +3759,28 @@ Promise_then_impl(JSContext* cx, HandleV
 {
     // Step 1 (implicit).
     // Step 2.
     if (!promiseVal.isObject()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
                                   "Receiver of Promise.prototype.then call");
         return false;
     }
+
+    // Fast path when the default Promise state is intact.
+    if (CanCallOriginalPromiseThenBuiltin(cx, promiseVal))
+        return OriginalPromiseThenBuiltin(cx, promiseVal, onFulfilled, onRejected, rval, rvalUsed);
+
     RootedObject promiseObj(cx, &promiseVal.toObject());
     Rooted<PromiseObject*> promise(cx);
 
-    bool isPromise = promiseObj->is<PromiseObject>();
-    if (isPromise) {
+    if (promiseObj->is<PromiseObject>()) {
         promise = &promiseObj->as<PromiseObject>();
     } else {
-        RootedObject unwrappedPromiseObj(cx, CheckedUnwrap(promiseObj));
+        JSObject* unwrappedPromiseObj = CheckedUnwrap(promiseObj);
         if (!unwrappedPromiseObj) {
             ReportAccessDenied(cx);
             return false;
         }
         if (!unwrappedPromiseObj->is<PromiseObject>()) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                                       "Promise", "then", "value");
             return false;
@@ -3495,62 +3821,58 @@ Promise_then(JSContext* cx, unsigned arg
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(), true);
 }
 
 // ES2016, 25.4.5.3.1.
 static MOZ_MUST_USE bool
 PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
-                   HandleValue onRejected_, HandleObject resultPromise,
-                   HandleObject resolve, HandleObject reject)
+                   HandleValue onRejected_, Handle<PromiseCapability> resultCapability)
 {
     // Step 1 (implicit).
     // Step 2 (implicit).
 
     // Step 3.
     RootedValue onFulfilled(cx, onFulfilled_);
     if (!IsCallable(onFulfilled))
         onFulfilled = Int32Value(PromiseHandlerIdentity);
 
     // Step 4.
     RootedValue onRejected(cx, onRejected_);
     if (!IsCallable(onRejected))
         onRejected = Int32Value(PromiseHandlerThrower);
 
     // Step 7.
-    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
+    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultCapability,
                                                                   onFulfilled, onRejected,
-                                                                  resolve, reject,
                                                                   IncumbentGlobalObject::Yes));
     if (!reaction)
         return false;
 
     return PerformPromiseThenWithReaction(cx, promise, reaction);
 }
 
 static MOZ_MUST_USE bool
 PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise,
                                         Handle<PromiseObject*> promiseToResolve,
-                                        HandleObject resultPromise, HandleObject resolve,
-                                        HandleObject reject)
+                                        Handle<PromiseCapability> resultCapability)
 {
     // Step 1 (implicit).
     // Step 2 (implicit).
 
     // Step 3.
     HandleValue onFulfilled = NullHandleValue;
 
     // Step 4.
     HandleValue onRejected = NullHandleValue;
 
     // Step 7.
-    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
+    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultCapability,
                                                                   onFulfilled, onRejected,
-                                                                  resolve, reject,
                                                                   IncumbentGlobalObject::Yes));
     if (!reaction)
         return false;
 
     reaction->setIsDefaultResolvingHandler(promiseToResolve);
 
     return PerformPromiseThenWithReaction(cx, promise, reaction);
 }
@@ -3594,144 +3916,16 @@ PerformPromiseThenWithReaction(JSContext
 
     // Step 10.
     promise->setFixedSlot(PromiseSlot_Flags, Int32Value(flags | PROMISE_FLAG_HANDLED));
 
     // Step 11.
     return true;
 }
 
-/**
- * Calls |promise.then| with the provided hooks and adds |blockedPromise| to
- * its list of dependent promises. Used by |Promise.all| and |Promise.race|.
- *
- * If |promise.then| is the original |Promise.prototype.then| function and
- * the call to |promise.then| would use the original |Promise| constructor to
- * create the resulting promise, this function skips the call to |promise.then|
- * and thus creating a new promise that would not be observable by content.
- */
-static MOZ_MUST_USE bool
-BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromise_,</