Merge mozilla-central to inbound. r=merge a=merge on CLOSED TREE
authorNARCIS BELEUZU <nbeleuzu@mozilla.com>
Fri, 03 Nov 2017 12:22:35 +0200
changeset 443297 c17190dfd88b8427b19349e32f689567bad6e079
parent 443296 5c77250f74a4dc112204cb9164698868aad59f7c (current diff)
parent 443245 4e6df5159df3e64c3c453c0db0a2e1d126819b71 (diff)
child 443298 203ea4c2406fc81abd51fe7d6ba81c49e655f70f
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound. r=merge a=merge on CLOSED TREE
browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
browser/locales/searchplugins/wikipediaro.xml
browser/themes/linux/menuPanel-customize.png
browser/themes/linux/menuPanel-customize@2x.png
browser/themes/linux/menuPanel-exit.png
browser/themes/linux/menuPanel-exit@2x.png
browser/themes/linux/menuPanel-help.png
browser/themes/linux/menuPanel-help@2x.png
browser/themes/osx/menu-forward.png
browser/themes/osx/menuPanel-customize-yosemite.png
browser/themes/osx/menuPanel-customize-yosemite@2x.png
browser/themes/osx/menuPanel-customize.png
browser/themes/osx/menuPanel-customize@2x.png
browser/themes/osx/menuPanel-exit-yosemite.png
browser/themes/osx/menuPanel-exit-yosemite@2x.png
browser/themes/osx/menuPanel-exit.png
browser/themes/osx/menuPanel-exit@2x.png
browser/themes/osx/menuPanel-help-yosemite.png
browser/themes/osx/menuPanel-help-yosemite@2x.png
browser/themes/osx/menuPanel-help.png
browser/themes/osx/menuPanel-help@2x.png
browser/themes/shared/customizableui/menuPanel-customizeFinish.png
browser/themes/shared/customizableui/menuPanel-customizeFinish@2x.png
browser/themes/shared/customizableui/subView-arrow-back-inverted-rtl.png
browser/themes/shared/customizableui/subView-arrow-back-inverted-rtl@2x.png
browser/themes/shared/customizableui/subView-arrow-back-inverted.png
browser/themes/shared/customizableui/subView-arrow-back-inverted@2x.png
browser/themes/shared/customizableui/whimsy@2x.png
browser/themes/windows/menu-forward.png
browser/themes/windows/menuPanel-customize.png
browser/themes/windows/menuPanel-customize@2x.png
browser/themes/windows/menuPanel-exit.png
browser/themes/windows/menuPanel-exit@2x.png
browser/themes/windows/menuPanel-help.png
browser/themes/windows/menuPanel-help@2x.png
mobile/android/Makefile.in
mobile/android/config/tooltool-manifests/android-frontend/releng.manifest
mobile/android/config/tooltool-manifests/android-gradle-dependencies/releng.manifest
tools/fuzzing/libfuzzer/Makefile.in
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -335,30 +335,17 @@ toolbarpaletteitem {
 #main-window[inFullscreen] #high-priority-global-notificationbox {
   visibility: collapse;
 }
 
 #navigator-toolbox[fullscreenShouldAnimate] {
   transition: 1.5s margin-top ease-out;
 }
 
-/* Rules to help integrate SDK widgets */
-toolbaritem[sdkstylewidget="true"] > toolbarbutton,
-toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe,
-toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-text {
-  display: none;
-}
-
-toolbarpaletteitem:-moz-any([place="palette"], [place="panel"]) > toolbaritem[sdkstylewidget="true"] > toolbarbutton {
-  display: -moz-box;
-}
-
-toolbarpaletteitem > toolbaritem[sdkstylewidget="true"][cui-areatype="toolbar"] > .toolbarbutton-text {
-  display: -moz-box;
-}
+/* Rules to help integrate WebExtension buttons */
 
 .webextension-browser-action > .toolbarbutton-badge-stack > .toolbarbutton-icon {
   height: 16px;
   width: 16px;
 }
 
 @media not all and (min-resolution: 1.1dppx) {
   .webextension-browser-action {
@@ -1167,16 +1154,17 @@ toolbarpaletteitem[place="palette"] > #d
 #BMB_bookmarksPopup[animate="cancel"] {
   -moz-window-transform: none;
 }
 
 %elifndef MOZ_WIDGET_GTK
 
 #BMB_bookmarksPopup:not([animate="false"]) {
   opacity: 0;
+  will-change: transform; /* workaround for bug 1414033 */
   transform: translateY(-70px);
   transition-property: transform, opacity;
   transition-duration: 0.18s, 0.18s;
   transition-timing-function:
     var(--animation-easing-function), ease-out;
 }
 
 #BMB_bookmarksPopup[side="bottom"]:not([animate="false"]) {
@@ -1191,21 +1179,16 @@ toolbarpaletteitem[place="palette"] > #d
     var(--animation-easing-function), ease-in-out;
 }
 
 #BMB_bookmarksPopup[animate="cancel"] {
   transform: none;
 }
 %endif
 
-/* Customize mode */
-#PanelUI-contents > .panel-customization-placeholder > .panel-customization-placeholder-child {
-  list-style-image: none;
-}
-
 /* Apply crisp rendering for favicons at exactly 2dppx resolution */
 @media (resolution: 2dppx) {
   #PanelUI-remotetabs-tabslist > toolbarbutton > .toolbarbutton-icon,
   #PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon,
   #PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon,
   #PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon {
     image-rendering: -moz-crisp-edges;
   }
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -102,17 +102,16 @@ function CustomizeMode(aWindow) {
   this.browser = aWindow.gBrowser;
   this.areas = new Set();
 
   // There are two palettes - there's the palette that can be overlayed with
   // toolbar items in browser.xul. This is invisible, and never seen by the
   // user. Then there's the visible palette, which gets populated and displayed
   // to the user when in customizing mode.
   this.visiblePalette = this.document.getElementById(kPaletteId);
-  this.paletteEmptyNotice = this.document.getElementById("customization-empty");
   this.pongArena = this.document.getElementById("customization-pong-arena");
   if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
     let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
     lwthemeButton.setAttribute("hidden", "true");
   }
   if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
     this._updateTitlebarCheckbox();
     this._updateDragSpaceCheckbox();
@@ -405,17 +404,16 @@ CustomizeMode.prototype = {
     CustomizableUI.removeListener(this);
 
     this.document.removeEventListener("keypress", this);
 
     let window = this.window;
     let document = this.document;
 
     this.togglePong(false);
-    this.paletteEmptyNotice.hidden = true;
 
     // Disable the reset and undo reset buttons while transitioning:
     let resetButton = this.document.getElementById("customization-reset-button");
     let undoResetButton = this.document.getElementById("customization-undo-reset-button");
     undoResetButton.hidden = resetButton.disabled = true;
 
     this._transitioning = true;
 
@@ -1531,17 +1529,16 @@ CustomizeMode.prototype = {
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
     }
     CustomizableUI.dispatchToolboxEvent("customizationchange");
   },
 
   _updateEmptyPaletteNotice() {
     let paletteItems = this.visiblePalette.getElementsByTagName("toolbarpaletteitem");
-    this.paletteEmptyNotice.hidden = !!paletteItems.length;
     let whimsyButton = this.document.getElementById("whimsy-button");
 
     if (paletteItems.length == 1 &&
         paletteItems[0].id.includes("wrapper-customizableui-special-spring")) {
       whimsyButton.hidden = false;
     } else {
       this.togglePong(false);
       whimsyButton.hidden = true;
@@ -2726,17 +2723,17 @@ CustomizeMode.prototype = {
     let window = this.window;
     rAFHandle = window.requestAnimationFrame(function animate() {
       update();
       draw();
       if (quit) {
         elements.score.textContent = score;
         elements.lives && elements.lives.setAttribute("lives", lives);
         elements.arena.setAttribute("score", score);
-        elements.arena.setAttribute("lives", "0");
+        elements.arena.setAttribute("lives", lives);
       } else {
         rAFHandle = window.requestAnimationFrame(animate);
       }
     });
 
     return uninit;
   },
 };
--- a/browser/components/customizableui/content/customizeMode.inc.xul
+++ b/browser/components/customizableui/content/customizeMode.inc.xul
@@ -3,25 +3,16 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <box id="customization-container" flex="1" hidden="true">
   <box id="customization-content-container">
     <box flex="1" id="customization-palette-container">
       <label id="customization-header">
         &customizeMode.menuAndToolbars.header3;
       </label>
-      <hbox id="customization-empty" hidden="true">
-        <label>&customizeMode.menuAndToolbars.empty;</label>
-        <label onclick="BrowserOpenAddonsMgr('addons://discover/');"
-               onkeypress="BrowserOpenAddonsMgr('addons://discover/');"
-               id="customization-more-tools"
-               class="text-link">
-          &customizeMode.menuAndToolbars.emptyLink;
-        </label>
-      </hbox>
       <vbox id="customization-palette" class="customization-palette" hidden="true"/>
       <vbox id="customization-pong-arena" hidden="true"/>
       <spacer id="customization-spacer"/>
     </box>
     <vbox id="customization-panel-container">
       <vbox id="customization-panelWrapper">
         <box class="panel-arrowbox">
           <image class="panel-arrow" side="top"/>
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -1,335 +1,12 @@
 <!-- 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/. -->
 
-<panel id="PanelUI-popup"
-       role="group"
-       type="arrow"
-       hidden="true"
-       flip="slide"
-       position="bottomcenter topright"
-       noautofocus="true">
-  <panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView"
-                  viewCacheId="appMenu-viewCache">
-    <panelview id="PanelUI-mainView" context="customizationPanelContextMenu"
-               descriptionheightworkaround="true" blockinboxworkaround="true">
-      <vbox id="PanelUI-contents-scroller">
-        <vbox id="PanelUI-contents" class="panelUI-grid"/>
-      </vbox>
-
-      <footer id="PanelUI-footer">
-        <vbox id="PanelUI-footer-addons"></vbox>
-        <toolbarbutton class="panel-banner-item"
-                       label-update-available="&updateAvailable.panelUI.label;"
-                       label-update-manual="&updateManual.panelUI.label;"
-                       label-update-restart="&updateRestart.panelUI.label2;"
-                       oncommand="PanelUI._onBannerItemSelected(event)"
-                       wrap="true"
-                       hidden="true"/>
-        <hbox id="PanelUI-fxa-container">
-          <hbox id="PanelUI-fxa-status"
-                label="&fxaSignedIn.tooltip;"
-                defaultlabel="&fxaSignIn.label;"
-                signedinTooltiptext="&fxaSignedIn.tooltip;"
-                tooltiptext="&fxaSignedIn.tooltip;"
-                errorlabel="&fxaSignInError.label;"
-                unverifiedlabel="&fxaUnverified.label;"
-                onclick="if (event.which == 1) gSync.onMenuPanelCommand();">
-            <image id="PanelUI-fxa-avatar"/>
-            <toolbarbutton id="PanelUI-fxa-label"
-                           label="&fxaSignIn.label;"
-                           fxabrandname="&syncBrand.fxAccount.label;"/>
-          </hbox>
-          <toolbarseparator/>
-          <toolbarbutton id="PanelUI-fxa-icon"
-                         oncommand="gSync.doSync();"
-                         closemenu="none">
-            <observes element="sync-status" attribute="syncstatus"/>
-            <observes element="sync-status" attribute="tooltiptext"/>
-          </toolbarbutton>
-        </hbox>
-
-        <hbox id="PanelUI-footer-inner">
-          <toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;"
-                         exitLabel="&appMenuCustomizeExit.label;"
-                         tooltiptext="&appMenuCustomize.tooltip;"
-                         exitTooltiptext="&appMenuCustomizeExit.tooltip;"
-                         closemenu="none"
-                         oncommand="gCustomizeMode.toggle();"/>
-          <toolbarseparator/>
-          <toolbarbutton id="PanelUI-help" label="&helpMenu.label;"
-                         closemenu="none"
-                         tooltiptext="&appMenuHelp.tooltip;"
-                         oncommand="PanelUI.showHelpView(this);"/>
-          <toolbarseparator/>
-          <toolbarbutton id="PanelUI-quit"
-#ifdef XP_WIN
-                         label="&quitApplicationCmdWin2.label;"
-                         tooltiptext="&quitApplicationCmdWin2.tooltip;"
-#else
-#ifdef XP_MACOSX
-                         label="&quitApplicationCmdMac2.label;"
-#else
-                         label="&quitApplicationCmd.label;"
-#endif
-#endif
-                         command="cmd_quitApplication"/>
-        </hbox>
-      </footer>
-    </panelview>
-
-    <panelview id="PanelUI-history" flex="1">
-      <vbox class="panel-subview-body">
-        <toolbarbutton id="appMenuViewHistorySidebar"
-                       label="&appMenuHistory.viewSidebar.label;"
-                       type="checkbox"
-                       class="subviewbutton subviewbutton-iconic"
-                       key="key_gotoHistory"
-                       oncommand="SidebarUI.toggle('viewHistorySidebar'); PanelUI.hide();">
-          <observes element="viewHistorySidebar" attribute="checked"/>
-        </toolbarbutton>
-        <toolbarbutton id="appMenuClearRecentHistory"
-                       label="&appMenuHistory.clearRecent.label;"
-                       class="subviewbutton subviewbutton-iconic"
-                       command="Tools:Sanitize"/>
-        <toolbarseparator/>
-        <toolbarbutton id="appMenuRecentlyClosedTabs"
-                       label="&historyUndoMenu.label;"
-                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
-                       closemenu="none"
-                       oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedTabs', this)"/>
-        <toolbarbutton id="appMenuRecentlyClosedWindows"
-                       label="&historyUndoWindowMenu.label;"
-                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
-                       closemenu="none"
-                       oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedWindows', this)"/>
-        <toolbarseparator/>
-        <label value="&appMenuHistory.recentHistory.label;"
-               class="subview-subheader"/>
-        <toolbaritem id="appMenu_historyMenu"
-                     orient="vertical"
-                     smoothscroll="false"
-                     flatList="true"
-                     tooltip="bhTooltip">
-          <!-- history menu items will go here -->
-        </toolbaritem>
-      </vbox>
-      <toolbarbutton id="PanelUI-historyMore"
-                     class="panel-subview-footer subviewbutton"
-                     label="&appMenuHistory.showAll.label;"
-                     oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/>
-    </panelview>
-
-    <panelview id="appMenu-library-recentlyClosedTabs"/>
-    <panelview id="appMenu-library-recentlyClosedWindows"/>
-
-    <panelview id="PanelUI-remotetabs" flex="1" class="PanelUI-subView"
-               descriptionheightworkaround="true">
-      <vbox class="panel-subview-body">
-        <!-- this widget has 3 boxes in the body, but only 1 is ever visible -->
-        <!-- When Sync is ready to sync -->
-        <vbox id="PanelUI-remotetabs-main" observes="sync-syncnow-state">
-          <vbox id="PanelUI-remotetabs-buttons">
-            <toolbarbutton id="PanelUI-remotetabs-view-sidebar"
-                           class="subviewbutton subviewbutton-iconic"
-                           observes="viewTabsSidebar"
-                           label="&appMenuRemoteTabs.sidebar.label;"/>
-            <toolbarbutton id="PanelUI-remotetabs-view-managedevices"
-                           class="subviewbutton subviewbutton-iconic"
-                           label="&appMenuRemoteTabs.managedevices.label;"
-                           oncommand="gSync.openDevicesManagementPage('syncedtabs-menupanel');"/>
-            <toolbarbutton id="PanelUI-remotetabs-syncnow"
-                           observes="sync-status"
-                           class="subviewbutton subviewbutton-iconic"
-                           oncommand="gSync.doSync();"
-                           closemenu="none"/>
-            <menuseparator id="PanelUI-remotetabs-separator"/>
-          </vbox>
-          <deck id="PanelUI-remotetabs-deck">
-            <!-- Sync is ready to Sync and the "tabs" engine is enabled -->
-            <vbox id="PanelUI-remotetabs-tabspane">
-              <vbox id="PanelUI-remotetabs-tabslist"
-                    showAllLabel="&appMenuRemoteTabs.showAll.label;"
-                    showAllTooltipText="&appMenuRemoteTabs.showAll.tooltip;"
-                    showMoreLabel="&appMenuRemoteTabs.showMore.label;"
-                    showMoreTooltipText="&appMenuRemoteTabs.showMore.tooltip;"
-                    notabsforclientlabel="&appMenuRemoteTabs.notabs.label;"
-                    />
-            </vbox>
-            <!-- Sync is ready to Sync but the "tabs" engine isn't enabled-->
-            <hbox id="PanelUI-remotetabs-tabsdisabledpane" pack="center" flex="1">
-              <vbox class="PanelUI-remotetabs-instruction-box" align="center">
-                <hbox pack="center">
-                  <image class="fxaSyncIllustration"/>
-                </hbox>
-                <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label>
-                <hbox pack="center">
-                  <toolbarbutton class="PanelUI-remotetabs-prefs-button"
-                                 label="&appMenuRemoteTabs.openprefs.label;"
-                                 oncommand="gSync.openPrefs('synced-tabs');"/>
-                </hbox>
-              </vbox>
-            </hbox>
-            <!-- Sync is ready to Sync but we are still fetching the tabs to show -->
-            <vbox id="PanelUI-remotetabs-fetching">
-              <!-- Show intentionally blank panel, see bug 1239845 -->
-            </vbox>
-            <!-- Sync has only 1 (ie, this) device connected -->
-            <hbox id="PanelUI-remotetabs-nodevicespane" pack="center" flex="1">
-              <vbox class="PanelUI-remotetabs-instruction-box">
-                <hbox pack="center">
-                  <image class="fxaSyncIllustration"/>
-                </hbox>
-                <label class="PanelUI-remotetabs-instruction-title">&appMenuRemoteTabs.noclients.title;</label>
-                <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.noclients.subtitle;</label>
-                <!-- The inner HTML for PanelUI-remotetabs-mobile-promo is built at runtime -->
-                <label id="PanelUI-remotetabs-mobile-promo" fxAccountsBrand="&syncBrand.fxAccount.label;"/>
-              </vbox>
-            </hbox>
-          </deck>
-        </vbox>
-        <!-- a box to ensure contained boxes are centered horizonally -->
-        <hbox pack="center" flex="1">
-          <!-- When Sync is not configured -->
-          <vbox id="PanelUI-remotetabs-setupsync"
-                flex="1"
-                align="center"
-                class="PanelUI-remotetabs-instruction-box"
-                observes="sync-setup-state">
-            <image class="fxaSyncIllustration"/>
-            <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
-            <toolbarbutton class="PanelUI-remotetabs-prefs-button"
-                           label="&appMenuRemoteTabs.signin.label;"
-                           oncommand="gSync.openPrefs('synced-tabs');"/>
-          </vbox>
-          <!-- When Sync needs re-authentication. This uses the exact same messaging
-               as "Sync is not configured" but remains a separate box so we get
-               the goodness of observing broadcasters to manage the hidden states -->
-          <vbox id="PanelUI-remotetabs-reauthsync"
-                flex="1"
-                align="center"
-                class="PanelUI-remotetabs-instruction-box"
-                observes="sync-reauth-state">
-            <image class="fxaSyncIllustration"/>
-            <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
-            <toolbarbutton class="PanelUI-remotetabs-prefs-button"
-                           label="&appMenuRemoteTabs.signin.label;"
-                           oncommand="gSync.openPrefs('synced-tabs');"/>
-          </vbox>
-        </hbox>
-      </vbox>
-    </panelview>
-
-    <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView">
-      <vbox class="panel-subview-body">
-        <toolbarbutton id="panelMenuBookmarkThisPage"
-                       class="subviewbutton subviewbutton-iconic"
-                       observes="bookmarkThisPageBroadcaster"
-                       command="Browser:AddBookmarkAs"
-                       onclick="PanelUI.hide();"/>
-        <toolbarbutton id="panelMenu_bookmarkingTools"
-                       label="&bookmarkingTools.label;"
-                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
-                       closemenu="none"
-                       oncommand="BookmarkingUI.showBookmarkingTools(this);"/>
-        <toolbarbutton id="panelMenu_searchBookmarks"
-                       label="&searchBookmarks.label;"
-                       class="subviewbutton subviewbutton-iconic"
-                       oncommand="PlacesCommandHook.searchBookmarks(); PanelUI.hide();"/>
-        <toolbarseparator/>
-        <label id="panelMenu_recentBookmarks"
-               value="&recentBookmarks.label;"
-               class="subview-subheader"/>
-        <toolbaritem id="panelMenu_bookmarksMenu"
-                     orient="vertical"
-                     smoothscroll="false"
-                     flatList="true"
-                     tooltip="bhTooltip">
-          <!-- bookmarks menu items will go here -->
-        </toolbaritem>
-      </vbox>
-      <toolbarbutton id="panelMenu_showAllBookmarks"
-                     label="&showAllBookmarks2.label;"
-                     class="subviewbutton panel-subview-footer"
-                     command="Browser:ShowAllBookmarks"
-                     onclick="PanelUI.hide();"/>
-    </panelview>
-
-    <panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);">
-    </panelview>
-
-    <panelview id="PanelUI-containers" flex="1">
-      <vbox id="PanelUI-containersItems"/>
-    </panelview>
-
-    <panelview id="PanelUI-helpView" flex="1" class="PanelUI-subView">
-      <vbox id="PanelUI-helpItems" class="panel-subview-body"/>
-    </panelview>
-
-    <panelview id="PanelUI-developer" flex="1">
-      <vbox id="PanelUI-developerItems" class="panel-subview-body"/>
-    </panelview>
-
-    <panelview id="PanelUI-characterEncodingView" flex="1">
-      <vbox class="panel-subview-body">
-        <vbox id="PanelUI-characterEncodingView-pinned"
-              class="PanelUI-characterEncodingView-list"/>
-        <toolbarseparator/>
-        <vbox id="PanelUI-characterEncodingView-charsets"
-              class="PanelUI-characterEncodingView-list"/>
-        <toolbarseparator/>
-        <vbox>
-          <label id="PanelUI-characterEncodingView-autodetect-label"/>
-          <vbox id="PanelUI-characterEncodingView-autodetect"
-                class="PanelUI-characterEncodingView-list"/>
-        </vbox>
-      </vbox>
-    </panelview>
-
-    <panelview id="PanelUI-panicView" flex="1"
-               descriptionheightworkaround="true">
-      <vbox class="panel-subview-body">
-        <hbox id="PanelUI-panic-timeframe">
-          <image id="PanelUI-panic-timeframe-icon" alt=""/>
-          <vbox flex="1">
-            <hbox id="PanelUI-panic-header">
-              <image id="PanelUI-panic-timeframe-icon-small" alt=""/>
-              <description id="PanelUI-panic-mainDesc" flex="1">&panicButton.view.mainTimeframeDesc;</description>
-            </hbox>
-            <radiogroup id="PanelUI-panic-timeSpan" aria-labelledby="PanelUI-panic-mainDesc" closemenu="none">
-              <radio id="PanelUI-panic-5min" label="&panicButton.view.5min;" selected="true"
-                     value="5" class="subviewradio"/>
-              <radio id="PanelUI-panic-2hr" label="&panicButton.view.2hr;"
-                     value="2" class="subviewradio"/>
-              <radio id="PanelUI-panic-day" label="&panicButton.view.day;"
-                     value="6" class="subviewradio"/>
-            </radiogroup>
-          </vbox>
-        </hbox>
-        <vbox id="PanelUI-panic-explanations">
-          <label id="PanelUI-panic-actionlist-main-label">&panicButton.view.mainActionDesc;</label>
-
-          <label id="PanelUI-panic-actionlist-windows" class="PanelUI-panic-actionlist">&panicButton.view.deleteTabsAndWindows;</label>
-          <label id="PanelUI-panic-actionlist-cookies" class="PanelUI-panic-actionlist">&panicButton.view.deleteCookies;</label>
-          <label id="PanelUI-panic-actionlist-history" class="PanelUI-panic-actionlist">&panicButton.view.deleteHistory;</label>
-          <label id="PanelUI-panic-actionlist-newwindow" class="PanelUI-panic-actionlist">&panicButton.view.openNewWindow;</label>
-
-          <label id="PanelUI-panic-warning">&panicButton.view.undoWarning;</label>
-        </vbox>
-        <button id="PanelUI-panic-view-button"
-                label="&panicButton.view.forgetButton;"/>
-      </vbox>
-    </panelview>
-
-  </panelmultiview>
-
-</panel>
-
 <panel id="widget-overflow"
        role="group"
        type="arrow"
        noautofocus="true"
        position="bottomcenter topright"
        photon="true"
        hidden="true">
   <photonpanelmultiview mainViewId="widget-overflow-mainView" disablekeynav="true">
@@ -670,16 +347,259 @@
 #else
                        label="&quitApplicationCmd.label;"
 #endif
                        key="key_quitApplication"
                        command="cmd_quitApplication"/>
 #endif
       </vbox>
     </panelview>
+    <panelview id="PanelUI-history" flex="1">
+      <vbox class="panel-subview-body">
+        <toolbarbutton id="appMenuViewHistorySidebar"
+                       label="&appMenuHistory.viewSidebar.label;"
+                       type="checkbox"
+                       class="subviewbutton subviewbutton-iconic"
+                       key="key_gotoHistory"
+                       oncommand="SidebarUI.toggle('viewHistorySidebar'); PanelUI.hide();">
+          <observes element="viewHistorySidebar" attribute="checked"/>
+        </toolbarbutton>
+        <toolbarbutton id="appMenuClearRecentHistory"
+                       label="&appMenuHistory.clearRecent.label;"
+                       class="subviewbutton subviewbutton-iconic"
+                       command="Tools:Sanitize"/>
+        <toolbarseparator/>
+        <toolbarbutton id="appMenuRecentlyClosedTabs"
+                       label="&historyUndoMenu.label;"
+                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
+                       closemenu="none"
+                       oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedTabs', this)"/>
+        <toolbarbutton id="appMenuRecentlyClosedWindows"
+                       label="&historyUndoWindowMenu.label;"
+                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
+                       closemenu="none"
+                       oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedWindows', this)"/>
+        <toolbarseparator/>
+        <label value="&appMenuHistory.recentHistory.label;"
+               class="subview-subheader"/>
+        <toolbaritem id="appMenu_historyMenu"
+                     orient="vertical"
+                     smoothscroll="false"
+                     flatList="true"
+                     tooltip="bhTooltip">
+          <!-- history menu items will go here -->
+        </toolbaritem>
+      </vbox>
+      <toolbarbutton id="PanelUI-historyMore"
+                     class="panel-subview-footer subviewbutton"
+                     label="&appMenuHistory.showAll.label;"
+                     oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/>
+    </panelview>
+
+    <panelview id="appMenu-library-recentlyClosedTabs"/>
+    <panelview id="appMenu-library-recentlyClosedWindows"/>
+
+    <panelview id="PanelUI-remotetabs" flex="1" class="PanelUI-subView"
+               descriptionheightworkaround="true">
+      <vbox class="panel-subview-body">
+        <!-- this widget has 3 boxes in the body, but only 1 is ever visible -->
+        <!-- When Sync is ready to sync -->
+        <vbox id="PanelUI-remotetabs-main" observes="sync-syncnow-state">
+          <vbox id="PanelUI-remotetabs-buttons">
+            <toolbarbutton id="PanelUI-remotetabs-view-sidebar"
+                           class="subviewbutton subviewbutton-iconic"
+                           observes="viewTabsSidebar"
+                           label="&appMenuRemoteTabs.sidebar.label;"/>
+            <toolbarbutton id="PanelUI-remotetabs-view-managedevices"
+                           class="subviewbutton subviewbutton-iconic"
+                           label="&appMenuRemoteTabs.managedevices.label;"
+                           oncommand="gSync.openDevicesManagementPage('syncedtabs-menupanel');"/>
+            <toolbarbutton id="PanelUI-remotetabs-syncnow"
+                           observes="sync-status"
+                           class="subviewbutton subviewbutton-iconic"
+                           oncommand="gSync.doSync();"
+                           closemenu="none"/>
+            <menuseparator id="PanelUI-remotetabs-separator"/>
+          </vbox>
+          <deck id="PanelUI-remotetabs-deck">
+            <!-- Sync is ready to Sync and the "tabs" engine is enabled -->
+            <vbox id="PanelUI-remotetabs-tabspane">
+              <vbox id="PanelUI-remotetabs-tabslist"
+                    showAllLabel="&appMenuRemoteTabs.showAll.label;"
+                    showAllTooltipText="&appMenuRemoteTabs.showAll.tooltip;"
+                    showMoreLabel="&appMenuRemoteTabs.showMore.label;"
+                    showMoreTooltipText="&appMenuRemoteTabs.showMore.tooltip;"
+                    notabsforclientlabel="&appMenuRemoteTabs.notabs.label;"
+                    />
+            </vbox>
+            <!-- Sync is ready to Sync but the "tabs" engine isn't enabled-->
+            <hbox id="PanelUI-remotetabs-tabsdisabledpane" pack="center" flex="1">
+              <vbox class="PanelUI-remotetabs-instruction-box" align="center">
+                <hbox pack="center">
+                  <image class="fxaSyncIllustration"/>
+                </hbox>
+                <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label>
+                <hbox pack="center">
+                  <toolbarbutton class="PanelUI-remotetabs-prefs-button"
+                                 label="&appMenuRemoteTabs.openprefs.label;"
+                                 oncommand="gSync.openPrefs('synced-tabs');"/>
+                </hbox>
+              </vbox>
+            </hbox>
+            <!-- Sync is ready to Sync but we are still fetching the tabs to show -->
+            <vbox id="PanelUI-remotetabs-fetching">
+              <!-- Show intentionally blank panel, see bug 1239845 -->
+            </vbox>
+            <!-- Sync has only 1 (ie, this) device connected -->
+            <hbox id="PanelUI-remotetabs-nodevicespane" pack="center" flex="1">
+              <vbox class="PanelUI-remotetabs-instruction-box">
+                <hbox pack="center">
+                  <image class="fxaSyncIllustration"/>
+                </hbox>
+                <label class="PanelUI-remotetabs-instruction-title">&appMenuRemoteTabs.noclients.title;</label>
+                <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.noclients.subtitle;</label>
+                <!-- The inner HTML for PanelUI-remotetabs-mobile-promo is built at runtime -->
+                <label id="PanelUI-remotetabs-mobile-promo" fxAccountsBrand="&syncBrand.fxAccount.label;"/>
+              </vbox>
+            </hbox>
+          </deck>
+        </vbox>
+        <!-- a box to ensure contained boxes are centered horizonally -->
+        <hbox pack="center" flex="1">
+          <!-- When Sync is not configured -->
+          <vbox id="PanelUI-remotetabs-setupsync"
+                flex="1"
+                align="center"
+                class="PanelUI-remotetabs-instruction-box"
+                observes="sync-setup-state">
+            <image class="fxaSyncIllustration"/>
+            <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
+            <toolbarbutton class="PanelUI-remotetabs-prefs-button"
+                           label="&appMenuRemoteTabs.signin.label;"
+                           oncommand="gSync.openPrefs('synced-tabs');"/>
+          </vbox>
+          <!-- When Sync needs re-authentication. This uses the exact same messaging
+               as "Sync is not configured" but remains a separate box so we get
+               the goodness of observing broadcasters to manage the hidden states -->
+          <vbox id="PanelUI-remotetabs-reauthsync"
+                flex="1"
+                align="center"
+                class="PanelUI-remotetabs-instruction-box"
+                observes="sync-reauth-state">
+            <image class="fxaSyncIllustration"/>
+            <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
+            <toolbarbutton class="PanelUI-remotetabs-prefs-button"
+                           label="&appMenuRemoteTabs.signin.label;"
+                           oncommand="gSync.openPrefs('synced-tabs');"/>
+          </vbox>
+        </hbox>
+      </vbox>
+    </panelview>
+
+    <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView">
+      <vbox class="panel-subview-body">
+        <toolbarbutton id="panelMenuBookmarkThisPage"
+                       class="subviewbutton subviewbutton-iconic"
+                       observes="bookmarkThisPageBroadcaster"
+                       command="Browser:AddBookmarkAs"
+                       onclick="PanelUI.hide();"/>
+        <toolbarbutton id="panelMenu_bookmarkingTools"
+                       label="&bookmarkingTools.label;"
+                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
+                       closemenu="none"
+                       oncommand="BookmarkingUI.showBookmarkingTools(this);"/>
+        <toolbarbutton id="panelMenu_searchBookmarks"
+                       label="&searchBookmarks.label;"
+                       class="subviewbutton subviewbutton-iconic"
+                       oncommand="PlacesCommandHook.searchBookmarks(); PanelUI.hide();"/>
+        <toolbarseparator/>
+        <label id="panelMenu_recentBookmarks"
+               value="&recentBookmarks.label;"
+               class="subview-subheader"/>
+        <toolbaritem id="panelMenu_bookmarksMenu"
+                     orient="vertical"
+                     smoothscroll="false"
+                     flatList="true"
+                     tooltip="bhTooltip">
+          <!-- bookmarks menu items will go here -->
+        </toolbaritem>
+      </vbox>
+      <toolbarbutton id="panelMenu_showAllBookmarks"
+                     label="&showAllBookmarks2.label;"
+                     class="subviewbutton panel-subview-footer"
+                     command="Browser:ShowAllBookmarks"
+                     onclick="PanelUI.hide();"/>
+    </panelview>
+
+    <panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);">
+    </panelview>
+
+    <panelview id="PanelUI-containers" flex="1">
+      <vbox id="PanelUI-containersItems"/>
+    </panelview>
+
+    <panelview id="PanelUI-helpView" flex="1" class="PanelUI-subView">
+      <vbox id="PanelUI-helpItems" class="panel-subview-body"/>
+    </panelview>
+
+    <panelview id="PanelUI-developer" flex="1">
+      <vbox id="PanelUI-developerItems" class="panel-subview-body"/>
+    </panelview>
+
+    <panelview id="PanelUI-characterEncodingView" flex="1">
+      <vbox class="panel-subview-body">
+        <vbox id="PanelUI-characterEncodingView-pinned"
+              class="PanelUI-characterEncodingView-list"/>
+        <toolbarseparator/>
+        <vbox id="PanelUI-characterEncodingView-charsets"
+              class="PanelUI-characterEncodingView-list"/>
+        <toolbarseparator/>
+        <vbox>
+          <label id="PanelUI-characterEncodingView-autodetect-label"/>
+          <vbox id="PanelUI-characterEncodingView-autodetect"
+                class="PanelUI-characterEncodingView-list"/>
+        </vbox>
+      </vbox>
+    </panelview>
+
+    <panelview id="PanelUI-panicView" flex="1"
+               descriptionheightworkaround="true">
+      <vbox class="panel-subview-body">
+        <hbox id="PanelUI-panic-timeframe">
+          <image id="PanelUI-panic-timeframe-icon" alt=""/>
+          <vbox flex="1">
+            <hbox id="PanelUI-panic-header">
+              <image id="PanelUI-panic-timeframe-icon-small" alt=""/>
+              <description id="PanelUI-panic-mainDesc" flex="1">&panicButton.view.mainTimeframeDesc;</description>
+            </hbox>
+            <radiogroup id="PanelUI-panic-timeSpan" aria-labelledby="PanelUI-panic-mainDesc" closemenu="none">
+              <radio id="PanelUI-panic-5min" label="&panicButton.view.5min;" selected="true"
+                     value="5" class="subviewradio"/>
+              <radio id="PanelUI-panic-2hr" label="&panicButton.view.2hr;"
+                     value="2" class="subviewradio"/>
+              <radio id="PanelUI-panic-day" label="&panicButton.view.day;"
+                     value="6" class="subviewradio"/>
+            </radiogroup>
+          </vbox>
+        </hbox>
+        <vbox id="PanelUI-panic-explanations">
+          <label id="PanelUI-panic-actionlist-main-label">&panicButton.view.mainActionDesc;</label>
+
+          <label id="PanelUI-panic-actionlist-windows" class="PanelUI-panic-actionlist">&panicButton.view.deleteTabsAndWindows;</label>
+          <label id="PanelUI-panic-actionlist-cookies" class="PanelUI-panic-actionlist">&panicButton.view.deleteCookies;</label>
+          <label id="PanelUI-panic-actionlist-history" class="PanelUI-panic-actionlist">&panicButton.view.deleteHistory;</label>
+          <label id="PanelUI-panic-actionlist-newwindow" class="PanelUI-panic-actionlist">&panicButton.view.openNewWindow;</label>
+
+          <label id="PanelUI-panic-warning">&panicButton.view.undoWarning;</label>
+        </vbox>
+        <button id="PanelUI-panic-view-button"
+                label="&panicButton.view.forgetButton;"/>
+      </vbox>
+    </panelview>
+
     <panelview id="appMenu-moreView" title="&moreMenu.label;" class="PanelUI-subView">
       <vbox class="panel-subview-body">
         <toolbarbutton id="appMenu-characterencoding-button"
                        class="subviewbutton subviewbutton-nav"
                        label="&charsetMenu2.label;"
                        closemenu="none"
                        oncommand="PanelUI.showSubView('PanelUI-characterEncodingView', this)"/>
         <toolbarbutton id="appMenu-workoffline-button"
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -36,19 +36,16 @@ skip-if = os == "linux"
 
 [browser_914138_widget_API_overflowable_toolbar.js]
 skip-if = os == "linux"
 
 [browser_918049_skipintoolbarset_dnd.js]
 [browser_923857_customize_mode_event_wrapping_during_reset.js]
 [browser_927717_customize_drag_empty_toolbar.js]
 
-[browser_932928_show_notice_when_palette_empty.js]
-disabled=Bug 1163231 - Fails on all platforms
-
 [browser_934113_menubar_removable.js]
 # Because this test is about the menubar, it can't be run on mac
 skip-if = os == "mac"
 
 [browser_934951_zoom_in_toolbar.js]
 [browser_938980_navbar_collapsed.js]
 [browser_938995_indefaultstate_nonremovable.js]
 [browser_940013_registerToolbarNode_calls_registerArea.js]
deleted file mode 100644
--- a/browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-// There should be an advert to get more addons when the palette is empty.
-add_task(async function() {
-  await startCustomizing();
-  let visiblePalette = document.getElementById("customization-palette");
-  let emptyPaletteNotice = document.getElementById("customization-empty");
-  is(emptyPaletteNotice.hidden, true, "The empty palette notice should not be shown when there are items in the palette.");
-
-  while (visiblePalette.childElementCount) {
-    gCustomizeMode.addToToolbar(visiblePalette.children[0]);
-  }
-  is(visiblePalette.childElementCount, 0, "There shouldn't be any items remaining in the visible palette.");
-  is(emptyPaletteNotice.hidden, false, "The empty palette notice should be shown when there are no items in the palette.");
-
-  await endCustomizing();
-  await startCustomizing();
-  visiblePalette = document.getElementById("customization-palette");
-  emptyPaletteNotice = document.getElementById("customization-empty");
-  is(emptyPaletteNotice.hidden, false,
-     "The empty palette notice should be shown when there are no items in the palette and cust. mode is re-entered.");
-
-  gCustomizeMode.removeFromArea(document.getElementById("wrapper-home-button"));
-  is(emptyPaletteNotice.hidden, true,
-     "The empty palette notice should not be shown when there is at least one item in the palette.");
-});
-
-add_task(async function asyncCleanup() {
-  await endCustomizing();
-  await resetCustomization();
-});
--- a/browser/components/customizableui/test/browser_switch_to_customize_mode.js
+++ b/browser/components/customizableui/test/browser_switch_to_customize_mode.js
@@ -23,12 +23,10 @@ add_task(async function() {
   is(newKidCount, paletteKidCount, "Should have just as many items in the palette as before.");
   await endCustomizing();
   is(startedCount, 1, "Should have only started once");
   gNavToolbox.removeEventListener("customizationstarting", handler);
   let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true])");
   for (let toolbar of customizableToolbars) {
     ok(!toolbar.hasAttribute("customizing"), "Toolbar " + toolbar.id + " is no longer customizing");
   }
-  let menuitem = document.getElementById("PanelUI-customize");
-  isnot(menuitem.getAttribute("label"), menuitem.getAttribute("exitLabel"), "Should have exited successfully");
 });
 
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -62,17 +62,17 @@ this.pageAction = class extends Extensio
     this.defaults.icon = await StartupCache.get(
       extension, ["pageAction", "default_icon"],
       () => IconDetails.normalize({path: options.default_icon}, extension));
 
     if (!this.browserPageAction) {
       this.browserPageAction = PageActions.addAction(new PageActions.Action({
         id: widgetId,
         title: this.defaults.title,
-        iconURL: this.defaults.icon,
+        iconURL: this.getIconData(this.defaults.icon),
         shownInUrlbar: true,
         disabled: true,
         onCommand: (event, buttonNode) => {
           this.handleClick(event.target.ownerGlobal);
         },
         onBeforePlacedInWindow: browserWindow => {
           if (this.extension.hasPermission("menus") ||
               this.extension.hasPermission("contextMenus")) {
@@ -132,24 +132,33 @@ this.pageAction = class extends Extensio
     this.browserPageAction.setTitle(title, window);
     this.browserPageAction.setTooltip(title, window);
     this.browserPageAction.setDisabled(!tabData.show, window);
 
     let iconURL;
     if (typeof(tabData.icon) == "string") {
       iconURL = IconDetails.escapeUrl(tabData.icon);
     } else {
-      iconURL = Object.entries(tabData.icon).reduce((memo, [size, url]) => {
-        memo[size] = IconDetails.escapeUrl(url);
-        return memo;
-      }, {});
+      iconURL = this.getIconData(tabData.icon);
     }
     this.browserPageAction.setIconURL(iconURL, window);
   }
 
+  getIconData(icons) {
+    let getIcon = size => {
+      let {icon} = IconDetails.getPreferredIcon(icons, this.extension, size);
+      // TODO: implement theme based icon for pageAction (Bug 1398156)
+      return IconDetails.escapeUrl(icon);
+    };
+    return {
+      "16": getIcon(16),
+      "32": getIcon(32),
+    };
+  }
+
   /**
    * Triggers this page action for the given window, with the same effects as
    * if it were clicked by a user.
    *
    * This has no effect if the page action is hidden for the selected tab.
    *
    * @param {Window} window
    */
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js
@@ -259,26 +259,30 @@ add_task(async function testDetailsObjec
   const RESOLUTION_PREF = "layout.css.devPixelsPerPx";
 
   await extension.startup();
 
   let pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
   let browserActionWidget = getBrowserActionWidget(extension);
 
   let tests = await extension.awaitMessage("ready");
+
+  // The initial icon should be the default icon since no icon is in the manifest.
+  const DEFAULT_ICON = "chrome://browser/content/extension.svg";
+  let browserActionButton = browserActionWidget.forWindow(window).node;
+  let pageActionImage = document.getElementById(pageActionId);
+  is(getListStyleImage(browserActionButton), DEFAULT_ICON, `browser action has the correct default image`);
+  is(getListStyleImage(pageActionImage), DEFAULT_ICON, `page action has the correct default image`);
+
   for (let test of tests) {
     extension.sendMessage("setIcon", test);
     await extension.awaitMessage("iconSet");
 
     await promiseAnimationFrame();
 
-    let browserActionButton = browserActionWidget.forWindow(window).node;
-    let pageActionImage = document.getElementById(pageActionId);
-
-
     // Test icon sizes in the toolbar/urlbar.
     for (let resolution of Object.keys(test.resolutions)) {
       await SpecialPowers.pushPrefEnv({set: [[RESOLUTION_PREF, resolution]]});
 
       is(window.devicePixelRatio, +resolution, "window has the required resolution");
 
       let imageURL = test.resolutions[resolution];
       is(getListStyleImage(browserActionButton), imageURL, `browser action has the correct image at ${resolution}x resolution`);
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1,21 +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/. */
 
 /* import-globals-from preferences.js */
 /* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
 /* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
 
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
-                                  "resource://gre/modules/ExtensionSettingsStore.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
-                                  "resource://gre/modules/AddonManager.jsm");
-
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/Downloads.jsm");
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource:///modules/ShellService.jsm");
 Components.utils.import("resource:///modules/TransientPrefs.jsm");
 Components.utils.import("resource://gre/modules/AppConstants.jsm");
 Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
 Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
@@ -36,16 +31,23 @@ const PREF_DISABLED_PLUGIN_TYPES = "plug
 // Pref for when containers is being controlled
 const PREF_CONTAINERS_EXTENSION = "privacy.userContext.extension";
 
 // Preferences that affect which entries to show in the list.
 const PREF_SHOW_PLUGINS_IN_LIST = "browser.download.show_plugins_in_list";
 const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
   "browser.download.hide_plugins_without_extensions";
 
+// Strings to identify ExtensionSettingsStore overrides
+const PREF_SETTING_TYPE = "prefs";
+const CONTAINERS_KEY = "privacy.containers";
+const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
+const URL_OVERRIDES_TYPE = "url_overrides";
+const NEW_TAB_KEY = "newTabURL";
+
 /*
  * Preferences where we store handling information about the feed type.
  *
  * browser.feeds.handler
  * - "bookmarks", "reader" (clarified further using the .default preference),
  *   or "ask" -- indicates the default handler being used to process feeds;
  *   "bookmarks" is obsolete; to specify that the handler is bookmarks,
  *   set browser.feeds.handler.default to "bookmarks";
@@ -213,20 +215,20 @@ var gMainPane = {
     this.updatePerformanceSettingsBox({ duringChangeEvent: false });
 
     // set up the "use current page" label-changing listener
     this._updateUseCurrentButton();
     window.addEventListener("focus", this._updateUseCurrentButton.bind(this));
 
     this.updateBrowserStartupLastSession();
 
-    handleControllingExtension("url_overrides", "newTabURL");
+    handleControllingExtension(URL_OVERRIDES_TYPE, NEW_TAB_KEY);
     let newTabObserver = {
       observe(subject, topic, data) {
-          handleControllingExtension("url_overrides", "newTabURL");
+          handleControllingExtension(URL_OVERRIDES_TYPE, NEW_TAB_KEY);
       },
     };
     Services.obs.addObserver(newTabObserver, "newtab-url-changed");
     window.addEventListener("unload", () => {
       Services.obs.removeObserver(newTabObserver, "newtab-url-changed");
     });
 
     if (AppConstants.platform == "win") {
@@ -255,21 +257,21 @@ var gMainPane = {
     }
     setEventListener("useCurrent", "command",
       gMainPane.setHomePageToCurrent);
     setEventListener("useBookmark", "command",
       gMainPane.setHomePageToBookmark);
     setEventListener("restoreDefaultHomePage", "command",
       gMainPane.restoreDefaultHomePage);
     setEventListener("disableHomePageExtension", "command",
-                     gMainPane.makeDisableControllingExtension("prefs", "homepage_override"));
+                     makeDisableControllingExtension(PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY));
     setEventListener("disableContainersExtension", "command",
-                     gMainPane.makeDisableControllingExtension("prefs", "privacy.containers"));
+                     makeDisableControllingExtension(PREF_SETTING_TYPE, CONTAINERS_KEY));
     setEventListener("disableNewTabExtension", "command",
-                     gMainPane.makeDisableControllingExtension("url_overrides", "newTabURL"));
+                     makeDisableControllingExtension(URL_OVERRIDES_TYPE, NEW_TAB_KEY));
     setEventListener("chooseLanguage", "command",
       gMainPane.showLanguages);
     setEventListener("translationAttributionImage", "click",
       gMainPane.openTranslationProviderAttribution);
     setEventListener("translateButton", "command",
       gMainPane.showTranslationExceptions);
     setEventListener("font.language.group", "change",
       gMainPane._rebuildFonts);
@@ -479,17 +481,17 @@ var gMainPane = {
   readBrowserContainersCheckbox() {
     const pref = document.getElementById("privacy.userContext.enabled");
     const settings = document.getElementById("browserContainersSettings");
 
     settings.disabled = !pref.value;
     const containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
     const containersCheckbox = document.getElementById("browserContainersCheckbox");
     containersCheckbox.checked = containersEnabled;
-    handleControllingExtension("prefs", "privacy.containers")
+    handleControllingExtension(PREF_SETTING_TYPE, CONTAINERS_KEY)
       .then((isControlled) => {
         containersCheckbox.disabled = isControlled;
       });
   },
 
   /**
    * Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
    */
@@ -611,21 +613,21 @@ var gMainPane = {
         .forEach((element) => {
           let isLocked = document.getElementById(element.getAttribute("preference")).locked;
           element.disabled = isLocked || isControlled;
         });
     }
 
     if (homePref.locked) {
       // An extension can't control these settings if they're locked.
-      hideControllingExtension("homepage_override");
+      hideControllingExtension(HOMEPAGE_OVERRIDE_KEY);
       setInputDisabledStates(false);
     } else {
       // Asynchronously update the extension controlled UI.
-      handleControllingExtension("prefs", "homepage_override")
+      handleControllingExtension(PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY)
         .then(setInputDisabledStates);
     }
 
     // If the pref is set to about:home or about:newtab, set the value to ""
     // to show the placeholder text (about:home title) rather than
     // exposing those URLs to users.
     let defaultBranch = Services.prefs.getDefaultBranch("");
     let defaultValue = defaultBranch.getComplexValue("browser.startup.homepage",
@@ -724,17 +726,17 @@ var gMainPane = {
     let tabs = this._getTabsForHomePage();
 
     if (tabs.length > 1)
       useCurrent.label = useCurrent.getAttribute("label2");
     else
       useCurrent.label = useCurrent.getAttribute("label1");
 
     // If the homepage is controlled by an extension then you can't use this.
-    if (await getControllingExtensionId("prefs", "homepage_override")) {
+    if (await getControllingExtensionInfo(PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY)) {
       useCurrent.disabled = true;
       return;
     }
 
     // In this case, the button's disabled state is set by preferences.xml.
     let prefName = "pref.browser.homepage.disable_button.current_page";
     if (document.getElementById(prefName).locked)
       return;
@@ -770,24 +772,16 @@ var gMainPane = {
   /**
    * Restores the default home page as the user's home page.
    */
   restoreDefaultHomePage() {
     var homePage = document.getElementById("browser.startup.homepage");
     homePage.value = homePage.defaultValue;
   },
 
-  makeDisableControllingExtension(type, settingName) {
-    return async function disableExtension() {
-      let id = await getControllingExtensionId(type, settingName);
-      let addon = await AddonManager.getAddonByID(id);
-      addon.userDisabled = true;
-    };
-  },
-
   /**
    * Utility function to enable/disable the button specified by aButtonID based
    * on the value of the Boolean preference specified by aPreferenceID.
    */
   updateButtons(aButtonID, aPreferenceID) {
     var button = document.getElementById(aButtonID);
     var preference = document.getElementById(aPreferenceID);
     button.disabled = preference.value != true;
@@ -2584,85 +2578,16 @@ function getLocalHandlerApp(aFile) {
   var localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
     createInstance(Ci.nsILocalHandlerApp);
   localHandlerApp.name = getFileDisplayName(aFile);
   localHandlerApp.executable = aFile;
 
   return localHandlerApp;
 }
 
-let extensionControlledContentIds = {
-  "privacy.containers": "browserContainersExtensionContent",
-  "homepage_override": "browserHomePageExtensionContent",
-  "newTabURL": "browserNewTabExtensionContent",
-};
-
-/**
-  * Check if a pref is being managed by an extension.
-  */
-async function getControllingExtensionId(type, settingName) {
-  await ExtensionSettingsStore.initialize();
-  return ExtensionSettingsStore.getTopExtensionId(type, settingName);
-}
-
-function getControllingExtensionEl(settingName) {
-  return document.getElementById(extensionControlledContentIds[settingName]);
-}
-
-async function handleControllingExtension(type, settingName) {
-  let controllingExtensionId = await getControllingExtensionId(type, settingName);
-  let addon = controllingExtensionId
-    && await AddonManager.getAddonByID(controllingExtensionId);
-
-  // Sometimes the ExtensionSettingsStore gets in a bad state where it thinks
-  // an extension is controlling a setting but the extension has been uninstalled
-  // outside of the regular lifecycle. If the extension isn't currently installed
-  // then we should treat the setting as not being controlled.
-  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1411046 for an example.
-  if (addon) {
-    showControllingExtension(settingName, addon);
-  } else {
-    hideControllingExtension(settingName);
-  }
-
-  return !!addon;
-}
-
-async function showControllingExtension(settingName, addon) {
-  // Tell the user what extension is controlling the setting.
-  let extensionControlledContent = getControllingExtensionEl(settingName);
-  const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
-  let stringParts = document
-    .getElementById("bundlePreferences")
-    .getString(`extensionControlled.${settingName}`)
-    .split("%S");
-  let description = extensionControlledContent.querySelector("description");
-
-  // Remove the old content from the description.
-  while (description.firstChild) {
-    description.firstChild.remove();
-  }
-
-  // Populate the description.
-  description.appendChild(document.createTextNode(stringParts[0]));
-  let image = document.createElement("image");
-  image.setAttribute("src", addon.iconURL || defaultIcon);
-  image.classList.add("extension-controlled-icon");
-  description.appendChild(image);
-  description.appendChild(document.createTextNode(` ${addon.name}`));
-  description.appendChild(document.createTextNode(stringParts[1]));
-
-  // Show the controlling extension row and hide the old label.
-  extensionControlledContent.hidden = false;
-}
-
-function hideControllingExtension(settingName) {
-  getControllingExtensionEl(settingName).hidden = true;
-}
-
 /**
  * An enumeration of items in a JS array.
  *
  * FIXME: use ArrayConverter once it lands (bug 380839).
  *
  * @constructor
  */
 function ArrayEnumerator(aItems) {
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -18,16 +18,21 @@ var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
+                                  "resource://gre/modules/ExtensionSettingsStore.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                  "resource://gre/modules/AddonManager.jsm");
+
 var gLastHash = "";
 
 var gCategoryInits = new Map();
 function init_category_if_required(category) {
   let categoryInfo = gCategoryInits.get(category);
   if (!categoryInfo) {
     throw "Unknown in-content prefs category! Can't init " + category;
   }
@@ -317,8 +322,93 @@ function confirmRestartPrompt(aRestartTo
 function appendSearchKeywords(aId, keywords) {
   let element = document.getElementById(aId);
   let searchKeywords = element.getAttribute("searchkeywords");
   if (searchKeywords) {
     keywords.push(searchKeywords);
   }
   element.setAttribute("searchkeywords", keywords.join(" "));
 }
+
+let extensionControlledContentIds = {
+  "privacy.containers": "browserContainersExtensionContent",
+  "homepage_override": "browserHomePageExtensionContent",
+  "newTabURL": "browserNewTabExtensionContent",
+  "defaultSearch": "browserDefaultSearchExtensionContent",
+};
+
+/**
+  * Check if a pref is being managed by an extension.
+  */
+async function getControllingExtensionInfo(type, settingName) {
+  await ExtensionSettingsStore.initialize();
+  return ExtensionSettingsStore.getSetting(type, settingName);
+}
+
+function getControllingExtensionEl(settingName) {
+  return document.getElementById(extensionControlledContentIds[settingName]);
+}
+
+async function handleControllingExtension(type, settingName) {
+  let info = await getControllingExtensionInfo(type, settingName);
+  let addon = info && info.id
+    && await AddonManager.getAddonByID(info.id);
+
+  // Sometimes the ExtensionSettingsStore gets in a bad state where it thinks
+  // an extension is controlling a setting but the extension has been uninstalled
+  // outside of the regular lifecycle. If the extension isn't currently installed
+  // then we should treat the setting as not being controlled.
+  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1411046 for an example.
+  if (addon) {
+    showControllingExtension(settingName, addon);
+  } else {
+    hideControllingExtension(settingName);
+  }
+
+  return !!addon;
+}
+
+async function showControllingExtension(settingName, addon) {
+  // Tell the user what extension is controlling the setting.
+  let extensionControlledContent = getControllingExtensionEl(settingName);
+  extensionControlledContent.classList.remove("extension-controlled-disabled");
+  const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
+  let stringParts = document
+    .getElementById("bundlePreferences")
+    .getString(`extensionControlled.${settingName}`)
+    .split("%S");
+  let description = extensionControlledContent.querySelector("description");
+
+  // Remove the old content from the description.
+  while (description.firstChild) {
+    description.firstChild.remove();
+  }
+
+  // Populate the description.
+  description.appendChild(document.createTextNode(stringParts[0]));
+  let image = document.createElement("image");
+  image.setAttribute("src", addon.iconURL || defaultIcon);
+  image.classList.add("extension-controlled-icon");
+  description.appendChild(image);
+  description.appendChild(document.createTextNode(` ${addon.name}`));
+  description.appendChild(document.createTextNode(stringParts[1]));
+
+  let disableButton = extensionControlledContent.querySelector("button");
+  if (disableButton) {
+    disableButton.hidden = false;
+  }
+
+  // Show the controlling extension row and hide the old label.
+  extensionControlledContent.hidden = false;
+}
+
+function hideControllingExtension(settingName) {
+  getControllingExtensionEl(settingName).hidden = true;
+}
+
+
+function makeDisableControllingExtension(type, settingName) {
+  return async function disableExtension() {
+    let {id} = await getControllingExtensionInfo(type, settingName);
+    let addon = await AddonManager.getAddonByID(id);
+    addon.userDisabled = true;
+  };
+}
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -2,18 +2,22 @@
  * 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-globals-from preferences.js */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
+                                  "resource://gre/modules/ExtensionSettingsStore.jsm");
 
 const ENGINE_FLAVOR = "text/x-moz-search-engine";
+const SEARCH_TYPE = "default_search";
+const SEARCH_KEY = "defaultSearch";
 
 var gEngineView = null;
 
 var gSearchPane = {
 
   /**
    * Initialize autocomplete to ensure prefs are in sync.
    */
@@ -92,16 +96,27 @@ var gSearchPane = {
       item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
       if (e.iconURI) {
         item.setAttribute("image", e.iconURI.spec);
       }
       item.engine = e;
       if (e.name == currentEngine)
         list.selectedItem = item;
     });
+
+    handleControllingExtension(SEARCH_TYPE, SEARCH_KEY);
+    let searchEngineListener = {
+      observe(subject, topic, data) {
+        handleControllingExtension(SEARCH_TYPE, SEARCH_KEY);
+      },
+    };
+    Services.obs.addObserver(searchEngineListener, "browser-search-engine-modified");
+    window.addEventListener("unload", () => {
+      Services.obs.removeObserver(searchEngineListener, "browser-search-engine-modified");
+    });
   },
 
   handleEvent(aEvent) {
     switch (aEvent.type) {
       case "click":
         if (aEvent.target.id != "engineChildren" &&
             !aEvent.target.classList.contains("searchEngineAction")) {
           let engineList = document.getElementById("engineList");
@@ -302,16 +317,17 @@ var gSearchPane = {
     }
     document.getElementById("browser.search.hiddenOneOffs").value =
       hiddenList.join(",");
   },
 
   setDefaultEngine() {
     Services.search.currentEngine =
       document.getElementById("defaultEngine").selectedItem.engine;
+    ExtensionSettingsStore.setByUser(SEARCH_TYPE, SEARCH_KEY);
   }
 };
 
 function onDragEngineStart(event) {
   var selectedIndex = gEngineView.selectedIndex;
   var tree = document.getElementById("engineList");
   var row = { }, col = { }, child = { };
   tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, child);
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -39,24 +39,30 @@
         <image class="searchBarImage searchBarShownImage" role="presentation"/>
       </radiogroup>
     </groupbox>
 
     <!-- Default Search Engine -->
     <groupbox id="defaultEngineGroup" data-category="paneSearch">
       <caption><label>&defaultSearchEngine.label;</label></caption>
       <description>&chooseYourDefaultSearchEngine2.label;</description>
+
+      <hbox id="browserDefaultSearchExtensionContent" align="center" hidden="true">
+        <description control="disableDefaultSearchExtension" flex="1"/>
+      </hbox>
+
       <hbox>
         <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
         <hbox>
           <menulist id="defaultEngine">
             <menupopup/>
           </menulist>
         </hbox>
       </hbox>
+
       <checkbox id="suggestionsInSearchFieldsCheckbox"
                 label="&provideSearchSuggestions.label;"
                 accesskey="&provideSearchSuggestions.accesskey;"
                 preference="browser.search.suggest.enabled"/>
       <vbox class="indent">
         <checkbox id="urlBarSuggestion" label="&showURLBarSuggestions2.label;"
                   accesskey="&showURLBarSuggestions2.accesskey;"
                   preference="browser.urlbar.suggest.searches"/>
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -270,23 +270,118 @@ add_task(async function testExtensionCon
   is(controlledContent.hidden, false, "The extension controlled row is hidden");
 
   // Disable the extension.
   doc.getElementById("disableNewTabExtension").click();
 
   await waitForMessageHidden("browserNewTabExtensionContent");
 
   ok(!aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab page is set back to default");
-  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+  is(controlledContent.hidden, true, "The extension controlled row is shown");
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
   let addon = await AddonManager.getAddonByID("@set_newtab");
   addon.uninstall();
 });
 
+add_task(async function testExtensionControlledDefaultSearch() {
+  await openPreferencesViaOpenPreferencesAPI("paneSearch", {leaveOpen: true});
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
+  let doc = gBrowser.contentDocument;
+  let extensionId = "@set_default_search";
+  let manifest = {
+    manifest_version: 2,
+    name: "set_default_search",
+    applications: {gecko: {id: extensionId}},
+    description: "set_default_search description",
+    permissions: [],
+    chrome_settings_overrides: {
+      search_provider: {
+        name: "Yahoo",
+        search_url: "https://search.yahoo.com/yhs/search?p=%s&ei=UTF-8&hspart=mozilla&hsimp=yhs-002",
+        is_default: true,
+      },
+    }
+  };
+
+  function setEngine(engine) {
+    doc.querySelector(`#defaultEngine menuitem[label="${engine.name}"]`)
+       .doCommand();
+  }
+
+  is(gBrowser.currentURI.spec, "about:preferences#search",
+     "#search should be in the URI for about:preferences");
+
+  let controlledContent = doc.getElementById("browserDefaultSearchExtensionContent");
+  let initialEngine = Services.search.currentEngine;
+
+  // Ensure the controlled content is hidden when not controlled.
+  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+  // Install an extension that will set the default search engine.
+  let originalExtension = ExtensionTestUtils.loadExtension({
+    useAddonManager: "permanent",
+    manifest: Object.assign({}, manifest, {version: "1.0"}),
+  });
+
+  let messageShown = waitForMessageShown("browserDefaultSearchExtensionContent");
+  await originalExtension.startup();
+  await messageShown;
+
+  let addon = await AddonManager.getAddonByID(extensionId);
+  is(addon.version, "1.0", "The addon has the expected version.");
+
+  // The default search engine has been set by the extension and the user is notified.
+  let controlledLabel = controlledContent.querySelector("description");
+  let extensionEngine = Services.search.currentEngine;
+  ok(initialEngine != extensionEngine, "The default engine has changed.");
+  // There are two spaces before "set_default_search" because it's " <image /> set_default_search".
+  is(controlledLabel.textContent,
+     "An extension,  set_default_search, has set your default search engine.",
+     "The user is notified that an extension is controlling the default search engine");
+  is(controlledContent.hidden, false, "The extension controlled row is shown");
+
+  // Set the engine back to the initial one, ensure the message is hidden.
+  setEngine(initialEngine);
+  await waitForMessageHidden(controlledContent.id);
+
+  is(initialEngine, Services.search.currentEngine,
+     "default search engine is set back to default");
+  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+  // Setting the engine back to the extension's engine does not show the message.
+  setEngine(extensionEngine);
+
+  is(extensionEngine, Services.search.currentEngine,
+     "default search engine is set back to extension");
+  is(controlledContent.hidden, true, "The extension controlled row is still hidden");
+
+  // Set the engine to the initial one and verify an upgrade doesn't change it.
+  setEngine(initialEngine);
+  await waitForMessageHidden(controlledContent.id);
+
+  // Update the extension and wait for "ready".
+  let updatedExtension = ExtensionTestUtils.loadExtension({
+    useAddonManager: "permanent",
+    manifest: Object.assign({}, manifest, {version: "2.0"}),
+  });
+  await updatedExtension.startup();
+  addon = await AddonManager.getAddonByID(extensionId);
+
+  // Verify the extension is updated and search engine didn't change.
+  is(addon.version, "2.0", "The updated addon has the expected version");
+  is(controlledContent.hidden, true, "The extension controlled row is hidden after update");
+  is(initialEngine, Services.search.currentEngine,
+     "default search engine is still the initial engine after update");
+
+  await originalExtension.unload();
+  await updatedExtension.unload();
+  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
 add_task(async function testExtensionControlledHomepageUninstalledAddon() {
   async function checkHomepageEnabled() {
     await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
     // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = gBrowser.contentDocument;
     is(gBrowser.currentURI.spec, "about:preferences#general",
       "#general should be in the URI for about:preferences");
     let controlledContent = doc.getElementById("browserHomePageExtensionContent");
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -103,16 +103,17 @@ AutofillProfileAutoCompleteSearch.protot
     let isAddressField = FormAutofillUtils.isAddressField(info.fieldName);
     let handler = FormAutofillContent.getFormHandler(focusedInput);
     let allFieldNames = handler.allFieldNames;
     let filledRecordGUID = isAddressField ? handler.address.filledRecordGUID : handler.creditCard.filledRecordGUID;
     let searchPermitted = isAddressField ?
                           FormAutofillUtils.isAutofillAddressesEnabled :
                           FormAutofillUtils.isAutofillCreditCardsEnabled;
 
+    ProfileAutocomplete.lastProfileAutoCompleteFocusedInput = focusedInput;
     // Fallback to form-history if ...
     //   - specified autofill feature is pref off.
     //   - no profile can fill the currently-focused input.
     //   - the current form has already been populated.
     //   - (address only) less than 3 inputs are covered by all saved fields in the storage.
     if (!searchPermitted || !savedFieldNames.has(info.fieldName) || filledRecordGUID || (isAddressField &&
         allFieldNames.filter(field => savedFieldNames.has(field)).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD)) {
       if (focusedInput.autocomplete == "off") {
@@ -121,17 +122,17 @@ AutofillProfileAutoCompleteSearch.protot
         listener.onSearchResult(this, result);
         return;
       }
       let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"]
                           .createInstance(Ci.nsIAutoCompleteSearch);
       formHistory.startSearch(searchString, searchParam, previousResult, {
         onSearchResult: (search, result) => {
           listener.onSearchResult(this, result);
-          ProfileAutocomplete.setProfileAutoCompleteResult(result);
+          ProfileAutocomplete.lastProfileAutoCompleteResult = result;
         },
       });
       return;
     }
 
     let infoWithoutElement = Object.assign({}, info);
     delete infoWithoutElement.elementWeakRef;
 
@@ -161,25 +162,25 @@ AutofillProfileAutoCompleteSearch.protot
 
         result = new CreditCardResult(searchString,
                                       info.fieldName,
                                       allFieldNames,
                                       adaptedRecords,
                                       {isSecure});
       }
       listener.onSearchResult(this, result);
-      ProfileAutocomplete.setProfileAutoCompleteResult(result);
+      ProfileAutocomplete.lastProfileAutoCompleteResult = result;
     });
   },
 
   /**
    * Stops an asynchronous search that is in progress
    */
   stopSearch() {
-    ProfileAutocomplete.setProfileAutoCompleteResult(null);
+    ProfileAutocomplete.lastProfileAutoCompleteResult = null;
     this.forceStop = true;
   },
 
   /**
    * Get the records from parent process for AutoComplete result.
    *
    * @private
    * @param  {Object} data
@@ -206,18 +207,18 @@ AutofillProfileAutoCompleteSearch.protot
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AutofillProfileAutoCompleteSearch]);
 
 let ProfileAutocomplete = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
-  _lastAutoCompleteResult: null,
-  _lastAutoCompleteFocusedInput: null,
+  lastProfileAutoCompleteResult: null,
+  lastProfileAutoCompleteFocusedInput: null,
   _registered: false,
   _factory: null,
 
   ensureRegistered() {
     if (this._registered) {
       return;
     }
 
@@ -239,25 +240,16 @@ let ProfileAutocomplete = {
     this._factory.unregister();
     this._factory = null;
     this._registered = false;
     this._lastAutoCompleteResult = null;
 
     Services.obs.removeObserver(this, "autocomplete-will-enter-text");
   },
 
-  getProfileAutoCompleteResult() {
-    return this._lastAutoCompleteResult;
-  },
-
-  setProfileAutoCompleteResult(result) {
-    this._lastAutoCompleteResult = result;
-    this._lastAutoCompleteFocusedInput = formFillController.focusedInput;
-  },
-
   observe(subject, topic, data) {
     switch (topic) {
       case "autocomplete-will-enter-text": {
         if (!formFillController.focusedInput) {
           // The observer notification is for autocomplete in a different process.
           break;
         }
         this._fillFromAutocompleteRow(formFillController.focusedInput);
@@ -288,51 +280,51 @@ let ProfileAutocomplete = {
     let formDetails = FormAutofillContent.getFormDetails(focusedInput);
     if (!formDetails) {
       // The observer notification is for a different frame.
       return;
     }
 
     let selectedIndex = this._getSelectedIndex(focusedInput.ownerGlobal);
     if (selectedIndex == -1 ||
-        !this._lastAutoCompleteResult ||
-        this._lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
+        !this.lastProfileAutoCompleteResult ||
+        this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
       return;
     }
 
-    let profile = JSON.parse(this._lastAutoCompleteResult.getCommentAt(selectedIndex));
+    let profile = JSON.parse(this.lastProfileAutoCompleteResult.getCommentAt(selectedIndex));
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.autofillFormFields(profile, focusedInput);
   },
 
   _clearProfilePreview() {
-    let focusedInput = formFillController.focusedInput || this._lastAutoCompleteFocusedInput;
+    let focusedInput = formFillController.focusedInput || this.lastProfileAutoCompleteFocusedInput;
     if (!focusedInput || !FormAutofillContent.getFormDetails(focusedInput)) {
       return;
     }
 
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.clearPreviewedFormFields(focusedInput);
   },
 
   _previewSelectedProfile(selectedIndex) {
     let focusedInput = formFillController.focusedInput;
     if (!focusedInput || !FormAutofillContent.getFormDetails(focusedInput)) {
       // The observer notification is for a different process/frame.
       return;
     }
 
-    if (!this._lastAutoCompleteResult ||
-        this._lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
+    if (!this.lastProfileAutoCompleteResult ||
+        this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
       return;
     }
 
-    let profile = JSON.parse(this._lastAutoCompleteResult.getCommentAt(selectedIndex));
+    let profile = JSON.parse(this.lastProfileAutoCompleteResult.getCommentAt(selectedIndex));
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.previewFormFields(profile, focusedInput);
   },
 };
 
 /**
  * Handles content's interactions for the process.
@@ -517,17 +509,17 @@ var FormAutofillContent = {
     validDetails.forEach(detail =>
       this._markAsAutofillField(detail.elementWeakRef.get())
     );
   },
 
   previewProfile(doc) {
     let docWin = doc.ownerGlobal;
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(docWin);
-    let lastAutoCompleteResult = ProfileAutocomplete.getProfileAutoCompleteResult();
+    let lastAutoCompleteResult = ProfileAutocomplete.lastProfileAutoCompleteResult;
     let focusedInput = formFillController.focusedInput;
     let mm = this._messageManagerFromWindow(docWin);
 
     if (selectedIndex === -1 ||
         !focusedInput ||
         !lastAutoCompleteResult ||
         lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
       mm.sendAsyncMessage("FormAutofill:UpdateWarningMessage", {});
@@ -545,16 +537,21 @@ var FormAutofillContent = {
         focusedCategory,
         categories,
       });
 
       ProfileAutocomplete._previewSelectedProfile(selectedIndex);
     }
   },
 
+  onPopupClosed() {
+    ProfileAutocomplete._clearProfilePreview();
+    ProfileAutocomplete.lastProfileAutoCompleteResult = null;
+  },
+
   _markAsAutofillField(field) {
     // Since Form Autofill popup is only for input element, any non-Input
     // element should be excluded here.
     if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
       return;
     }
 
     formFillController.markAsAutofillField(field);
@@ -564,20 +561,21 @@ var FormAutofillContent = {
     return win.QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIWebNavigation)
               .QueryInterface(Ci.nsIDocShell)
               .QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIContentFrameMessageManager);
   },
 
   _onKeyDown(e) {
-    let lastAutoCompleteResult = ProfileAutocomplete.getProfileAutoCompleteResult();
+    let lastAutoCompleteResult = ProfileAutocomplete.lastProfileAutoCompleteResult;
     let focusedInput = formFillController.focusedInput;
 
-    if (e.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN || !lastAutoCompleteResult || !focusedInput) {
+    if (e.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN || !lastAutoCompleteResult ||
+        !focusedInput || focusedInput != ProfileAutocomplete.lastProfileAutoCompleteFocusedInput) {
       return;
     }
 
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(e.target.ownerGlobal);
     let selectedRowStyle = lastAutoCompleteResult.getStyleAt(selectedIndex);
     if (selectedRowStyle == "autofill-footer") {
       focusedInput.addEventListener("DOMAutoComplete", () => {
         Services.cpmm.sendAsyncMessage("FormAutofill:OpenPreferences");
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -84,17 +84,17 @@ var FormAutofillFrameScript = {
     const {chromeEventHandler} = doc.ownerGlobal.getInterface(Ci.nsIDocShell);
 
     switch (message.name) {
       case "FormAutofill:PreviewProfile": {
         FormAutofillContent.previewProfile(doc);
         break;
       }
       case "FormAutoComplete:PopupClosed": {
-        FormAutofillContent.previewProfile(doc);
+        FormAutofillContent.onPopupClosed();
         chromeEventHandler.removeEventListener("keydown", FormAutofillContent._onKeyDown,
                                                {capturing: true});
         break;
       }
       case "FormAutoComplete:PopupOpened": {
         chromeEventHandler.addEventListener("keydown", FormAutofillContent._onKeyDown,
                                             {capturing: true});
       }
--- a/browser/extensions/shield-recipe-client/bootstrap.js
+++ b/browser/extensions/shield-recipe-client/bootstrap.js
@@ -8,16 +8,18 @@ Cu.import("resource://gre/modules/AppCon
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LogManager",
   "resource://shield-recipe-client/lib/LogManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShieldRecipeClient",
   "resource://shield-recipe-client/lib/ShieldRecipeClient.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PreferenceExperiments",
+  "resource://shield-recipe-client/lib/PreferenceExperiments.jsm");
 
 // Act as both a normal bootstrap.js and a JS module so that we can test
 // startup methods without having to install/uninstall the add-on.
 this.EXPORTED_SYMBOLS = ["Bootstrap"];
 
 const REASON_APP_STARTUP = 1;
 const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored";
 const STARTUP_EXPERIMENT_PREFS_BRANCH = "extensions.shield-recipe-client.startupExperimentPrefs.";
@@ -38,16 +40,18 @@ const DEFAULT_PREFS = {
   "app.shield.optoutstudies.enabled": AppConstants.MOZ_DATA_REPORTING,
 };
 
 // Logging
 const log = Log.repository.getLogger(BOOTSTRAP_LOGGER_NAME);
 log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
 log.level = Services.prefs.getIntPref(PREF_LOGGING_LEVEL, Log.Level.Warn);
 
+let studyPrefsChanged = {};
+
 this.Bootstrap = {
   initShieldPrefs(defaultPrefs) {
     const prefBranch = Services.prefs.getDefaultBranch("");
     for (const [name, value] of Object.entries(defaultPrefs)) {
       switch (typeof value) {
         case "string":
           prefBranch.setCharPref(name, value);
           break;
@@ -59,28 +63,53 @@ this.Bootstrap = {
           break;
         default:
           throw new Error(`Invalid default preference type ${typeof value}`);
       }
     }
   },
 
   initExperimentPrefs() {
+    studyPrefsChanged = {};
     const defaultBranch = Services.prefs.getDefaultBranch("");
     const experimentBranch = Services.prefs.getBranch(STARTUP_EXPERIMENT_PREFS_BRANCH);
 
     for (const prefName of experimentBranch.getChildList("")) {
       const experimentPrefType = experimentBranch.getPrefType(prefName);
       const realPrefType = defaultBranch.getPrefType(prefName);
 
       if (realPrefType !== Services.prefs.PREF_INVALID && realPrefType !== experimentPrefType) {
         log.error(`Error setting startup pref ${prefName}; pref type does not match.`);
         continue;
       }
 
+      // record the value of the default branch before setting it
+      switch (realPrefType) {
+        case Services.prefs.PREF_STRING:
+          studyPrefsChanged[prefName] = defaultBranch.getCharPref(prefName);
+          break;
+
+        case Services.prefs.PREF_INT:
+          studyPrefsChanged[prefName] = defaultBranch.getIntPref(prefName);
+          break;
+
+        case Services.prefs.PREF_BOOL:
+          studyPrefsChanged[prefName] = defaultBranch.getBoolPref(prefName);
+          break;
+
+        case Services.prefs.PREF_INVALID:
+          studyPrefsChanged[prefName] = null;
+          break;
+
+        default:
+          // This should never happen
+          log.error(`Error getting startup pref ${prefName}; unknown value type ${experimentPrefType}.`);
+      }
+
+      // now set the new default value
       switch (experimentPrefType) {
         case Services.prefs.PREF_STRING:
           defaultBranch.setCharPref(prefName, experimentBranch.getCharPref(prefName));
           break;
 
         case Services.prefs.PREF_INT:
           defaultBranch.setIntPref(prefName, experimentBranch.getIntPref(prefName));
           break;
@@ -99,17 +128,17 @@ this.Bootstrap = {
           log.error(`Error getting startup pref ${prefName}; unknown value type ${experimentPrefType}.`);
       }
     }
   },
 
   observe(subject, topic, data) {
     if (topic === UI_AVAILABLE_NOTIFICATION) {
       Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
-      ShieldRecipeClient.startup();
+      this.finishStartup();
     }
   },
 
   install() {
     // Nothing to do during install
   },
 
   startup(data, reason) {
@@ -117,20 +146,25 @@ this.Bootstrap = {
     this.initShieldPrefs(DEFAULT_PREFS);
     this.initExperimentPrefs();
 
     // If the app is starting up, wait until the UI is available before finishing
     // init.
     if (reason === REASON_APP_STARTUP) {
       Services.obs.addObserver(this, UI_AVAILABLE_NOTIFICATION);
     } else {
-      ShieldRecipeClient.startup();
+      this.finishStartup();
     }
   },
 
+  async finishStartup() {
+    await PreferenceExperiments.recordOriginalValues(studyPrefsChanged);
+    ShieldRecipeClient.startup();
+  },
+
   async shutdown(data, reason) {
     // Wait for async write operations during shutdown before unloading modules.
     await ShieldRecipeClient.shutdown(reason);
 
     // In case the observer didn't run, clean it up.
     try {
       Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
     } catch (err) {
--- a/browser/extensions/shield-recipe-client/install.rdf.in
+++ b/browser/extensions/shield-recipe-client/install.rdf.in
@@ -3,17 +3,17 @@
 #filter substitution
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>shield-recipe-client@mozilla.org</em:id>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:unpack>false</em:unpack>
-    <em:version>76</em:version>
+    <em:version>76.1</em:version>
     <em:name>Shield Recipe Client</em:name>
     <em:description>Client to download and run recipes for SHIELD, Heartbeat, etc.</em:description>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
 
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
--- a/browser/extensions/shield-recipe-client/lib/PreferenceExperiments.jsm
+++ b/browser/extensions/shield-recipe-client/lib/PreferenceExperiments.jsm
@@ -97,26 +97,32 @@ function ensureStorage() {
 }
 
 const log = LogManager.getLogger("preference-experiments");
 
 // List of active preference observers. Cleaned up on shutdown.
 let experimentObservers = new Map();
 CleanupManager.addCleanupHandler(() => PreferenceExperiments.stopAllObservers());
 
-function getPref(prefBranch, prefName, prefType, defaultVal) {
+function getPref(prefBranch, prefName, prefType) {
+  if (prefBranch.getPrefType(prefName) === 0) {
+    // pref doesn't exist
+    return null;
+  }
+
   switch (prefType) {
-    case "boolean":
-      return prefBranch.getBoolPref(prefName, defaultVal);
+    case "boolean": {
+      return prefBranch.getBoolPref(prefName);
+    }
 
     case "string":
-      return prefBranch.getStringPref(prefName, defaultVal);
+      return prefBranch.getStringPref(prefName);
 
     case "integer":
-      return prefBranch.getIntPref(prefName, defaultVal);
+      return prefBranch.getIntPref(prefName);
 
     default:
       throw new TypeError(`Unexpected preference type (${prefType}) for ${prefName}.`);
   }
 }
 
 function setPref(prefBranch, prefName, prefType, prefValue) {
   switch (prefType) {
@@ -134,25 +140,49 @@ function setPref(prefBranch, prefName, p
 
     default:
       throw new TypeError(`Unexpected preference type (${prefType}) for ${prefName}.`);
   }
 }
 
 this.PreferenceExperiments = {
   /**
+   * Update the the experiment storage with changes that happened during early startup.
+   * @param {object} studyPrefsChanged Map from pref name to previous pref value
+   */
+  async recordOriginalValues(studyPrefsChanged) {
+    const store = await ensureStorage();
+
+    for (const experiment of Object.values(store.data)) {
+      if (studyPrefsChanged.hasOwnProperty(experiment.preferenceName)) {
+        if (experiment.expired) {
+          log.warn("Expired preference experiment changed value during startup");
+        }
+        if (experiment.branch !== "default") {
+          log.warn("Non-default branch preference experiment changed value during startup");
+        }
+        experiment.previousPreferenceValue = studyPrefsChanged[experiment.preferenceName];
+      }
+    }
+
+    // not calling store.saveSoon() because if the data doesn't get
+    // written, it will get updated with fresher data next time the
+    // browser starts.
+  },
+
+  /**
    * Set the default preference value for active experiments that use the
    * default preference branch.
    */
   async init() {
     CleanupManager.addCleanupHandler(this.saveStartupPrefs.bind(this));
 
     for (const experiment of await this.getAllActive()) {
       // Check that the current value of the preference is still what we set it to
-      if (getPref(UserPreferences, experiment.preferenceName, experiment.preferenceType, undefined) !== experiment.preferenceValue) {
+      if (getPref(UserPreferences, experiment.preferenceName, experiment.preferenceType) !== experiment.preferenceValue) {
         // if not, stop the experiment, and skip the remaining steps
         log.info(`Stopping experiment "${experiment.name}" because its value changed`);
         await this.stop(experiment.name, false);
         continue;
       }
 
       // Notify Telemetry of experiments we're running, since they don't persist between restarts
       TelemetryEnvironment.setExperimentActive(
@@ -270,17 +300,17 @@ this.PreferenceExperiments = {
     const experiment = {
       name,
       branch,
       expired: false,
       lastSeen: new Date().toJSON(),
       preferenceName,
       preferenceValue,
       preferenceType,
-      previousPreferenceValue: getPref(preferences, preferenceName, preferenceType, undefined),
+      previousPreferenceValue: getPref(preferences, preferenceName, preferenceType),
       preferenceBranchType,
     };
 
     const prevPrefType = Services.prefs.getPrefType(preferenceName);
     const givenPrefType = PREFERENCE_TYPE_MAP[preferenceType];
 
     if (!preferenceType || !givenPrefType) {
       throw new Error(`Invalid preferenceType provided (given "${preferenceType}")`);
@@ -318,17 +348,17 @@ this.PreferenceExperiments = {
       throw new Error(
         `An observer for the preference experiment ${experimentName} is already active.`
       );
     }
 
     const observerInfo = {
       preferenceName,
       observer() {
-        const newValue = getPref(UserPreferences, preferenceName, preferenceType, undefined);
+        const newValue = getPref(UserPreferences, preferenceName, preferenceType);
         if (newValue !== preferenceValue) {
           PreferenceExperiments.stop(experimentName, false)
                                .catch(Cu.reportError);
         }
       },
     };
     experimentObservers.set(experimentName, observerInfo);
     Services.prefs.addObserver(preferenceName, observerInfo.observer);
@@ -419,23 +449,29 @@ this.PreferenceExperiments = {
 
     if (PreferenceExperiments.hasObserver(experimentName)) {
       PreferenceExperiments.stopObserver(experimentName);
     }
 
     if (resetValue) {
       const {preferenceName, preferenceType, previousPreferenceValue, preferenceBranchType} = experiment;
       const preferences = PreferenceBranchType[preferenceBranchType];
-      if (previousPreferenceValue !== undefined) {
+
+      if (previousPreferenceValue !== null) {
         setPref(preferences, preferenceName, preferenceType, previousPreferenceValue);
+      } else if (preferenceBranchType === "user") {
+        // Remove the "user set" value (which Shield set), but leave the default intact.
+        preferences.clearUserPref(preferenceName);
       } else {
-        // This does nothing if we're on the default branch, which is fine. The
-        // preference will be reset on next restart, and most preferences should
-        // have had a default value set before the experiment anyway.
-        preferences.clearUserPref(preferenceName);
+        // Remove both the user and default branch preference. This
+        // is ok because we only do this when studies expire, not
+        // when users actively leave a study by changing the
+        // preference, so there should not be a user branch value at
+        // this point.
+        Services.prefs.getDefaultBranch("").deleteBranch(preferenceName);
       }
     }
 
     experiment.expired = true;
     store.saveSoon();
 
     TelemetryEnvironment.setExperimentInactive(experimentName, experiment.branch);
     await this.saveStartupPrefs();
--- a/browser/extensions/shield-recipe-client/test/browser/browser_PreferenceExperiments.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_PreferenceExperiments.js
@@ -422,17 +422,17 @@ add_task(withMockExperiments(withMockPre
   const stopObserver = sinon.stub(PreferenceExperiments, "stopObserver");
   mockPreferences.set("fake.preference", "experimentvalue", "user");
   experiments.test = experimentFactory({
     name: "test",
     expired: false,
     preferenceName: "fake.preference",
     preferenceValue: "experimentvalue",
     preferenceType: "string",
-    previousPreferenceValue: undefined,
+    previousPreferenceValue: null,
     preferenceBranchType: "user",
   });
 
   await PreferenceExperiments.stop("test");
   ok(
     !Preferences.isSet("fake.preference"),
     "stop removed the preference that had no value prior to the experiment",
   );
@@ -688,8 +688,103 @@ decorate_task(
     });
 
     await Assert.rejects(
       PreferenceExperiments.saveStartupPrefs(),
       "saveStartupPrefs throws if an experiment has an invalid preference value type",
     );
   },
 );
+
+// test that default branch prefs restore to the right value if the default pref changes
+decorate_task(
+  withMockExperiments,
+  withMockPreferences,
+  withStub(PreferenceExperiments, "startObserver"),
+  withStub(PreferenceExperiments, "stopObserver"),
+  async function testDefaultBranchStop(mockExperiments, mockPreferences, stopObserverStub) {
+    const prefName = "fake.preference";
+    mockPreferences.set(prefName, "old version's value", "default");
+
+    // start an experiment
+    await PreferenceExperiments.start({
+      name: "test",
+      branch: "branch",
+      preferenceName: prefName,
+      preferenceValue: "experiment value",
+      preferenceBranchType: "default",
+      preferenceType: "string",
+    });
+
+    is(
+      Services.prefs.getCharPref(prefName),
+      "experiment value",
+      "Starting an experiment should change the pref",
+    );
+
+    // Now pretend that firefox has updated and restarted to a version
+    // where the built-default value of fake.preference is something
+    // else. Bootstrap has run and changed the pref to the
+    // experimental value, and produced the call to
+    // recordOriginalValues below.
+    PreferenceExperiments.recordOriginalValues({ [prefName]: "new version's value" });
+    is(
+      Services.prefs.getCharPref(prefName),
+      "experiment value",
+      "Recording original values shouldn't affect the preference."
+    );
+
+    // Now stop the experiment. It should revert to the new version's default, not the old.
+    await PreferenceExperiments.stop("test");
+    is(
+      Services.prefs.getCharPref(prefName),
+      "new version's value",
+      "Preference should revert to new default",
+    );
+  },
+);
+
+// test that default branch prefs restore to the right value if the preference is removed
+decorate_task(
+  withMockExperiments,
+  withMockPreferences,
+  withStub(PreferenceExperiments, "startObserver"),
+  withStub(PreferenceExperiments, "stopObserver"),
+  async function testDefaultBranchStop(mockExperiments, mockPreferences, stopObserverStub) {
+    const prefName = "fake.preference";
+    mockPreferences.set(prefName, "old version's value", "default");
+
+    // start an experiment
+    await PreferenceExperiments.start({
+      name: "test",
+      branch: "branch",
+      preferenceName: prefName,
+      preferenceValue: "experiment value",
+      preferenceBranchType: "default",
+      preferenceType: "string",
+    });
+
+    is(
+      Services.prefs.getCharPref(prefName),
+      "experiment value",
+      "Starting an experiment should change the pref",
+    );
+
+    // Now pretend that firefox has updated and restarted to a version
+    // where fake.preference has been removed in the default pref set.
+    // Bootstrap has run and changed the pref to the experimental
+    // value, and produced the call to recordOriginalValues below.
+    PreferenceExperiments.recordOriginalValues({ [prefName]: null });
+    is(
+      Services.prefs.getCharPref(prefName),
+      "experiment value",
+      "Recording original values shouldn't affect the preference."
+    );
+
+    // Now stop the experiment. It should remove the preference
+    await PreferenceExperiments.stop("test");
+    is(
+      Services.prefs.getCharPref(prefName, "DEFAULT"),
+      "DEFAULT",
+      "Preference should be absent",
+    );
+  },
+);
--- a/browser/extensions/shield-recipe-client/test/browser/browser_bootstrap.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_bootstrap.js
@@ -1,11 +1,12 @@
 "use strict";
 
 Cu.import("resource://shield-recipe-client/lib/ShieldRecipeClient.jsm", this);
+Cu.import("resource://shield-recipe-client/lib/PreferenceExperiments.jsm", this);
 
 // We can't import bootstrap.js directly since it isn't in the jar manifest, but
 // we can use Addon.getResourceURI to get a path to the file and import using
 // that instead.
 Cu.import("resource://gre/modules/AddonManager.jsm", this);
 const bootstrapPromise = AddonManager.getAddonByID("shield-recipe-client@mozilla.org").then(addon => {
   const bootstrapUri = addon.getResourceURI("bootstrap.js");
   const {Bootstrap} = Cu.import(bootstrapUri.spec, {});
@@ -18,16 +19,22 @@ function withBootstrap(testFunction) {
     const Bootstrap = await bootstrapPromise;
     return testFunction(...args, Bootstrap);
   };
 }
 
 const initPref1 = "test.initShieldPrefs1";
 const initPref2 = "test.initShieldPrefs2";
 const initPref3 = "test.initShieldPrefs3";
+
+const experimentPref1 = "test.initExperimentPrefs1";
+const experimentPref2 = "test.initExperimentPrefs2";
+const experimentPref3 = "test.initExperimentPrefs3";
+const experimentPref4 = "test.initExperimentPrefs4";
+
 decorate_task(
   withPrefEnv({
     clear: [[initPref1], [initPref2], [initPref3]],
   }),
   withBootstrap,
   async function testInitShieldPrefs(Bootstrap) {
     const defaultBranch = Services.prefs.getDefaultBranch("");
     const prefDefaults = {
@@ -75,19 +82,16 @@ decorate_task(
   async function testInitShieldPrefsError(Bootstrap) {
     Assert.throws(
       () => Bootstrap.initShieldPrefs({"test.prefTypeError": new Date()}),
       "initShieldPrefs throws when given an invalid type for the pref value.",
     );
   },
 );
 
-const experimentPref1 = "test.initExperimentPrefs1";
-const experimentPref2 = "test.initExperimentPrefs2";
-const experimentPref3 = "test.initExperimentPrefs3";
 decorate_task(
   withPrefEnv({
     set: [
       [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref1}`, true],
       [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref2}`, 2],
       [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref3}`, "string"],
     ],
     clear: [[experimentPref1], [experimentPref2], [experimentPref3]],
@@ -164,35 +168,87 @@ decorate_task(
       Services.prefs.PREF_INT,
       "initExperimentPrefs skips prefs that don't match the existing default value's type.",
     );
   },
 );
 
 decorate_task(
   withBootstrap,
-  withStub(ShieldRecipeClient, "startup"),
-  async function testStartupDelayed(Bootstrap, startupStub) {
-    Bootstrap.startup(undefined, 1); // 1 == APP_STARTUP
-    ok(
-      !startupStub.called,
-      "When started at app startup, do not call ShieldRecipeClient.startup immediately.",
-    );
+  async function testStartupDelayed(Bootstrap) {
+    const finishStartupStub = sinon.stub(Bootstrap, "finishStartup");
+    try {
+      Bootstrap.startup(undefined, 1); // 1 == APP_STARTUP
+      ok(
+        !finishStartupStub.called,
+        "When started at app startup, do not call ShieldRecipeClient.startup immediately.",
+      );
 
-    Bootstrap.observe(null, "sessionstore-windows-restored");
-    ok(
-      startupStub.called,
-      "Once the sessionstore-windows-restored event is observed, call ShieldRecipeClient.startup.",
-    );
+      Bootstrap.observe(null, "sessionstore-windows-restored");
+      ok(
+        finishStartupStub.called,
+        "Once the sessionstore-windows-restored event is observed, call ShieldRecipeClient.startup.",
+      );
+    } finally {
+      finishStartupStub.restore();
+    }
   },
 );
 
 decorate_task(
   withBootstrap,
-  withStub(ShieldRecipeClient, "startup"),
-  async function testStartupDelayed(Bootstrap, startupStub) {
-    Bootstrap.startup(undefined, 3); // 1 == ADDON_ENABLED
-    ok(
-      startupStub.called,
-      "When the add-on is enabled outside app startup, call ShieldRecipeClient.startup immediately.",
+  async function testStartupDelayed(Bootstrap) {
+    const finishStartupStub = sinon.stub(Bootstrap, "finishStartup");
+    try {
+      Bootstrap.startup(undefined, 3); // 3 == ADDON_ENABLED
+      ok(
+        finishStartupStub.called,
+        "When the add-on is enabled outside app startup, call ShieldRecipeClient.startup immediately.",
+      );
+    } finally {
+      finishStartupStub.restore();
+    }
+  },
+);
+
+// During startup, preferences that are changed for experiments should
+// be record by calling PreferenceExperiments.recordOriginalValues.
+decorate_task(
+  withPrefEnv({
+    set: [
+      [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref1}`, true],
+      [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref2}`, 2],
+      [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref3}`, "string"],
+      [`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref4}`, "another string"],
+    ],
+    clear: [
+      [experimentPref1],
+      [experimentPref2],
+      [experimentPref3],
+      [experimentPref4],
+      ["extensions.shield-recipe-client.startupExperimentPrefs.existingPref"],
+    ],
+  }),
+  withBootstrap,
+  withStub(PreferenceExperiments, "recordOriginalValues"),
+  async function testInitExperimentPrefs(Bootstrap, recordOriginalValuesStub) {
+    const defaultBranch = Services.prefs.getDefaultBranch("");
+
+    defaultBranch.setBoolPref(experimentPref1, false);
+    defaultBranch.setIntPref(experimentPref2, 1);
+    defaultBranch.setCharPref(experimentPref3, "original string");
+    // experimentPref4 is left unset
+
+    Bootstrap.initExperimentPrefs();
+    await Bootstrap.finishStartup();
+
+    Assert.deepEqual(
+      recordOriginalValuesStub.getCall(0).args,
+      [{
+        [experimentPref1]: false,
+        [experimentPref2]: 1,
+        [experimentPref3]: "original string",
+        [experimentPref4]: null,  // null because it was not initially set.
+      }],
+      "finishStartup should record original values of the prefs initExperimentPrefs changed",
     );
   },
 );
--- a/browser/extensions/shield-recipe-client/vendor/LICENSE_THIRDPARTY
+++ b/browser/extensions/shield-recipe-client/vendor/LICENSE_THIRDPARTY
@@ -1,29 +1,40 @@
-fbjs@0.8.16 MIT
-MIT License
+fbjs@0.8.14 BSD-3-Clause
+BSD License
+
+For fbjs software
 
 Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
 
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 react-dom@15.6.1 BSD-3-Clause
 BSD License
 
 For React software
 
 Copyright (c) 2013-present, Facebook, Inc.
@@ -141,38 +152,48 @@ WARRANTIES OF MERCHANTABILITY AND FITNES
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-create-react-class@15.6.2 MIT
-MIT License
+create-react-class@15.6.0 BSD-3-Clause
+BSD License
+
+For React software
 
 Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
 
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 mozjexl@1.1.5 MIT
 Copyright for portions of mozJexl are held by TechnologyAdvice, 2015 as part of Jexl.
 All other copyright for mozJexl are held by the Mozilla Foundation, 2017.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -343,27 +343,22 @@ These should match what Safari and other
 <!ENTITY historyUndoMenu.label "Recently Closed Tabs">
 <!-- LOCALIZATION NOTE (historyUndoWindowMenu): see bug 394759 -->
 <!ENTITY historyUndoWindowMenu.label "Recently Closed Windows">
 <!ENTITY historyRestoreLastSession.label "Restore Previous Session">
 
 <!ENTITY showAllHistoryCmd2.label "Show All History">
 <!ENTITY showAllHistoryCmd.commandkey "H">
 
-<!ENTITY appMenuCustomize.label "Customize">
-<!ENTITY appMenuCustomize.tooltip "Customize the Menu and Toolbars">
-<!ENTITY appMenuCustomizeExit.label "Exit Customize">
-<!ENTITY appMenuCustomizeExit.tooltip "Finish Customizing">
 <!ENTITY appMenuHistory.showAll.label "Show All History">
 <!ENTITY appMenuHistory.clearRecent.label "Clear Recent History…">
 <!ENTITY appMenuHistory.restoreSession.label "Restore Previous Session">
 <!ENTITY appMenuHistory.viewSidebar.label "View History Sidebar">
 <!ENTITY appMenuHistory.recentHistory.label "Recent History">
 <!ENTITY appMenuHelp.label "Help">
-<!ENTITY appMenuHelp.tooltip "Open Help Menu">
 
 <!ENTITY appMenuRemoteTabs.label "Synced Tabs">
 <!-- LOCALIZATION NOTE (appMenuRemoteTabs.notabs.label): This is shown beneath
      the name of a device when that device has no open tabs -->
 <!ENTITY appMenuRemoteTabs.notabs.label "No open tabs">
 <!-- LOCALIZATION NOTE (appMenuRemoteTabs.showMore.label, appMenuRemoteTabs.showMore.tooltip):
      This is shown after the tabs list if we can display more tabs by clicking on the button -->
 <!ENTITY appMenuRemoteTabs.showMore.label "Show More">
@@ -826,18 +821,16 @@ you can use these alternative items. Oth
 <!ENTITY syncSignIn.accesskey         "Y">
 <!ENTITY syncSyncNowItem.label        "Sync Now">
 <!ENTITY syncSyncNowItem.accesskey    "S">
 <!ENTITY syncReAuthItem.label         "Reconnect to &syncBrand.shortName.label;…">
 <!ENTITY syncReAuthItem.accesskey     "R">
 <!ENTITY syncToolbarButton.label      "Sync">
 
 <!ENTITY customizeMode.menuAndToolbars.header3 "Drag your favorite items into the toolbar or overflow menu.">
-<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
-<!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
 <!ENTITY customizeMode.restoreDefaults "Restore Defaults">
 <!ENTITY customizeMode.done "Done">
 <!ENTITY customizeMode.titlebar "Title Bar">
 <!ENTITY customizeMode.extraDragSpace "Drag Space">
 <!ENTITY customizeMode.toolbars2 "Toolbars">
 <!ENTITY customizeMode.lwthemes "Themes">
 <!ENTITY customizeMode.lwthemes.myThemes "My Themes">
 <!ENTITY customizeMode.lwthemes.recommended "Recommended">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -271,12 +271,17 @@ defaultContentProcessCount=%S (default)
 # LOCALIZATION NOTE (extensionControlled.homepage_override):
 # This string is shown to notify the user that their home page is being controlled by an extension.
 extensionControlled.homepage_override = An extension, %S, controls your home page.
 
 # LOCALIZATION NOTE (extensionControlled.newTabURL):
 # This string is shown to notify the user that their new tab page is being controlled by an extension.
 extensionControlled.newTabURL = An extension, %S, controls your New Tab page.
 
+# LOCALIZATION NOTE (extensionControlled.defaultSearch):
+# This string is shown to notify the user that the default search engine is being controlled
+# by an extension. %S is the icon and name of the extension.
+extensionControlled.defaultSearch = An extension, %S, has set your default search engine.
+
 # LOCALIZATION NOTE (extensionControlled.privacy.containers):
 # This string is shown to notify the user that Container Tabs are being enabled by an extension
 # %S is the container addon controlling it
 extensionControlled.privacy.containers = An extension, %S, requires Container Tabs.
--- a/browser/locales/search/list.json
+++ b/browser/locales/search/list.json
@@ -586,16 +586,23 @@
     },
     "nn-NO": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "amazon-en-GB", "ddg", "gulesider-NO", "bok-NO", "qxl-NO", "wikipedia-NN"
         ]
       }
     },
+    "oc": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "bing", "ddg", "twitter", "wikipedia-oc", "wiktionary-oc"
+        ]
+      }
+    },
     "or": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo-in", "bing", "amazondotcom", "ddg", "wikipedia-or"
         ]
       }
     },
     "pa-IN": {
@@ -631,17 +638,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo-ch", "bing", "ddg", "ebay-ch", "leo_ende_de-rm", "pledarigrond", "wikipedia-rm"
         ]
       }
     },
     "ro": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipediaro"
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipedia-ro"
         ]
       }
     },
     "ru": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-ru", "google", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
         ]
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/wikipedia-oc.xml
@@ -0,0 +1,19 @@
+<!-- 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/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Wikipèdia (oc)</ShortName>
+<Description>Wikipèdia, l'enciclopèdia liura</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">resource://search-plugins/images/wikipedia.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://oc.wikipedia.org/w/api.php">
+  <Param name="action" value="opensearch"/>
+  <Param name="search" value="{searchTerms}"/>
+</Url>
+<Url type="text/html" method="GET" template="https://oc.wikipedia.org/wiki/Especial:Recèrca"
+     resultdomain="wikipedia.org" rel="searchform">
+  <Param name="search" value="{searchTerms}"/>
+  <Param name="sourceid" value="Mozilla-search"/>
+</Url>
+</SearchPlugin>
rename from browser/locales/searchplugins/wikipediaro.xml
rename to browser/locales/searchplugins/wikipedia-ro.xml
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/wiktionary-oc.xml
@@ -0,0 +1,19 @@
+<!-- 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/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Wikiccionari (oc)</ShortName>
+<Description>Wikiccionari, lo diccionari liure</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAEAgQAhIOEAMjHyABIR0gA6ejpAGlqaQCpqKkAKCgoAPz9%2FAAZGBkAmJiYANjZ2ABXWFcAent6ALm6uQA8OjwAiIiIiIiIiIiIiI4oiL6IiIiIgzuIV4iIiIhndo53KIiIiB%2FWvXoYiIiIfEZfWBSIiIEGi%2FfoqoiIgzuL84i9iIjpGIoMiEHoiMkos3FojmiLlUipYliEWIF%2BiDe0GoRa7D6GPbjcu1yIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://oc.wiktionary.org/w/api.php">
+  <Param name="action" value="opensearch"/>
+  <Param name="search" value="{searchTerms}"/>
+  <Param name="namespace" value="0"/>
+</Url>
+<Url type="text/html" method="get" template="https://oc.wiktionary.org/wiki/Especial:Recèrca"
+     resultdomain="wiktionary.org" rel="searchform">
+  <Param name="search" value="{searchTerms}"/>
+</Url>
+</SearchPlugin>
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -6,22 +6,16 @@ browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 % override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
 * skin/classic/browser/syncedtabs/sidebar.css     (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
-  skin/classic/browser/menuPanel-customize.png
-  skin/classic/browser/menuPanel-customize@2x.png
-  skin/classic/browser/menuPanel-exit.png
-  skin/classic/browser/menuPanel-exit@2x.png
-  skin/classic/browser/menuPanel-help.png
-  skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
deleted file mode 100644
index e0b0a70a3b82a18c974bd1bc5f1dff863405dd61..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 5ce3b766a1bb9b298120472bdf42b0bc63404918..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 8daaffe9556f3fc93fbfa7883fa0639b72e0a26e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index d48426546fa492f78bd3e22676184b7dece8bcb3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 962001ff652e963009be9837e12859f48d1b29da..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b8f0a80fa168230973a6eb53f8bfe93d2cc981df..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -6,22 +6,16 @@ browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
 * skin/classic/browser/syncedtabs/sidebar.css          (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
   skin/classic/browser/subtle-pattern.png
-  skin/classic/browser/menuPanel-customize.png
-  skin/classic/browser/menuPanel-customize@2x.png
-  skin/classic/browser/menuPanel-exit.png
-  skin/classic/browser/menuPanel-exit@2x.png
-  skin/classic/browser/menuPanel-help.png
-  skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/panel-expander-closed.png
   skin/classic/browser/panel-expander-closed@2x.png
   skin/classic/browser/panel-expander-open.png
   skin/classic/browser/panel-expander-open@2x.png
   skin/classic/browser/panel-plus-sign.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/pageInfo.css
   skin/classic/browser/searchbar.css
@@ -65,29 +59,16 @@ browser.jar:
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/applications.css         (preferences/applications.css)
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabbrowser/tabDragIndicator@2x.png                (tabbrowser/tabDragIndicator@2x.png)
   skin/classic/browser/sync-desktopIcon.svg  (../shared/sync-desktopIcon.svg)
   skin/classic/browser/sync-mobileIcon.svg  (../shared/sync-mobileIcon.svg)
-  skin/classic/browser/yosemite/menuPanel-customize.png                (menuPanel-customize-yosemite.png)
-  skin/classic/browser/yosemite/menuPanel-customize@2x.png             (menuPanel-customize-yosemite@2x.png)
-  skin/classic/browser/yosemite/menuPanel-exit.png                     (menuPanel-exit-yosemite.png)
-  skin/classic/browser/yosemite/menuPanel-exit@2x.png                  (menuPanel-exit-yosemite@2x.png)
-  skin/classic/browser/yosemite/menuPanel-help.png                     (menuPanel-help-yosemite.png)
-  skin/classic/browser/yosemite/menuPanel-help@2x.png                  (menuPanel-help-yosemite@2x.png)
   skin/classic/browser/e10s-64@2x.png                                  (../shared/e10s-64@2x.png)
 
 [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/feeds/audioFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png                 chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png                 chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/notification-icons/geo-detailed.svg       chrome://browser/skin/notification-icons/geo.svg
-
-% override chrome://browser/skin/menuPanel-customize.png                   chrome://browser/skin/yosemite/menuPanel-customize.png                  os=Darwin osversion>=10.10
-% override chrome://browser/skin/menuPanel-customize@2x.png                chrome://browser/skin/yosemite/menuPanel-customize@2x.png               os=Darwin osversion>=10.10
-% override chrome://browser/skin/menuPanel-exit.png                        chrome://browser/skin/yosemite/menuPanel-exit.png                       os=Darwin osversion>=10.10
-% override chrome://browser/skin/menuPanel-exit@2x.png                     chrome://browser/skin/yosemite/menuPanel-exit@2x.png                    os=Darwin osversion>=10.10
-% override chrome://browser/skin/menuPanel-help.png                        chrome://browser/skin/yosemite/menuPanel-help.png                       os=Darwin osversion>=10.10
-% override chrome://browser/skin/menuPanel-help@2x.png                     chrome://browser/skin/yosemite/menuPanel-help@2x.png                    os=Darwin osversion>=10.10
deleted file mode 100644
index b3b40e394dbfa412189a8a452c73f72d227fc4a4..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 93b6606928039af13895a3bb66ac27806a733671..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 43cde4a68273f05a025b9a3f369e8c644ff0ab06..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b0772d82223f86362416ff69417fbd44c4731ed5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index aba481aeb49b48bfc317bdeaeb00ea4048869533..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4115b53ec7dcf32351bf1fdb97ce321fa7e7e411..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index af3160621c36d2c8b067cec4d4b05acb339881c7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 126cde0880537831e032e3627450cc34ec7b93d1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 1ccdd65b97db020dd98ff6d9e788447449fb72af..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index ad1783de69ea14968959e182f8ef3767d6c3307f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4a4c3bcaeb0b070b71d109888233678e60bf8f9f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index a9b34c132043b4ec2023846582f2e2fb8d15fcd1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index acf2e531cb81cd1dba010a7b55c79b04e0fd13f3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -190,17 +190,17 @@
 .identity-popup-headline {
   margin: 3px 0 4px;
   font-size: 150%;
 }
 
 .identity-popup-host {
   word-wrap: break-word;
   /* 1em + 2em + 24px is #identity-popup-security-content padding
-   * 30em is .panel-mainview:not([panelid="PanelUI-popup"]) width */
+   * 30em is .panel-mainview width */
   max-width: calc(30rem - 3rem - 24px - @identityPopupExpanderWidth@);
 }
 
 .identity-popup-warning-gray {
   padding-inline-start: 24px;
   background: url(chrome://browser/skin/controlcenter/warning-gray.svg) no-repeat 0 50%;
 }
 
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -19,18 +19,17 @@
   text-shadow: none;
 }
 
 #customization-container:-moz-lwtheme {
   background-color: transparent;
   background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-non-lwt-bgcolor) 45px);
 }
 
-#customization-palette,
-#customization-empty {
+#customization-palette {
   padding: 5px 20px 20px;
 }
 
 #customization-header {
   font-weight: 500;
   font-size: 1.2em;
   margin: 20px 20px 15px;
 }
deleted file mode 100644
index 07be6a76a86efd878a2476d39f68c84b4ad4e2bc..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 7562e138c3d7db91dc7828c01d2277bcb8990ce2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -24,79 +24,16 @@
 :root {
   --panel-ui-exit-subview-gutter-width: 38px;
   --appmenu-yellow-warning-border-color: hsl(45, 100%, 77%);
   --appmenu-yellow-warning-color: #FFEFBF;
   --appmenu-yellow-warning-hover-color: #FFE8A2;
   --appmenu-yellow-warning-active-color: #FFE38F;
 }
 
-#PanelUI-popup #PanelUI-contents:empty {
-  height: 128px;
-}
-
-#PanelUI-popup #PanelUI-contents:empty::before {
-  content: "";
-  background-image: url(chrome://browser/skin/customizableui/whimsy.png);
-  background-size: 64px 64px;
-  display: block;
-  width: 64px;
-  height: 64px;
-  position: absolute;
-  transition: transform 1s ease-out;
-  animation: whimsyMoveX 3.05s linear 0s infinite alternate,
-             whimsyMoveY 3.4s linear 0s infinite alternate;
-}
-
-#PanelUI-popup #PanelUI-contents:not(:hover):empty::before {
-  filter: grayscale(100%);
-}
-
-#PanelUI-popup #PanelUI-contents:active:empty::before {
-  animation: whimsyMoveX 3.05s linear 0s infinite alternate,
-             whimsyMoveY 3.4s linear 0s infinite alternate,
-             whimsyRotate 1s linear 0s infinite normal;
-}
-
-#PanelUI-popup #PanelUI-contents:-moz-locale-dir(rtl):empty::before {
-  animation: whimsyMoveXRTL 3.05s linear 0s infinite alternate,
-             whimsyMoveY 3.4s linear 0s infinite alternate;
-}
-
-#PanelUI-popup #PanelUI-contents:-moz-locale-dir(rtl):active:empty::before {
-  animation: whimsyMoveXRTL 3.05s linear 0s infinite alternate,
-             whimsyMoveY 3.4s linear 0s infinite alternate,
-             whimsyRotate 1s linear 0s infinite normal;
-}
-
-@media (min-resolution: 2dppx) {
-  #PanelUI-popup #PanelUI-contents:empty::before {
-    background-image: url(chrome://browser/skin/customizableui/whimsy@2x.png);
-  }
-}
-
-@keyframes whimsyMoveX {
-  /* These values are adjusted for the padding on the panel. */
-  from { margin-left: -15px; } to { margin-left: calc(100% - 49px); }
-}
-
-@keyframes whimsyMoveXRTL {
-  /* These values are adjusted for the padding on the panel. */
-  from { margin-right: -15px; } to { margin-right: calc(100% - 49px); }
-}
-
-@keyframes whimsyMoveY {
-  /* These values are adjusted for the padding and height of the panel. */
-  from { margin-top: -.5em; } to { margin-top: calc(64px - .5em); }
-}
-
-@keyframes whimsyRotate {
-  to { transform: perspective(5000px) rotateY(360deg); }
-}
-
 :root:not([uidensity=compact]):not([chromehidden~="toolbar"]) #PanelUI-button {
   margin-inline-start: 3px;
   border-inline-start: 1px solid;
   border-image: linear-gradient(transparent 4px, rgba(0,0,0,.1) 4px, rgba(0,0,0,.1) calc(100% - 4px), transparent calc(100% - 4px));
   border-image-slice: 1;
 }
 
 :root:not([uidensity=compact]):not([chromehidden~="toolbar"]) #nav-bar[brighttext] > #PanelUI-button {
@@ -265,50 +202,42 @@ panelview {
   -moz-box-flex: 1;
 }
 
 .panel-view-body-unscrollable {
   overflow: hidden;
   -moz-box-flex: 1;
 }
 
-#PanelUI-popup .panel-subview-body {
-  margin: -4px;
-  padding: 4px 4px;
-}
-
 .subviewbutton.panel-subview-footer {
   box-sizing: border-box;
   min-height: 41px;
 }
 
 .cui-widget-panelview menuitem.subviewbutton.panel-subview-footer {
   margin: 4px 0 0;
 }
 
 .cui-widget-panelview .subviewbutton.panel-subview-footer > .menu-text {
   -moz-box-flex: 1;
 }
 
-#appMenu-popup > arrowscrollbox > autorepeatbutton,
-#PanelUI-popup > arrowscrollbox > autorepeatbutton {
+#appMenu-popup > arrowscrollbox > autorepeatbutton {
   display: none;
 }
 
-#appMenu-popup > arrowscrollbox > scrollbox,
-#PanelUI-popup > arrowscrollbox > scrollbox {
+#appMenu-popup > arrowscrollbox > scrollbox {
   overflow: visible;
 }
 
 #appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent,
 panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
   overflow: hidden;
 }
 
-#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
 .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box {
   padding: 0;
 }
 
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
   line-height: 1.2;
   max-height: 2.4em;
@@ -337,22 +266,18 @@ panel[photon] > .panel-arrowcontainer > 
   margin: -1px 0 0;
 }
 
 #wrapper-edit-controls:-moz-any([place="palette"],[place="panel"]) > #edit-controls,
 #wrapper-zoom-controls:-moz-any([place="palette"],[place="panel"]) > #zoom-controls {
   margin-inline-start: 0;
 }
 
-#PanelUI-contents {
-  max-width: @menuPanelWidth@;
-}
-
 #BMB_bookmarksPopup,
-.panel-mainview:not([panelid="PanelUI-popup"]) {
+.panel-mainview {
   max-width: @standaloneSubviewWidth@;
 }
 
 #pageActionFeedback > .panel-arrowcontainer > .panel-arrowbox {
   /* Don't display the arrow but keep the popup at the same vertical
      offset as other arrow panels. */
   visibility: hidden;
 }
@@ -546,167 +471,32 @@ photonpanelmultiview .panel-subview-body
     transform: scale(.5);
   }
 }
 
 toolbarpaletteitem[place=panel] > .toolbarbutton-1 {
   -moz-box-flex: 1;
 }
 
-/* Help SDK buttons fit in. */
+/* Help webextension buttons fit in. */
 toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-icon,
 toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
-toolbarpaletteitem[place="palette"] > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-1 > .toolbarbutton-icon,
-toolbarpaletteitem[place="panel"] > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-1 > .toolbarbutton-icon,
 toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon,
 toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
   height: @panelPaletteIconSize@;
   width: @panelPaletteIconSize@;
 }
 
 #customization-palette .toolbarbutton-1 {
   -moz-appearance: none;
   -moz-box-orient: vertical;
   padding: 12px 0 9px;
   margin: 0;
 }
 
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-  -moz-appearance: none;
-  -moz-box-orient: vertical;
-  width: calc(@menuPanelButtonWidth@ - 2px);
-  height: calc(49px + 2.2em);
-  border: 0;
-}
-
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text,
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text {
-  margin-top: 2px; /* Hack needed to get the label of type=menu-button aligned with other buttons */
-}
-
-.panel-customization-placeholder-child {
-  margin: 6px 0 0;
-  padding: 2px 6px;
-  border: 1px solid transparent;
-}
-
-.panelUI-grid .toolbarbutton-1[type="menu"] {
-  background-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow.png");
-  background-position: right 3px top 16px;
-  background-repeat: no-repeat;
-}
-
-.panelUI-grid .toolbarbutton-1[type="menu"]:-moz-locale-dir(rtl) {
-  background-position: left 3px top 16px;
-}
-
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
-  display: none;
-}
-
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  -moz-box-align: center;
-  width: 16px;
-  margin-inline-start: -16px;
-  height: 51px;
-  margin-bottom: 2.2em;
-  padding: 0;
-}
-
-.panelUI-grid .toolbarbutton-1:not([buttonover])@buttonStateHover@ > .toolbarbutton-menubutton-dropmarker {
-  background-color: var(--arrowpanel-dimmed) !important;
-  border-radius: 0 0 0 2px;
-}
-
-.panelUI-grid .toolbarbutton-1:not([buttonover])@buttonStateHover@ > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) {
-  border-radius: 0 0 2px 0;
-}
-
-#main-window:not([customizing]) .panel-combined-button[disabled] > .toolbarbutton-icon {
-  opacity: .5;
-}
-
-toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) {
-  width: calc(@menuPanelButtonWidth@);
-  margin: 0 !important;
-}
-
-toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) {
-  -moz-box-align: center;
-  -moz-box-pack: center;
-}
-
-toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] > iframe {
-  margin: 4px auto;
-}
-
-#PanelUI-multiView[viewtype="subview"] > .panel-viewcontainer > .panel-viewstack > .panel-mainview >  #PanelUI-mainView {
-  background-color: var(--arrowpanel-dimmed);
-}
-
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .panel-wide-item,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .toolbarbutton-1:not([panel-multiview-anchor="true"]),
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > .panel-banner-item,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-fxa-container > #PanelUI-fxa-status > #PanelUI-fxa-avatar,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-fxa-container > #PanelUI-fxa-status > #PanelUI-fxa-label,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-fxa-container > #PanelUI-fxa-icon,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-footer-inner > toolbarseparator,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-customize,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-help:not([panel-multiview-anchor="true"]) {
-  opacity: .5;
-}
-
-/*
- * XXXgijs: this is a workaround for a layout issue that was caused by these iframes,
- * which was affecting subview display. Because of this, we're hiding the iframe *only*
- * when displaying a subview. The discerning user might notice this, but it's not nearly
- * as bad as the brokenness.
- * This hack should be removed once https://bugzilla.mozilla.org/show_bug.cgi?id=975375
- * is addressed.
- */
-#PanelUI-multiView[viewtype="subview"] toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) > iframe {
-  visibility: hidden;
-}
-
-toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) > .toolbarbutton-text {
-  text-align: center;
-}
-
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-icon,
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack,
-.customization-palette .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-.customization-palette .toolbarbutton-1 > .toolbarbutton-icon,
-.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack,
-.panel-customization-placeholder-child > .toolbarbutton-icon {
-  width: @panelPaletteIconSize@;
-  height: @panelPaletteIconSize@;
-  min-width: @panelPaletteIconSize@;
-  min-height: @panelPaletteIconSize@;
-}
-
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-icon,
-.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack,
-.panel-customization-placeholder-child > .toolbarbutton-icon {
-  /* Explanation for the below formula (A / B - C)
-     A
-       Each button is @menuPanelButtonWidth@ wide
-     B
-       Each button has two margins.
-     C (46px / 2 = 23px)
-       The button icon is 32 pixels wide.
-       The button has 12px of horizontal padding (6 on each side).
-       The button has 2px of horizontal border (1 on each side).
-       Total width of button's icon + button padding should therefore be 46px,
-       which means each horizontal margin should be the half the button's width - (46/2) px.
-  */
-  margin: 4px calc(@menuPanelButtonWidth@ / 2 - 23px);
-}
-
 /* above we treat the container as the icon for the margins, that is so the
 /* badge itself is positioned correctly. Here we make sure that the icon itself
 /* has the minimum size we want, but no padding/margin. */
 .customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon,
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
   width: @panelPaletteIconSize@;
   height: @panelPaletteIconSize@;
   min-width: @panelPaletteIconSize@;
@@ -723,46 +513,16 @@ toolbaritem[cui-areatype="menu-panel"][s
 }
 
 #zoom-in-button > .toolbarbutton-text,
 #zoom-out-button > .toolbarbutton-text,
 #zoom-reset-button > .toolbarbutton-icon {
   display: none;
 }
 
-#PanelUI-footer {
-  display: flex;
-  flex-shrink: 0;
-  flex-direction: column;
-  background-color: var(--arrowpanel-dimmed);
-  padding: 0;
-  margin: 0;
-}
-
-#main-window[customizing] #PanelUI-fxa-container {
-  display: none;
-}
-
-#PanelUI-fxa-container:not([fxastatus="signedin"]) > toolbarseparator,
-#PanelUI-fxa-container:not([fxastatus="signedin"]) > #PanelUI-fxa-icon {
-  display: none;
-}
-
-#PanelUI-fxa-container[fxastatus="login-failed"] > #PanelUI-fxa-status::after,
-#PanelUI-fxa-container[fxastatus="unverified"] > #PanelUI-fxa-status::after {
-  content: url(chrome://browser/skin/warning.svg);
-  filter: drop-shadow(0 1px 0 hsla(206,50%,10%,.15));
-  width: 47px;
-  padding-top: 1px;
-  display: block;
-  text-align: center;
-  position: relative;
-  top: 25%;
-}
-
 .addon-banner-item::after,
 .panel-banner-item::after {
   content: "";
   width: 16px;
   height: 16px;
   margin-inline-end: 16.5px;
   display: -moz-box;
 }
@@ -771,16 +531,17 @@ toolbaritem[cui-areatype="menu-panel"][s
   background-color: var(--appmenu-yellow-warning-color);
   /* Force border to override `.addon-banner-item` selector below */
   border-top: 1px solid var(--appmenu-yellow-warning-border-color) !important;
   display: flex;
   flex: 1 1 0%;
   width: calc(@menuPanelWidth@ + 30px);
   padding-inline-start: 15px;
   border-inline-start-style: none;
+  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 .addon-banner-item:hover {
   background-color: var(--appmenu-yellow-warning-hover-color);
 }
 
 .addon-banner-item:active {
   background-color: var(--appmenu-yellow-warning-active-color);
@@ -790,87 +551,49 @@ toolbaritem[cui-areatype="menu-panel"][s
   width: 16px;
   height: 16px;
 }
 
 .addon-banner-item::after {
   background: #FFBF00 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
 }
 
-#PanelUI-fxa-status {
-  display: flex;
-  flex: 1 1 0%;
-  width: 1px;
-}
-
-#PanelUI-footer-inner,
-#PanelUI-fxa-container:not([hidden]) {
-  display: flex;
-  border-top: 1px solid var(--panel-separator-color);
-}
-
-#PanelUI-multiView[viewtype="subview"] #PanelUI-footer-inner,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-fxa-container {
-  position: relative;
-}
-
-#PanelUI-footer-inner > toolbarseparator,
-#PanelUI-fxa-container > toolbarseparator {
-  border: 0;
-  border-left: 1px solid var(--panel-separator-color);
-  margin: 7px 0 7px;
-  -moz-appearance: none;
-}
-
-#PanelUI-footer-inner:hover > toolbarseparator,
-#PanelUI-fxa-container:hover > toolbarseparator {
-  margin: 0;
-}
-
 .addon-banner-item,
-.panel-banner-item,
-#PanelUI-help,
-#PanelUI-fxa-label,
-#PanelUI-fxa-icon,
-#PanelUI-customize,
-#PanelUI-quit {
+.panel-banner-item {
   margin: 0;
   padding: 11px 0;
   box-sizing: border-box;
   min-height: 40px;
   -moz-appearance: none;
   box-shadow: none;
   border: none;
   border-radius: 0;
   transition: background-color;
   -moz-box-orient: horizontal;
 }
 
 .panel-banner-item {
   border-top: 1px solid var(--panel-separator-color);
-  border-bottom: 1px solid transparent;
-  margin-bottom: -1px;
-}
-
-/* in Photon, we have a bottom border as well. Reconcile with the above rule
- * after photon launch. */
-#appMenu-mainView > .panel-subview-body > .panel-banner-item {
   border-bottom: 1px solid var(--panel-separator-color);
   margin-bottom: 3px;
   padding-inline-start: 12px;
 }
 
 #appMenu-addon-banners > .addon-banner-item {
   padding-inline-start: 12px;
 }
 
 .panel-banner-item > .toolbarbutton-text {
   width: 0; /* Fancy cropping solution for flexbox. */
 }
 
+.panel-banner-item > .toolbarbutton-icon {
+  width: 16px;
+}
+
 /* FxAccount indicator bits. */
 
 /* Add the .toolbaritem-combined-buttons class to increase the specificity so as
  * to override the end margin for .toolbaritem-combined-buttons items further down. */
 #appMenu-fxa-container.toolbaritem-combined-buttons:not([fxastatus="signedin"]) {
   margin-inline-end: 0;
 }
 
@@ -941,71 +664,34 @@ toolbaritem[cui-areatype="menu-panel"][s
   background-color: var(--appmenu-yellow-warning-hover-color);
 }
 
 #appMenu-fxa-container[fxastatus="login-failed"] > #appMenu-fxa-status:hover:active,
 #appMenu-fxa-container[fxastatus="unverified"] > #appMenu-fxa-status:hover:active {
   background-color: var(--appmenu-yellow-warning-active-color);
 }
 
-#PanelUI-help,
-#PanelUI-quit {
-  min-width: 46px;
-}
-
 .addon-banner-item > .toolbarbutton-text,
-.panel-banner-item > .toolbarbutton-text,
-#PanelUI-fxa-label > .toolbarbutton-text,
-#PanelUI-customize > .toolbarbutton-text {
+.panel-banner-item > .toolbarbutton-text {
   margin: 0;
   padding: 0 6px;
   text-align: start;
 }
 
-#PanelUI-help > .toolbarbutton-text,
-#PanelUI-quit > .toolbarbutton-text,
-#PanelUI-fxa-avatar > .toolbarbutton-text {
-  display: none;
-}
-
 .addon-banner-item > .toolbarbutton-icon,
-.panel-banner-item > .toolbarbutton-icon,
-#PanelUI-fxa-label > .toolbarbutton-icon,
-#PanelUI-fxa-icon > .toolbarbutton-icon,
-#PanelUI-customize > .toolbarbutton-icon,
-#PanelUI-help > .toolbarbutton-icon,
-#PanelUI-quit > .toolbarbutton-icon {
+.panel-banner-item > .toolbarbutton-icon {
   margin-inline-end: 0;
 }
 
-#PanelUI-fxa-icon {
-  padding-inline-start: 15px;
-  padding-inline-end: 15px;
-}
-
-#PanelUI-fxa-label,
-.addon-banner-item,
-#PanelUI-customize {
+.addon-banner-item {
   flex: 1;
   padding-inline-start: 15px;
   border-inline-start-style: none;
 }
 
-#PanelUI-fxa-container[fxastatus="signedin"] > #PanelUI-fxa-status > #PanelUI-fxa-label {
-  padding-inline-start: 0px;
-}
-
-/* descend from #PanelUI-footer to add specificity, or else the
-   padding-inline-start will be overridden */
-#PanelUI-footer > .panel-banner-item {
-  width: calc(@menuPanelWidth@ + 30px);
-  padding-inline-start: 15px;
-  border-inline-start-style: none;
-}
-
 #PanelUI-remotetabs {
   --panel-ui-sync-illustration-height: 157.5px;
 }
 
 .PanelUI-remotetabs-instruction-title,
 .PanelUI-remotetabs-instruction-label,
 #PanelUI-remotetabs-mobile-promo {
   /* If you change the margin here, the min-height of the synced tabs panel
@@ -1115,171 +801,29 @@ toolbaritem[cui-areatype="menu-panel"][s
 #PanelUI-remotetabs-deck:not([selectedIndex="3"]) > #PanelUI-remotetabs-nodevicespane {
   visibility: collapse;
 }
 
 #PanelUI-remotetabs-main[devices-status="single"] > #PanelUI-remotetabs-buttons {
   display: none;
 }
 
-#PanelUI-customize {
-  list-style-image: url(chrome://browser/skin/menuPanel-customize.png);
-}
-
-#customization-panelHolder #PanelUI-customize {
-  list-style-image: url(chrome://browser/skin/customizableui/menuPanel-customizeFinish.png);
-}
-
-#PanelUI-help {
-  list-style-image: url(chrome://browser/skin/menuPanel-help.png);
-}
-
-#PanelUI-quit {
-  border-inline-end-style: none;
-  list-style-image: url(chrome://browser/skin/menuPanel-exit.png);
-}
-
-#PanelUI-fxa-label,
-#PanelUI-fxa-icon,
-.addon-banner-item,
-#PanelUI-customize,
-#PanelUI-help,
-#PanelUI-quit {
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-#PanelUI-fxa-container[fxastatus="signedin"] > #PanelUI-fxa-status > #PanelUI-fxa-label > .toolbarbutton-icon,
-#PanelUI-fxa-container:not([fxastatus="signedin"]) > #PanelUI-fxa-status > #PanelUI-fxa-avatar {
-  display: none;
-}
-
-#PanelUI-fxa-avatar {
-  width: 32px;
-  height: 32px;
-  border-radius: 50%;
-  background-repeat: no-repeat;
-  background-position: 0 0;
-  background-size: contain;
-  align-self: center;
-  margin: 0px 7px;
-  padding: 0px;
-  border: 0px none;
-  margin-inline-end: 0;
-}
-
-#PanelUI-fxa-container > #PanelUI-fxa-status > #PanelUI-fxa-avatar {
-  list-style-image: url(chrome://browser/skin/fxa/default-avatar.svg);
-}
-
-#PanelUI-customize:hover,
-#PanelUI-help:not([disabled]):hover,
-#PanelUI-quit:not([disabled]):hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#PanelUI-customize:hover:active,
-#PanelUI-help:not([disabled]):hover:active,
-#PanelUI-quit:not([disabled]):hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
-#PanelUI-help[panel-multiview-anchor="true"] {
-  -moz-image-region: rect(0, 64px, 16px, 48px);
-}
-
-#PanelUI-help[disabled],
-#PanelUI-quit[disabled] {
-  opacity: 0.4;
-}
-
-#PanelUI-fxa-status:hover,
-#PanelUI-fxa-icon:hover,
-#PanelUI-help:not([disabled]):hover,
-#PanelUI-customize:hover,
-#PanelUI-quit:not([disabled]):hover {
-  outline: 1px solid var(--arrowpanel-dimmed);
-  background-color: var(--arrowpanel-dimmed);
-}
-
-#PanelUI-fxa-status:hover:active,
-#PanelUI-fxa-icon:hover:active,
-#PanelUI-help:not([disabled]):hover:active,
-#PanelUI-customize:hover:active,
-#PanelUI-quit:not([disabled]):hover:active {
-  outline: 1px solid var(--arrowpanel-dimmed-further);
-  background-color: var(--arrowpanel-dimmed-further);
-  box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
-}
-
-#PanelUI-fxa-status:hover,
-#PanelUI-fxa-status:hover:active,
-#PanelUI-fxa-icon:hover,
-#PanelUI-fxa-icon:hover:active {
-  outline: none;
-}
-
-#PanelUI-fxa-container[fxastatus="login-failed"],
-#PanelUI-fxa-container[fxastatus="unverified"] {
-  background-color: hsl(42,94%,88%);
-  border-top: 1px solid hsl(42,94%,70%);
-}
-
-#PanelUI-fxa-container[fxastatus="login-failed"] > #PanelUI-fxa-status:hover,
-#PanelUI-fxa-container[fxastatus="unverified"] > #PanelUI-fxa-status:hover {
-  background-color: hsl(42,94%,85%);
-}
-
-#PanelUI-fxa-container[fxastatus="login-failed"] > #PanelUI-fxa-status:hover:active,
-#PanelUI-fxa-container[fxastatus="unverified"] > #PanelUI-fxa-status:hover:active {
-  background-color: hsl(42,94%,82%);
-  box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
-}
-
 .panel-banner-item {
   color: black;
   background-color: hsla(96,65%,75%,.5);
 }
 
 .panel-banner-item:not([disabled]):hover {
   background-color: hsla(96,65%,75%,.8);
 }
 
 .panel-banner-item:not([disabled]):hover:active {
   background-color: hsl(96,65%,75%);
 }
 
-#PanelUI-quit:not([disabled]):hover {
-  background-color: #d94141;
-  outline-color: #c23a3a;
-}
-
-#PanelUI-quit:not([disabled]):hover:active {
-  background-color: #ad3434;
-  outline-color: #992e2e;
-}
-
-#customization-panelHolder #PanelUI-customize {
-  color: white;
-  background-color: hsl(108,66%,30%);
-  text-shadow: none;
-  margin-top: -1px;
-}
-
-#customization-panelHolder #PanelUI-customize + toolbarseparator {
-  display: none;
-}
-
-#customization-panelHolder #PanelUI-customize:hover {
-  background-color: hsl(109,65%,26%);
-}
-
-#customization-panelHolder #PanelUI-customize:hover:active {
-  background-color: hsl(109,65%,22%);
-}
-
 #customization-palette .toolbarbutton-multiline-text,
 #customization-palette .toolbarbutton-text {
   display: none;
 }
 
 .subview-subheader,
 panelview .toolbarbutton-1,
 .subviewbutton,
@@ -1419,16 +963,25 @@ panelview .toolbarbutton-1,
 /* This is a <label> but it should fit in with the menu font- and colorwise. */
 #PanelUI-characterEncodingView-autodetect-label {
   font: menu;
   color: inherit;
 }
 
 /* START photon adjustments */
 
+.subviewbutton[checked="true"] {
+  background: url(chrome://browser/skin/check.svg) center left 7px / 11px 11px no-repeat transparent;
+  fill: currentColor;
+}
+
+.subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
+  background-position: center right 7px;
+}
+
 photonpanelmultiview .subviewbutton[checked="true"] {
   background: none;
   list-style-image: url(chrome://browser/skin/check.svg);
 }
 
 photonpanelmultiview .subviewbutton > .menu-iconic-left {
   -moz-appearance: none;
   margin-inline-end: 0;
@@ -1662,63 +1215,16 @@ menuitem.panel-subview-footer@menuStateA
 #PanelUI-remotetabs-tabslist > toolbarbutton[itemtype="tab"] > .toolbarbutton-icon,
 #PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon,
 #PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon,
 #PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
 }
 
-toolbarbutton[panel-multiview-anchor="true"],
-toolbarbutton[panel-multiview-anchor="true"] > .toolbarbutton-menubutton-button {
-  color: HighlightText;
-  background-color: Highlight;
-}
-
-#PanelUI-help[panel-multiview-anchor="true"] + toolbarseparator {
-  display: none;
-}
-
-#PanelUI-help[panel-multiview-anchor="true"] {
-  background-image: linear-gradient(rgba(255,255,255,0.3), transparent);
-  background-position: 0;
-}
-
-#PanelUI-help[panel-multiview-anchor="true"]::after {
-  content: "";
-  position: absolute;
-  top: 0;
-  height: 100%;
-  width: var(--panel-ui-exit-subview-gutter-width);
-  background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
-                    linear-gradient(rgba(255,255,255,0.3), transparent);
-  background-repeat: no-repeat;
-  background-color: Highlight;
-  background-position: left 10px center, 0;
-}
-
-#PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after {
-  background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl.png),
-                    linear-gradient(rgba(255,255,255,0.3), transparent);
-  background-position: right 10px center, 0;
-}
-
-toolbarbutton[panel-multiview-anchor="true"] {
-  background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
-                    linear-gradient(rgba(255,255,255,0.3), transparent);
-  background-position: right calc(@menuPanelButtonWidth@ / 2 - var(--panel-ui-exit-subview-gutter-width) + 2px) center;
-  background-repeat: no-repeat, repeat;
-}
-
-toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
-  background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl.png),
-                    linear-gradient(rgba(255,255,255,0.3), transparent);
-  background-position: left calc(@menuPanelButtonWidth@ / 2 - var(--panel-ui-exit-subview-gutter-width) + 2px) center;
-}
-
 toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
 #bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menu-dropmarker,
 #bookmarks-menu-button[overflowedItem] > .toolbarbutton-menu-dropmarker,
 toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 #bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker {
   display: none;
 }
 
@@ -1824,16 +1330,17 @@ toolbaritem[overflowedItem=true],
 .widget-overflow-list .toolbarbutton-1 {
   -moz-box-align: center;
   -moz-box-orient: horizontal;
 }
 
 .widget-overflow-list .subviewbutton-nav:-moz-locale-dir(ltr)::after {
     transform: scaleX(-1);
 }
+
 .widget-overflow-list .subviewbutton-nav::after {
     margin-inline-start: 10px;
     -moz-context-properties: fill;
     content: url(chrome://browser/skin/back-12.svg);
     fill: GrayText;
     float: right;
 }
 
@@ -1841,24 +1348,16 @@ toolbarpaletteitem[place=panel] > .subvi
   opacity: 0.5;
 }
 
 .widget-overflow-list .toolbarbutton-1:not(.toolbarbutton-combined) > .toolbarbutton-text {
   text-align: start;
   padding-inline-start: .5em;
 }
 
-.subviewbutton[checked="true"] {
-  background: url("chrome://global/skin/menu/shared-menu-check.png") center left 7px / 11px 11px no-repeat transparent;
-}
-
-.subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
-  background-position: center right 7px;
-}
-
 .subviewbutton > .menu-iconic-left {
   -moz-appearance: none;
   margin-inline-end: 3px;
 }
 
 menuitem[checked="true"].subviewbutton > .menu-iconic-left {
   visibility: hidden;
 }
@@ -2048,87 +1547,20 @@ menuitem[checked="true"].subviewbutton >
 }
 
 #panic-button-success-closebutton:hover:active {
   background-color: #d0d0d0;
   border-color: #aaa;
 }
 
 @media (min-resolution: 1.1dppx) {
-  #PanelUI-help[panel-multiview-anchor="true"]::after,
-  toolbarbutton[panel-multiview-anchor="true"] {
-    background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted@2x.png),
-                      linear-gradient(rgba(255,255,255,0.3), transparent);
-    background-size: 16px, auto;
-  }
-
-  #PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after,
-  toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
-    background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl@2x.png),
-                      linear-gradient(rgba(255,255,255,0.3), transparent);
-  }
-
   .panel-banner-item[notificationid^=update] {
     list-style-image: url(chrome://branding/content/icon32.png);
   }
 
-  #PanelUI-customize {
-    list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
-  }
-
-  #customization-panelHolder #PanelUI-customize {
-    list-style-image: url(chrome://browser/skin/customizableui/menuPanel-customizeFinish@2x.png);
-  }
-
-  #PanelUI-help {
-    list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png);
-  }
-
-  #PanelUI-quit {
-    list-style-image: url(chrome://browser/skin/menuPanel-exit@2x.png);
-  }
-
-  #PanelUI-fxa-label,
-  #PanelUI-fxa-icon,
-  #PanelUI-customize,
-  #PanelUI-help,
-  #PanelUI-quit {
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  .panel-banner-item > .toolbarbutton-icon,
-  #PanelUI-fxa-label > .toolbarbutton-icon,
-  #PanelUI-fxa-icon > .toolbarbutton-icon,
-  #PanelUI-customize > .toolbarbutton-icon,
-  #PanelUI-help > .toolbarbutton-icon,
-  #PanelUI-quit > .toolbarbutton-icon {
-    width: 16px;
-  }
-
-  #PanelUI-customize:hover,
-  #PanelUI-help:not([disabled]):hover,
-  #PanelUI-quit:not([disabled]):hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  #PanelUI-customize:hover:active,
-  #PanelUI-help:not([disabled]):hover:active,
-  #PanelUI-quit:not([disabled]):hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
-  #PanelUI-help[panel-multiview-anchor="true"] {
-    -moz-image-region: rect(0, 128px, 32px, 96px);
-    background-size: auto;
-  }
-
-  .subviewbutton[checked="true"] {
-    background-image: url("chrome://global/skin/menu/shared-menu-check@2x.png");
-  }
-
   #panic-button-success-icon,
   #PanelUI-panic-timeframe-icon {
     list-style-image: url(chrome://browser/skin/panic-panel/header@2x.png);
   }
 
   #PanelUI-panic-timeframe-icon-small {
     list-style-image: url(chrome://browser/skin/panic-panel/header-small@2x.png);
   }
deleted file mode 100644
index cf4198c60004b0f0f0a55b6c18d6660f631588d3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index bb250403d47d3bdc55e39b9eca61c77e17a5d4ca..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 86178abfecd2e16d60e721c88cb2e2b57b4dce53..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 1c8e86db37d9406c3c64f2194c773b5f0f132dbb..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 61f55f60fff5f5f044d6449bdb08d1a9def95c4a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -23,29 +23,22 @@
 * skin/classic/browser/controlcenter/conn-not-secure.svg       (../shared/controlcenter/conn-not-secure.svg)
   skin/classic/browser/controlcenter/connection.svg            (../shared/controlcenter/connection.svg)
   skin/classic/browser/controlcenter/mcb-disabled.svg          (../shared/controlcenter/mcb-disabled.svg)
   skin/classic/browser/controlcenter/extension.svg             (../shared/controlcenter/extension.svg)
 * skin/classic/browser/controlcenter/permissions.svg           (../shared/controlcenter/permissions.svg)
 * skin/classic/browser/controlcenter/tracking-protection.svg   (../shared/controlcenter/tracking-protection.svg)
   skin/classic/browser/controlcenter/warning-gray.svg          (../shared/controlcenter/warning-gray.svg)
   skin/classic/browser/controlcenter/warning-yellow.svg        (../shared/controlcenter/warning-yellow.svg)
-  skin/classic/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
-  skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
   skin/classic/browser/customizableui/empty-overflow-panel.png     (../shared/customizableui/empty-overflow-panel.png)
   skin/classic/browser/customizableui/empty-overflow-panel@2x.png  (../shared/customizableui/empty-overflow-panel@2x.png)
   skin/classic/browser/customizableui/density-compact.svg      (../shared/customizableui/density-compact.svg)
   skin/classic/browser/customizableui/density-normal.svg       (../shared/customizableui/density-normal.svg)
   skin/classic/browser/customizableui/density-touch.svg        (../shared/customizableui/density-touch.svg)
-  skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
-  skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png  (../shared/customizableui/subView-arrow-back-inverted@2x.png)
-  skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png  (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
-  skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl@2x.png  (../shared/customizableui/subView-arrow-back-inverted-rtl@2x.png)
   skin/classic/browser/customizableui/whimsy.png               (../shared/customizableui/whimsy.png)
-  skin/classic/browser/customizableui/whimsy@2x.png            (../shared/customizableui/whimsy@2x.png)
   skin/classic/browser/downloads/contentAreaDownloadsView.css  (../shared/downloads/contentAreaDownloadsView.css)
   skin/classic/browser/downloads/download-blocked.svg          (../shared/downloads/download-blocked.svg)
   skin/classic/browser/downloads/download-summary.svg          (../shared/downloads/download-summary.svg)
   skin/classic/browser/downloads/download-icons.svg            (../shared/downloads/download-icons.svg)
   skin/classic/browser/downloads/notification-start-animation.svg  (../shared/downloads/notification-start-animation.svg)
   skin/classic/browser/drm-icon.svg                            (../shared/drm-icon.svg)
   skin/classic/browser/fullscreen/insecure.svg                 (../shared/fullscreen/insecure.svg)
   skin/classic/browser/fullscreen/secure.svg                   (../shared/fullscreen/secure.svg)
@@ -202,17 +195,16 @@
   skin/classic/browser/tabbrowser/indicator-tab-attention.svg  (../shared/tabbrowser/indicator-tab-attention.svg)
   skin/classic/browser/tabbrowser/pendingpaint.png             (../shared/tabbrowser/pendingpaint.png)
   skin/classic/browser/tabbrowser/tab-audio-playing.svg        (../shared/tabbrowser/tab-audio-playing.svg)
   skin/classic/browser/tabbrowser/tab-audio-muted.svg          (../shared/tabbrowser/tab-audio-muted.svg)
   skin/classic/browser/tabbrowser/tab-audio-blocked.svg        (../shared/tabbrowser/tab-audio-blocked.svg)
   skin/classic/browser/tabbrowser/tab-audio-small.svg          (../shared/tabbrowser/tab-audio-small.svg)
   skin/classic/browser/tabbrowser/tab-overflow-indicator.png   (../shared/tabbrowser/tab-overflow-indicator.png)
 
-  skin/classic/browser/toolbarbutton-dropdown-arrow.png        (../shared/toolbarbutton-dropdown-arrow.png)
   skin/classic/browser/translating-16.png                      (../shared/translation/translating-16.png)
   skin/classic/browser/translating-16@2x.png                   (../shared/translation/translating-16@2x.png)
   skin/classic/browser/translation-16.png                      (../shared/translation/translation-16.png)
   skin/classic/browser/translation-16@2x.png                   (../shared/translation/translation-16@2x.png)
   skin/classic/browser/update-badge.svg                        (../shared/update-badge.svg)
   skin/classic/browser/update-badge-failed.svg                 (../shared/update-badge-failed.svg)
   skin/classic/browser/warning.svg                             (../shared/warning.svg)
   skin/classic/browser/warning-white.svg                       (../shared/warning-white.svg)
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -961,17 +961,21 @@ notification[value="translation"] {
 
   notification[value="translation"] button[anonid="translate"]:hover,
   notification[value="translation"] button[anonid="translate"]:active {
     background-color: #008ACB;
   }
 
   notification[value="translation"] button[type="menu"] > .button-box > .button-menu-dropmarker,
   notification[value="translation"] menulist > .menulist-dropmarker {
-    list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow.png");
+    list-style-image: url(chrome://global/skin/icons/arrow-dropdown-16.svg);
+  }
+  notification[value="translation"] menulist > .menulist-dropmarker > .dropmarker-icon {
+    width: 11px;
+    height: 11px;
   }
 
   notification[value="translation"] button > .button-box,
   notification[value="translation"] button[type="menu"] > .button-box > .button-menu-dropmarker {
     padding: 0;
     margin-inline-start: 3ch;
   }
 
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -5,32 +5,25 @@
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
 * skin/classic/browser/syncedtabs/sidebar.css     (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
-  skin/classic/browser/menuPanel-customize.png
-  skin/classic/browser/menuPanel-customize@2x.png
-  skin/classic/browser/menuPanel-exit.png
-  skin/classic/browser/menuPanel-exit@2x.png
-  skin/classic/browser/menuPanel-help.png
-  skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/sync-desktopIcon.svg  (../shared/sync-desktopIcon.svg)
   skin/classic/browser/sync-mobileIcon.svg  (../shared/sync-mobileIcon.svg)
-  skin/classic/browser/toolbarbutton-dropdown-arrow-win7.png
   skin/classic/browser/webRTC-indicator.css  (../shared/webRTC-indicator.css)
 * skin/classic/browser/controlcenter/panel.css                 (controlcenter/panel.css)
   skin/classic/browser/customizableui/menu-arrow.svg           (customizableui/menu-arrow.svg)
 * skin/classic/browser/customizableui/panelUI.css       (customizableui/panelUI.css)
 * skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
 * skin/classic/browser/downloads/downloads.css                 (downloads/downloads.css)
   skin/classic/browser/feeds/feedIcon.png                      (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
@@ -75,10 +68,8 @@ browser.jar:
   skin/classic/browser/e10s-64@2x.png                            (../shared/e10s-64@2x.png)
 
 [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/page-livemarks.png                   chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/audioFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
-
-% override chrome://browser/skin/toolbarbutton-dropdown-arrow.png     chrome://browser/skin/toolbarbutton-dropdown-arrow-win7.png   os=WINNT osversion<=6.1
deleted file mode 100644
index 82cd8748308aba98d718599b31d0c1d57d23fd78..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 161426f8940172261ebd2f48f7ad376ba7ac8a85..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 5ce3b766a1bb9b298120472bdf42b0bc63404918..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 8daaffe9556f3fc93fbfa7883fa0639b72e0a26e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index d48426546fa492f78bd3e22676184b7dece8bcb3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 2f2b010bc7028fdbd4fe331c2004ea0b3e4f9cce..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b8f0a80fa168230973a6eb53f8bfe93d2cc981df..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/build/autoconf/clang-plugin.m4
+++ b/build/autoconf/clang-plugin.m4
@@ -153,14 +153,14 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
 
     CLANG_PLUGIN_FLAGS="-Xclang -load -Xclang $CLANG_PLUGIN -Xclang -add-plugin -Xclang moz-check"
 
     AC_DEFINE(MOZ_CLANG_PLUGIN)
 fi
 
 AC_SUBST_LIST(CLANG_PLUGIN_FLAGS)
 AC_SUBST_LIST(LLVM_CXXFLAGS)
-AC_SUBST(LLVM_LDFLAGS)
-AC_SUBST(CLANG_LDFLAGS)
+AC_SUBST_LIST(LLVM_LDFLAGS)
+AC_SUBST_LIST(CLANG_LDFLAGS)
 
 AC_SUBST(ENABLE_CLANG_PLUGIN)
 
 ])
--- a/build/clang-plugin/Makefile.in
+++ b/build/clang-plugin/Makefile.in
@@ -1,33 +1,27 @@
 # 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/.
 
-# LLVM_CXXFLAGS comes with its own optimization flags.
-MOZ_OPTIMIZE =
-
 include $(topsrcdir)/config/config.mk
 
 # In the current moz.build world, we need to override essentially every
 # variable to limit ourselves to what we need to build the clang plugin.
 ifneq ($(HOST_OS_ARCH),WINNT)
 DSO_LDOPTS := -shared
 endif
-OS_LDFLAGS := $(LLVM_LDFLAGS) $(CLANG_LDFLAGS)
 
 ifeq ($(HOST_OS_ARCH)_$(OS_ARCH),Linux_Darwin)
 # Use the host compiler instead of the target compiler.
 CXX := $(HOST_CXX)
 # expandlibs doesn't know the distinction between host and target toolchains,
 # and on cross linux/darwin builds, the options to give to the linker for file
 # lists differ between both, so don't use file lists.
 EXPAND_MKSHLIB_ARGS :=
-# Don't pass OSX linker arguments.
-MOZ_FIX_LINK_PATHS :=
 endif
 
 # Use the default OS X deployment target to enable using the libc++ headers
 # correctly.  Note that the binary produced here is a host tool and doesn't need
 # to be distributed.
 MACOSX_DEPLOYMENT_TARGET :=
 
 # Temporarily relax the requirements for libstdc++ symbol versions on static
--- a/build/clang-plugin/moz.build
+++ b/build/clang-plugin/moz.build
@@ -70,8 +70,17 @@ else:
 
 if CONFIG['LLVM_CXXFLAGS']:
     COMPILE_FLAGS['OS_CXXFLAGS'] = CONFIG['LLVM_CXXFLAGS'] + extra_cxxflags
 
 COMPILE_FLAGS['CLANG_PLUGIN'] = []
 COMPILE_FLAGS['OPTIMIZE'] = []
 COMPILE_FLAGS['DEBUG'] = []
 COMPILE_FLAGS['OS_COMPILE_CXXFLAGS'] = []
+
+LINK_FLAGS['OS'] = CONFIG['LLVM_LDFLAGS'] + CONFIG['CLANG_LDFLAGS']
+# The ldflags above override most other categories.
+for var in ('LINKER', 'OPTIMIZE'):
+    LINK_FLAGS[var] = []
+
+if CONFIG['HOST_OS_ARCH'] == 'Linux' and CONFIG['OS_ARCH'] == 'Darwin':
+    # Don't pass OSX linker arguments.
+    LINK_FLAGS['FIX_LINK_PATHS'] = []
--- a/config/config.mk
+++ b/config/config.mk
@@ -131,61 +131,32 @@ CXX := $(CXX_WRAPPER) $(CXX)
 MKDIR ?= mkdir
 SLEEP ?= sleep
 TOUCH ?= touch
 
 PYTHON_PATH = $(PYTHON) $(topsrcdir)/config/pythonpath.py
 
 # determine debug-related options
 _DEBUG_ASFLAGS :=
-_DEBUG_LDFLAGS :=
 
 ifneq (,$(MOZ_DEBUG)$(MOZ_DEBUG_SYMBOLS))
   ifeq ($(AS),$(YASM))
     ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
       _DEBUG_ASFLAGS += -g cv8
     else
       ifneq ($(OS_ARCH),Darwin)
         _DEBUG_ASFLAGS += -g dwarf2
       endif
     endif
   else
     _DEBUG_ASFLAGS += $(MOZ_DEBUG_FLAGS)
   endif
-  _DEBUG_LDFLAGS += $(MOZ_DEBUG_LDFLAGS)
 endif
 
 ASFLAGS += $(_DEBUG_ASFLAGS)
-OS_LDFLAGS += $(_DEBUG_LDFLAGS)
-
-# XXX: What does this? Bug 482434 filed for better explanation.
-ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
-ifndef MOZ_DEBUG
-
-# MOZ_DEBUG_SYMBOLS generates debug symbols in separate PDB files.
-# Used for generating an optimized build with debugging symbols.
-# Used in the Windows nightlies to generate symbols for crash reporting.
-ifdef MOZ_DEBUG_SYMBOLS
-OS_LDFLAGS += -DEBUG
-endif
-
-#
-# Handle DMD in optimized builds.
-#
-ifdef MOZ_DMD
-OS_LDFLAGS = -DEBUG
-endif # MOZ_DMD
-
-ifdef MOZ_OPTIMIZE
-OS_LDFLAGS += -OPT:REF,ICF
-endif # MOZ_OPTIMIZE
-
-endif # MOZ_DEBUG
-
-endif # WINNT && !GNU_CC
 
 #
 # Build using PIC by default
 #
 _ENABLE_PIC=1
 
 # Don't build SIMPLE_PROGRAMS with PGO, since they don't need it anyway,
 # and we don't have the same build logic to re-link them in the second pass.
@@ -197,34 +168,31 @@ endif
 ifdef CPP_UNIT_TESTS
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 endif
 
 # Enable profile-based feedback
 ifneq (1,$(NO_PROFILE_GUIDED_OPTIMIZE))
 ifdef MOZ_PROFILE_GENERATE
 PGO_CFLAGS += $(if $(filter $(notdir $<),$(notdir $(NO_PROFILE_GUIDED_OPTIMIZE))),,$(PROFILE_GEN_CFLAGS))
-OS_LDFLAGS += $(PROFILE_GEN_LDFLAGS)
+PGO_LDFLAGS += $(PROFILE_GEN_LDFLAGS)
 ifeq (WINNT,$(OS_ARCH))
 AR_FLAGS += -LTCG
 endif
 endif # MOZ_PROFILE_GENERATE
 
 ifdef MOZ_PROFILE_USE
 PGO_CFLAGS += $(if $(filter $(notdir $<),$(notdir $(NO_PROFILE_GUIDED_OPTIMIZE))),,$(PROFILE_USE_CFLAGS))
-OS_LDFLAGS += $(PROFILE_USE_LDFLAGS)
+PGO_LDFLAGS += $(PROFILE_USE_LDFLAGS)
 ifeq (WINNT,$(OS_ARCH))
 AR_FLAGS += -LTCG
 endif
 endif # MOZ_PROFILE_USE
 endif # NO_PROFILE_GUIDED_OPTIMIZE
 
-# linker
-OS_LDFLAGS += $(LINKER_LDFLAGS)
-
 MAKE_JARS_FLAGS = \
 	-t $(topsrcdir) \
 	-f $(MOZ_JAR_MAKER_FILE_FORMAT) \
 	$(NULL)
 
 ifdef USE_EXTENSION_MANIFEST
 MAKE_JARS_FLAGS += -e
 endif
@@ -246,21 +214,17 @@ INCLUDES = \
   -I$(srcdir) \
   -I$(CURDIR) \
   $(LOCAL_INCLUDES) \
   -I$(ABS_DIST)/include \
   $(NULL)
 
 include $(MOZILLA_DIR)/config/static-checking-config.mk
 
-LDFLAGS		= $(OS_LDFLAGS) $(MOZBUILD_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
-
-ifdef MOZ_OPTIMIZE
-LDFLAGS		+= $(MOZ_OPTIMIZE_LDFLAGS)
-endif # MOZ_OPTIMIZE
+LDFLAGS		= $(COMPUTED_LDFLAGS) $(PGO_LDFLAGS) $(MK_LDFLAGS)
 
 COMPILE_CFLAGS	= $(COMPUTED_CFLAGS) $(PGO_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
 COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(PGO_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
 COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS)
 COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
 ASFLAGS += $(MOZBUILD_ASFLAGS)
 
 HOST_CFLAGS = $(COMPUTED_HOST_CFLAGS) $(_DEPEND_CFLAGS)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -163,29 +163,19 @@ endif
 COMPILE_CFLAGS += $(COMPILE_PDB_FLAG)
 COMPILE_CXXFLAGS += $(COMPILE_PDB_FLAG)
 
 LINK_PDBFILE ?= $(basename $(@F)).pdb
 ifdef MOZ_DEBUG
 CODFILE=$(basename $(@F)).cod
 endif
 
-ifdef DEFFILE
-OS_LDFLAGS += -DEF:$(call normalizepath,$(DEFFILE))
-EXTRA_DEPS += $(DEFFILE)
-endif
-
-else #!GNU_CC
+endif # !GNU_CC
 
-ifdef DEFFILE
-OS_LDFLAGS += $(call normalizepath,$(DEFFILE))
 EXTRA_DEPS += $(DEFFILE)
-endif
-
-endif # !GNU_CC
 
 endif # WINNT
 
 ifeq (arm-Darwin,$(CPU_ARCH)-$(OS_TARGET))
 ifdef PROGRAM
 MOZ_PROGRAM_LDFLAGS += -Wl,-rpath -Wl,@executable_path/Frameworks
 endif
 endif
--- a/devtools/shared/heapsnapshot/CoreDump.pb.cc
+++ b/devtools/shared/heapsnapshot/CoreDump.pb.cc
@@ -6,20 +6,17 @@
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/generated_message_reflection.h>
-#include <google/protobuf/reflection_ops.h>
-#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 // @@protoc_insertion_point(includes)
 
 namespace mozilla {
 namespace devtools {
 namespace protobuf {
 class MetadataDefaultTypeInternal {
 public:
  ::google::protobuf::internal::ExplicitlyConstructed<Metadata>
@@ -57,23 +54,16 @@ public:
  ::google::protobuf::internal::ExplicitlyConstructed<Edge>
      _instance;
   ::google::protobuf::internal::ArenaStringPtr name_;
   ::google::protobuf::uint64 nameref_;
 } _Edge_default_instance_;
 
 namespace protobuf_CoreDump_2eproto {
 
-
-namespace {
-
-::google::protobuf::Metadata file_level_metadata[5];
-
-}  // namespace
-
 PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField
     const TableStruct::entries[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
   {0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},
 };
 
 PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField
     const TableStruct::aux[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
   ::google::protobuf::internal::AuxillaryParseTableField(),
@@ -82,253 +72,70 @@ PROTOBUF_CONSTEXPR_VAR ::google::protobu
     TableStruct::schema[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
   { NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
   { NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
   { NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
   { NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
   { NULL, NULL, 0, -1, -1, -1, -1, NULL, false },
 };
 
-const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, _has_bits_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, _internal_metadata_),
-  ~0u,  // no _extensions_
-  ~0u,  // no _oneof_case_
-  ~0u,  // no _weak_field_map_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, timestamp_),
-  0,
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _has_bits_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _internal_metadata_),
-  ~0u,  // no _extensions_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _oneof_case_[0]),
-  ~0u,  // no _weak_field_map_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, id_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, parent_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, line_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, column_),
-  offsetof(StackFrame_DataDefaultTypeInternal, source_),
-  offsetof(StackFrame_DataDefaultTypeInternal, sourceref_),
-  offsetof(StackFrame_DataDefaultTypeInternal, functiondisplayname_),
-  offsetof(StackFrame_DataDefaultTypeInternal, functiondisplaynameref_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, issystem_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, isselfhosted_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, SourceOrRef_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, FunctionDisplayNameOrRef_),
-  1,
-  0,
-  2,
-  3,
-  ~0u,
-  ~0u,
-  ~0u,
-  ~0u,
-  4,
-  5,
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _has_bits_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _internal_metadata_),
-  ~0u,  // no _extensions_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _oneof_case_[0]),
-  ~0u,  // no _weak_field_map_
-  offsetof(StackFrameDefaultTypeInternal, data_),
-  offsetof(StackFrameDefaultTypeInternal, ref_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, StackFrameType_),
-  ~0u,
-  ~0u,
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _has_bits_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _internal_metadata_),
-  ~0u,  // no _extensions_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _oneof_case_[0]),
-  ~0u,  // no _weak_field_map_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, id_),
-  offsetof(NodeDefaultTypeInternal, typename__),
-  offsetof(NodeDefaultTypeInternal, typenameref_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, size_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, edges_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, allocationstack_),
-  offsetof(NodeDefaultTypeInternal, jsobjectclassname_),
-  offsetof(NodeDefaultTypeInternal, jsobjectclassnameref_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, coarsetype_),
-  offsetof(NodeDefaultTypeInternal, scriptfilename_),
-  offsetof(NodeDefaultTypeInternal, scriptfilenameref_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, TypeNameOrRef_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, JSObjectClassNameOrRef_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, ScriptFilenameOrRef_),
-  1,
-  ~0u,
-  ~0u,
-  2,
-  ~0u,
-  0,
-  ~0u,
-  ~0u,
-  3,
-  ~0u,
-  ~0u,
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _has_bits_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _internal_metadata_),
-  ~0u,  // no _extensions_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _oneof_case_[0]),
-  ~0u,  // no _weak_field_map_
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, referent_),
-  offsetof(EdgeDefaultTypeInternal, name_),
-  offsetof(EdgeDefaultTypeInternal, nameref_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, EdgeNameOrRef_),
-  0,
-  ~0u,
-  ~0u,
-};
-static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, 6, sizeof(Metadata)},
-  { 7, 24, sizeof(StackFrame_Data)},
-  { 34, 42, sizeof(StackFrame)},
-  { 44, 63, sizeof(Node)},
-  { 74, 83, sizeof(Edge)},
-};
-
-static ::google::protobuf::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::google::protobuf::Message*>(&_Metadata_default_instance_),
-  reinterpret_cast<const ::google::protobuf::Message*>(&_StackFrame_Data_default_instance_),
-  reinterpret_cast<const ::google::protobuf::Message*>(&_StackFrame_default_instance_),
-  reinterpret_cast<const ::google::protobuf::Message*>(&_Node_default_instance_),
-  reinterpret_cast<const ::google::protobuf::Message*>(&_Edge_default_instance_),
-};
-
-namespace {
-
-void protobuf_AssignDescriptors() {
-  AddDescriptors();
-  ::google::protobuf::MessageFactory* factory = NULL;
-  AssignDescriptors(
-      "CoreDump.proto", schemas, file_default_instances, TableStruct::offsets, factory,
-      file_level_metadata, NULL, NULL);
-}
-
-void protobuf_AssignDescriptorsOnce() {
-  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
-  ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
-}
-
-void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
-void protobuf_RegisterTypes(const ::std::string&) {
-  protobuf_AssignDescriptorsOnce();
-  ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 5);
-}
-
-}  // namespace
 void TableStruct::InitDefaultsImpl() {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
   ::google::protobuf::internal::InitProtobufDefaults();
   _Metadata_default_instance_._instance.DefaultConstruct();
   ::google::protobuf::internal::OnShutdownDestroyMessage(
       &_Metadata_default_instance_);_StackFrame_Data_default_instance_._instance.DefaultConstruct();
   ::google::protobuf::internal::OnShutdownDestroyMessage(
       &_StackFrame_Data_default_instance_);_StackFrame_default_instance_._instance.DefaultConstruct();
   ::google::protobuf::internal::OnShutdownDestroyMessage(
       &_StackFrame_default_instance_);_Node_default_instance_._instance.DefaultConstruct();
   ::google::protobuf::internal::OnShutdownDestroyMessage(
       &_Node_default_instance_);_Edge_default_instance_._instance.DefaultConstruct();
   ::google::protobuf::internal::OnShutdownDestroyMessage(
       &_Edge_default_instance_);_StackFrame_Data_default_instance_._instance.get_mutable()->parent_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(
       ::mozilla::devtools::protobuf::StackFrame::internal_default_instance());
-  _StackFrame_Data_default_instance_.source_.UnsafeSetDefault(
-      &::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  _StackFrame_Data_default_instance_.sourceref_ = GOOGLE_ULONGLONG(0);
-  _StackFrame_Data_default_instance_.functiondisplayname_.UnsafeSetDefault(
-      &::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  _StackFrame_Data_default_instance_.functiondisplaynameref_ = GOOGLE_ULONGLONG(0);
-  _StackFrame_default_instance_.data_ = const_cast< ::mozilla::devtools::protobuf::StackFrame_Data*>(
-      ::mozilla::devtools::protobuf::StackFrame_Data::internal_default_instance());
-  _StackFrame_default_instance_.ref_ = GOOGLE_ULONGLONG(0);
-  _Node_default_instance_.typename__.UnsafeSetDefault(
-      &::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  _Node_default_instance_.typenameref_ = GOOGLE_ULONGLONG(0);
   _Node_default_instance_._instance.get_mutable()->allocationstack_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(
       ::mozilla::devtools::protobuf::StackFrame::internal_default_instance());
-  _Node_default_instance_.jsobjectclassname_.UnsafeSetDefault(
-      &::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  _Node_default_instance_.jsobjectclassnameref_ = GOOGLE_ULONGLONG(0);
-  _Node_default_instance_.scriptfilename_.UnsafeSetDefault(
-      &::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  _Node_default_instance_.scriptfilenameref_ = GOOGLE_ULONGLONG(0);
-  _Edge_default_instance_.name_.UnsafeSetDefault(
-      &::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  _Edge_default_instance_.nameref_ = GOOGLE_ULONGLONG(0);
 }
 
 void InitDefaults() {
   static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
   ::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);
 }
 namespace {
 void AddDescriptorsImpl() {
   InitDefaults();
-  static const char descriptor[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
-      "\n\016CoreDump.proto\022\031mozilla.devtools.proto"
-      "buf\"\035\n\010Metadata\022\021\n\ttimeStamp\030\001 \001(\004\"\216\003\n\nS"
-      "tackFrame\022:\n\004data\030\001 \001(\0132*.mozilla.devtoo"
-      "ls.protobuf.StackFrame.DataH\000\022\r\n\003ref\030\002 \001"
-      "(\004H\000\032\242\002\n\004Data\022\n\n\002id\030\001 \001(\004\0225\n\006parent\030\002 \001("
-      "\0132%.mozilla.devtools.protobuf.StackFrame"
-      "\022\014\n\004line\030\003 \001(\r\022\016\n\006column\030\004 \001(\r\022\020\n\006source"
-      "\030\005 \001(\014H\000\022\023\n\tsourceRef\030\006 \001(\004H\000\022\035\n\023functio"
-      "nDisplayName\030\007 \001(\014H\001\022 \n\026functionDisplayN"
-      "ameRef\030\010 \001(\004H\001\022\020\n\010isSystem\030\t \001(\010\022\024\n\014isSe"
-      "lfHosted\030\n \001(\010B\r\n\013SourceOrRefB\032\n\030Functio"
-      "nDisplayNameOrRefB\020\n\016StackFrameType\"\210\003\n\004"
-      "Node\022\n\n\002id\030\001 \001(\004\022\022\n\010typeName\030\002 \001(\014H\000\022\025\n\013"
-      "typeNameRef\030\003 \001(\004H\000\022\014\n\004size\030\004 \001(\004\022.\n\005edg"
-      "es\030\005 \003(\0132\037.mozilla.devtools.protobuf.Edg"
-      "e\022>\n\017allocationStack\030\006 \001(\0132%.mozilla.dev"
-      "tools.protobuf.StackFrame\022\033\n\021jsObjectCla"
-      "ssName\030\007 \001(\014H\001\022\036\n\024jsObjectClassNameRef\030\010"
-      " \001(\004H\001\022\025\n\ncoarseType\030\t \001(\r:\0010\022\030\n\016scriptF"
-      "ilename\030\n \001(\014H\002\022\033\n\021scriptFilenameRef\030\013 \001"
-      "(\004H\002B\017\n\rTypeNameOrRefB\030\n\026JSObjectClassNa"
-      "meOrRefB\025\n\023ScriptFilenameOrRef\"L\n\004Edge\022\020"
-      "\n\010referent\030\001 \001(\004\022\016\n\004name\030\002 \001(\014H\000\022\021\n\007name"
-      "Ref\030\003 \001(\004H\000B\017\n\rEdgeNameOrRef"
-  };
-  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
-      descriptor, 948);
-  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
-    "CoreDump.proto", &protobuf_RegisterTypes);
 }
 } // anonymous namespace
 
 void AddDescriptors() {
   static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
   ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
 }
-// Force AddDescriptors() to be called at dynamic initialization time.
-struct StaticDescriptorInitializer {
-  StaticDescriptorInitializer() {
-    AddDescriptors();
-  }
-} static_descriptor_initializer;
 
 }  // namespace protobuf_CoreDump_2eproto
 
 
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Metadata::kTimeStampFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Metadata::Metadata()
-  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  : ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
   if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
     protobuf_CoreDump_2eproto::InitDefaults();
   }
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Metadata)
 }
 Metadata::Metadata(const Metadata& from)
-  : ::google::protobuf::Message(),
+  : ::google::protobuf::MessageLite(),
       _internal_metadata_(NULL),
       _has_bits_(from._has_bits_),
       _cached_size_(0) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   timestamp_ = from.timestamp_;
   // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Metadata)
 }
 
@@ -345,21 +152,16 @@ Metadata::~Metadata() {
 void Metadata::SharedDtor() {
 }
 
 void Metadata::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
-const ::google::protobuf::Descriptor* Metadata::descriptor() {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
-}
-
 const Metadata& Metadata::default_instance() {
   protobuf_CoreDump_2eproto::InitDefaults();
   return *internal_default_instance();
 }
 
 Metadata* Metadata::New(::google::protobuf::Arena* arena) const {
   Metadata* n = new Metadata;
   if (arena != NULL) {
@@ -378,16 +180,22 @@ void Metadata::Clear() {
   _has_bits_.Clear();
   _internal_metadata_.Clear();
 }
 
 bool Metadata::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(
+      ::google::protobuf::NewPermanentCallback(&_internal_metadata_,
+          &::google::protobuf::internal::InternalMetadataWithArenaLite::
+              mutable_unknown_fields));
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string, false);
   // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Metadata)
   for (;;) {
     ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
     tag = p.first;
     if (!p.second) goto handle_unusual;
     switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
       // optional uint64 timeStamp = 1;
       case 1: {
@@ -403,18 +211,18 @@ bool Metadata::MergePartialFromCodedStre
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0) {
           goto success;
         }
-        DO_(::google::protobuf::internal::WireFormat::SkipField(
-              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
         break;
       }
     }
   }
 success:
   // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Metadata)
   return true;
 failure:
@@ -430,101 +238,58 @@ void Metadata::SerializeWithCachedSizes(
   (void) cached_has_bits;
 
   cached_has_bits = _has_bits_[0];
   // optional uint64 timeStamp = 1;
   if (cached_has_bits & 0x00000001u) {
     ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->timestamp(), output);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
+  output->WriteRaw(_internal_metadata_.unknown_fields().data(),
+                   static_cast<int>(_internal_metadata_.unknown_fields().size()));
   // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Metadata)
 }
 
-::google::protobuf::uint8* Metadata::InternalSerializeWithCachedSizesToArray(
-    bool deterministic, ::google::protobuf::uint8* target) const {
-  (void)deterministic; // Unused
-  // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Metadata)
-  ::google::protobuf::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional uint64 timeStamp = 1;
-  if (cached_has_bits & 0x00000001u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->timestamp(), target);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Metadata)
-  return target;
-}
-
 size_t Metadata::ByteSizeLong() const {
 // @@protoc_insertion_point(message_byte_size_start:mozilla.devtools.protobuf.Metadata)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
+  total_size += _internal_metadata_.unknown_fields().size();
+
   // optional uint64 timeStamp = 1;
   if (has_timestamp()) {
     total_size += 1 +
       ::google::protobuf::internal::WireFormatLite::UInt64Size(
         this->timestamp());
   }
 
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = cached_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
-void Metadata::MergeFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_merge_from_start:mozilla.devtools.protobuf.Metadata)
-  GOOGLE_DCHECK_NE(&from, this);
-  const Metadata* source =
-      ::google::protobuf::internal::DynamicCastToGenerated<const Metadata>(
-          &from);
-  if (source == NULL) {
-  // @@protoc_insertion_point(generalized_merge_from_cast_fail:mozilla.devtools.protobuf.Metadata)
-    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
-  } else {
-  // @@protoc_insertion_point(generalized_merge_from_cast_success:mozilla.devtools.protobuf.Metadata)
-    MergeFrom(*source);
-  }
+void Metadata::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const Metadata*>(&from));
 }
 
 void Metadata::MergeFrom(const Metadata& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:mozilla.devtools.protobuf.Metadata)
   GOOGLE_DCHECK_NE(&from, this);
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   ::google::protobuf::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   if (from.has_timestamp()) {
     set_timestamp(from.timestamp());
   }
 }
 
-void Metadata::CopyFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_copy_from_start:mozilla.devtools.protobuf.Metadata)
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
 void Metadata::CopyFrom(const Metadata& from) {
 // @@protoc_insertion_point(class_specific_copy_from_start:mozilla.devtools.protobuf.Metadata)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 bool Metadata::IsInitialized() const {
@@ -538,19 +303,18 @@ void Metadata::Swap(Metadata* other) {
 void Metadata::InternalSwap(Metadata* other) {
   using std::swap;
   swap(timestamp_, other->timestamp_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_cached_size_, other->_cached_size_);
 }
 
-::google::protobuf::Metadata Metadata::GetMetadata() const {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages];
+::std::string Metadata::GetTypeName() const {
+  return "mozilla.devtools.protobuf.Metadata";
 }
 
 #if PROTOBUF_INLINE_NOT_IN_HEADERS
 // Metadata
 
 // optional uint64 timeStamp = 1;
 bool Metadata::has_timestamp() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
@@ -588,25 +352,25 @@ const int StackFrame_Data::kSourceFieldN
 const int StackFrame_Data::kSourceRefFieldNumber;
 const int StackFrame_Data::kFunctionDisplayNameFieldNumber;
 const int StackFrame_Data::kFunctionDisplayNameRefFieldNumber;
 const int StackFrame_Data::kIsSystemFieldNumber;
 const int StackFrame_Data::kIsSelfHostedFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 StackFrame_Data::StackFrame_Data()
-  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  : ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
   if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
     protobuf_CoreDump_2eproto::InitDefaults();
   }
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.StackFrame.Data)
 }
 StackFrame_Data::StackFrame_Data(const StackFrame_Data& from)
-  : ::google::protobuf::Message(),
+  : ::google::protobuf::MessageLite(),
       _internal_metadata_(NULL),
       _has_bits_(from._has_bits_),
       _cached_size_(0) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   if (from.has_parent()) {
     parent_ = new ::mozilla::devtools::protobuf::StackFrame(*from.parent_);
   } else {
     parent_ = NULL;
@@ -669,21 +433,16 @@ void StackFrame_Data::SharedDtor() {
   }
 }
 
 void StackFrame_Data::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
-const ::google::protobuf::Descriptor* StackFrame_Data::descriptor() {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
-}
-
 const StackFrame_Data& StackFrame_Data::default_instance() {
   protobuf_CoreDump_2eproto::InitDefaults();
   return *internal_default_instance();
 }
 
 StackFrame_Data* StackFrame_Data::New(::google::protobuf::Arena* arena) const {
   StackFrame_Data* n = new StackFrame_Data;
   if (arena != NULL) {
@@ -750,16 +509,22 @@ void StackFrame_Data::Clear() {
   _has_bits_.Clear();
   _internal_metadata_.Clear();
 }
 
 bool StackFrame_Data::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(
+      ::google::protobuf::NewPermanentCallback(&_internal_metadata_,
+          &::google::protobuf::internal::InternalMetadataWithArenaLite::
+              mutable_unknown_fields));
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string, false);
   // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.StackFrame.Data)
   for (;;) {
     ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
     tag = p.first;
     if (!p.second) goto handle_unusual;
     switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
       // optional uint64 id = 1;
       case 1: {
@@ -897,18 +662,18 @@ bool StackFrame_Data::MergePartialFromCo
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0) {
           goto success;
         }
-        DO_(::google::protobuf::internal::WireFormat::SkipField(
-              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
         break;
       }
     }
   }
 success:
   // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.StackFrame.Data)
   return true;
 failure:
@@ -926,17 +691,17 @@ void StackFrame_Data::SerializeWithCache
   cached_has_bits = _has_bits_[0];
   // optional uint64 id = 1;
   if (cached_has_bits & 0x00000002u) {
     ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->id(), output);
   }
 
   // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
   if (cached_has_bits & 0x00000001u) {
-    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
       2, *this->parent_, output);
   }
 
   // optional uint32 line = 3;
   if (cached_has_bits & 0x00000004u) {
     ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->line(), output);
   }
 
@@ -970,102 +735,27 @@ void StackFrame_Data::SerializeWithCache
     ::google::protobuf::internal::WireFormatLite::WriteBool(9, this->issystem(), output);
   }
 
   // optional bool isSelfHosted = 10;
   if (cached_has_bits & 0x00000020u) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->isselfhosted(), output);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
+  output->WriteRaw(_internal_metadata_.unknown_fields().data(),
+                   static_cast<int>(_internal_metadata_.unknown_fields().size()));
   // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.StackFrame.Data)
 }
 
-::google::protobuf::uint8* StackFrame_Data::InternalSerializeWithCachedSizesToArray(
-    bool deterministic, ::google::protobuf::uint8* target) const {
-  (void)deterministic; // Unused
-  // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.StackFrame.Data)
-  ::google::protobuf::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional uint64 id = 1;
-  if (cached_has_bits & 0x00000002u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->id(), target);
-  }
-
-  // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
-  if (cached_has_bits & 0x00000001u) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      InternalWriteMessageNoVirtualToArray(
-        2, *this->parent_, deterministic, target);
-  }
-
-  // optional uint32 line = 3;
-  if (cached_has_bits & 0x00000004u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->line(), target);
-  }
-
-  // optional uint32 column = 4;
-  if (cached_has_bits & 0x00000008u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->column(), target);
-  }
-
-  switch (SourceOrRef_case()) {
-    case kSource:
-      target =
-        ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
-          5, this->source(), target);
-      break;
-    case kSourceRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(6, this->sourceref(), target);
-      break;
-    default: ;
-  }
-  switch (FunctionDisplayNameOrRef_case()) {
-    case kFunctionDisplayName:
-      target =
-        ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
-          7, this->functiondisplayname(), target);
-      break;
-    case kFunctionDisplayNameRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->functiondisplaynameref(), target);
-      break;
-    default: ;
-  }
-  // optional bool isSystem = 9;
-  if (cached_has_bits & 0x00000010u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(9, this->issystem(), target);
-  }
-
-  // optional bool isSelfHosted = 10;
-  if (cached_has_bits & 0x00000020u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->isselfhosted(), target);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.StackFrame.Data)
-  return target;
-}
-
 size_t StackFrame_Data::ByteSizeLong() const {
 // @@protoc_insertion_point(message_byte_size_start:mozilla.devtools.protobuf.StackFrame.Data)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
+  total_size += _internal_metadata_.unknown_fields().size();
+
   if (_has_bits_[0 / 32] & 63u) {
     // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
     if (has_parent()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
           *this->parent_);
     }
 
@@ -1141,29 +831,19 @@ size_t StackFrame_Data::ByteSizeLong() c
   }
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = cached_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
-void StackFrame_Data::MergeFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_merge_from_start:mozilla.devtools.protobuf.StackFrame.Data)
-  GOOGLE_DCHECK_NE(&from, this);
-  const StackFrame_Data* source =
-      ::google::protobuf::internal::DynamicCastToGenerated<const StackFrame_Data>(
-          &from);
-  if (source == NULL) {
-  // @@protoc_insertion_point(generalized_merge_from_cast_fail:mozilla.devtools.protobuf.StackFrame.Data)
-    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
-  } else {
-  // @@protoc_insertion_point(generalized_merge_from_cast_success:mozilla.devtools.protobuf.StackFrame.Data)
-    MergeFrom(*source);
-  }
+void StackFrame_Data::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const StackFrame_Data*>(&from));
 }
 
 void StackFrame_Data::MergeFrom(const StackFrame_Data& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:mozilla.devtools.protobuf.StackFrame.Data)
   GOOGLE_DCHECK_NE(&from, this);
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   ::google::protobuf::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -1213,23 +893,16 @@ void StackFrame_Data::MergeFrom(const St
       break;
     }
     case FUNCTIONDISPLAYNAMEORREF_NOT_SET: {
       break;
     }
   }
 }
 
-void StackFrame_Data::CopyFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_copy_from_start:mozilla.devtools.protobuf.StackFrame.Data)
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
 void StackFrame_Data::CopyFrom(const StackFrame_Data& from) {
 // @@protoc_insertion_point(class_specific_copy_from_start:mozilla.devtools.protobuf.StackFrame.Data)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 bool StackFrame_Data::IsInitialized() const {
@@ -1252,19 +925,18 @@ void StackFrame_Data::InternalSwap(Stack
   swap(_oneof_case_[0], other->_oneof_case_[0]);
   swap(FunctionDisplayNameOrRef_, other->FunctionDisplayNameOrRef_);
   swap(_oneof_case_[1], other->_oneof_case_[1]);
   swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_cached_size_, other->_cached_size_);
 }
 
-::google::protobuf::Metadata StackFrame_Data::GetMetadata() const {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages];
+::std::string StackFrame_Data::GetTypeName() const {
+  return "mozilla.devtools.protobuf.StackFrame.Data";
 }
 
 #if PROTOBUF_INLINE_NOT_IN_HEADERS
 // StackFrame_Data
 
 // optional uint64 id = 1;
 bool StackFrame_Data::has_id() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
@@ -1702,25 +1374,25 @@ StackFrame_Data::FunctionDisplayNameOrRe
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int StackFrame::kDataFieldNumber;
 const int StackFrame::kRefFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 StackFrame::StackFrame()
-  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  : ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
   if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
     protobuf_CoreDump_2eproto::InitDefaults();
   }
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.StackFrame)
 }
 StackFrame::StackFrame(const StackFrame& from)
-  : ::google::protobuf::Message(),
+  : ::google::protobuf::MessageLite(),
       _internal_metadata_(NULL),
       _has_bits_(from._has_bits_),
       _cached_size_(0) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   clear_has_StackFrameType();
   switch (from.StackFrameType_case()) {
     case kData: {
       mutable_data()->::mozilla::devtools::protobuf::StackFrame_Data::MergeFrom(from.data());
@@ -1753,21 +1425,16 @@ void StackFrame::SharedDtor() {
   }
 }
 
 void StackFrame::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
-const ::google::protobuf::Descriptor* StackFrame::descriptor() {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
-}
-
 const StackFrame& StackFrame::default_instance() {
   protobuf_CoreDump_2eproto::InitDefaults();
   return *internal_default_instance();
 }
 
 StackFrame* StackFrame::New(::google::protobuf::Arena* arena) const {
   StackFrame* n = new StackFrame;
   if (arena != NULL) {
@@ -1805,16 +1472,22 @@ void StackFrame::Clear() {
   _has_bits_.Clear();
   _internal_metadata_.Clear();
 }
 
 bool StackFrame::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(
+      ::google::protobuf::NewPermanentCallback(&_internal_metadata_,
+          &::google::protobuf::internal::InternalMetadataWithArenaLite::
+              mutable_unknown_fields));
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string, false);
   // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.StackFrame)
   for (;;) {
     ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
     tag = p.first;
     if (!p.second) goto handle_unusual;
     switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
       // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
       case 1: {
@@ -1843,18 +1516,18 @@ bool StackFrame::MergePartialFromCodedSt
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0) {
           goto success;
         }
-        DO_(::google::protobuf::internal::WireFormat::SkipField(
-              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
         break;
       }
     }
   }
 success:
   // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.StackFrame)
   return true;
 failure:
@@ -1866,66 +1539,35 @@ failure:
 void StackFrame::SerializeWithCachedSizes(
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.StackFrame)
   ::google::protobuf::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   switch (StackFrameType_case()) {
     case kData:
-      ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      ::google::protobuf::internal::WireFormatLite::WriteMessage(
         1, *StackFrameType_.data_, output);
       break;
     case kRef:
       ::google::protobuf::internal::WireFormatLite::WriteUInt64(2, this->ref(), output);
       break;
     default: ;
   }
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
+  output->WriteRaw(_internal_metadata_.unknown_fields().data(),
+                   static_cast<int>(_internal_metadata_.unknown_fields().size()));
   // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.StackFrame)
 }
 
-::google::protobuf::uint8* StackFrame::InternalSerializeWithCachedSizesToArray(
-    bool deterministic, ::google::protobuf::uint8* target) const {
-  (void)deterministic; // Unused
-  // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.StackFrame)
-  ::google::protobuf::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  switch (StackFrameType_case()) {
-    case kData:
-      target = ::google::protobuf::internal::WireFormatLite::
-        InternalWriteMessageNoVirtualToArray(
-          1, *StackFrameType_.data_, deterministic, target);
-      break;
-    case kRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(2, this->ref(), target);
-      break;
-    default: ;
-  }
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.StackFrame)
-  return target;
-}
-
 size_t StackFrame::ByteSizeLong() const {
 // @@protoc_insertion_point(message_byte_size_start:mozilla.devtools.protobuf.StackFrame)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
+  total_size += _internal_metadata_.unknown_fields().size();
+
   switch (StackFrameType_case()) {
     // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
     case kData: {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
           *StackFrameType_.data_);
       break;
     }
@@ -1942,29 +1584,19 @@ size_t StackFrame::ByteSizeLong() const 
   }
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = cached_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
-void StackFrame::MergeFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_merge_from_start:mozilla.devtools.protobuf.StackFrame)
-  GOOGLE_DCHECK_NE(&from, this);
-  const StackFrame* source =
-      ::google::protobuf::internal::DynamicCastToGenerated<const StackFrame>(
-          &from);
-  if (source == NULL) {
-  // @@protoc_insertion_point(generalized_merge_from_cast_fail:mozilla.devtools.protobuf.StackFrame)
-    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
-  } else {
-  // @@protoc_insertion_point(generalized_merge_from_cast_success:mozilla.devtools.protobuf.StackFrame)
-    MergeFrom(*source);
-  }
+void StackFrame::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const StackFrame*>(&from));
 }
 
 void StackFrame::MergeFrom(const StackFrame& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:mozilla.devtools.protobuf.StackFrame)
   GOOGLE_DCHECK_NE(&from, this);
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   ::google::protobuf::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -1979,23 +1611,16 @@ void StackFrame::MergeFrom(const StackFr
       break;
     }
     case STACKFRAMETYPE_NOT_SET: {
       break;
     }
   }
 }
 
-void StackFrame::CopyFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_copy_from_start:mozilla.devtools.protobuf.StackFrame)
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
 void StackFrame::CopyFrom(const StackFrame& from) {
 // @@protoc_insertion_point(class_specific_copy_from_start:mozilla.devtools.protobuf.StackFrame)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 bool StackFrame::IsInitialized() const {
@@ -2010,19 +1635,18 @@ void StackFrame::InternalSwap(StackFrame
   using std::swap;
   swap(StackFrameType_, other->StackFrameType_);
   swap(_oneof_case_[0], other->_oneof_case_[0]);
   swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_cached_size_, other->_cached_size_);
 }
 
-::google::protobuf::Metadata StackFrame::GetMetadata() const {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages];
+::std::string StackFrame::GetTypeName() const {
+  return "mozilla.devtools.protobuf.StackFrame";
 }
 
 #if PROTOBUF_INLINE_NOT_IN_HEADERS
 // StackFrame
 
 // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
 bool StackFrame::has_data() const {
   return StackFrameType_case() == kData;
@@ -2123,25 +1747,25 @@ const int Node::kAllocationStackFieldNum
 const int Node::kJsObjectClassNameFieldNumber;
 const int Node::kJsObjectClassNameRefFieldNumber;
 const int Node::kCoarseTypeFieldNumber;
 const int Node::kScriptFilenameFieldNumber;
 const int Node::kScriptFilenameRefFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Node::Node()
-  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  : ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
   if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
     protobuf_CoreDump_2eproto::InitDefaults();
   }
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Node)
 }
 Node::Node(const Node& from)
-  : ::google::protobuf::Message(),
+  : ::google::protobuf::MessageLite(),
       _internal_metadata_(NULL),
       _has_bits_(from._has_bits_),
       _cached_size_(0),
       edges_(from.edges_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   if (from.has_allocationstack()) {
     allocationstack_ = new ::mozilla::devtools::protobuf::StackFrame(*from.allocationstack_);
   } else {
@@ -2223,21 +1847,16 @@ void Node::SharedDtor() {
   }
 }
 
 void Node::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
-const ::google::protobuf::Descriptor* Node::descriptor() {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
-}
-
 const Node& Node::default_instance() {
   protobuf_CoreDump_2eproto::InitDefaults();
   return *internal_default_instance();
 }
 
 Node* Node::New(::google::protobuf::Arena* arena) const {
   Node* n = new Node;
   if (arena != NULL) {
@@ -2324,16 +1943,22 @@ void Node::Clear() {
   _has_bits_.Clear();
   _internal_metadata_.Clear();
 }
 
 bool Node::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(
+      ::google::protobuf::NewPermanentCallback(&_internal_metadata_,
+          &::google::protobuf::internal::InternalMetadataWithArenaLite::
+              mutable_unknown_fields));
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string, false);
   // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Node)
   for (;;) {
     ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
     tag = p.first;
     if (!p.second) goto handle_unusual;
     switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
       // optional uint64 id = 1;
       case 1: {
@@ -2482,18 +2107,18 @@ bool Node::MergePartialFromCodedStream(
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0) {
           goto success;
         }
-        DO_(::google::protobuf::internal::WireFormat::SkipField(
-              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
         break;
       }
     }
   }
 success:
   // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Node)
   return true;
 failure:
@@ -2527,23 +2152,23 @@ void Node::SerializeWithCachedSizes(
   // optional uint64 size = 4;
   if (cached_has_bits & 0x00000004u) {
     ::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->size(), output);
   }
 
   // repeated .mozilla.devtools.protobuf.Edge edges = 5;
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->edges_size()); i < n; i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
       5, this->edges(static_cast<int>(i)), output);
   }
 
   // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
   if (cached_has_bits & 0x00000001u) {
-    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
       6, *this->allocationstack_, output);
   }
 
   switch (JSObjectClassNameOrRef_case()) {
     case kJsObjectClassName:
       ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
         7, this->jsobjectclassname(), output);
       break;
@@ -2562,111 +2187,27 @@ void Node::SerializeWithCachedSizes(
       ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
         10, this->scriptfilename(), output);
       break;
     case kScriptFilenameRef:
       ::google::protobuf::internal::WireFormatLite::WriteUInt64(11, this->scriptfilenameref(), output);
       break;
     default: ;
   }
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
+  output->WriteRaw(_internal_metadata_.unknown_fields().data(),
+                   static_cast<int>(_internal_metadata_.unknown_fields().size()));
   // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Node)
 }
 
-::google::protobuf::uint8* Node::InternalSerializeWithCachedSizesToArray(
-    bool deterministic, ::google::protobuf::uint8* target) const {
-  (void)deterministic; // Unused
-  // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Node)
-  ::google::protobuf::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional uint64 id = 1;
-  if (cached_has_bits & 0x00000002u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->id(), target);
-  }
-
-  switch (TypeNameOrRef_case()) {
-    case kTypeName:
-      target =
-        ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
-          2, this->typename_(), target);
-      break;
-    case kTypeNameRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->typenameref(), target);
-      break;
-    default: ;
-  }
-  // optional uint64 size = 4;
-  if (cached_has_bits & 0x00000004u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->size(), target);
-  }
-
-  // repeated .mozilla.devtools.protobuf.Edge edges = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->edges_size()); i < n; i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      InternalWriteMessageNoVirtualToArray(
-        5, this->edges(static_cast<int>(i)), deterministic, target);
-  }
-
-  // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
-  if (cached_has_bits & 0x00000001u) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      InternalWriteMessageNoVirtualToArray(
-        6, *this->allocationstack_, deterministic, target);
-  }
-
-  switch (JSObjectClassNameOrRef_case()) {
-    case kJsObjectClassName:
-      target =
-        ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
-          7, this->jsobjectclassname(), target);
-      break;
-    case kJsObjectClassNameRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->jsobjectclassnameref(), target);
-      break;
-    default: ;
-  }
-  // optional uint32 coarseType = 9 [default = 0];
-  if (cached_has_bits & 0x00000008u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->coarsetype(), target);
-  }
-
-  switch (ScriptFilenameOrRef_case()) {
-    case kScriptFilename:
-      target =
-        ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
-          10, this->scriptfilename(), target);
-      break;
-    case kScriptFilenameRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(11, this->scriptfilenameref(), target);
-      break;
-    default: ;
-  }
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Node)
-  return target;
-}
-
 size_t Node::ByteSizeLong() const {
 // @@protoc_insertion_point(message_byte_size_start:mozilla.devtools.protobuf.Node)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
+  total_size += _internal_metadata_.unknown_fields().size();
+
   // repeated .mozilla.devtools.protobuf.Edge edges = 5;
   {
     unsigned int count = static_cast<unsigned int>(this->edges_size());
     total_size += 1UL * count;
     for (unsigned int i = 0; i < count; i++) {
       total_size +=
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
           this->edges(static_cast<int>(i)));
@@ -2762,29 +2303,19 @@ size_t Node::ByteSizeLong() const {
   }
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = cached_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
-void Node::MergeFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_merge_from_start:mozilla.devtools.protobuf.Node)
-  GOOGLE_DCHECK_NE(&from, this);
-  const Node* source =
-      ::google::protobuf::internal::DynamicCastToGenerated<const Node>(
-          &from);
-  if (source == NULL) {
-  // @@protoc_insertion_point(generalized_merge_from_cast_fail:mozilla.devtools.protobuf.Node)
-    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
-  } else {
-  // @@protoc_insertion_point(generalized_merge_from_cast_success:mozilla.devtools.protobuf.Node)
-    MergeFrom(*source);
-  }
+void Node::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const Node*>(&from));
 }
 
 void Node::MergeFrom(const Node& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:mozilla.devtools.protobuf.Node)
   GOOGLE_DCHECK_NE(&from, this);
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   ::google::protobuf::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2842,23 +2373,16 @@ void Node::MergeFrom(const Node& from) {
       break;
     }
     case SCRIPTFILENAMEORREF_NOT_SET: {
       break;
     }
   }
 }
 
-void Node::CopyFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_copy_from_start:mozilla.devtools.protobuf.Node)
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
 void Node::CopyFrom(const Node& from) {
 // @@protoc_insertion_point(class_specific_copy_from_start:mozilla.devtools.protobuf.Node)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 bool Node::IsInitialized() const {
@@ -2882,19 +2406,18 @@ void Node::InternalSwap(Node* other) {
   swap(_oneof_case_[1], other->_oneof_case_[1]);
   swap(ScriptFilenameOrRef_, other->ScriptFilenameOrRef_);
   swap(_oneof_case_[2], other->_oneof_case_[2]);
   swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_cached_size_, other->_cached_size_);
 }
 
-::google::protobuf::Metadata Node::GetMetadata() const {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages];
+::std::string Node::GetTypeName() const {
+  return "mozilla.devtools.protobuf.Node";
 }
 
 #if PROTOBUF_INLINE_NOT_IN_HEADERS
 // Node
 
 // optional uint64 id = 1;
 bool Node::has_id() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
@@ -3448,25 +2971,25 @@ Node::ScriptFilenameOrRefCase Node::Scri
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Edge::kReferentFieldNumber;
 const int Edge::kNameFieldNumber;
 const int Edge::kNameRefFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Edge::Edge()
-  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  : ::google::protobuf::MessageLite(), _internal_metadata_(NULL) {
   if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
     protobuf_CoreDump_2eproto::InitDefaults();
   }
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Edge)
 }
 Edge::Edge(const Edge& from)
-  : ::google::protobuf::Message(),
+  : ::google::protobuf::MessageLite(),
       _internal_metadata_(NULL),
       _has_bits_(from._has_bits_),
       _cached_size_(0) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   referent_ = from.referent_;
   clear_has_EdgeNameOrRef();
   switch (from.EdgeNameOrRef_case()) {
     case kName: {
@@ -3501,21 +3024,16 @@ void Edge::SharedDtor() {
   }
 }
 
 void Edge::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
-const ::google::protobuf::Descriptor* Edge::descriptor() {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
-}
-
 const Edge& Edge::default_instance() {
   protobuf_CoreDump_2eproto::InitDefaults();
   return *internal_default_instance();
 }
 
 Edge* Edge::New(::google::protobuf::Arena* arena) const {
   Edge* n = new Edge;
   if (arena != NULL) {
@@ -3554,16 +3072,22 @@ void Edge::Clear() {
   _has_bits_.Clear();
   _internal_metadata_.Clear();
 }
 
 bool Edge::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(
+      ::google::protobuf::NewPermanentCallback(&_internal_metadata_,
+          &::google::protobuf::internal::InternalMetadataWithArenaLite::
+              mutable_unknown_fields));
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string, false);
   // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Edge)
   for (;;) {
     ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
     tag = p.first;
     if (!p.second) goto handle_unusual;
     switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
       // optional uint64 referent = 1;
       case 1: {
@@ -3606,18 +3130,18 @@ bool Edge::MergePartialFromCodedStream(
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0) {
           goto success;
         }
-        DO_(::google::protobuf::internal::WireFormat::SkipField(
-              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
         break;
       }
     }
   }
 success:
   // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Edge)
   return true;
 failure:
@@ -3643,64 +3167,27 @@ void Edge::SerializeWithCachedSizes(
       ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
         2, this->name(), output);
       break;
     case kNameRef:
       ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->nameref(), output);
       break;
     default: ;
   }
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
+  output->WriteRaw(_internal_metadata_.unknown_fields().data(),
+                   static_cast<int>(_internal_metadata_.unknown_fields().size()));
   // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Edge)
 }
 
-::google::protobuf::uint8* Edge::InternalSerializeWithCachedSizesToArray(
-    bool deterministic, ::google::protobuf::uint8* target) const {
-  (void)deterministic; // Unused
-  // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Edge)
-  ::google::protobuf::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional uint64 referent = 1;
-  if (cached_has_bits & 0x00000001u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->referent(), target);
-  }
-
-  switch (EdgeNameOrRef_case()) {
-    case kName:
-      target =
-        ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
-          2, this->name(), target);
-      break;
-    case kNameRef:
-      target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->nameref(), target);
-      break;
-    default: ;
-  }
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Edge)
-  return target;
-}
-
 size_t Edge::ByteSizeLong() const {
 // @@protoc_insertion_point(message_byte_size_start:mozilla.devtools.protobuf.Edge)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
+  total_size += _internal_metadata_.unknown_fields().size();
+
   // optional uint64 referent = 1;
   if (has_referent()) {
     total_size += 1 +
       ::google::protobuf::internal::WireFormatLite::UInt64Size(
         this->referent());
   }
 
   switch (EdgeNameOrRef_case()) {
@@ -3724,29 +3211,19 @@ size_t Edge::ByteSizeLong() const {
   }
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = cached_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
-void Edge::MergeFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_merge_from_start:mozilla.devtools.protobuf.Edge)
-  GOOGLE_DCHECK_NE(&from, this);
-  const Edge* source =
-      ::google::protobuf::internal::DynamicCastToGenerated<const Edge>(
-          &from);
-  if (source == NULL) {
-  // @@protoc_insertion_point(generalized_merge_from_cast_fail:mozilla.devtools.protobuf.Edge)
-    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
-  } else {
-  // @@protoc_insertion_point(generalized_merge_from_cast_success:mozilla.devtools.protobuf.Edge)
-    MergeFrom(*source);
-  }
+void Edge::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const Edge*>(&from));
 }
 
 void Edge::MergeFrom(const Edge& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:mozilla.devtools.protobuf.Edge)
   GOOGLE_DCHECK_NE(&from, this);
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   ::google::protobuf::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -3764,23 +3241,16 @@ void Edge::MergeFrom(const Edge& from) {
       break;
     }
     case EDGENAMEORREF_NOT_SET: {
       break;
     }
   }
 }
 
-void Edge::CopyFrom(const ::google::protobuf::Message& from) {
-// @@protoc_insertion_point(generalized_copy_from_start:mozilla.devtools.protobuf.Edge)
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
 void Edge::CopyFrom(const Edge& from) {
 // @@protoc_insertion_point(class_specific_copy_from_start:mozilla.devtools.protobuf.Edge)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 bool Edge::IsInitialized() const {
@@ -3796,19 +3266,18 @@ void Edge::InternalSwap(Edge* other) {
   swap(referent_, other->referent_);
   swap(EdgeNameOrRef_, other->EdgeNameOrRef_);
   swap(_oneof_case_[0], other->_oneof_case_[0]);
   swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_cached_size_, other->_cached_size_);
 }
 
-::google::protobuf::Metadata Edge::GetMetadata() const {
-  protobuf_CoreDump_2eproto::protobuf_AssignDescriptorsOnce();
-  return protobuf_CoreDump_2eproto::file_level_metadata[kIndexInFileMessages];
+::std::string Edge::GetTypeName() const {
+  return "mozilla.devtools.protobuf.Edge";
 }
 
 #if PROTOBUF_INLINE_NOT_IN_HEADERS
 // Edge
 
 // optional uint64 referent = 1;
 bool Edge::has_referent() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
--- a/devtools/shared/heapsnapshot/CoreDump.pb.h
+++ b/devtools/shared/heapsnapshot/CoreDump.pb.h
@@ -19,21 +19,20 @@
 #error regenerate this file with a newer version of protoc.
 #endif
 
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
-#include <google/protobuf/metadata.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
-#include <google/protobuf/unknown_field_set.h>
 // @@protoc_insertion_point(includes)
 namespace mozilla {
 namespace devtools {
 namespace protobuf {
 class Edge;
 class EdgeDefaultTypeInternal;
 extern EdgeDefaultTypeInternal _Edge_default_instance_;
 class Metadata;
@@ -68,17 +67,17 @@ struct TableStruct {
   static void InitDefaultsImpl();
 };
 void AddDescriptors();
 void InitDefaults();
 }  // namespace protobuf_CoreDump_2eproto
 
 // ===================================================================
 
-class Metadata : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.Metadata) */ {
+class Metadata : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.Metadata) */ {
  public:
   Metadata();
   virtual ~Metadata();
 
   Metadata(const Metadata& from);
 
   inline Metadata& operator=(const Metadata& from) {
     CopyFrom(from);
@@ -94,24 +93,23 @@ class Metadata : public ::google::protob
     if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
       if (this != &from) InternalSwap(&from);
     } else {
       CopyFrom(from);
     }
     return *this;
   }
   #endif
-  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+  inline const ::std::string& unknown_fields() const {
     return _internal_metadata_.unknown_fields();
   }
-  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+  inline ::std::string* mutable_unknown_fields() {
     return _internal_metadata_.mutable_unknown_fields();
   }
 
-  static const ::google::protobuf::Descriptor* descriptor();
   static const Metadata& default_instance();
 
   static inline const Metadata* internal_default_instance() {
     return reinterpret_cast<const Metadata*>(
                &_Metadata_default_instance_);
   }
   static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
     0;
@@ -121,46 +119,45 @@ class Metadata : public ::google::protob
     a.Swap(&b);
   }
 
   // implements Message ----------------------------------------------
 
   inline Metadata* New() const PROTOBUF_FINAL { return New(NULL); }
 
   Metadata* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
-  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
-  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
+    PROTOBUF_FINAL;
   void CopyFrom(const Metadata& from);
   void MergeFrom(const Metadata& from);
   void Clear() PROTOBUF_FINAL;
   bool IsInitialized() const PROTOBUF_FINAL;
 
   size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
-  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  void DiscardUnknownFields();
   int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void SetCachedSize(int size) const;
   void InternalSwap(Metadata* other);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return NULL;
   }
   inline void* MaybeArenaPtr() const {
     return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+  ::std::string GetTypeName() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
   // optional uint64 timeStamp = 1;
   bool has_timestamp() const;
   void clear_timestamp();
@@ -168,25 +165,25 @@ class Metadata : public ::google::protob
   ::google::protobuf::uint64 timestamp() const;
   void set_timestamp(::google::protobuf::uint64 value);
 
   // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Metadata)
  private:
   void set_has_timestamp();
   void clear_has_timestamp();
 
-  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
   ::google::protobuf::internal::HasBits<1> _has_bits_;
   mutable int _cached_size_;
   ::google::protobuf::uint64 timestamp_;
   friend struct protobuf_CoreDump_2eproto::TableStruct;
 };
 // -------------------------------------------------------------------
 
-class StackFrame_Data : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.StackFrame.Data) */ {
+class StackFrame_Data : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.StackFrame.Data) */ {
  public:
   StackFrame_Data();
   virtual ~StackFrame_Data();
 
   StackFrame_Data(const StackFrame_Data& from);
 
   inline StackFrame_Data& operator=(const StackFrame_Data& from) {
     CopyFrom(from);
@@ -202,24 +199,23 @@ class StackFrame_Data : public ::google:
     if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
       if (this != &from) InternalSwap(&from);
     } else {
       CopyFrom(from);
     }
     return *this;
   }
   #endif
-  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+  inline const ::std::string& unknown_fields() const {
     return _internal_metadata_.unknown_fields();
   }
-  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+  inline ::std::string* mutable_unknown_fields() {
     return _internal_metadata_.mutable_unknown_fields();
   }
 
-  static const ::google::protobuf::Descriptor* descriptor();
   static const StackFrame_Data& default_instance();
 
   enum SourceOrRefCase {
     kSource = 5,
     kSourceRef = 6,
     SOURCEORREF_NOT_SET = 0,
   };
 
@@ -241,46 +237,45 @@ class StackFrame_Data : public ::google:
     a.Swap(&b);
   }
 
   // implements Message ----------------------------------------------
 
   inline StackFrame_Data* New() const PROTOBUF_FINAL { return New(NULL); }
 
   StackFrame_Data* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
-  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
-  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
+    PROTOBUF_FINAL;
   void CopyFrom(const StackFrame_Data& from);
   void MergeFrom(const StackFrame_Data& from);
   void Clear() PROTOBUF_FINAL;
   bool IsInitialized() const PROTOBUF_FINAL;
 
   size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
-  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  void DiscardUnknownFields();
   int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void SetCachedSize(int size) const;
   void InternalSwap(StackFrame_Data* other);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return NULL;
   }
   inline void* MaybeArenaPtr() const {
     return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+  ::std::string GetTypeName() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
   // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
   bool has_parent() const;
   void clear_parent();
@@ -393,17 +388,17 @@ class StackFrame_Data : public ::google:
   inline bool has_SourceOrRef() const;
   void clear_SourceOrRef();
   inline void clear_has_SourceOrRef();
 
   inline bool has_FunctionDisplayNameOrRef() const;
   void clear_FunctionDisplayNameOrRef();
   inline void clear_has_FunctionDisplayNameOrRef();
 
-  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
   ::google::protobuf::internal::HasBits<1> _has_bits_;
   mutable int _cached_size_;
   ::mozilla::devtools::protobuf::StackFrame* parent_;
   ::google::protobuf::uint64 id_;
   ::google::protobuf::uint32 line_;
   ::google::protobuf::uint32 column_;
   bool issystem_;
   bool isselfhosted_;
@@ -418,17 +413,17 @@ class StackFrame_Data : public ::google:
     ::google::protobuf::uint64 functiondisplaynameref_;
   } FunctionDisplayNameOrRef_;
   ::google::protobuf::uint32 _oneof_case_[2];
 
   friend struct protobuf_CoreDump_2eproto::TableStruct;
 };
 // -------------------------------------------------------------------
 
-class StackFrame : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.StackFrame) */ {
+class StackFrame : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.StackFrame) */ {
  public:
   StackFrame();
   virtual ~StackFrame();
 
   StackFrame(const StackFrame& from);
 
   inline StackFrame& operator=(const StackFrame& from) {
     CopyFrom(from);
@@ -444,24 +439,23 @@ class StackFrame : public ::google::prot
     if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
       if (this != &from) InternalSwap(&from);
     } else {
       CopyFrom(from);
     }
     return *this;
   }
   #endif
-  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+  inline const ::std::string& unknown_fields() const {
     return _internal_metadata_.unknown_fields();
   }
-  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+  inline ::std::string* mutable_unknown_fields() {
     return _internal_metadata_.mutable_unknown_fields();
   }
 
-  static const ::google::protobuf::Descriptor* descriptor();
   static const StackFrame& default_instance();
 
   enum StackFrameTypeCase {
     kData = 1,
     kRef = 2,
     STACKFRAMETYPE_NOT_SET = 0,
   };
 
@@ -477,46 +471,45 @@ class StackFrame : public ::google::prot
     a.Swap(&b);
   }
 
   // implements Message ----------------------------------------------
 
   inline StackFrame* New() const PROTOBUF_FINAL { return New(NULL); }
 
   StackFrame* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
-  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
-  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
+    PROTOBUF_FINAL;
   void CopyFrom(const StackFrame& from);
   void MergeFrom(const StackFrame& from);
   void Clear() PROTOBUF_FINAL;
   bool IsInitialized() const PROTOBUF_FINAL;
 
   size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
-  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  void DiscardUnknownFields();
   int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void SetCachedSize(int size) const;
   void InternalSwap(StackFrame* other);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return NULL;
   }
   inline void* MaybeArenaPtr() const {
     return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+  ::std::string GetTypeName() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   typedef StackFrame_Data Data;
 
   // accessors -------------------------------------------------------
 
   // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
@@ -540,31 +533,31 @@ class StackFrame : public ::google::prot
  private:
   void set_has_data();
   void set_has_ref();
 
   inline bool has_StackFrameType() const;
   void clear_StackFrameType();
   inline void clear_has_StackFrameType();
 
-  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
   ::google::protobuf::internal::HasBits<1> _has_bits_;
   mutable int _cached_size_;
   union StackFrameTypeUnion {
     StackFrameTypeUnion() {}
     ::mozilla::devtools::protobuf::StackFrame_Data* data_;
     ::google::protobuf::uint64 ref_;
   } StackFrameType_;
   ::google::protobuf::uint32 _oneof_case_[1];
 
   friend struct protobuf_CoreDump_2eproto::TableStruct;
 };
 // -------------------------------------------------------------------
 
-class Node : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.Node) */ {
+class Node : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.Node) */ {
  public:
   Node();
   virtual ~Node();
 
   Node(const Node& from);
 
   inline Node& operator=(const Node& from) {
     CopyFrom(from);
@@ -580,24 +573,23 @@ class Node : public ::google::protobuf::
     if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
       if (this != &from) InternalSwap(&from);
     } else {
       CopyFrom(from);
     }
     return *this;
   }
   #endif
-  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+  inline const ::std::string& unknown_fields() const {
     return _internal_metadata_.unknown_fields();
   }
-  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+  inline ::std::string* mutable_unknown_fields() {
     return _internal_metadata_.mutable_unknown_fields();
   }
 
-  static const ::google::protobuf::Descriptor* descriptor();
   static const Node& default_instance();
 
   enum TypeNameOrRefCase {
     kTypeName = 2,
     kTypeNameRef = 3,
     TYPENAMEORREF_NOT_SET = 0,
   };
 
@@ -625,46 +617,45 @@ class Node : public ::google::protobuf::
     a.Swap(&b);
   }
 
   // implements Message ----------------------------------------------
 
   inline Node* New() const PROTOBUF_FINAL { return New(NULL); }
 
   Node* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
-  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
-  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
+    PROTOBUF_FINAL;
   void CopyFrom(const Node& from);
   void MergeFrom(const Node& from);
   void Clear() PROTOBUF_FINAL;
   bool IsInitialized() const PROTOBUF_FINAL;
 
   size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
-  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  void DiscardUnknownFields();
   int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void SetCachedSize(int size) const;
   void InternalSwap(Node* other);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return NULL;
   }
   inline void* MaybeArenaPtr() const {
     return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+  ::std::string GetTypeName() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
   // repeated .mozilla.devtools.protobuf.Edge edges = 5;
   int edges_size() const;
   void clear_edges();
@@ -800,17 +791,17 @@ class Node : public ::google::protobuf::
   inline bool has_JSObjectClassNameOrRef() const;
   void clear_JSObjectClassNameOrRef();
   inline void clear_has_JSObjectClassNameOrRef();
 
   inline bool has_ScriptFilenameOrRef() const;
   void clear_ScriptFilenameOrRef();
   inline void clear_has_ScriptFilenameOrRef();
 
-  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
   ::google::protobuf::internal::HasBits<1> _has_bits_;
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge > edges_;
   ::mozilla::devtools::protobuf::StackFrame* allocationstack_;
   ::google::protobuf::uint64 id_;
   ::google::protobuf::uint64 size_;
   ::google::protobuf::uint32 coarsetype_;
   union TypeNameOrRefUnion {
@@ -829,17 +820,17 @@ class Node : public ::google::protobuf::
     ::google::protobuf::uint64 scriptfilenameref_;
   } ScriptFilenameOrRef_;
   ::google::protobuf::uint32 _oneof_case_[3];
 
   friend struct protobuf_CoreDump_2eproto::TableStruct;
 };
 // -------------------------------------------------------------------
 
-class Edge : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.Edge) */ {
+class Edge : public ::google::protobuf::MessageLite /* @@protoc_insertion_point(class_definition:mozilla.devtools.protobuf.Edge) */ {
  public:
   Edge();
   virtual ~Edge();
 
   Edge(const Edge& from);
 
   inline Edge& operator=(const Edge& from) {
     CopyFrom(from);
@@ -855,24 +846,23 @@ class Edge : public ::google::protobuf::
     if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
       if (this != &from) InternalSwap(&from);
     } else {
       CopyFrom(from);
     }
     return *this;
   }
   #endif
-  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+  inline const ::std::string& unknown_fields() const {
     return _internal_metadata_.unknown_fields();
   }
-  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+  inline ::std::string* mutable_unknown_fields() {
     return _internal_metadata_.mutable_unknown_fields();
   }
 
-  static const ::google::protobuf::Descriptor* descriptor();
   static const Edge& default_instance();
 
   enum EdgeNameOrRefCase {
     kName = 2,
     kNameRef = 3,
     EDGENAMEORREF_NOT_SET = 0,
   };
 
@@ -888,46 +878,45 @@ class Edge : public ::google::protobuf::
     a.Swap(&b);
   }
 
   // implements Message ----------------------------------------------
 
   inline Edge* New() const PROTOBUF_FINAL { return New(NULL); }
 
   Edge* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
-  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
-  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)
+    PROTOBUF_FINAL;
   void CopyFrom(const Edge& from);
   void MergeFrom(const Edge& from);
   void Clear() PROTOBUF_FINAL;
   bool IsInitialized() const PROTOBUF_FINAL;
 
   size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
-  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  void DiscardUnknownFields();
   int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void SetCachedSize(int size) const;
   void InternalSwap(Edge* other);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return NULL;
   }
   inline void* MaybeArenaPtr() const {
     return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+  ::std::string GetTypeName() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
   // optional uint64 referent = 1;
   bool has_referent() const;
   void clear_referent();
@@ -964,17 +953,17 @@ class Edge : public ::google::protobuf::
   void clear_has_referent();
   void set_has_name();
   void set_has_nameref();
 
   inline bool has_EdgeNameOrRef() const;
   void clear_EdgeNameOrRef();
   inline void clear_has_EdgeNameOrRef();
 
-  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::InternalMetadataWithArenaLite _internal_metadata_;
   ::google::protobuf::internal::HasBits<1> _has_bits_;
   mutable int _cached_size_;
   ::google::protobuf::uint64 referent_;
   union EdgeNameOrRefUnion {
     EdgeNameOrRefUnion() {}
     ::google::protobuf::internal::ArenaStringPtr name_;
     ::google::protobuf::uint64 nameref_;
   } EdgeNameOrRef_;
--- a/devtools/shared/heapsnapshot/CoreDump.proto
+++ b/devtools/shared/heapsnapshot/CoreDump.proto
@@ -52,16 +52,19 @@
 // be a reference to the first as the edgeNameRef oneof property whose value is
 // K.
 //
 // We would ordinarily abstract these de-duplicated strings with messages of
 // their own, but unfortunately, the protobuf compiler does not have a way to
 // inline a messsage within another message and the child message must be
 // referenced by pointer. This leads to extra mallocs that we wish to avoid.
 
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
 
 package mozilla.devtools.protobuf;
 
 // A collection of metadata about this core dump.
 message Metadata {
     // Number of microseconds since midnight (00:00:00) 1 January 1970 UTC.
     optional uint64 timeStamp = 1;
 }
--- a/dom/media/ChannelMediaResource.cpp
+++ b/dom/media/ChannelMediaResource.cpp
@@ -739,19 +739,20 @@ ChannelMediaResource::Resume()
       // If mOffset is at the end of the stream, then we shouldn't try to
       // seek to it. The seek will fail and be wasted anyway. We can leave
       // the channel dead; if the media cache wants to read some other data
       // in the future, it will call CacheClientSeek itself which will reopen the
       // channel.
       if (totalLength < 0 || GetOffset() < totalLength) {
         // There is (or may be) data to read, so start reading it.
         // Need to recreate the channel.
-        Seek(mPendingSeekOffset != -1 ? mPendingSeekOffset : GetOffset(),
-             false);
+        int64_t offset =
+          mPendingSeekOffset != -1 ? mPendingSeekOffset : GetOffset();
         mPendingSeekOffset = -1;
+        Seek(offset, false);
         element->DownloadResumed();
       } else {
         // The channel remains dead. Do not notify DownloadResumed() which
         // will leave the media element in NETWORK_LOADING state.
       }
     }
   }
 }
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -192,16 +192,18 @@ skip-if = toolkit == 'android'
 [test_peerConnection_restartIceNoBundleNoRtcpMux.html]
 skip-if = toolkit == 'android'
 [test_peerConnection_restartIceNoRtcpMux.html]
 skip-if = toolkit == 'android'
 [test_peerConnection_restartIceLocalRollback.html]
 skip-if = toolkit == 'android'
 [test_peerConnection_restartIceLocalAndRemoteRollback.html]
 skip-if = toolkit == 'android'
+[test_peerConnection_restartIceBadAnswer.html]
+skip-if = toolkit == 'android'
 [test_peerConnection_scaleResolution.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_simulcastOffer.html]
 skip-if = android_version # no simulcast support on android
 [test_peerConnection_simulcastAnswer.html]
 skip-if = android_version # no simulcast support on android
 [test_peerConnection_relayOnly.html]
 disabled=
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_restartIceBadAnswer.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "1413709",
+    title: "Renegotiation: bad answer ICE credentials"
+  });
+
+  var test;
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+
+    addRenegotiation(test.chain,
+      [
+        function PC_LOCAL_ADD_SECOND_STREAM(test) {
+          test.setMediaConstraints([{audio: true}],
+                                   []);
+          return test.pcLocal.getAllUserMedia([{audio: true}]);
+        },
+      ]
+    );
+
+    // If the offerer hasn't indicated ICE restart, then an answer
+    // arriving during renegotiation that has modified ICE credentials
+    // should cause an error
+    test.chain.replaceAfter("PC_LOCAL_GET_ANSWER",
+      [
+        function PC_LOCAL_REWRITE_REMOTE_SDP_ICE_CREDS(test) {
+          test._remote_answer.sdp =
+            test._remote_answer.sdp.replace(/a=ice-pwd:.*\r\n/g,
+                                            "a=ice-pwd:bad-pwd\r\n")
+                                   .replace(/a=ice-ufrag:.*\r\n/g,
+                                            "a=ice-ufrag:bad-ufrag\r\n");
+        },
+
+        function PC_LOCAL_EXPECT_SET_REMOTE_DESCRIPTION_FAIL(test) {
+          return test.setRemoteDescription(test.pcLocal,
+                                           test._remote_answer,
+                                           STABLE)
+           .then(() => ok(false, "setRemoteDescription must fail"),
+                 e => is(e.name, "InvalidSessionDescriptionError",
+                         "setRemoteDescription must fail and did"));
+         }
+      ], 1 // replace after the second PC_LOCAL_GET_ANSWER
+    );
+
+    test.setMediaConstraints([{audio: true}], []);
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/SingleTiledContentClient.h"
 
 #include "ClientTiledPaintedLayer.h"
+#include "mozilla/Maybe.h"
 
 namespace mozilla {
 namespace layers {
 
 
 SingleTiledContentClient::SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
                                                    ClientLayerManager* aManager)
   : TiledContentClient(aManager, "Single")
@@ -196,41 +197,42 @@ ClientSingleTiledLayerBuffer::PaintThebe
   if (discardedFrontBuffer) {
     nsIntRegion copyableRegion;
     copyableRegion.And(aNewValidRegion, discardedValidRegion);
     copyableRegion.SubOut(aDirtyRegion);
 
     if (!copyableRegion.IsEmpty()) {
       TextureClientAutoLock frontLock(discardedFrontBuffer,
                                       OpenMode::OPEN_READ);
-      if (frontLock.Succeeded()) {
+      Maybe<TextureClientAutoLock> frontOnWhiteLock;
+      if (discardedFrontBufferOnWhite && backBufferOnWhite) {
+        frontOnWhiteLock.emplace(discardedFrontBufferOnWhite, OpenMode::OPEN_READ);
+      }
+
+      // Copy to both backBuffer and backBufferOnWhite if required, or copy to neither.
+      if (frontLock.Succeeded() && (!frontOnWhiteLock || frontOnWhiteLock->Succeeded())) {
         for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
           const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
           const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
           discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest);
         }
 
-        if (discardedFrontBufferOnWhite && backBufferOnWhite) {
-          TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite,
-                                                OpenMode::OPEN_READ);
-          if (frontOnWhiteLock.Succeeded()) {
-            for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
-              const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
-              const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
-
-              discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
-                                                              &rect, &dest);
-            }
-
-            TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
-
-            // We don't need to repaint valid content that was just copied.
-            paintRegion.SubOut(copyableRegion);
+        if (frontOnWhiteLock) {
+          for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
+            const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
+            const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
+            discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
+                                                             &rect, &dest);
           }
         }
+
+        TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
+
+        // We don't need to repaint valid content that was just copied.
+        paintRegion.SubOut(copyableRegion);
       }
     }
   }
 
   if (dtOnWhite) {
     dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite);
     dtOnWhite = nullptr;
   }
--- a/gfx/layers/protobuf/LayerScopePacket.proto
+++ b/gfx/layers/protobuf/LayerScopePacket.proto
@@ -1,10 +1,12 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 
+syntax = "proto2";
+
 option optimize_for = LITE_RUNTIME;
 
 package mozilla.layers.layerscope;
 
 // ===============================
 // Server to Client messages
 // ===============================
 message FramePacket {
--- a/js/src/build/Makefile.in
+++ b/js/src/build/Makefile.in
@@ -2,17 +2,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/.
 
 # Ensure symbol versions of shared library on Linux do not conflict
 # with those in libxul.
 ifeq (Linux,$(OS_TARGET))
-OS_LDFLAGS += -Wl,-version-script,symverscript
 
 symverscript: symverscript.in
 	$(call py_action,preprocessor, \
 		-DVERSION='$(subst -,_,$(LIBRARY_NAME))' $< -o $@)
 
 EXTRA_DEPS += symverscript
 endif
 
@@ -24,17 +23,17 @@ check-vanilla-allocations:
 	$(PYTHON) $(topsrcdir)/config/check_vanilla_allocations.py $(REAL_LIBRARY)
 
 # The "aggressive" variant will likely fail on some compiler/platform
 # combinations, but is worth running by hand every once in a while.
 check-vanilla-allocations-aggressive:
 	$(PYTHON) $(topsrcdir)/config/check_vanilla_allocations.py --aggressive $(REAL_LIBRARY)
 
 ifeq ($(OS_ARCH),Linux)
-ifeq (,$(filter -flto,$(COMPUTED_CFLAGS) $(COMPUTED_CXXFLAGS) $(LDFLAGS)))
+ifeq (,$(filter -flto,$(COMPUTED_CFLAGS) $(COMPUTED_CXXFLAGS) $(COMPUTED_LDFLAGS)))
 check:: check-vanilla-allocations
 endif
 endif
 
 $(LIBRARY_NAME).pc: js.pc
 	cp $^ $@
 
 # Install versioned file, for parallel installability in Linux distributions
--- a/js/src/build/moz.build
+++ b/js/src/build/moz.build
@@ -70,8 +70,13 @@ if CONFIG['OS_ARCH'] == 'SunOS':
         'socket',
     ]
 
 OS_LIBS += CONFIG['REALTIME_LIBS']
 
 NO_EXPAND_LIBS = True
 
 DIST_INSTALL = True
+
+# Ensure symbol versions of shared library on Linux do not conflict
+# with those in libxul.
+if CONFIG['OS_TARGET'] == 'Linux':
+    LDFLAGS += ['-Wl,-version-script,symverscript']
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1466,17 +1466,17 @@ if test -n "$MOZ_OPTIMIZE"; then
         AC_MSG_ERROR([These compiler flags are invalid: $MOZ_OPTIMIZE_FLAGS])
     fi
     CFLAGS=$_SAVE_CFLAGS
 fi
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST_LIST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST_LIST(MOZ_OPTIMIZE_FLAGS)
-AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
+AC_SUBST_LIST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST_LIST(MOZ_PGO_OPTIMIZE_FLAGS)
 
 dnl ========================================================
 dnl = Trace logging. Enabled by default in DEBUG builds.
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(trace-logging,
 [  --enable-trace-logging   Enable trace logging],
     ENABLE_TRACE_LOGGING=1,
@@ -1915,25 +1915,25 @@ AC_SUBST(AS)
 AC_SUBST(ASFLAGS)
 AC_SUBST(AS_DASH_C_FLAG)
 AC_SUBST(RC)
 AC_SUBST(RCFLAGS)
 AC_SUBST(WINDRES)
 AC_SUBST(IMPLIB)
 AC_SUBST(FILTER)
 AC_SUBST(BIN_FLAGS)
-AC_SUBST(MOZ_DEBUG_LDFLAGS)
+AC_SUBST_LIST(MOZ_DEBUG_LDFLAGS)
 AC_SUBST(WARNINGS_AS_ERRORS)
 AC_SUBST(LIBICONV)
 
 AC_SUBST(ENABLE_STRIP)
 AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(INCREMENTAL_LINKER)
 
-AC_SUBST(MOZ_FIX_LINK_PATHS)
+AC_SUBST_LIST(MOZ_FIX_LINK_PATHS)
 
 AC_SUBST(MOZ_POST_PROGRAM_COMMAND)
 
 AC_SUBST(MOZ_APP_NAME)
 AC_SUBST(MOZ_APP_DISPLAYNAME)
 AC_SUBST(MOZ_APP_VERSION)
 
 AC_SUBST(MOZ_PKG_SPECIAL)
@@ -1979,17 +1979,17 @@ OS_COMPILE_CFLAGS="$COMPILE_CFLAGS"
 OS_COMPILE_CXXFLAGS="$COMPILE_CXXFLAGS"
 OS_LDFLAGS="$LDFLAGS"
 OS_LIBS="$LIBS"
 AC_SUBST_LIST(OS_CFLAGS)
 AC_SUBST_LIST(OS_CXXFLAGS)
 AC_SUBST_LIST(OS_CPPFLAGS)
 AC_SUBST_LIST(OS_COMPILE_CFLAGS)
 AC_SUBST_LIST(OS_COMPILE_CXXFLAGS)
-AC_SUBST(OS_LDFLAGS)
+AC_SUBST_LIST(OS_LDFLAGS)
 AC_SUBST(OS_LIBS)
 
 AC_SUBST(HOST_CC)
 AC_SUBST(HOST_CXX)
 AC_SUBST_LIST(HOST_CFLAGS)
 AC_SUBST_LIST(HOST_CPPFLAGS)
 AC_SUBST_LIST(HOST_CXXFLAGS)
 AC_SUBST(HOST_LDFLAGS)
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -642,20 +642,20 @@ load 1234701-1.html
 load 1234701-2.html
 load 1271765.html
 asserts(2) asserts-if(stylo&&Android,1) load 1272983-1.html # bug 586628
 asserts(2) asserts-if(stylo&&Android,1) load 1272983-2.html # bug 586628
 load 1275059.html
 load 1278007.html
 load 1278080.html
 load 1279814.html
-load large-border-radius-dashed.html
-load large-border-radius-dashed2.html
-load large-border-radius-dotted.html
-load large-border-radius-dotted2.html
+skip-if(webrender) load large-border-radius-dashed.html # see bug 1409243, not handled by webrender
+skip-if(webrender) load large-border-radius-dashed2.html # see bug 1409243, not handled by webrender
+skip-if(webrender) load large-border-radius-dotted.html # see bug 1409243, not handled by webrender
+skip-if(webrender) load large-border-radius-dotted2.html # see bug 1409243, not handled by webrender
 load 1278461-1.html
 load 1278461-2.html
 load 1281102.html
 load 1297427-non-equal-centers.html
 load 1304441.html
 load 1308876-1.html
 load 1316649.html
 load 1349650.html
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3586,21 +3586,16 @@ nsCSSBorderRenderer::DrawBorders()
 
 bool
 nsCSSBorderRenderer::CanCreateWebRenderCommands()
 {
   NS_FOR_CSS_SIDES(i) {
     if (mCompositeColors[i] != nullptr) {
       return false;
     }
-
-    if (mBorderStyles[i] == NS_STYLE_BORDER_STYLE_DOTTED ||
-        mBorderStyles[i] == NS_STYLE_BORDER_STYLE_DASHED) {
-      return false;
-    }
   }
 
   return true;
 }
 
 void
 nsCSSBorderRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
                                              wr::DisplayListBuilder& aBuilder,
--- a/layout/printing/DrawEventRecorder.h
+++ b/layout/printing/DrawEventRecorder.h
@@ -2,70 +2,117 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layout_printing_DrawEventRecorder_h
 #define mozilla_layout_printing_DrawEventRecorder_h
 
+#include <memory>
+
 #include "mozilla/gfx/DrawEventRecorder.h"
 #include "mozilla/gfx/RecordingTypes.h"
 #include "prio.h"
 
 namespace mozilla {
 namespace layout {
 
 class PRFileDescStream : public mozilla::gfx::EventStream {
+  // Most writes, as seen in the print IPC use case, are very small (<32 bytes),
+  // with a small number of very large (>40KB) writes. Writes larger than this
+  // value are not buffered.
+  static const size_t kBufferSize = 1024;
 public:
-  PRFileDescStream() : mFd(nullptr), mGood(true) {}
+  PRFileDescStream() : mFd(nullptr), mBuffer(nullptr), mBufferPos(0),
+                       mGood(true) {}
 
   void OpenFD(PRFileDesc* aFd) {
     MOZ_ASSERT(!IsOpen());
     mFd = aFd;
     mGood = true;
+    mBuffer.reset(new uint8_t[kBufferSize]);
+    mBufferPos = 0;
   }
 
   void Close() {
+    Flush();
     PR_Close(mFd);
     mFd = nullptr;
+    mBuffer.reset();
+    mBufferPos = 0;
   }
 
   bool IsOpen() {
     return mFd != nullptr;
   }
 
   void Flush() {
-    // For std::ostream this flushes any internal buffers. PRFileDesc's IO isn't
-    // buffered, so nothing to do here.
+    // We need to be API compatible with std::ostream, and so we silently handle
+    // flushes on a closed FD.
+    if (IsOpen() && mBufferPos > 0) {
+      PR_Write(mFd, static_cast<const void*>(mBuffer.get()), mBufferPos);
+      mBufferPos = 0;
+    }
   }
 
   void Seek(PRInt32 aOffset, PRSeekWhence aWhence) {
+    Flush();
     PR_Seek(mFd, aOffset, aWhence);
   }
 
   void write(const char* aData, size_t aSize) {
-    // We need to be API compatible with std::ostream, and so we silently handle
-    // writes on a closed FD.
+    // See comment in Flush().
     if (IsOpen()) {
-      PR_Write(mFd, static_cast<const void*>(aData), aSize);
+      // If we're writing more data than could ever fit in our buffer, flush the
+      // buffer and write directly.
+      if (aSize > kBufferSize) {
+        Flush();
+        PR_Write(mFd, static_cast<const void*>(aData), aSize);
+      // If our write could fit in our buffer, but doesn't because the buffer is
+      // partially full, write to the buffer, flush the buffer, and then write
+      // the rest of the data to the buffer.
+      } else if (aSize > AvailableBufferSpace()) {
+        size_t length = AvailableBufferSpace();
+        WriteToBuffer(aData, length);
+        Flush();
+
+        MOZ_ASSERT(aSize <= kBufferSize);
+        WriteToBuffer(aData + length, aSize - length);
+      // Write fits in the buffer.
+      } else {
+        WriteToBuffer(aData, aSize);
+      }
     }
   }
 
   void read(char* aOut, size_t aSize) {
+    Flush();
     PRInt32 res = PR_Read(mFd, static_cast<void*>(aOut), aSize);
     mGood = res >= 0 && ((size_t)res == aSize);
   }
 
   bool good() {
     return mGood;
   }
 
 private:
+  size_t AvailableBufferSpace() {
+    return kBufferSize - mBufferPos;
+  }
+
+  void WriteToBuffer(const char* aData, size_t aSize) {
+    MOZ_ASSERT(aSize <= AvailableBufferSpace());
+    memcpy(mBuffer.get() + mBufferPos, aData, aSize);
+    mBufferPos += aSize;
+  }
+
   PRFileDesc* mFd;
+  std::unique_ptr<uint8_t[]> mBuffer;
+  size_t mBufferPos;
   bool mGood;
 };
 
 class DrawEventRecorderPRFileDesc : public gfx::DrawEventRecorderPrivate
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPRFileDesc, override)
   explicit DrawEventRecorderPRFileDesc() { };
--- a/layout/reftests/border-dotted/reftest.list
+++ b/layout/reftests/border-dotted/reftest.list
@@ -1,16 +1,16 @@
 # Composing dotted/dashed border rendering and not-filled or not-unfilled mask
 # matches to full-filled box, using fuzzyy because of anti-aliasing.
 # These check filled and unfilled regions with solid opaque color,
 # so difference less than 80 is ignorable.
 
 # XXX: We mark fails-if to these tests for now to enable styled border in WR.
 # We should remove them after Bug 1399485 is fixed.
-fuzzy(80,1500) == border-dotted-interaction.html masked.html
-fuzzy(80,1500) == border-dotted-no-radius.html masked.html
+fuzzy(80,1500) fails-if(webrender) == border-dotted-interaction.html masked.html
+fuzzy(80,1500) fails-if(webrender) == border-dotted-no-radius.html masked.html
 fuzzy(80,1500) fails-if(webrender) == border-dotted-radius.html masked.html
-fuzzy(80,1500) == border-dashed-no-radius.html masked.html
+fuzzy(80,1500) fails-if(webrender) == border-dashed-no-radius.html masked.html
 fuzzy(80,1500) fails-if(webrender) == border-dashed-radius.html masked.html
 fuzzy(80,1500) fails-if(webrender) == border-mixed.html masked.html
 fuzzy(80,1500) fails-if(webrender) == border-dashed-non-integer.html masked.html
 fuzzy(80,1500) fails-if(webrender) == border-dashed-radius-zoom.html masked-zoom.html
-fuzzy(80,1500) == border-dotted-radius-zero.html masked-small.html
+fuzzy(80,1500) fails-if(webrender) == border-dotted-radius-zero.html masked-small.html
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,12 +1,12 @@
 default-preferences pref(layout.css.box-decoration-break.enabled,true)
 
 == box-decoration-break-1.html box-decoration-break-1-ref.html
-fuzzy(1,20) fuzzy-if(skiaContent,1,700) fuzzy-if(webrender,4-4,292-292) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
+fuzzy(1,20) fuzzy-if(skiaContent,1,700) fuzzy-if(webrender,6-6,250-250) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 fuzzy(45,460) fuzzy-if(skiaContent,57,439) fuzzy-if(Android,57,1330) fuzzy-if(styloVsGecko,45,1410) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543
 random-if(!gtkWidget) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
 fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
 == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html
 == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html
--- a/media/webrtc/signaling/gtest/jsep_session_unittest.cpp
+++ b/media/webrtc/signaling/gtest/jsep_session_unittest.cpp
@@ -78,36 +78,56 @@ public:
 
     mOffCandidates = MakeUnique<CandidateSet>();
     mAnsCandidates = MakeUnique<CandidateSet>();
   }
 protected:
   struct TransportData {
     std::string mIceUfrag;
     std::string mIcePwd;
+    int iceCredentialSerial;
     std::map<std::string, std::vector<uint8_t> > mFingerprints;
   };
 
   void
+  GenerateNewIceCredentials(const JsepSessionImpl& session,
+                            TransportData& tdata)
+  {
+    std::ostringstream ostr;
+    ostr << session.GetName() << "-" << ++tdata.iceCredentialSerial;
+
+    // Values here semi-borrowed from JSEP draft.
+    tdata.mIceUfrag = ostr.str() + "-ufrag";
+    tdata.mIcePwd = ostr.str() + "-1234567890";
+  }
+
+  void
+  ModifyOffererIceCredentials()
+  {
+    GenerateNewIceCredentials(*mSessionOff, *mOffererTransport);
+    mSessionOff->SetIceCredentials(mOffererTransport->mIceUfrag,
+                                   mOffererTransport->mIcePwd);
+  }
+
+  void
   AddDtlsFingerprint(const std::string& alg, JsepSessionImpl& session,
                      TransportData& tdata)
   {
     std::vector<uint8_t> fp;
     fp.assign((alg == "sha-1") ? 20 : 32,
               (session.GetName() == "Offerer") ? 0x4f : 0x41);
     session.AddDtlsFingerprint(alg, fp);
     tdata.mFingerprints[alg] = fp;
   }
 
   void
   AddTransportData(JsepSessionImpl& session, TransportData& tdata)
   {
-    // Values here semi-borrowed from JSEP draft.
-    tdata.mIceUfrag = session.GetName() + "-ufrag";
-    tdata.mIcePwd = session.GetName() + "-1234567890";
+    tdata.iceCredentialSerial = 0;
+    GenerateNewIceCredentials(session, tdata);
     session.SetIceCredentials(tdata.mIceUfrag, tdata.mIcePwd);
     AddDtlsFingerprint("sha-1", session, tdata);
     AddDtlsFingerprint("sha-256", session, tdata);
   }
 
   std::string
   CreateOffer(const Maybe<JsepOfferOptions>& options = Nothing())
   {
@@ -519,16 +539,24 @@ protected:
     }
   }
 
   std::string
   CreateAnswer()
   {
     JsepAnswerOptions options;
     std::string answer;
+
+    // detect ice restart and generate new ice credentials (like
+    // PeerConnectionImpl does).
+    if (mSessionAns->RemoteIceIsRestarting()) {
+      GenerateNewIceCredentials(*mSessionAns, *mAnswererTransport);
+      mSessionAns->SetIceCredentials(mAnswererTransport->mIceUfrag,
+                                     mAnswererTransport->mIcePwd);
+    }
     nsresult rv = mSessionAns->CreateAnswer(options, &answer);
     EXPECT_EQ(NS_OK, rv);
 
     std::cerr << "ANSWER: " << answer << std::endl;
 
     ValidateTransport(*mAnswererTransport, answer);
 
     return answer;
@@ -4098,16 +4126,103 @@ TEST_F(JsepSessionTest, TestIceOptions)
 
   ASSERT_EQ(1U, mSessionOff->GetIceOptions().size());
   ASSERT_EQ("trickle", mSessionOff->GetIceOptions()[0]);
 
   ASSERT_EQ(1U, mSessionAns->GetIceOptions().size());
   ASSERT_EQ("trickle", mSessionAns->GetIceOptions()[0]);
 }
 
+TEST_F(JsepSessionTest, TestIceRestart)
+{
+  AddTracks(*mSessionOff, "audio");
+  AddTracks(*mSessionAns, "audio");
+  std::string offer = CreateOffer();
+  SetLocalOffer(offer, CHECK_SUCCESS);
+  SetRemoteOffer(offer, CHECK_SUCCESS);
+  std::string answer = CreateAnswer();
+  SetLocalAnswer(answer, CHECK_SUCCESS);
+  SetRemoteAnswer(answer, CHECK_SUCCESS);
+
+  JsepOfferOptions options;
+  options.mIceRestart = Some(true);
+  ModifyOffererIceCredentials();
+
+  std::string reoffer = CreateOffer(Some(options));
+  SetLocalOffer(reoffer, CHECK_SUCCESS);
+  SetRemoteOffer(reoffer, CHECK_SUCCESS);
+  std::string reanswer = CreateAnswer();
+  SetLocalAnswer(reanswer, CHECK_SUCCESS);
+  SetRemoteAnswer(reanswer, CHECK_SUCCESS);
+
+  UniquePtr<Sdp> parsedOffer(Parse(offer));
+  ASSERT_EQ(1U, parsedOffer->GetMediaSectionCount());
+  UniquePtr<Sdp> parsedReoffer(Parse(reoffer));
+  ASSERT_EQ(1U, parsedReoffer->GetMediaSectionCount());
+
+  UniquePtr<Sdp> parsedAnswer(Parse(answer));
+  ASSERT_EQ(1U, parsedAnswer->GetMediaSectionCount());
+  UniquePtr<Sdp> parsedReanswer(Parse(reanswer));
+  ASSERT_EQ(1U, parsedReanswer->GetMediaSectionCount());
+
+  // verify ice pwd/ufrag are present in offer/answer and reoffer/reanswer
+  auto& offerMediaAttrs = parsedOffer->GetMediaSection(0).GetAttributeList();
+  ASSERT_TRUE(offerMediaAttrs.HasAttribute(SdpAttribute::kIcePwdAttribute));
+  ASSERT_TRUE(offerMediaAttrs.HasAttribute(SdpAttribute::kIceUfragAttribute));
+
+  auto& reofferMediaAttrs = parsedReoffer->GetMediaSection(0).GetAttributeList();
+  ASSERT_TRUE(reofferMediaAttrs.HasAttribute(SdpAttribute::kIcePwdAttribute));
+  ASSERT_TRUE(reofferMediaAttrs.HasAttribute(SdpAttribute::kIceUfragAttribute));
+
+  auto& answerMediaAttrs = parsedAnswer->GetMediaSection(0).GetAttributeList();
+  ASSERT_TRUE(answerMediaAttrs.HasAttribute(SdpAttribute::kIcePwdAttribute));
+  ASSERT_TRUE(answerMediaAttrs.HasAttribute(SdpAttribute::kIceUfragAttribute));
+
+  auto& reanswerMediaAttrs = parsedReanswer->GetMediaSection(0).GetAttributeList();
+  ASSERT_TRUE(reanswerMediaAttrs.HasAttribute(SdpAttribute::kIcePwdAttribute));
+  ASSERT_TRUE(reanswerMediaAttrs.HasAttribute(SdpAttribute::kIceUfragAttribute));
+
+  // make sure offer/reoffer ice pwd/ufrag changed on ice restart
+  ASSERT_NE(offerMediaAttrs.GetIcePwd().c_str(),
+            reofferMediaAttrs.GetIcePwd().c_str());
+  ASSERT_NE(offerMediaAttrs.GetIceUfrag().c_str(),
+            reofferMediaAttrs.GetIceUfrag().c_str());
+
+  // make sure answer/reanswer ice pwd/ufrag changed on ice restart
+  ASSERT_NE(answerMediaAttrs.GetIcePwd().c_str(),
+            reanswerMediaAttrs.GetIcePwd().c_str());
+  ASSERT_NE(answerMediaAttrs.GetIceUfrag().c_str(),
+            reanswerMediaAttrs.GetIceUfrag().c_str());
+}
+
+TEST_F(JsepSessionTest, TestAnswererIndicatingIceRestart)
+{
+  AddTracks(*mSessionOff, "audio");
+  AddTracks(*mSessionAns, "audio");
+  std::string offer = CreateOffer();
+  SetLocalOffer(offer, CHECK_SUCCESS);
+  SetRemoteOffer(offer, CHECK_SUCCESS);
+  std::string answer = CreateAnswer();
+  SetLocalAnswer(answer, CHECK_SUCCESS);
+  SetRemoteAnswer(answer, CHECK_SUCCESS);
+
+  // reoffer, but we'll improperly indicate an ice restart in the answer by
+  // modifying the ice pwd and ufrag
+  std::string reoffer = CreateOffer();
+  SetLocalOffer(reoffer, CHECK_SUCCESS);
+  SetRemoteOffer(reoffer, CHECK_SUCCESS);
+  std::string reanswer = CreateAnswer();
+
+  // change the ice pwd and ufrag
+  ReplaceInSdp(&reanswer, "Answerer-1-", "bad-2-");
+  SetLocalAnswer(reanswer, CHECK_SUCCESS);
+  nsresult rv = mSessionOff->SetRemoteDescription(kJsepSdpAnswer, reanswer);
+  ASSERT_NE(NS_OK, rv); // NS_ERROR_INVALID_ARG
+}
+
 TEST_F(JsepSessionTest, TestExtmap)
 {
   AddTracks(*mSessionOff, "audio");
   AddTracks(*mSessionAns, "audio");
   // ssrc-audio-level will be extmap 1 for both
   mSessionOff->AddAudioRtpExtension("foo"); // Default mapping of 3
   mSessionOff->AddAudioRtpExtension("bar"); // Default mapping of 4
   mSessionAns->AddAudioRtpExtension("bar"); // Default mapping of 4
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -457,22 +457,16 @@ static Mutex gInitLock = { OS_SPINLOCK_I
 static Mutex gInitLock = { PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP };
 #else
 static Mutex gInitLock = { PTHREAD_MUTEX_INITIALIZER };
 #endif
 
 // ***************************************************************************
 // Statistics data structures.
 
-struct malloc_bin_stats_t
-{
-  // Current number of runs in this bin.
-  unsigned long curruns;
-};
-
 struct arena_stats_t
 {
   // Number of bytes currently mapped.
   size_t mapped;
 
   // Current number of committed pages.
   size_t committed;
 
@@ -804,42 +798,42 @@ struct arena_run_t
   // Bitmask of in-use regions (0: in use, 1: free).
   unsigned regs_mask[1]; // Dynamically sized.
 };
 
 struct arena_bin_t
 {
   // Current run being used to service allocations of this bin's size
   // class.
-  arena_run_t* runcur;
+  arena_run_t* mCurrentRun;
 
   // Tree of non-full runs.  This tree is used when looking for an
-  // existing run when runcur is no longer usable.  We choose the
+  // existing run when mCurrentRun is no longer usable.  We choose the
   // non-full run that is lowest in memory; this policy tends to keep
   // objects packed well, and it can also help reduce the number of
   // almost-empty chunks.
-  RedBlackTree<arena_chunk_map_t, ArenaRunTreeTrait> runs;
-
-  // Size of regions in a run for this bin's size class.
-  size_t reg_size;
+  RedBlackTree<arena_chunk_map_t, ArenaRunTreeTrait> mNonFullRuns;
+
+  // Bin's size class.
+  size_t mSizeClass;
 
   // Total size of a run for this bin's size class.
-  size_t run_size;
+  size_t mRunSize;
 
   // Total number of regions in a run for this bin's size class.
-  uint32_t nregs;
+  uint32_t mRunNumRegions;
 
   // Number of elements in a run's regs_mask for this bin's size class.
-  uint32_t regs_mask_nelms;
+  uint32_t mRunNumRegionsMask;
 
   // Offset of first region in a run for this bin's size class.
-  uint32_t reg0_offset;
-
-  // Bin statistics.
-  malloc_bin_stats_t stats;
+  uint32_t mRunFirstRegionOffset;
+
+  // Current number of runs in this bin, full or otherwise.
+  unsigned long mNumRuns;
 };
 
 struct arena_t
 {
 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
   uint32_t mMagic;
 #define ARENA_MAGIC 0x947d3d24
 #endif
@@ -2203,49 +2197,49 @@ choose_arena(size_t size)
 
 static inline void*
 arena_run_reg_alloc(arena_run_t* run, arena_bin_t* bin)
 {
   void* ret;
   unsigned i, mask, bit, regind;
 
   MOZ_DIAGNOSTIC_ASSERT(run->magic == ARENA_RUN_MAGIC);
-  MOZ_ASSERT(run->regs_minelm < bin->regs_mask_nelms);
+  MOZ_ASSERT(run->regs_minelm < bin->mRunNumRegionsMask);
 
   // Move the first check outside the loop, so that run->regs_minelm can
   // be updated unconditionally, without the possibility of updating it
   // multiple times.
   i = run->regs_minelm;
   mask = run->regs_mask[i];
   if (mask != 0) {
     // Usable allocation found.
     bit = CountTrailingZeroes32(mask);
 
     regind = ((i << (LOG2(sizeof(int)) + 3)) + bit);
-    MOZ_ASSERT(regind < bin->nregs);
-    ret =
-      (void*)(((uintptr_t)run) + bin->reg0_offset + (bin->reg_size * regind));
+    MOZ_ASSERT(regind < bin->mRunNumRegions);
+    ret = (void*)(((uintptr_t)run) + bin->mRunFirstRegionOffset +
+                  (bin->mSizeClass * regind));
 
     // Clear bit.
     mask ^= (1U << bit);
     run->regs_mask[i] = mask;
 
     return ret;
   }
 
-  for (i++; i < bin->regs_mask_nelms; i++) {
+  for (i++; i < bin->mRunNumRegionsMask; i++) {
     mask = run->regs_mask[i];
     if (mask != 0) {
       // Usable allocation found.
       bit = CountTrailingZeroes32(mask);
 
       regind = ((i << (LOG2(sizeof(int)) + 3)) + bit);
-      MOZ_ASSERT(regind < bin->nregs);
-      ret =
-        (void*)(((uintptr_t)run) + bin->reg0_offset + (bin->reg_size * regind));
+      MOZ_ASSERT(regind < bin->mRunNumRegions);
+      ret = (void*)(((uintptr_t)run) + bin->mRunFirstRegionOffset +
+                    (bin->mSizeClass * regind));
 
       // Clear bit.
       mask ^= (1U << bit);
       run->regs_mask[i] = mask;
 
       // Make a note that nothing before this element
       // contains a free region.
       run->regs_minelm = i; // Low payoff: + (mask == 0);
@@ -2298,17 +2292,18 @@ arena_run_reg_dalloc(arena_run_t* run, a
   unsigned diff, regind, elm, bit;
 
   MOZ_DIAGNOSTIC_ASSERT(run->magic == ARENA_RUN_MAGIC);
   MOZ_ASSERT(((sizeof(size_invs)) / sizeof(unsigned)) + 3 >=
              (SMALL_MAX_DEFAULT >> QUANTUM_2POW_MIN));
 
   // Avoid doing division with a variable divisor if possible.  Using
   // actual division here can reduce allocator throughput by over 20%!
-  diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
+  diff =
+    (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->mRunFirstRegionOffset);
   if ((size & (size - 1)) == 0) {
     // log2_table allows fast division of a power of two in the
     // [1..128] range.
     //
     // (x / divisor) becomes (x >> log2_table[divisor - 1]).
     // clang-format off
     static const unsigned char log2_table[] = {
       0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
@@ -2338,17 +2333,17 @@ arena_run_reg_dalloc(arena_run_t* run, a
   } else {
     // size_invs isn't large enough to handle this size class, so
     // calculate regind using actual division.  This only happens
     // if the user increases small_max via the 'S' runtime
     // configuration option.
     regind = diff / size;
   };
   MOZ_DIAGNOSTIC_ASSERT(diff == regind * size);
-  MOZ_DIAGNOSTIC_ASSERT(regind < bin->nregs);
+  MOZ_DIAGNOSTIC_ASSERT(regind < bin->mRunNumRegions);
 
   elm = regind >> (LOG2(sizeof(int)) + 3);
   if (elm < run->regs_minelm) {
     run->regs_minelm = elm;
   }
   bit = regind - (elm << (LOG2(sizeof(int)) + 3));
   MOZ_DIAGNOSTIC_ASSERT((run->regs_mask[elm] & (1U << bit)) == 0);
   run->regs_mask[elm] |= (1U << bit);
@@ -2688,17 +2683,17 @@ arena_t::DallocRun(arena_run_t* aRun, bo
 
   chunk = GetChunkForPtr(aRun);
   run_ind = (size_t)((uintptr_t(aRun) - uintptr_t(chunk)) >> pagesize_2pow);
   MOZ_DIAGNOSTIC_ASSERT(run_ind >= arena_chunk_header_npages);
   MOZ_DIAGNOSTIC_ASSERT(run_ind < chunk_npages);
   if ((chunk->map[run_ind].bits & CHUNK_MAP_LARGE) != 0) {
     size = chunk->map[run_ind].bits & ~pagesize_mask;
   } else {
-    size = aRun->bin->run_size;
+    size = aRun->bin->mRunSize;
   }
   run_pages = (size >> pagesize_2pow);
 
   // Mark pages as unallocated in the chunk map.
   if (aDirty) {
     size_t i;
 
     for (i = 0; i < run_pages; i++) {
@@ -2825,164 +2820,164 @@ arena_t::TrimRunTail(arena_chunk_t* aChu
 arena_run_t*
 arena_t::GetNonFullBinRun(arena_bin_t* aBin)
 {
   arena_chunk_map_t* mapelm;
   arena_run_t* run;
   unsigned i, remainder;
 
   // Look for a usable run.
-  mapelm = aBin->runs.First();
+  mapelm = aBin->mNonFullRuns.First();
   if (mapelm) {
     // run is guaranteed to have available space.
-    aBin->runs.Remove(mapelm);
+    aBin->mNonFullRuns.Remove(mapelm);
     run = (arena_run_t*)(mapelm->bits & ~pagesize_mask);
     return run;
   }
   // No existing runs have any space available.
 
   // Allocate a new run.
-  run = AllocRun(aBin, aBin->run_size, false, false);
+  run = AllocRun(aBin, aBin->mRunSize, false, false);
   if (!run) {
     return nullptr;
   }
   // Don't initialize if a race in arena_t::RunAlloc() allowed an existing
   // run to become usable.
-  if (run == aBin->runcur) {
+  if (run == aBin->mCurrentRun) {
     return run;
   }
 
   // Initialize run internals.
   run->bin = aBin;
 
-  for (i = 0; i < aBin->regs_mask_nelms - 1; i++) {
+  for (i = 0; i < aBin->mRunNumRegionsMask - 1; i++) {
     run->regs_mask[i] = UINT_MAX;
   }
-  remainder = aBin->nregs & ((1U << (LOG2(sizeof(int)) + 3)) - 1);
+  remainder = aBin->mRunNumRegions & ((1U << (LOG2(sizeof(int)) + 3)) - 1);
   if (remainder == 0) {
     run->regs_mask[i] = UINT_MAX;
   } else {
     // The last element has spare bits that need to be unset.
     run->regs_mask[i] =
       (UINT_MAX >> ((1U << (LOG2(sizeof(int)) + 3)) - remainder));
   }
 
   run->regs_minelm = 0;
 
-  run->nfree = aBin->nregs;
+  run->nfree = aBin->mRunNumRegions;
 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
   run->magic = ARENA_RUN_MAGIC;
 #endif
 
-  aBin->stats.curruns++;
+  aBin->mNumRuns++;
   return run;
 }
 
-// bin->runcur must have space available before this function is called.
+// bin->mCurrentRun must have space available before this function is called.
 void*
 arena_t::MallocBinEasy(arena_bin_t* aBin, arena_run_t* aRun)
 {
   void* ret;
 
   MOZ_DIAGNOSTIC_ASSERT(aRun->magic == ARENA_RUN_MAGIC);
   MOZ_DIAGNOSTIC_ASSERT(aRun->nfree > 0);
 
   ret = arena_run_reg_alloc(aRun, aBin);
   MOZ_DIAGNOSTIC_ASSERT(ret);
   aRun->nfree--;
 
   return ret;
 }
 
-// Re-fill aBin->runcur, then call arena_t::MallocBinEasy().
+// Re-fill aBin->mCurrentRun, then call arena_t::MallocBinEasy().
 void*
 arena_t::MallocBinHard(arena_bin_t* aBin)
 {
-  aBin->runcur = GetNonFullBinRun(aBin);
-  if (!aBin->runcur) {
+  aBin->mCurrentRun = GetNonFullBinRun(aBin);
+  if (!aBin->mCurrentRun) {
     return nullptr;
   }
-  MOZ_DIAGNOSTIC_ASSERT(aBin->runcur->magic == ARENA_RUN_MAGIC);
-  MOZ_DIAGNOSTIC_ASSERT(aBin->runcur->nfree > 0);
-
-  return MallocBinEasy(aBin, aBin->runcur);
+  MOZ_DIAGNOSTIC_ASSERT(aBin->mCurrentRun->magic == ARENA_RUN_MAGIC);
+  MOZ_DIAGNOSTIC_ASSERT(aBin->mCurrentRun->nfree > 0);
+
+  return MallocBinEasy(aBin, aBin->mCurrentRun);
 }
 
-// Calculate bin->run_size such that it meets the following constraints:
+// Calculate bin->mRunSize such that it meets the following constraints:
 //
-//   *) bin->run_size >= min_run_size
-//   *) bin->run_size <= arena_maxclass
-//   *) bin->run_size <= RUN_MAX_SMALL
+//   *) bin->mRunSize >= min_run_size
+//   *) bin->mRunSize <= arena_maxclass
+//   *) bin->mRunSize <= RUN_MAX_SMALL
 //   *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
 //
-// bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
+// bin->mRunNumRegions, bin->mRunNumRegionsMask, and bin->mRunFirstRegionOffset are
 // also calculated here, since these settings are all interdependent.
 static size_t
 arena_bin_run_size_calc(arena_bin_t* bin, size_t min_run_size)
 {
   size_t try_run_size, good_run_size;
   unsigned good_nregs, good_mask_nelms, good_reg0_offset;
   unsigned try_nregs, try_mask_nelms, try_reg0_offset;
 
   MOZ_ASSERT(min_run_size >= pagesize);
   MOZ_ASSERT(min_run_size <= arena_maxclass);
 
-  // Calculate known-valid settings before entering the run_size
+  // Calculate known-valid settings before entering the mRunSize
   // expansion loop, so that the first part of the loop always copies
   // valid settings.
   //
   // The do..while loop iteratively reduces the number of regions until
   // the run header and the regions no longer overlap.  A closed formula
   // would be quite messy, since there is an interdependency between the
   // header's mask length and the number of regions.
   try_run_size = min_run_size;
-  try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size) +
+  try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->mSizeClass) +
               1; // Counter-act try_nregs-- in loop.
   do {
     try_nregs--;
     try_mask_nelms =
       (try_nregs >> (LOG2(sizeof(int)) + 3)) +
       ((try_nregs & ((1U << (LOG2(sizeof(int)) + 3)) - 1)) ? 1 : 0);
-    try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
+    try_reg0_offset = try_run_size - (try_nregs * bin->mSizeClass);
   } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)) >
            try_reg0_offset);
 
-  // run_size expansion loop.
+  // mRunSize expansion loop.
   do {
     // Copy valid settings before trying more aggressive settings.
     good_run_size = try_run_size;
     good_nregs = try_nregs;
     good_mask_nelms = try_mask_nelms;
     good_reg0_offset = try_reg0_offset;
 
     // Try more aggressive settings.
     try_run_size += pagesize;
-    try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size) +
+    try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->mSizeClass) +
                 1; // Counter-act try_nregs-- in loop.
     do {
       try_nregs--;
       try_mask_nelms =
         (try_nregs >> (LOG2(sizeof(int)) + 3)) +
         ((try_nregs & ((1U << (LOG2(sizeof(int)) + 3)) - 1)) ? 1 : 0);
-      try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
+      try_reg0_offset = try_run_size - (try_nregs * bin->mSizeClass);
     } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)) >
              try_reg0_offset);
   } while (try_run_size <= arena_maxclass &&
-           RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX &&
+           RUN_MAX_OVRHD * (bin->mSizeClass << 3) > RUN_MAX_OVRHD_RELAX &&
            (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size);
 
   MOZ_ASSERT(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1)) <=
              good_reg0_offset);
   MOZ_ASSERT((good_mask_nelms << (LOG2(sizeof(int)) + 3)) >= good_nregs);
 
   // Copy final settings.
-  bin->run_size = good_run_size;
-  bin->nregs = good_nregs;
-  bin->regs_mask_nelms = good_mask_nelms;
-  bin->reg0_offset = good_reg0_offset;
+  bin->mRunSize = good_run_size;
+  bin->mRunNumRegions = good_nregs;
+  bin->mRunNumRegionsMask = good_mask_nelms;
+  bin->mRunFirstRegionOffset = good_reg0_offset;
 
   return good_run_size;
 }
 
 void*
 arena_t::MallocSmall(size_t aSize, bool aZero)
 {
   void* ret;
@@ -3001,21 +2996,21 @@ arena_t::MallocSmall(size_t aSize, bool 
     aSize = QUANTUM_CEILING(aSize);
     bin = &mBins[ntbins + (aSize >> QUANTUM_2POW_MIN) - 1];
   } else {
     // Sub-page.
     aSize = RoundUpPow2(aSize);
     bin = &mBins[ntbins + nqbins +
                  (FloorLog2(aSize >> SMALL_MAX_2POW_DEFAULT) - 1)];
   }
-  MOZ_DIAGNOSTIC_ASSERT(aSize == bin->reg_size);
+  MOZ_DIAGNOSTIC_ASSERT(aSize == bin->mSizeClass);
 
   {
     MutexAutoLock lock(mLock);
-    if ((run = bin->runcur) && run->nfree > 0) {
+    if ((run = bin->mCurrentRun) && run->nfree > 0) {
       ret = MallocBinEasy(bin, run);
     } else {
       ret = MallocBinHard(bin);
     }
 
     if (!ret) {
       return nullptr;
     }
@@ -3241,17 +3236,17 @@ arena_salloc(const void* ptr)
 
   chunk = GetChunkForPtr(ptr);
   pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow);
   mapbits = chunk->map[pageind].bits;
   MOZ_DIAGNOSTIC_ASSERT((mapbits & CHUNK_MAP_ALLOCATED) != 0);
   if ((mapbits & CHUNK_MAP_LARGE) == 0) {
     arena_run_t* run = (arena_run_t*)(mapbits & ~pagesize_mask);
     MOZ_DIAGNOSTIC_ASSERT(run->magic == ARENA_RUN_MAGIC);
-    ret = run->bin->reg_size;
+    ret = run->bin->mSizeClass;
   } else {
     ret = mapbits & ~pagesize_mask;
     MOZ_DIAGNOSTIC_ASSERT(ret != 0);
   }
 
   return ret;
 }
 
@@ -3423,20 +3418,20 @@ MozJemalloc::jemalloc_ptr_info(const voi
     return;
   }
 
   // It must be a small allocation.
   auto run = (arena_run_t*)(mapbits & ~pagesize_mask);
   MOZ_DIAGNOSTIC_ASSERT(run->magic == ARENA_RUN_MAGIC);
 
   // The allocation size is stored in the run metadata.
-  size_t size = run->bin->reg_size;
+  size_t size = run->bin->mSizeClass;
 
   // Address of the first possible pointer in the run after its headers.
-  uintptr_t reg0_addr = (uintptr_t)run + run->bin->reg0_offset;
+  uintptr_t reg0_addr = (uintptr_t)run + run->bin->mRunFirstRegionOffset;
   if (aPtr < (void*)reg0_addr) {
     // In the run header.
     *aInfo = { TagUnknown, nullptr, 0 };
     return;
   }
 
   // Position in the run.
   unsigned regind = ((uintptr_t)aPtr - reg0_addr) / size;
@@ -3471,71 +3466,74 @@ arena_t::DallocSmall(arena_chunk_t* aChu
 {
   arena_run_t* run;
   arena_bin_t* bin;
   size_t size;
 
   run = (arena_run_t*)(aMapElm->bits & ~pagesize_mask);
   MOZ_DIAGNOSTIC_ASSERT(run->magic == ARENA_RUN_MAGIC);
   bin = run->bin;
-  size = bin->reg_size;
-  MOZ_DIAGNOSTIC_ASSERT(uintptr_t(aPtr) >= uintptr_t(run) + bin->reg0_offset);
+  size = bin->mSizeClass;
+  MOZ_DIAGNOSTIC_ASSERT(uintptr_t(aPtr) >=
+                        uintptr_t(run) + bin->mRunFirstRegionOffset);
   MOZ_DIAGNOSTIC_ASSERT(
-    (uintptr_t(aPtr) - (uintptr_t(run) + bin->reg0_offset)) % size == 0);
+    (uintptr_t(aPtr) - (uintptr_t(run) + bin->mRunFirstRegionOffset)) % size ==
+    0);
 
   memset(aPtr, kAllocPoison, size);
 
   arena_run_reg_dalloc(run, bin, aPtr, size);
   run->nfree++;
 
-  if (run->nfree == bin->nregs) {
+  if (run->nfree == bin->mRunNumRegions) {
     // Deallocate run.
-    if (run == bin->runcur) {
-      bin->runcur = nullptr;
-    } else if (bin->nregs != 1) {
+    if (run == bin->mCurrentRun) {
+      bin->mCurrentRun = nullptr;
+    } else if (bin->mRunNumRegions != 1) {
       size_t run_pageind =
         (uintptr_t(run) - uintptr_t(aChunk)) >> pagesize_2pow;
       arena_chunk_map_t* run_mapelm = &aChunk->map[run_pageind];
 
       // This block's conditional is necessary because if the
       // run only contains one region, then it never gets
       // inserted into the non-full runs tree.
-      MOZ_DIAGNOSTIC_ASSERT(bin->runs.Search(run_mapelm) == run_mapelm);
-      bin->runs.Remove(run_mapelm);
+      MOZ_DIAGNOSTIC_ASSERT(bin->mNonFullRuns.Search(run_mapelm) == run_mapelm);
+      bin->mNonFullRuns.Remove(run_mapelm);
     }
 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
     run->magic = 0;
 #endif
     DallocRun(run, true);
-    bin->stats.curruns--;
-  } else if (run->nfree == 1 && run != bin->runcur) {
-    // Make sure that bin->runcur always refers to the lowest
+    bin->mNumRuns--;
+  } else if (run->nfree == 1 && run != bin->mCurrentRun) {
+    // Make sure that bin->mCurrentRun always refers to the lowest
     // non-full run, if one exists.
-    if (!bin->runcur) {
-      bin->runcur = run;
-    } else if (uintptr_t(run) < uintptr_t(bin->runcur)) {
-      // Switch runcur.
-      if (bin->runcur->nfree > 0) {
-        arena_chunk_t* runcur_chunk = GetChunkForPtr(bin->runcur);
+    if (!bin->mCurrentRun) {
+      bin->mCurrentRun = run;
+    } else if (uintptr_t(run) < uintptr_t(bin->mCurrentRun)) {
+      // Switch mCurrentRun.
+      if (bin->mCurrentRun->nfree > 0) {
+        arena_chunk_t* runcur_chunk = GetChunkForPtr(bin->mCurrentRun);
         size_t runcur_pageind =
-          (uintptr_t(bin->runcur) - uintptr_t(runcur_chunk)) >> pagesize_2pow;
+          (uintptr_t(bin->mCurrentRun) - uintptr_t(runcur_chunk)) >>
+          pagesize_2pow;
         arena_chunk_map_t* runcur_mapelm = &runcur_chunk->map[runcur_pageind];
 
         // Insert runcur.
-        MOZ_DIAGNOSTIC_ASSERT(!bin->runs.Search(runcur_mapelm));
-        bin->runs.Insert(runcur_mapelm);
+        MOZ_DIAGNOSTIC_ASSERT(!bin->mNonFullRuns.Search(runcur_mapelm));
+        bin->mNonFullRuns.Insert(runcur_mapelm);
       }
-      bin->runcur = run;
+      bin->mCurrentRun = run;
     } else {
       size_t run_pageind =
         (uintptr_t(run) - uintptr_t(aChunk)) >> pagesize_2pow;
       arena_chunk_map_t* run_mapelm = &aChunk->map[run_pageind];
 
-      MOZ_DIAGNOSTIC_ASSERT(bin->runs.Search(run_mapelm) == nullptr);
-      bin->runs.Insert(run_mapelm);
+      MOZ_DIAGNOSTIC_ASSERT(bin->mNonFullRuns.Search(run_mapelm) == nullptr);
+      bin->mNonFullRuns.Insert(run_mapelm);
     }
   }
   mStats.allocated_small -= size;
 }
 
 void
 arena_t::DallocLarge(arena_chunk_t* aChunk, void* aPtr)
 {
@@ -3781,50 +3779,50 @@ arena_t::arena_t()
   mRunsAvail.Init();
 
   // Initialize bins.
   prev_run_size = pagesize;
 
   // (2^n)-spaced tiny bins.
   for (i = 0; i < ntbins; i++) {
     bin = &mBins[i];
-    bin->runcur = nullptr;
-    bin->runs.Init();
-
-    bin->reg_size = (1ULL << (TINY_MIN_2POW + i));
+    bin->mCurrentRun = nullptr;
+    bin->mNonFullRuns.Init();
+
+    bin->mSizeClass = (1ULL << (TINY_MIN_2POW + i));
 
     prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
 
-    memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+    bin->mNumRuns = 0;
   }
 
   // Quantum-spaced bins.
   for (; i < ntbins + nqbins; i++) {
     bin = &mBins[i];
-    bin->runcur = nullptr;
-    bin->runs.Init();
-
-    bin->reg_size = quantum * (i - ntbins + 1);
+    bin->mCurrentRun = nullptr;
+    bin->mNonFullRuns.Init();
+
+    bin->mSizeClass = quantum * (i - ntbins + 1);
 
     prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
 
-    memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+    bin->mNumRuns = 0;
   }
 
   // (2^n)-spaced sub-page bins.
   for (; i < ntbins + nqbins + nsbins; i++) {
     bin = &mBins[i];
-    bin->runcur = nullptr;
-    bin->runs.Init();
-
-    bin->reg_size = (small_max << (i - (ntbins + nqbins) + 1));
+    bin->mCurrentRun = nullptr;
+    bin->mNonFullRuns.Init();
+
+    bin->mSizeClass = (small_max << (i - (ntbins + nqbins) + 1));
 
     prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
 
-    memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+    bin->mNumRuns = 0;
   }
 
 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
   mMagic = ARENA_MAGIC;
 #endif
 }
 
 arena_t*
@@ -4588,27 +4586,27 @@ MozJemalloc::jemalloc_stats(jemalloc_sta
         arena->mStats.allocated_small + arena->mStats.allocated_large;
 
       arena_dirty = arena->mNumDirty << pagesize_2pow;
 
       for (j = 0; j < ntbins + nqbins + nsbins; j++) {
         arena_bin_t* bin = &arena->mBins[j];
         size_t bin_unused = 0;
 
-        for (auto mapelm : bin->runs.iter()) {
+        for (auto mapelm : bin->mNonFullRuns.iter()) {
           run = (arena_run_t*)(mapelm->bits & ~pagesize_mask);
-          bin_unused += run->nfree * bin->reg_size;
+          bin_unused += run->nfree * bin->mSizeClass;
         }
 
-        if (bin->runcur) {
-          bin_unused += bin->runcur->nfree * bin->reg_size;
+        if (bin->mCurrentRun) {
+          bin_unused += bin->mCurrentRun->nfree * bin->mSizeClass;
         }
 
         arena_unused += bin_unused;
-        arena_headers += bin->stats.curruns * bin->reg0_offset;
+        arena_headers += bin->mNumRuns * bin->mRunFirstRegionOffset;
       }
     }
 
     MOZ_ASSERT(arena_mapped >= arena_committed);
     MOZ_ASSERT(arena_committed >= arena_allocated + arena_dirty);
 
     // "waste" is committed memory that is neither dirty nor
     // allocated.
deleted file mode 100644
--- a/mobile/android/Makefile.in
+++ /dev/null
@@ -1,11 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/rules.mk
-include $(topsrcdir)/testing/testsuite-targets.mk
-
-package-mobile-tests:
-	$(MAKE) stage-mochitest DIST_BIN=$(DEPTH)/$(DIST)/bin/xulrunner
-	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
-	@(cd $(PKG_STAGE) && tar $(TAR_CREATE_FLAGS) - *) | bzip2 -f > $(DIST)/$(PKG_PATH)$(TEST_PACKAGE)
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -537,8 +537,32 @@ android.applicationVariants.all { varian
                         .each { it.replaceNode {} }
 
                     manifestOutFile.write(XmlUtil.serialize(xml), 'UTF-8')
                 }
             })
         }
     }
 }
+
+android.applicationVariants.all { variant ->
+    def processResourcesTask = tasks["process${variant.name.capitalize()}Resources"]
+    def assembleTask = tasks["assemble${variant.name.capitalize()}"]
+
+    def dumpTask = task("dump${variant.name.capitalize()}RTxt", type: Copy) {
+        from "${project.buildDir}/intermediates/symbols"
+        into "${project.buildDir}/R/symbols-${System.env.AB_CD}"
+        include "**/R.txt"
+
+        includeEmptyDirs = false
+
+        // Force task to run.
+        outputs.upToDateWhen { false }
+
+        rename { filename ->
+            filename.replace 'R.txt', "R-${new Date().format('yyyyMMddHHmmssSSS')}.txt"
+        }
+
+        dependsOn processResourcesTask
+    }
+
+    assembleTask.dependsOn dumpTask
+}
--- a/mobile/android/config/mozconfigs/android-api-16-frontend/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16-frontend/nightly
@@ -9,19 +9,16 @@ MOZ_AUTOMATION_UPLOAD=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=0
 
 NO_CACHE=1
 NO_NDK=1
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common"
 
-ac_add_options --with-gradle="$topsrcdir/android-gradle-dependencies/gradle-dist/bin/gradle"
-export GRADLE_MAVEN_REPOSITORIES="file://$topsrcdir/android-gradle-dependencies/jcenter","file://$topsrcdir/android-gradle-dependencies/google"
-
 unset HOST_CC
 unset HOST_CXX
 unset RUSTC
 unset CARGO
 
 ac_add_options --disable-compile-environment
 ac_add_options --disable-tests
 
--- a/mobile/android/config/mozconfigs/android-api-16-gradle/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16-gradle/nightly
@@ -1,8 +1,7 @@
 . "$topsrcdir/mobile/android/config/mozconfigs/common"
 
 . "$topsrcdir/mobile/android/config/mozconfigs/android-api-16/nightly"
 
-ac_add_options --with-gradle="$topsrcdir/android-gradle-dependencies/gradle-dist/bin/gradle"
-export GRADLE_MAVEN_REPOSITORIES="file://$topsrcdir/android-gradle-dependencies/jcenter","file://$topsrcdir/android-gradle-dependencies/google"
+ac_add_options --without-gradle
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/common
+++ b/mobile/android/config/mozconfigs/common
@@ -44,16 +44,19 @@ ac_add_options --enable-elf-hack
 
 ANDROID_NDK_VERSION="r10e"
 ANDROID_NDK_VERSION_32BIT="r8c"
 
 # Build Fennec
 ac_add_options --enable-application=mobile/android
 ac_add_options --with-android-sdk="$topsrcdir/android-sdk-linux"
 
+ac_add_options --with-gradle="$topsrcdir/android-gradle-dependencies/gradle-dist/bin/gradle"
+export GRADLE_MAVEN_REPOSITORIES="file://$topsrcdir/android-gradle-dependencies/jcenter","file://$topsrcdir/android-gradle-dependencies/google"
+
 if [ -z "$NO_NDK" ]; then
     ac_add_options --with-android-ndk="$topsrcdir/android-ndk"
 fi
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-fennec-geoloc-api.key
deleted file mode 100644
--- a/mobile/android/config/tooltool-manifests/android-frontend/releng.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-[
-]
deleted file mode 100644
--- a/mobile/android/config/tooltool-manifests/android-gradle-dependencies/releng.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-[
-]
--- a/mobile/android/mach_commands.py
+++ b/mobile/android/mach_commands.py
@@ -311,20 +311,30 @@ class MachCommands(MachCommandBase):
         # filter strings.xml, which is really UTF-8; the ellipsis character is
         # replaced with ??? in some encodings (including ASCII).  It's not yet
         # possible to filter with encodings in Gradle
         # (https://github.com/gradle/gradle/pull/520) and it's challenging to
         # do our filtering with Gradle's Ant support.  Moreover, all of the
         # Android tools expect UTF-8: see
         # http://tools.android.com/knownissues/encoding.  See
         # http://stackoverflow.com/a/21267635 for discussion of this approach.
+        #
+        # It's not even enough to set the encoding just for Gradle; it
+        # needs to be for JVMs spawned by Gradle as well.  This
+        # happens during the maven deployment generating the GeckoView
+        # documents; this works around "error: unmappable character
+        # for encoding ASCII" in exoplayer2.  See
+        # https://discuss.gradle.org/t/unmappable-character-for-encoding-ascii-when-building-a-utf-8-project/10692/11
+        # and especially https://stackoverflow.com/a/21755671.
+
         return self.run_process([self.substs['GRADLE']] + gradle_flags + ['--console=plain'] + args,
             append_env={
                 'GRADLE_OPTS': '-Dfile.encoding=utf-8',
                 'JAVA_HOME': java_home,
+                'JAVA_TOOL_OPTIONS': '-Dfile.encoding=utf-8',
             },
             pass_thru=True, # Allow user to run gradle interactively.
             ensure_exit_code=False, # Don't throw on non-zero exit code.
             cwd=mozpath.join(self.topsrcdir))
 
     @Command('gradle-install', category='devenv',
         conditions=[REMOVED])
     def gradle_install(self):
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5887,16 +5887,21 @@ pref("dom.timeout.max_consecutive_callba
 // Use this preference to house "Payment Request API" during development
 pref("dom.payments.request.enabled", false);
 pref("dom.payments.loglevel", "Warn");
 
 #ifdef FUZZING
 pref("fuzzing.enabled", false);
 #endif
 
+#ifdef MOZ_ASAN_REPORTER
+pref("asanreporter.apiurl", "https://anf1.fuzzing.mozilla.org/crashproxy/submit/");
+pref("asanreporter.clientid", "unknown");
+#endif
+
 #if defined(XP_WIN)
 pref("layers.mlgpu.enabled", true);
 
 // Both this and the master "enabled" pref must be on to use Advanced Layers
 // on Windows 7.
 pref("layers.mlgpu.enable-on-windows7", true);
 #endif
 
--- a/mozglue/build/Makefile.in
+++ b/mozglue/build/Makefile.in
@@ -9,15 +9,8 @@ include $(topsrcdir)/config/config.mk
 ifeq (WINNT,$(OS_TARGET))
 mozglue.def: mozglue.def.in $(GLOBAL_DEPS)
 	$(call py_action,preprocessor,$(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(ACDEFINES) $< -o $@)
 
 GARBAGE += mozglue.def
 endif
 
 include $(topsrcdir)/mozglue/build/replace_malloc.mk
-
-ifdef MOZ_LINKER
-ifeq (arm, $(TARGET_CPU))
-OS_LDFLAGS += -Wl,-version-script,$(srcdir)/arm-eabi-filter
-endif
-
-endif
--- a/mozglue/build/moz.build
+++ b/mozglue/build/moz.build
@@ -93,9 +93,12 @@ if CONFIG['OS_TARGET'] == 'Darwin':
     # symbol resolution for symbols that jemalloc itself uses. While it
     # might be possible to find a way to avoid all such symbol resolutions,
     # it's currently not possible because at the very least there's a call
     # to pthread_self from tsd_init_check_recursion, which is necessary
     # because somehow clang doesn't want to accept the __thread keyword
     # for TLS.
     LDFLAGS += ['-Wl,-bind_at_load']
 
+if CONFIG['MOZ_LINKER'] and CONFIG['TARGET_CPU'] == 'arm':
+    LDFLAGS += ['-Wl,-version-script,%s/arm-eabi-filter' % SRCDIR]
+
 DIST_INSTALL = True
--- a/mozglue/build/replace_malloc.mk
+++ b/mozglue/build/replace_malloc.mk
@@ -1,13 +1,13 @@
 # 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/.
 
 ifeq (Darwin_1,$(OS_TARGET)_$(MOZ_REPLACE_MALLOC))
 # Technically, ) is not a necessary delimiter in the awk call, but make
 # doesn't like the opening ( there being alone...
-OS_LDFLAGS += \
+MK_LDFLAGS = \
   $(shell awk -F'[(),]' '/^MALLOC_DECL/{print "-Wl,-U,_replace_" $$2}' $(topsrcdir)/memory/build/malloc_decls.h) \
   $(NULL)
 
 EXTRA_DEPS += $(topsrcdir)/memory/build/malloc_decls.h
 endif
--- a/netwerk/wifi/nsWifiScannerDBus.cpp
+++ b/netwerk/wifi/nsWifiScannerDBus.cpp
@@ -29,88 +29,150 @@ nsWifiScannerDBus::~nsWifiScannerDBus()
 }
 
 nsresult
 nsWifiScannerDBus::Scan()
 {
   if (!mConnection) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  return SendMessage("org.freedesktop.NetworkManager",
-                     "/org/freedesktop/NetworkManager",
-                     "GetDevices");
+  return SendGetDevices();
+}
+
+// http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
+// Refer to function dbus_connection_send_with_reply_and_block.
+static const uint32_t DBUS_DEFAULT_TIMEOUT = -1;
+
+nsresult
+nsWifiScannerDBus::SendGetDevices()
+{
+  RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
+    dbus_message_new_method_call("org.freedesktop.NetworkManager",
+                                 "/org/freedesktop/NetworkManager",
+                                 "org.freedesktop.NetworkManager",
+                                 "GetDevices"));
+  if (!msg) {
+    return NS_ERROR_FAILURE;
+  }
+
+  DBusError err;
+  dbus_error_init(&err);
+
+  RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
+    dbus_connection_send_with_reply_and_block(mConnection, msg,
+                                              DBUS_DEFAULT_TIMEOUT, &err));
+  if (dbus_error_is_set(&err)) {
+    dbus_error_free(&err);
+    return NS_ERROR_FAILURE;
+  }
+
+  return IdentifyDevices(reply);
 }
 
 nsresult
-nsWifiScannerDBus::SendMessage(const char* aInterface,
-                               const char* aPath,
-                               const char* aFuncCall)
+nsWifiScannerDBus::SendGetDeviceType(const char* aPath)
 {
   RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
     dbus_message_new_method_call("org.freedesktop.NetworkManager",
-                                 aPath, aInterface, aFuncCall));
+                                 aPath,
+                                 "org.freedesktop.DBus.Properties",
+                                 "Get"));
   if (!msg) {
     return NS_ERROR_FAILURE;
   }
 
   DBusMessageIter argsIter;
   dbus_message_iter_init_append(msg, &argsIter);
 
-  if (!strcmp(aFuncCall, "Get")) {
-    const char* paramInterface = "org.freedesktop.NetworkManager.Device";
-    if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
-                                        &paramInterface)) {
-      return NS_ERROR_FAILURE;
-    }
+  const char* paramInterface = "org.freedesktop.NetworkManager.Device";
+  if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
+                                      &paramInterface)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  const char* paramDeviceType = "DeviceType";
+  if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
+                                      &paramDeviceType)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  DBusError err;
+  dbus_error_init(&err);
 
-    const char* paramDeviceType = "DeviceType";
-    if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
-                                        &paramDeviceType)) {
-      return NS_ERROR_FAILURE;
-    }
-  } else if (!strcmp(aFuncCall, "GetAll")) {
-    const char* param = "";
-    if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &param)) {
-      return NS_ERROR_FAILURE;
-    }
+  RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
+    dbus_connection_send_with_reply_and_block(mConnection, msg,
+                                              DBUS_DEFAULT_TIMEOUT, &err));
+  if (dbus_error_is_set(&err)) {
+    dbus_error_free(&err);
+    return NS_ERROR_FAILURE;
+  }
+
+  return IdentifyDeviceType(reply, aPath);
+}
+
+nsresult
+nsWifiScannerDBus::SendGetAccessPoints(const char* aPath)
+{
+  RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
+    dbus_message_new_method_call("org.freedesktop.NetworkManager",
+                                 aPath,
+                                 "org.freedesktop.NetworkManager.Device.Wireless",
+                                 "GetAccessPoints"));
+  if (!msg) {
+    return NS_ERROR_FAILURE;
   }
 
   DBusError err;
   dbus_error_init(&err);
 
-  // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
-  // Refer to function dbus_connection_send_with_reply_and_block.
-  const uint32_t DBUS_DEFAULT_TIMEOUT = -1;
   RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
     dbus_connection_send_with_reply_and_block(mConnection, msg,
                                               DBUS_DEFAULT_TIMEOUT, &err));
   if (dbus_error_is_set(&err)) {
     dbus_error_free(&err);
-
     // In the GetAccessPoints case, if there are no access points, error is set.
     // We don't want to error out here.
-    if (!strcmp(aFuncCall, "GetAccessPoints")) {
-      return NS_OK;
-    }
+    return NS_OK;
+  }
+
+  return IdentifyAccessPoints(reply);
+}
+
+nsresult
+nsWifiScannerDBus::SendGetAPProperties(const char* aPath)
+{
+  RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
+    dbus_message_new_method_call("org.freedesktop.NetworkManager",
+                                 aPath,
+                                 "org.freedesktop.DBus.Properties",
+                                 "GetAll"));
+  if (!msg) {
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv;
-  if (!strcmp(aFuncCall, "GetDevices")) {
-    rv = IdentifyDevices(reply);
-  } else if (!strcmp(aFuncCall, "Get")) {
-    rv = IdentifyDeviceType(reply, aPath);
-  } else if (!strcmp(aFuncCall, "GetAccessPoints")) {
-    rv = IdentifyAccessPoints(reply);
-  } else if (!strcmp(aFuncCall, "GetAll")) {
-    rv = IdentifyAPProperties(reply);
-  } else {
-    rv = NS_ERROR_FAILURE;
+  DBusMessageIter argsIter;
+  dbus_message_iter_init_append(msg, &argsIter);
+
+  const char* param = "org.freedesktop.NetworkManager.AccessPoint";
+  if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &param)) {
+    return NS_ERROR_FAILURE;
   }
-  return rv;
+
+  DBusError err;
+  dbus_error_init(&err);
+
+  RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
+    dbus_connection_send_with_reply_and_block(mConnection, msg,
+                                              DBUS_DEFAULT_TIMEOUT, &err));
+  if (dbus_error_is_set(&err)) {
+    dbus_error_free(&err);
+    return NS_ERROR_FAILURE;
+  }
+
+  return IdentifyAPProperties(reply);
 }
 
 nsresult
 nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg)
 {
   DBusMessageIter iter;
   nsresult rv = GetDBusIterator(aMsg, &iter);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -121,17 +183,17 @@ nsWifiScannerDBus::IdentifyDevices(DBusM
       return NS_ERROR_FAILURE;
     }
 
     dbus_message_iter_get_basic(&iter, &devicePath);
     if (!devicePath) {
       return NS_ERROR_FAILURE;
     }
 
-    rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get");
+    rv = SendGetDeviceType(devicePath);
     NS_ENSURE_SUCCESS(rv, rv);
   } while (dbus_message_iter_next(&iter));
 
   return NS_OK;
 }
 
 nsresult
 nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath)
@@ -154,18 +216,17 @@ nsWifiScannerDBus::IdentifyDeviceType(DB
   uint32_t deviceType;
   dbus_message_iter_get_basic(&variantIter, &deviceType);
 
   // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html
   // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE.
   const uint32_t NM_DEVICE_TYPE_WIFI = 2;
   nsresult rv = NS_OK;
   if (deviceType == NM_DEVICE_TYPE_WIFI) {
-    rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless",
-                     aDevicePath, "GetAccessPoints");
+    rv = SendGetAccessPoints(aDevicePath);
   }
 
   return rv;
 }
 
 nsresult
 nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg)
 {
@@ -178,17 +239,17 @@ nsWifiScannerDBus::IdentifyAccessPoints(
     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
       return NS_ERROR_FAILURE;
     }
     dbus_message_iter_get_basic(&iter, &path);
     if (!path) {
       return NS_ERROR_FAILURE;
     }
 
-    rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll");
+    rv = SendGetAPProperties(path);
     NS_ENSURE_SUCCESS(rv, rv);
   } while (dbus_message_iter_next(&iter));
 
   return NS_OK;
 }
 
 nsresult
 nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg)
--- a/netwerk/wifi/nsWifiScannerDBus.h
+++ b/netwerk/wifi/nsWifiScannerDBus.h
@@ -18,19 +18,20 @@ class nsWifiScannerDBus final
 {
 public:
   explicit nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint>* aAccessPoints);
   ~nsWifiScannerDBus();
 
   nsresult Scan();
 
 private:
-  nsresult SendMessage(const char* aInterface,
-                       const char* aPath,
-                       const char* aFuncCall);
+  nsresult SendGetDevices();
+  nsresult SendGetDeviceType(const char* aPath);
+  nsresult SendGetAccessPoints(const char* aPath);
+  nsresult SendGetAPProperties(const char* aPath);
   nsresult IdentifyDevices(DBusMessage* aMsg);
   nsresult IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath);
   nsresult IdentifyAccessPoints(DBusMessage* aMsg);
   nsresult IdentifyAPProperties(DBusMessage* aMsg);
   nsresult StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp);
   nsresult SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp);
   nsresult GetDBusIterator(DBusMessage* aMsg, DBusMessageIter* aIterArray);
 
--- a/old-configure.in
+++ b/old-configure.in
@@ -3736,17 +3736,17 @@ if test -n "$MOZ_OPTIMIZE"; then
         AC_MSG_ERROR([These compiler flags for C are invalid: $MOZ_OPTIMIZE_FLAGS])
     fi
     CFLAGS=$_SAVE_CFLAGS
 fi
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST_LIST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST_LIST(MOZ_OPTIMIZE_FLAGS)
-AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
+AC_SUBST_LIST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST_LIST(MOZ_PGO_OPTIMIZE_FLAGS)
 
 dnl ========================================================
 dnl = Disable treating compiler warnings as errors
 dnl ========================================================
 if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
    WARNINGS_AS_ERRORS=''
 fi
@@ -4431,17 +4431,17 @@ AC_SUBST(AS_DASH_C_FLAG)
 AC_SUBST(RC)
 AC_SUBST(RCFLAGS)
 AC_SUBST(WINDRES)
 AC_SUBST(IMPLIB)
 AC_SUBST(FILTER)
 AC_SUBST(BIN_FLAGS)
 AC_SUBST(MOZ_AUTH_EXTENSION)
 AC_SUBST(MOZ_PREF_EXTENSIONS)
-AC_SUBST(MOZ_DEBUG_LDFLAGS)
+AC_SUBST_LIST(MOZ_DEBUG_LDFLAGS)
 AC_SUBST(WARNINGS_AS_ERRORS)
 AC_SUBST_SET(MOZ_EXTENSIONS)
 AC_SUBST(LIBICONV)
 AC_SUBST(MOZ_TOOLKIT_SEARCH)
 AC_SUBST(MOZ_FEEDS)
 
 AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
@@ -4465,17 +4465,17 @@ AC_SUBST(MOZ_ANDROID_APPLICATION_CLASS)
 AC_SUBST(MOZ_ANDROID_BROWSER_INTENT_CLASS)
 AC_SUBST(MOZ_EXCLUDE_HYPHENATION_DICTIONARIES)
 AC_SUBST(ENABLE_STRIP)
 AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(STRIP_FLAGS)
 AC_SUBST(USE_ELF_HACK)
 AC_SUBST(INCREMENTAL_LINKER)
 
-AC_SUBST(MOZ_FIX_LINK_PATHS)
+AC_SUBST_LIST(MOZ_FIX_LINK_PATHS)
 
 AC_SUBST(MOZ_POST_PROGRAM_COMMAND)
 AC_SUBST(MOZ_LINKER_EXTRACT)
 
 if test -n "$MOZ_BINARY_EXTENSIONS"; then
   AC_DEFINE(MOZ_BINARY_EXTENSIONS)
 fi
 
@@ -4762,17 +4762,17 @@ OS_COMPILE_CFLAGS="$COMPILE_CFLAGS"
 OS_COMPILE_CXXFLAGS="$COMPILE_CXXFLAGS"
 OS_LDFLAGS="$LDFLAGS"
 OS_LIBS="$LIBS"
 AC_SUBST_LIST(OS_CFLAGS)
 AC_SUBST_LIST(OS_CXXFLAGS)
 AC_SUBST_LIST(OS_CPPFLAGS)
 AC_SUBST_LIST(OS_COMPILE_CFLAGS)
 AC_SUBST_LIST(OS_COMPILE_CXXFLAGS)
-AC_SUBST(OS_LDFLAGS)
+AC_SUBST_LIST(OS_LDFLAGS)
 AC_SUBST(OS_LIBS)
 
 AC_SUBST(HOST_CC)
 AC_SUBST(HOST_CXX)
 AC_SUBST_LIST(HOST_CFLAGS)
 AC_SUBST_LIST(HOST_CPPFLAGS)
 AC_SUBST_LIST(HOST_CXXFLAGS)
 AC_SUBST(HOST_LDFLAGS)
--- a/python/mozbuild/mozbuild/action/langpack_manifest.py
+++ b/python/mozbuild/mozbuild/action/langpack_manifest.py
@@ -13,16 +13,17 @@ from __future__ import absolute_import
 import argparse
 import sys
 import os
 import json
 import io
 import datetime
 import requests
 import mozversioncontrol
+import mozpack.path as mozpath
 from mozpack.chrome.manifest import (
     Manifest,
     ManifestLocale,
     parse_manifest,
 )
 from mozbuild.preprocessor import Preprocessor
 
 
@@ -262,28 +263,29 @@ def parse_chrome_manifest(path, base_pat
     for entry in parse_manifest(None, path):
         if isinstance(entry, Manifest):
             parse_chrome_manifest(
                 os.path.join(os.path.dirname(path), entry.relpath),
                 base_path,
                 chrome_entries
             )
         elif isinstance(entry, ManifestLocale):
+            entry_path = os.path.join(
+                os.path.relpath(
+                    os.path.dirname(path),
+                    base_path
+                ),
+                entry.relpath
+            )
             chrome_entries.append({
                 'type': 'locale',
                 'alias': entry.name,
                 'locale': entry.id,
                 'platforms': convert_entry_flags_to_platform_codes(entry.flags),
-                'path': os.path.join(
-                    os.path.relpath(
-                        os.path.dirname(path),
-                        base_path
-                    ),
-                    entry.relpath
-                )
+                'path': mozpath.normsep(entry_path)
             })
         else:
             raise Exception('Unknown type {0}'.format(entry.name))
 
 
 ###
 # Generates a new web manifest dict with values specific for a language pack.
 #
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -339,16 +339,66 @@ class HostCompileFlags(BaseCompileFlags)
         optimize_flags = []
         if self._context.config.substs.get('CROSS_COMPILE'):
             optimize_flags += self._context.config.substs.get('HOST_OPTIMIZE_FLAGS')
         elif self._context.config.substs.get('MOZ_OPTIMIZE'):
             optimize_flags += self._context.config.substs.get('MOZ_OPTIMIZE_FLAGS')
         return optimize_flags
 
 
+class LinkFlags(BaseCompileFlags):
+    def __init__(self, context):
+        self._context = context
+
+        self.flag_variables = (
+            ('OS', self._os_ldflags(), ('LDFLAGS',)),
+            ('LINKER', context.config.substs.get('LINKER_LDFLAGS'),
+             ('LDFLAGS',)),
+            ('DEFFILE', None, ('LDFLAGS',)),
+            ('MOZBUILD', None, ('LDFLAGS',)),
+            ('FIX_LINK_PATHS', context.config.substs.get('MOZ_FIX_LINK_PATHS'),
+             ('LDFLAGS',)),
+            ('OPTIMIZE', (context.config.substs.get('MOZ_OPTIMIZE_LDFLAGS', []) if
+                          context.config.substs.get('MOZ_OPTIMIZE') else []),
+             ('LDFLAGS',)),
+        )
+        BaseCompileFlags.__init__(self, context)
+
+    def _os_ldflags(self):
+        flags = self._context.config.substs.get('OS_LDFLAGS', [])[:]
+
+        if (self._context.config.substs.get('MOZ_DEBUG') or
+            self._context.config.substs.get('MOZ_DEBUG_SYMBOLS')):
+            flags += self._context.config.substs.get('MOZ_DEBUG_LDFLAGS', [])
+
+        # TODO: This is pretty convoluted, and isn't really a per-context thing,
+        # configure would be a better place to aggregate these.
+        if all([self._context.config.substs.get('OS_ARCH') == 'WINNT',
+                not self._context.config.substs.get('GNU_CC'),
+                not self._context.config.substs.get('MOZ_DEBUG')]):
+
+            # MOZ_DEBUG_SYMBOLS generates debug symbols in separate PDB files.
+            # Used for generating an optimized build with debugging symbols.
+            # Used in the Windows nightlies to generate symbols for crash reporting.
+            if self._context.config.substs.get('MOZ_DEBUG_SYMBOLS'):
+                flags.append('-DEBUG')
+
+
+            if self._context.config.substs.get('MOZ_DMD'):
+                # On Windows Opt DMD builds we actually override everything
+                # from OS_LDFLAGS. Bug 1413728 is on file to figure out whether
+                # this is necessary.
+                flags = ['-DEBUG']
+
+            if self._context.config.substs.get('MOZ_OPTIMIZE'):
+                flags.append('-OPT:REF,ICF')
+
+        return flags
+
+
 class CompileFlags(BaseCompileFlags):
     def __init__(self, context):
         main_src_dir = mozpath.dirname(context.main_path)
         self._context = context
 
         self.flag_variables = (
             ('STL', context.config.substs.get('STL_FLAGS'), ('CXXFLAGS',)),
             ('VISIBILITY', context.config.substs.get('VISIBILITY_FLAGS'),
@@ -1901,16 +1951,21 @@ VARIABLES = {
         """Directories containing Python packages that Sphinx documents.
         """),
 
     'COMPILE_FLAGS': (CompileFlags, dict,
         """Recipe for compile flags for this context. Not to be manipulated
         directly.
         """),
 
+    'LINK_FLAGS': (LinkFlags, dict,
+        """Recipe for linker flags for this context. Not to be manipulated
+        directly.
+        """),
+
     'CFLAGS': (List, list,
         """Flags passed to the C compiler for all of the C source files
            declared in this directory.
 
            Note that the ordering of flags matters here, these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
@@ -2351,16 +2406,17 @@ SPECIAL_VARIABLES = {
                                   else TestDirsPlaceHolder, list,
         """Like DIRS but only for directories that contain test-only code.
 
         If tests are not enabled, this variable will be ignored.
 
         This variable may go away once the transition away from Makefiles is
         complete.
         """),
+
 }
 
 # Deprecation hints.
 DEPRECATION_HINTS = {
     'CPP_UNIT_TESTS': '''
         Please use'
 
             CppUnitTests(['foo', 'bar'])
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -919,16 +919,17 @@ class TreeMetadataEmitter(LoggingMixin):
         # We always emit a directory traversal descriptor. This is needed by
         # the recursive make backend.
         for o in self._emit_directory_traversal_from_context(context): yield o
 
         for obj in self._process_xpidl(context):
             yield obj
 
         computed_flags = ComputedFlags(context, context['COMPILE_FLAGS'])
+        computed_link_flags = ComputedFlags(context, context['LINK_FLAGS'])
         computed_host_flags = ComputedFlags(context, context['HOST_COMPILE_FLAGS'])
 
         # Proxy some variables as-is until we have richer classes to represent
         # them. We should aim to keep this set small because it violates the
         # desired abstraction of the build definition away from makefiles.
         passthru = VariablePassthru(context)
         varlist = [
             'ANDROID_APK_NAME',
@@ -950,28 +951,39 @@ class TreeMetadataEmitter(LoggingMixin):
                 passthru.variables[v] = context[v]
 
         if context.config.substs.get('OS_TARGET') == 'WINNT' and \
                 context['DELAYLOAD_DLLS']:
             context['LDFLAGS'].extend([('-DELAYLOAD:%s' % dll)
                 for dll in context['DELAYLOAD_DLLS']])
             context['OS_LIBS'].append('delayimp')
 
-        for v in ['CMFLAGS', 'CMMFLAGS', 'ASFLAGS', 'LDFLAGS']:
+        for v in ['CMFLAGS', 'CMMFLAGS', 'ASFLAGS']:
             if v in context and context[v]:
                 passthru.variables['MOZBUILD_' + v] = context[v]
 
         for v in ['CXXFLAGS', 'CFLAGS']:
             if v in context and context[v]:
                 computed_flags.resolve_flags('MOZBUILD_%s' % v, context[v])
 
         for v in ['HOST_CXXFLAGS', 'HOST_CFLAGS']:
             if v in context and context[v]:
                 computed_host_flags.resolve_flags('MOZBUILD_%s' % v, context[v])
 
+        if 'LDFLAGS' in context and context['LDFLAGS']:
+            computed_link_flags.resolve_flags('MOZBUILD', context['LDFLAGS'])
+
+        deffile = context['DEFFILE']
+        if deffile and context.config.substs.get('OS_ARCH') == 'WINNT':
+            if context.config.substs.get('GNU_CC'):
+                computed_link_flags.resolve_flags('DEFFILE', [deffile])
+            else:
+                computed_link_flags.resolve_flags('DEFFILE',
+                                                  ['-DEF:' + deffile])
+
         dist_install = context['DIST_INSTALL']
         if dist_install is True:
             passthru.variables['DIST_INSTALL'] = True
         elif dist_install is False:
             passthru.variables['NO_DIST_INSTALL'] = True
 
         # Ideally, this should be done in templates, but this is difficult at
         # the moment because USE_STATIC_LIBS can be set after a template
@@ -1183,16 +1195,17 @@ class TreeMetadataEmitter(LoggingMixin):
         if android_extra_packages:
             yield AndroidExtraPackages(context, android_extra_packages)
 
         if passthru.variables:
             yield passthru
 
         if context.objdir in self._compile_dirs:
             self._compile_flags[context.objdir] = computed_flags
+            yield computed_link_flags
         if context.objdir in self._host_compile_dirs:
             yield computed_host_flags
 
 
     def _create_substitution(self, cls, context, path):
         sub = cls(context)
         sub.input_path = '%s.in' % path.full_path
         sub.output_path = path.translated
--- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
@@ -4,10 +4,9 @@
 
 DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
 
 RCFILE = 'foo.rc'
 RESFILE = 'bar.res'
 RCINCLUDE = 'bar.rc'
 DEFFILE = 'baz.def'
 
-LDFLAGS += ['-ld flag with spaces', '-x']
 WIN32_EXE_LDFLAGS += ['-subsystem:console']
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -323,22 +323,16 @@ class TestRecursiveMakeBackend(BackendTe
                 'RESFILE := bar.res',
             ],
             'RCINCLUDE': [
                 'RCINCLUDE := bar.rc',
             ],
             'DEFFILE': [
                 'DEFFILE := baz.def',
             ],
-            'MOZBUILD_LDFLAGS': [
-                "MOZBUILD_LDFLAGS += '-ld flag with spaces'",
-                'MOZBUILD_LDFLAGS += -x',
-                'MOZBUILD_LDFLAGS += -DELAYLOAD:foo.dll',
-                'MOZBUILD_LDFLAGS += -DELAYLOAD:bar.dll',
-            ],
             'WIN32_EXE_LDFLAGS': [
                 'WIN32_EXE_LDFLAGS += -subsystem:console',
             ],
         }
 
         for var, val in expected.items():
             # print("test_variable_passthru[%s]" % (var))
             found = [str for str in lines if str.startswith(var)]
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/link-flags/moz.build
@@ -0,0 +1,14 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+@template
+def Library(name):
+    '''Template for libraries.'''
+    LIBRARY_NAME = name
+
+Library('dummy')
+
+UNIFIED_SOURCES += ['test1.c']
+
+LDFLAGS += ['-Wl,-U_foo']
+LDFLAGS += ['-framework Foo', '-x']
\ No newline at end of file
new file mode 100644
--- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -6,10 +6,9 @@ DIST_INSTALL = False
 
 DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
 
 RCFILE = 'foo.rc'
 RESFILE = 'bar.res'
 RCINCLUDE = 'bar.rc'
 DEFFILE = 'baz.def'
 
-LDFLAGS += ['-framework Foo', '-x']
 WIN32_EXE_LDFLAGS += ['-subsystem:console']
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -183,106 +183,158 @@ class TestEmitterBasic(unittest.TestCase
         self.assertIsInstance(objs[0], VariablePassthru)
 
         wanted = {
             'NO_DIST_INSTALL': True,
             'RCFILE': 'foo.rc',
             'RESFILE': 'bar.res',
             'RCINCLUDE': 'bar.rc',
             'DEFFILE': 'baz.def',
-            'MOZBUILD_LDFLAGS': ['-framework Foo', '-x', '-DELAYLOAD:foo.dll',
-                                 '-DELAYLOAD:bar.dll'],
             'WIN32_EXE_LDFLAGS': ['-subsystem:console'],
         }
 
         variables = objs[0].variables
         maxDiff = self.maxDiff
         self.maxDiff = None
         self.assertEqual(wanted, variables)
         self.maxDiff = maxDiff
 
     def test_compile_flags(self):
         reader = self.reader('compile-flags', extra_substs={
             'WARNINGS_AS_ERRORS': '-Werror',
         })
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['STL'], reader.config.substs['STL_FLAGS'])
         self.assertEqual(flags.flags['VISIBILITY'], reader.config.substs['VISIBILITY_FLAGS'])
         self.assertEqual(flags.flags['WARNINGS_AS_ERRORS'], ['-Werror'])
         self.assertEqual(flags.flags['MOZBUILD_CFLAGS'], ['-Wall', '-funroll-loops'])
         self.assertEqual(flags.flags['MOZBUILD_CXXFLAGS'], ['-funroll-loops', '-Wall'])
 
     def test_debug_flags(self):
         reader = self.reader('compile-flags', extra_substs={
             'MOZ_DEBUG_FLAGS': '-g',
             'MOZ_DEBUG_SYMBOLS': '1',
         })
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['DEBUG'], ['-g'])
 
     def test_disable_debug_flags(self):
         reader = self.reader('compile-flags', extra_substs={
             'MOZ_DEBUG_FLAGS': '-g',
             'MOZ_DEBUG_SYMBOLS': '',
         })
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['DEBUG'], [])
 
+    def test_link_flags(self):
+        reader = self.reader('link-flags', extra_substs={
+            'OS_LDFLAGS': ['-Wl,rpath-link=/usr/lib'],
+            'LINKER_LDFLAGS': ['-fuse-ld=gold'],
+            'MOZ_OPTIMIZE': '',
+            'MOZ_OPTIMIZE_LDFLAGS': ['-Wl,-dead_strip'],
+            'MOZ_DEBUG_LDFLAGS': ['-framework ExceptionHandling'],
+        })
+        sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+        self.assertIsInstance(ldflags, ComputedFlags)
+        self.assertEqual(ldflags.flags['OS'], reader.config.substs['OS_LDFLAGS'])
+        self.assertEqual(ldflags.flags['LINKER'], reader.config.substs['LINKER_LDFLAGS'])
+        self.assertEqual(ldflags.flags['MOZBUILD'], ['-Wl,-U_foo', '-framework Foo', '-x'])
+        self.assertEqual(ldflags.flags['OPTIMIZE'], [])
+
+    def test_debug_ldflags(self):
+        reader = self.reader('link-flags', extra_substs={
+            'MOZ_DEBUG_SYMBOLS': '1',
+            'MOZ_DEBUG_LDFLAGS': ['-framework ExceptionHandling'],
+        })
+        sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+        self.assertIsInstance(ldflags, ComputedFlags)
+        self.assertEqual(ldflags.flags['OS'],
+                         reader.config.substs['MOZ_DEBUG_LDFLAGS'])
+
+    def test_windows_opt_link_flags(self):
+        reader = self.reader('link-flags', extra_substs={
+            'OS_ARCH': 'WINNT',
+            'GNU_CC': '',
+            'MOZ_OPTIMIZE': '1',
+            'MOZ_DEBUG_SYMBOLS': '1',
+            'MOZ_OPTIMIZE_FLAGS': [],
+            'MOZ_OPTIMIZE_LDFLAGS': [],
+        })
+        sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+        self.assertIsInstance(ldflags, ComputedFlags)
+        self.assertIn('-DEBUG', ldflags.flags['OS'])
+        self.assertIn('-OPT:REF,ICF', ldflags.flags['OS'])
+
+    def test_windows_dmd_link_flags(self):
+        reader = self.reader('link-flags', extra_substs={
+            'OS_ARCH': 'WINNT',
+            'GNU_CC': '',
+            'MOZ_DMD': '1',
+            'MOZ_DEBUG_SYMBOLS': '1',
+            'MOZ_OPTIMIZE': '1',
+            'MOZ_OPTIMIZE_FLAGS': [],
+            'OS_LDFLAGS': ['-Wl,-U_foo'],
+        })
+        sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+        self.assertIsInstance(ldflags, ComputedFlags)
+        self.assertEqual(ldflags.flags['OS'],
+                         ['-DEBUG', '-OPT:REF,ICF'])
+
     def test_host_compile_flags(self):
         reader = self.reader('host-compile-flags', extra_substs={
             'HOST_CXXFLAGS': ['-Wall', '-Werror'],
             'HOST_CFLAGS': ['-Werror', '-Wall'],
         })
-        sources, flags, lib, target_flags = self.read_topsrcdir(reader)
+        sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['HOST_CXXFLAGS'], reader.config.substs['HOST_CXXFLAGS'])
         self.assertEqual(flags.flags['HOST_CFLAGS'], reader.config.substs['HOST_CFLAGS'])
         self.assertEqual(set(flags.flags['HOST_DEFINES']),
                          set(['-DFOO', '-DBAZ="abcd"', '-UQUX', '-DBAR=7', '-DVALUE=xyz']))
         self.assertEqual(flags.flags['MOZBUILD_HOST_CFLAGS'], ['-funroll-loops', '-host-arg'])
         self.assertEqual(flags.flags['MOZBUILD_HOST_CXXFLAGS'], [])
 
     def test_host_no_optimize_flags(self):
         reader = self.reader('host-compile-flags', extra_substs={
             'MOZ_OPTIMIZE': '',
             'MOZ_OPTIMIZE_FLAGS': ['-O2'],
         })
-        sources, flags, lib, target_flags = self.read_topsrcdir(reader)
+        sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['HOST_OPTIMIZE'], [])
 
     def test_host_optimize_flags(self):
         reader = self.reader('host-compile-flags', extra_substs={
             'MOZ_OPTIMIZE': '1',
             'MOZ_OPTIMIZE_FLAGS': ['-O2'],
         })
-        sources, flags, lib, target_flags = self.read_topsrcdir(reader)
+        sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['HOST_OPTIMIZE'], ['-O2'])
 
     def test_cross_optimize_flags(self):
         reader = self.reader('host-compile-flags', extra_substs={
             'MOZ_OPTIMIZE': '1',
             'MOZ_OPTIMIZE_FLAGS': ['-O2'],
             'HOST_OPTIMIZE_FLAGS': ['-O3'],
             'CROSS_COMPILE': '1',
         })
-        sources, flags, lib, target_flags = self.read_topsrcdir(reader)
+        sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['HOST_OPTIMIZE'], ['-O3'])
 
     def test_host_rtl_flag(self):
         reader = self.reader('host-compile-flags', extra_substs={
             'OS_ARCH': 'WINNT',
             'MOZ_DEBUG': '1',
         })
-        sources, flags, lib, target_flags = self.read_topsrcdir(reader)
+        sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['RTL'], ['-MDd'])
 
     def test_compile_flags_validation(self):
         reader = self.reader('compile-flags-field-validation')
 
         with self.assertRaisesRegexp(BuildReaderError, 'Invalid value.'):
             self.read_topsrcdir(reader)
@@ -296,73 +348,73 @@ class TestEmitterBasic(unittest.TestCase
         reader = self.reader('compile-flags-templates', extra_substs={
             'NSPR_CFLAGS': ['-I/nspr/path'],
             'NSS_CFLAGS': ['-I/nss/path'],
             'MOZ_JPEG_CFLAGS': ['-I/jpeg/path'],
             'MOZ_PNG_CFLAGS': ['-I/png/path'],
             'MOZ_ZLIB_CFLAGS': ['-I/zlib/path'],
             'MOZ_PIXMAN_CFLAGS': ['-I/pixman/path'],
         })
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['STL'], [])
         self.assertEqual(flags.flags['VISIBILITY'], [])
         self.assertEqual(flags.flags['OS_INCLUDES'], [
             '-I/nspr/path',
             '-I/nss/path',
             '-I/jpeg/path',
             '-I/png/path',
             '-I/zlib/path',
             '-I/pixman/path',
         ])
 
     def test_disable_stl_wrapping(self):
         reader = self.reader('disable-stl-wrapping')
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['STL'], [])
 
     def test_visibility_flags(self):
         reader = self.reader('visibility-flags')
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['VISIBILITY'], [])
 
     def test_defines_in_flags(self):
         reader = self.reader('compile-defines')
-        defines, sources, lib, flags = self.read_topsrcdir(reader)
+        defines, sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['LIBRARY_DEFINES'],
                          ['-DMOZ_LIBRARY_DEFINE=MOZ_TEST'])
         self.assertEqual(flags.flags['DEFINES'],
                          ['-DMOZ_TEST_DEFINE'])
 
     def test_resolved_flags_error(self):
         reader = self.reader('resolved-flags-error')
         with self.assertRaisesRegexp(BuildReaderError,
             "`DEFINES` may not be set in COMPILE_FLAGS from moz.build"):
             self.read_topsrcdir(reader)
 
     def test_includes_in_flags(self):
         reader = self.reader('compile-includes')
-        defines, sources, lib, flags = self.read_topsrcdir(reader)
+        defines, sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['BASE_INCLUDES'],
                          ['-I%s' % reader.config.topsrcdir,
                           '-I%s' % reader.config.topobjdir])
         self.assertEqual(flags.flags['EXTRA_INCLUDES'],
                          ['-I%s/dist/include' % reader.config.topobjdir])
         self.assertEqual(flags.flags['LOCAL_INCLUDES'],
                          ['-I%s/subdir' % reader.config.topsrcdir])
 
     def test_allow_compiler_warnings(self):
         reader = self.reader('allow-compiler-warnings', extra_substs={
             'WARNINGS_AS_ERRORS': '-Werror',
         })
-        sources, lib, flags = self.read_topsrcdir(reader)
+        sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertEqual(flags.flags['WARNINGS_AS_ERRORS'], [])
 
     def test_use_yasm(self):
         # When yasm is not available, this should raise.
         reader = self.reader('use-yasm')
         with self.assertRaisesRegexp(SandboxValidationError,
             'yasm is not available'):
             self.read_topsrcdir(reader)
@@ -538,25 +590,26 @@ class TestEmitterBasic(unittest.TestCase
         icons = files._children['icons']
 
         self.assertEqual(icons._strings, ['quux.icns'])
 
     def test_program(self):
         reader = self.reader('program')
         objs = self.read_topsrcdir(reader)
 
-        self.assertEqual(len(objs), 4)
+        self.assertEqual(len(objs), 5)
         self.assertIsInstance(objs[0], ComputedFlags)
-        self.assertIsInstance(objs[1], Program)
-        self.assertIsInstance(objs[2], SimpleProgram)
+        self.assertIsInstance(objs[1], ComputedFlags)
+        self.assertIsInstance(objs[2], Program)
         self.assertIsInstance(objs[3], SimpleProgram)
+        self.assertIsInstance(objs[4], SimpleProgram)
 
-        self.assertEqual(objs[1].program, 'test_program.prog')
-        self.assertEqual(objs[2].program, 'test_program1.prog')
-        self.assertEqual(objs[3].program, 'test_program2.prog')
+        self.assertEqual(objs[2].program, 'test_program.prog')
+        self.assertEqual(objs[3].program, 'test_program1.prog')
+        self.assertEqual(objs[4].program, 'test_program2.prog')
 
     def test_test_manifest_missing_manifest(self):
         """A missing manifest file should result in an error."""
         reader = self.reader('test-manifest-missing-manifest')
 
         with self.assertRaisesRegexp(BuildReaderError, 'IOError: Missing files'):
             self.read_topsrcdir(reader)
 
@@ -931,17 +984,18 @@ class TestEmitterBasic(unittest.TestCase
             self.read_topsrcdir(reader)
 
     def test_library_defines(self):
         """Test that LIBRARY_DEFINES is propagated properly."""
         reader = self.reader('library-defines')
         objs = self.read_topsrcdir(reader)
 
         libraries = [o for o in objs if isinstance(o,StaticLibrary)]
-        library_flags = [o for o in objs if isinstance(o, ComputedFlags)]
+        library_flags = [o for o in objs if isinstance(o, ComputedFlags)
+                         and 'LIBRARY_DEFINES' in o.flags]
         expected = {
             'liba': '-DIN_LIBA',
             'libb': '-DIN_LIBA -DIN_LIBB',
             'libc': '-DIN_LIBA -DIN_LIBB',
             'libd': ''
         }
         defines = {}
         for lib in libraries:
@@ -957,16 +1011,18 @@ class TestEmitterBasic(unittest.TestCase
         reader = self.reader('sources')
         objs = self.read_topsrcdir(reader)
 
         computed_flags = objs.pop()
         self.assertIsInstance(computed_flags, ComputedFlags)
         # The second to last object is a Linkable.
         linkable = objs.pop()
         self.assertTrue(linkable.cxx_link)
+        ld_flags = objs.pop()
+        self.assertIsInstance(ld_flags, ComputedFlags)
         self.assertEqual(len(objs), 6)
         for o in objs:
             self.assertIsInstance(o, Sources)
 
         suffix_map = {obj.canonical_suffix: obj for obj in objs}
         self.assertEqual(len(suffix_map), 6)
 
         expected = {
@@ -1013,17 +1069,17 @@ class TestEmitterBasic(unittest.TestCase
         reader = self.reader('generated-sources')
         objs = self.read_topsrcdir(reader)
 
         flags = objs.pop()
         self.assertIsInstance(flags, ComputedFlags)
         # The second to last object is a Linkable.
         linkable = objs.pop()
         self.assertTrue(linkable.cxx_link)
-        self.assertEqual(len(objs), 6)
+        self.assertEqual(len(objs), 7)
 
         generated_sources = [o for o in objs if isinstance(o, GeneratedSources)]
         self.assertEqual(len(generated_sources), 6)
 
         suffix_map = {obj.canonical_suffix: obj for obj in generated_sources}
         self.assertEqual(len(suffix_map), 6)
 
         expected = {
@@ -1047,18 +1103,21 @@ class TestEmitterBasic(unittest.TestCase
 
         # This objdir will generate target flags.
         flags = objs.pop()
         self.assertIsInstance(flags, ComputedFlags)
         # The second to last object is a Linkable
         linkable = objs.pop()
         self.assertTrue(linkable.cxx_link)
         # This objdir will also generate host flags.
-        flags = objs.pop()
-        self.assertIsInstance(flags, ComputedFlags)
+        host_flags = objs.pop()
+        self.assertIsInstance(host_flags, ComputedFlags)
+        # ...and ldflags.
+        ldflags = objs.pop()
+        self.assertIsInstance(ldflags, ComputedFlags)
         self.assertEqual(len(objs), 3)
         for o in objs:
             self.assertIsInstance(o, HostSources)
 
         suffix_map = {obj.canonical_suffix: obj for obj in objs}
         self.assertEqual(len(suffix_map), 3)
 
         expected = {
@@ -1073,18 +1132,18 @@ class TestEmitterBasic(unittest.TestCase
                 [mozpath.join(reader.config.topsrcdir, f) for f in files])
 
     def test_unified_sources(self):
         """Test that UNIFIED_SOURCES works properly."""
         reader = self.reader('unified-sources')
         objs = self.read_topsrcdir(reader)
 
         # The last object is a Linkable, the second to last ComputedFlags,
-        # ignore them.
-        objs = objs[:-2]
+        # followed by ldflags, ignore them.
+        objs = objs[:-3]
         self.assertEqual(len(objs), 3)
         for o in objs:
             self.assertIsInstance(o, UnifiedSources)
 
         suffix_map = {obj.canonical_suffix: obj for obj in objs}
         self.assertEqual(len(suffix_map), 3)
 
         expected = {
@@ -1100,18 +1159,18 @@ class TestEmitterBasic(unittest.TestCase
             self.assertTrue(sources.have_unified_mapping)
 
     def test_unified_sources_non_unified(self):
         """Test that UNIFIED_SOURCES with FILES_PER_UNIFIED_FILE=1 works properly."""
         reader = self.reader('unified-sources-non-unified')
         objs = self.read_topsrcdir(reader)
 
         # The last object is a Linkable, the second to last ComputedFlags,
-        # ignore them.
-        objs = objs[:-2]
+        # followed by ldflags, ignore them.
+        objs = objs[:-3]
         self.assertEqual(len(objs), 3)
         for o in objs:
             self.assertIsInstance(o, UnifiedSources)
 
         suffix_map = {obj.canonical_suffix: obj for obj in objs}
         self.assertEqual(len(suffix_map), 3)
 
         expected = {
@@ -1327,42 +1386,45 @@ class TestEmitterBasic(unittest.TestCase
         self.assertEquals([p.full_path for p in objs[0].paths], expected)
 
     def test_install_shared_lib(self):
         """Test that we can install a shared library with TEST_HARNESS_FILES"""
         reader = self.reader('test-install-shared-lib')
         objs = self.read_topsrcdir(reader)
         self.assertIsInstance(objs[0], TestHarnessFiles)
         self.assertIsInstance(objs[1], VariablePassthru)
-        self.assertIsInstance(objs[2], SharedLibrary)
-        self.assertIsInstance(objs[3], ComputedFlags)
+        self.assertIsInstance(objs[2], ComputedFlags)
+        self.assertIsInstance(objs[3], SharedLibrary)
+        self.assertIsInstance(objs[4], ComputedFlags)
         for path, files in objs[0].files.walk():
             for f in files:
                 self.assertEqual(str(f), '!libfoo.so')
                 self.assertEqual(path, 'foo/bar')
 
     def test_symbols_file(self):
         """Test that SYMBOLS_FILE works"""
         reader = self.reader('test-symbols-file')
-        genfile, shlib, flags = self.read_topsrcdir(reader)
+        genfile, ldflags, shlib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(genfile, GeneratedFile)
         self.assertIsInstance(flags, ComputedFlags)
+        self.assertIsInstance(ldflags, ComputedFlags)
         self.assertIsInstance(shlib, SharedLibrary)
         # This looks weird but MockConfig sets DLL_{PREFIX,SUFFIX} and
         # the reader method in this class sets OS_TARGET=WINNT.
         self.assertEqual(shlib.symbols_file, 'libfoo.so.def')
 
     def test_symbols_file_objdir(self):
         """Test that a SYMBOLS_FILE in the objdir works"""
         reader = self.reader('test-symbols-file-objdir')
-        genfile, shlib, flags = self.read_topsrcdir(reader)
+        genfile, ldflags, shlib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(genfile, GeneratedFile)
         self.assertEqual(genfile.script,
                          mozpath.join(reader.config.topsrcdir, 'foo.py'))
         self.assertIsInstance(flags, ComputedFlags)
+        self.assertIsInstance(ldflags, ComputedFlags)
         self.assertIsInstance(shlib, SharedLibrary)
         self.assertEqual(shlib.symbols_file, 'foo.symbols')
 
     def test_symbols_file_objdir_missing_generated(self):
         """Test that a SYMBOLS_FILE in the objdir that's missing
         from GENERATED_FILES is an error.
         """
         reader = self.reader('test-symbols-file-objdir-missing-generated')
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -290,34 +290,34 @@ dependencies = [
  "compositing 0.0.1",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "offscreen_gl_context 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "offscreen_gl_context 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "webrender 0.53.1 (git+https://github.com/servo/webrender)",
  "webrender_api 0.53.1 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "canvas_traits"
 version = "0.0.1"
 dependencies = [
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.0.1",
  "nonzero 0.0.1",
- "offscreen_gl_context 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "offscreen_gl_context 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "webrender_api 0.53.1 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "caseless"
 version = "0.1.3"
@@ -1048,17 +1048,17 @@ dependencies = [
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.53.1 (git+https://github.com/servo/webrender)",
  "xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "xml5ever 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xml5ever 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gfx_tests"
 version = "0.0.1"
 dependencies = [
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
@@ -1205,17 +1205,17 @@ dependencies = [
 
 [[package]]
 name = "html5ever"
 version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "markup5ever 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "markup5ever 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "httparse"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1682,31 +1682,31 @@ dependencies = [
  "hashglobe 0.1.0",
  "js 0.1.6 (git+https://github.com/servo/rust-mozjs)",
  "servo_arc 0.0.1",
  "smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.53.1 (git+https://github.com/servo/webrender)",
- "xml5ever 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xml5ever 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "malloc_size_of_derive"
 version = "0.0.1"
 dependencies = [
  "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "markup5ever"
-version = "0.6.0"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2079,17 +2079,17 @@ dependencies = [
 
 [[package]]
 name = "odds"
 version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "offscreen_gl_context"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gl_generator 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2542,17 +2542,17 @@ dependencies = [
  "metrics 0.0.1",
  "mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "nonzero 0.0.1",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "offscreen_gl_context 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "offscreen_gl_context 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile_traits 0.0.1",
  "ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2577,17 +2577,17 @@ dependencies = [
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "utf-8 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.53.1 (git+https://github.com/servo/webrender)",
  "webvr_traits 0.0.1",
- "xml5ever 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xml5ever 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "script_layout_interface"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3637,22 +3637,22 @@ name = "xml-rs"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "xml5ever"
-version = "0.11.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "markup5ever 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "markup5ever 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [metadata]
 "checksum adler32 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff33fe13a08dbce05bcefa2c68eea4844941437e33d6f808240b54d7157b9cd"
 "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
 "checksum alloc-no-stdlib 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b21f6ad9c9957eb5d70c3dee16d31c092b3cab339628f821766b05e6833d72b8"
 "checksum android_glue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d8289e9637439939cc92b1995b0972117905be88bc28116c86b64d6e589bcd38"
@@ -3787,17 +3787,17 @@ dependencies = [
 "checksum len-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "723558ab8acaa07cb831b424cd164b587ddc1648b34748a30953c404e9a4a65b"
 "checksum libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e7eb6b826bfc1fdea7935d46556250d1799b7fe2d9f7951071f4291710665e3e"
 "checksum libloading 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be99f814beb3e9503a786a592c909692bb6d4fc5a695f6ed7987223acfbd5194"
 "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16"
 "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
 "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
 "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
 "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
-"checksum markup5ever 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "42cbeefb74733fcb0ea1997095d3439fd62891c72c30f51aeed29751cfad94b0"
+"checksum markup5ever 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2cf89d3e0486c32c9d99521455ddf9a438910a1ce2bd376936086edc15dff5fc"
 "checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
 "checksum metadeps 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829fffe7ea1d747e23f64be972991bc516b2f1ac2ae4a3b33d8bea150c410151"
 "checksum mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d69889cdc6336ed56b174514ce876c4c3dc564cc23dd872e7bca589bb2a36c8"
 "checksum mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76da6df85047af8c0edfa53f48eb1073012ce1cc95c8fedc0a374f659a89dd65"
 "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
 "checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
@@ -3813,17 +3813,17 @@ dependencies = [
 "checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e"
 "checksum num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "c2dc5ea04020a8f18318ae485c751f8cfa1c0e69dcf465c29ddaaa64a313cc44"
 "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
 "checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
 "checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e"
 "checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
 "checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297"
 "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
-"checksum offscreen_gl_context 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2211cc1c0513c664d64f1e2a15d9d7ded52a90f115946e3b2acc7a651d8404f9"
+"checksum offscreen_gl_context 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a34d93fc471702a477584ad881d9e026bafb3479b76b9c300980ab810d9fc4ec"
 "checksum ogg 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7137bf02687385302f4c0aecd77cfce052b69f5b4ee937be778e125c62f67e30"
 "checksum ogg_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc665717454399cba557c55ad226148996e9266ee291f8a37a98bb2cded0a490"
 "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842"
 "checksum openssl 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bb5d1663b73d10c6a3eda53e2e9d0346f822394e7b858d7257718f65f61dfbe2"
 "checksum openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3a5886d87d3e2a0d890bf62dc8944f5e3769a405f7e1e9ef6e517e47fd7a0897"
 "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
 "checksum osmesa-src 17.3.1-devel (git+https://github.com/servo/osmesa-src)" = "<none>"
 "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
@@ -3934,9 +3934,9 @@ dependencies = [
 "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
 "checksum x11 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db27c597c187da52194a4b8232e7d869503911aab9ff726fefb76d7a830f78ed"
 "checksum x11-clipboard 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "731230b8edcbb9d99247105e4c9ec0a538594d50ad68d2afa8662195f9db2973"
 "checksum x11-dl 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "326c500cdc166fd7c70dd8c8a829cd5c0ce7be5a5d98c25817de2b9bdc67faf8"
 "checksum xcb 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "7cede38417fcdf2f0a9d8abf1cea1c1b066320a8a316e9583a0d717c334fafb2"
 "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61"
 "checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1"
 "checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562"
-"checksum xml5ever 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48ce5543b6396e3cd5f52e25a492857853bba3a93d457c76b9eaaca57a07e03"
+"checksum xml5ever 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7ea36cbec2df63ed95e07861d0868a12fb8cb73c88f4c0b0ebf36f2dfc86b6eb"
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -286,17 +286,17 @@ pub trait Flow: HasBaseFlow + fmt::Debug
         if overflow_x::T::visible != self.as_block().fragment.style.get_box().overflow_y {
             overflow.paint.origin.y = Au(0);
             overflow.paint.size.height = border_box.size.height;
             overflow.scroll.origin.y = Au(0);
             overflow.scroll.size.height = border_box.size.height;
         }
 
         if !self.as_block().fragment.establishes_stacking_context() ||
-           self.as_block().fragment.style.get_box().transform.0.is_none() {
+           self.as_block().fragment.style.get_box().transform.0.is_empty() {
             overflow.translate(&position.origin.to_vector());
             return overflow;
         }
 
         // TODO: Take into account 3d transforms, even though it's a fairly
         // uncommon case.
         let transform_2d = self.as_block()
                                .fragment
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -2495,17 +2495,17 @@ impl Fragment {
         Rect::new(Point2D::new(stacking_relative_border_box.origin.x + border_padding.left,
                                stacking_relative_border_box.origin.y + border_padding.top),
                   Size2D::new(stacking_relative_border_box.size.width - border_padding.horizontal(),
                               stacking_relative_border_box.size.height - border_padding.vertical()))
     }
 
     /// Returns true if this fragment has a filter, transform, or perspective property set.
     pub fn has_filter_transform_or_perspective(&self) -> bool {
-           self.style().get_box().transform.0.is_some() ||
+           !self.style().get_box().transform.0.is_empty() ||
            !self.style().get_effects().filter.0.is_empty() ||
            self.style().get_box().perspective != Either::Second(values::None_)
     }
 
     /// Returns true if this fragment establishes a new stacking context and false otherwise.
     pub fn establishes_stacking_context(&self) -> bool {
         // Text fragments shouldn't create stacking contexts.
         match self.specific {
@@ -2555,17 +2555,17 @@ impl Fragment {
     // per CSS 2 9.9.1 (http://www.w3.org/TR/CSS2/visuren.html#z-index), so this value may differ
     // from the value specified in the style.
     pub fn effective_z_index(&self) -> i32 {
         match self.style().get_box().position {
             position::T::static_ => {},
             _ => return self.style().get_position().z_index.integer_or(0),
         }
 
-        if self.style().get_box().transform.0.is_some() {
+        if !self.style().get_box().transform.0.is_empty() {
             return self.style().get_position().z_index.integer_or(0);
         }
 
         match self.style().get_box().display {
             display::T::flex => self.style().get_position().z_index.integer_or(0),
             _ => 0,
         }
     }
--- a/servo/components/script/dom/webgl2renderingcontext.rs
+++ b/servo/components/script/dom/webgl2renderingcontext.rs
@@ -904,11 +904,12 @@ impl WebGL2RenderingContextMethods for W
         self.base.FramebufferTexture2D(target, attachment, textarget, texture, level)
     }
 }
 
 
 impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {
     #[allow(unsafe_code)]
     unsafe fn canvas_data_source(&self) -> HTMLCanvasDataSource {
-        HTMLCanvasDataSource::WebGL((*self.unsafe_get()).base.layout_handle())
+        let this = &*self.unsafe_get();
+        HTMLCanvasDataSource::WebGL((*this.base.to_layout().unsafe_get()).layout_handle())
     }
 }
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -8,17 +8,17 @@ use gecko_bindings::bindings;
 use gecko_bindings::structs;
 use gecko_bindings::structs::{nsCSSValue, nsCSSUnit};
 use gecko_bindings::structs::{nsCSSValue_Array, nsCSSValueList, nscolor};
 use gecko_string_cache::Atom;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::{Index, IndexMut};
 use std::slice;
-use values::computed::{Angle, LengthOrPercentage, Percentage};
+use values::computed::{Angle, Length, LengthOrPercentage, Percentage};
 use values::specified::url::SpecifiedUrl;
 
 impl nsCSSValue {
     /// Create a CSSValue with null unit, useful to be used as a return value.
     #[inline]
     pub fn null() -> Self {
         unsafe { mem::zeroed() }
     }
@@ -99,31 +99,40 @@ impl nsCSSValue {
 
     /// Sets a percentage value to this nsCSSValue.
     pub unsafe fn set_percentage(&mut self, unit_value: f32) {
         bindings::Gecko_CSSValue_SetPercentage(self, unit_value)
     }
 
     /// Returns LengthOrPercentage value.
     pub unsafe fn get_lop(&self) -> LengthOrPercentage {
-        use values::computed::Length;
         match self.mUnit {
             nsCSSUnit::eCSSUnit_Pixel => {
                 LengthOrPercentage::Length(Length::new(bindings::Gecko_CSSValue_GetNumber(self)))
             },
             nsCSSUnit::eCSSUnit_Percent => {
                 LengthOrPercentage::Percentage(Percentage(bindings::Gecko_CSSValue_GetPercentage(self)))
             },
             nsCSSUnit::eCSSUnit_Calc => {
                 LengthOrPercentage::Calc(bindings::Gecko_CSSValue_GetCalc(self).into())
             },
             x => panic!("The unit should not be {:?}", x),
         }
     }
 
+    /// Returns Length  value.
+    pub unsafe fn get_length(&self) -> Length {
+        match self.mUnit {
+            nsCSSUnit::eCSSUnit_Pixel => {
+                Length::new(bindings::Gecko_CSSValue_GetNumber(self))
+            },
+            x => panic!("The unit should not be {:?}", x),
+        }
+    }
+
     fn set_valueless_unit(&mut self, unit: nsCSSUnit) {
         debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
         debug_assert!(unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32, "Not a valueless unit");
         self.mUnit = unit;
     }
 
     /// Set to an auto value
     ///
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -2887,28 +2887,60 @@ fn static_assert() {
     }
 
     pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T {
         let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect();
         longhands::scroll_snap_coordinate::computed_value::T(vec)
     }
 
     ${impl_css_url('_moz_binding', 'mBinding.mPtr')}
-
+    <%
+    transform_functions = [
+        ("Matrix3D", "matrix3d", ["number"] * 16),
+        ("PrefixedMatrix3D", "matrix3d", ["number"] * 12 + ["lopon"] * 2
+                                         + ["lon"] + ["number"]),
+        ("Matrix", "matrix", ["number"] * 6),
+        ("PrefixedMatrix", "matrix", ["number"] * 4 + ["lopon"] * 2),
+        ("Translate", "translate", ["lop", "optional_lop"]),
+        ("Translate3D", "translate3d", ["lop", "lop", "length"]),
+        ("TranslateX", "translatex", ["lop"]),
+        ("TranslateY", "translatey", ["lop"]),
+        ("TranslateZ", "translatez", ["length"]),
+        ("Scale3D", "scale3d", ["number"] * 3),
+        ("Scale", "scale", ["number", "optional_number"]),
+        ("ScaleX", "scalex", ["number"]),
+        ("ScaleY", "scaley", ["number"]),
+        ("ScaleZ", "scalez", ["number"]),
+        ("Rotate", "rotate", ["angle"]),
+        ("Rotate3D", "rotate3d", ["number"] * 3 + ["angle"]),
+        ("RotateX", "rotatex", ["angle"]),
+        ("RotateY", "rotatey", ["angle"]),
+        ("RotateZ", "rotatez", ["angle"]),
+        ("Skew", "skew", ["angle", "optional_angle"]),
+        ("SkewX", "skewx", ["angle"]),
+        ("SkewY", "skewy", ["angle"]),
+        ("Perspective", "perspective", ["length"]),
+        ("InterpolateMatrix", "interpolatematrix", ["list"] * 2 + ["percentage"]),
+        ("AccumulateMatrix", "accumulatematrix", ["list"] * 2 + ["integer_to_percentage"])
+    ]
+    %>
     <%def name="transform_function_arm(name, keyword, items)">
         <%
+            has_optional = items[-1].startswith("optional_")
             pattern = None
             if keyword == "matrix3d":
                 # m11: number1, m12: number2, ..
                 single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b)
                                    in enumerate(items)]
-                if name == "Matrix":
-                    pattern = "(ComputedMatrix { %s })" % ", ".join(single_patterns)
-                else:
-                    pattern = "(ComputedMatrixWithPercents { %s })" % ", ".join(single_patterns)
+                pattern = "(Matrix3D { %s })" % ", ".join(single_patterns)
+            elif keyword == "matrix":
+                # a: number1, b: number2, ..
+                single_patterns = ["%s: %s" % (chr(ord('a') + a), b + str(a + 1)) for (a, b)
+                                   in enumerate(items)]
+                pattern = "(Matrix { %s })" % ", ".join(single_patterns)
             elif keyword == "interpolatematrix":
                 pattern = " { from_list: ref list1, to_list: ref list2, progress: percentage3 }"
             elif keyword == "accumulatematrix":
                 pattern = " { from_list: ref list1, to_list: ref list2, count: integer_to_percentage3 }"
             else:
                 # Generate contents of pattern from items
                 pattern = "(%s)" % ", ".join([b + str(a+1) for (a,b) in enumerate(items)])
 
@@ -2916,67 +2948,93 @@ fn static_assert() {
             # %s substituted with the corresponding variable
             css_value_setters = {
                 "length" : "bindings::Gecko_CSSValue_SetPixelLength(%s, %s.px())",
                 "percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s.0)",
                 # Note: This is an integer type, but we use it as a percentage value in Gecko, so
                 #       need to cast it to f32.
                 "integer_to_percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s as f32)",
                 "lop" : "%s.set_lop(%s)",
+                "lopon" : "set_lopon(%s, %s)",
+                "lon" : "set_lon(%s, %s)",
                 "angle" : "%s.set_angle(%s)",
                 "number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
                 # Note: We use nsCSSValueSharedList here, instead of nsCSSValueList_heap
                 #       because this function is not called on the main thread and
                 #       nsCSSValueList_heap is not thread safe.
-                "list" : "%s.set_shared_list(%s.0.as_ref().unwrap().into_iter().map(&convert_to_ns_css_value));",
+                "list" : "%s.set_shared_list(%s.0.iter().map(&convert_to_ns_css_value));",
             }
         %>
-        longhands::transform::computed_value::ComputedOperation::${name}${pattern} => {
-            bindings::Gecko_CSSValue_SetFunction(gecko_value, ${len(items) + 1});
+        ::values::generics::transform::TransformOperation::${name}${pattern} => {
+            % if has_optional:
+                let optional_present = ${items[-1] + str(len(items))}.is_some();
+                let len = if optional_present {
+                    ${len(items) + 1}
+                } else {
+                    ${len(items)}
+                };
+            % else:
+                let len = ${len(items) + 1};
+            % endif
+            bindings::Gecko_CSSValue_SetFunction(gecko_value, len);
             bindings::Gecko_CSSValue_SetKeyword(
                 bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0),
                 structs::nsCSSKeyword::eCSSKeyword_${keyword}
             );
             % for index, item in enumerate(items):
+                <% replaced_item = item.replace("optional_", "") %>
+                % if item.startswith("optional"):
+                    if let Some(${replaced_item + str(index + 1)}) = ${item + str(index + 1)} {
+                % endif
                 % if item == "list":
-                    debug_assert!(${item}${index + 1}.0.is_some());
+                    debug_assert!(!${item}${index + 1}.0.is_empty());
                 % endif
-                ${css_value_setters[item] % (
+                ${css_value_setters[replaced_item] % (
                     "bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d)" % (index + 1),
-                    item + str(index + 1)
+                    replaced_item + str(index + 1)
                 )};
+                % if item.startswith("optional"):
+                    }
+                % endif
             % endfor
         }
     </%def>
     fn set_single_transform_function(servo_value: &longhands::transform::computed_value::ComputedOperation,
                                      gecko_value: &mut structs::nsCSSValue /* output */) {
-        use properties::longhands::transform::computed_value::ComputedMatrix;
-        use properties::longhands::transform::computed_value::ComputedMatrixWithPercents;
         use properties::longhands::transform::computed_value::ComputedOperation;
+        use values::computed::{Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrNumber};
+        use values::generics::transform::{Matrix, Matrix3D};
 
         let convert_to_ns_css_value = |item: &ComputedOperation| -> structs::nsCSSValue {
             let mut value = structs::nsCSSValue::null();
             Self::set_single_transform_function(item, &mut value);
             value
         };
 
+        unsafe fn set_lopon(css: &mut structs::nsCSSValue, lopon: LengthOrPercentageOrNumber) {
+            let lop = match lopon {
+                Either::First(number) => LengthOrPercentage::Length(Length::new(number)),
+                Either::Second(lop) => lop,
+            };
+            css.set_lop(lop);
+        }
+
+        unsafe fn set_lon(css: &mut structs::nsCSSValue, lopon: LengthOrNumber) {
+            let length = match lopon {
+                Either::Second(number) => Length::new(number),
+                Either::First(l) => l,
+            };
+            bindings::Gecko_CSSValue_SetPixelLength(css, length.px())
+        }
+
         unsafe {
             match *servo_value {
-                ${transform_function_arm("Matrix", "matrix3d", ["number"] * 16)}
-                ${transform_function_arm("MatrixWithPercents", "matrix3d", ["number"] * 12 + ["lop"] * 2
-                                         + ["length"] + ["number"])}
-                ${transform_function_arm("Skew", "skew", ["angle"] * 2)}
-                ${transform_function_arm("Translate", "translate3d", ["lop", "lop", "length"])}
-                ${transform_function_arm("Scale", "scale3d", ["number"] * 3)}
-                ${transform_function_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])}
-                ${transform_function_arm("Perspective", "perspective", ["length"])}
-                ${transform_function_arm("InterpolateMatrix", "interpolatematrix",
-                                         ["list"] * 2 + ["percentage"])}
-                ${transform_function_arm("AccumulateMatrix", "accumulatematrix",
-                                         ["list"] * 2 + ["integer_to_percentage"])}
+                % for servo, gecko, format in transform_functions:
+                    ${transform_function_arm(servo, gecko, format)}
+                % endfor
             }
         }
     }
     pub fn convert_transform(input: &[longhands::transform::computed_value::ComputedOperation],
                              output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList>) {
         use gecko_bindings::sugar::refptr::RefPtr;
 
         unsafe { output.clear() };
@@ -2989,84 +3047,111 @@ fn static_assert() {
             for (gecko, servo) in value_list.into_iter().zip(input.into_iter()) {
                 Self::set_single_transform_function(servo, gecko);
             }
         }
         unsafe { output.set_move(list) };
     }
 
     pub fn set_transform(&mut self, other: longhands::transform::computed_value::T) {
-        let vec = if let Some(v) = other.0 {
-            v
-        } else {
+        if other.0.is_empty() {
             unsafe {
                 self.gecko.mSpecifiedTransform.clear();
             }
             return;
         };
-        Self::convert_transform(&vec, &mut self.gecko.mSpecifiedTransform);
+        Self::convert_transform(&other.0, &mut self.gecko.mSpecifiedTransform);
     }
 
     pub fn copy_transform_from(&mut self, other: &Self) {
         unsafe { self.gecko.mSpecifiedTransform.set(&other.gecko.mSpecifiedTransform); }
     }
 
     pub fn reset_transform(&mut self, other: &Self) {
         self.copy_transform_from(other)
     }
 
     <%def name="computed_operation_arm(name, keyword, items)">
         <%
             # %s is substituted with the call to GetArrayItem.
             css_value_getters = {
                 "length" : "Length::new(bindings::Gecko_CSSValue_GetNumber(%s))",
                 "lop"