Merge mozilla-inbound to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Sat, 21 Jul 2018 00:42:01 +0300
changeset 821151 6eec814dea789707d04f42bbb01097d44532e2a9
parent 821150 d6a5e8aea6516422e3e34f6239228f2563adbf1f (current diff)
parent 821046 1f10db43a17ef31d377709c7ec966a45de2c166e (diff)
child 821152 4bd5ccd360f0ba8eeae30a92c7e7d2cc51836cde
child 821160 028d311f0394d2f2c921c035fb008257444094bc
child 821198 558782eeafe1ceb6bf672afe1bd0ef80e62b7cbb
child 821233 694a40b2558ca8d04954559e94400436854c8330
child 821352 cd50773ef18d243d316a6f450aa18cc164300614
child 821601 5a36dceac1b5c167720c9d8cc61955af485497c1
child 821606 c5e82b831aabc65d02460f5839ae91bc5c2a446e
child 822637 b973a562e612a4913b9f24bf413f10cdbc1fb169
child 822639 83b641206ff9df825425469ca2d715b0e5023397
child 823794 a9c93b2ff7255fbe63a1c4f38c518e49307d5d3b
push id117018
push userbmo:sfoster@mozilla.com
push dateSat, 21 Jul 2018 04:05:10 +0000
reviewersmerge
milestone63.0a1
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)