Merge inbound to mozilla-central. a=merge
authorNoemi Erli <nerli@mozilla.com>
Sat, 06 Oct 2018 12:27:35 +0300
changeset 495633 6f233fd06aac
parent 495608 e2ec1eeb812d (current diff)
parent 495632 78f6d666ce6e (diff)
child 495634 86cc3618811a
child 495638 76fafdaa9216
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
6f233fd06aac / 64.0a1 / 20181006100304 / files
nightly linux64
6f233fd06aac / 64.0a1 / 20181006100304 / files
nightly mac
6f233fd06aac / 64.0a1 / 20181006100304 / files
nightly win32
6f233fd06aac / 64.0a1 / 20181006100304 / files
nightly win64
6f233fd06aac / 64.0a1 / 20181006100304 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
ipc/chromium/atomics/moz.build
ipc/chromium/src/base/atomic_sequence_num.h
ipc/chromium/src/base/atomicops.h
ipc/chromium/src/base/atomicops_internals_arm64_gcc.h
ipc/chromium/src/base/atomicops_internals_arm_gcc.h
ipc/chromium/src/base/atomicops_internals_mips_gcc.h
ipc/chromium/src/base/atomicops_internals_mutex.cc
ipc/chromium/src/base/atomicops_internals_mutex.h
ipc/chromium/src/base/atomicops_internals_ppc_gcc.h
ipc/chromium/src/base/atomicops_internals_x86_gcc.cc
ipc/chromium/src/base/atomicops_internals_x86_gcc.h
ipc/chromium/src/base/atomicops_internals_x86_macosx.h
ipc/chromium/src/base/atomicops_internals_x86_msvc.h
ipc/chromium/src/base/singleton.h
ipc/chromium/src/base/singleton_objc.h
--- a/devtools/client/inspector/flexbox/actions/flexbox.js
+++ b/devtools/client/inspector/flexbox/actions/flexbox.js
@@ -1,17 +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/. */
 
 "use strict";
 
 const {
   CLEAR_FLEXBOX,
-  TOGGLE_FLEX_ITEM_SHOWN,
   UPDATE_FLEXBOX,
   UPDATE_FLEXBOX_COLOR,
   UPDATE_FLEXBOX_HIGHLIGHTED,
 } = require("./index");
 
 module.exports = {
 
   /**
@@ -19,31 +18,16 @@ module.exports = {
    */
   clearFlexbox() {
     return {
       type: CLEAR_FLEXBOX,
     };
   },
 
   /**
-   * Toggles the display of flex item sizing information shown for the given flex item
-   * actor ID.
-   *
-   * @param  {NodeFront} nodeFront
-   *         The NodeFront of the flex item to toggle the sizing information displayed
-   *         for.
-   */
-  toggleFlexItemShown(nodeFront) {
-    return {
-      type: TOGGLE_FLEX_ITEM_SHOWN,
-      nodeFront,
-    };
-  },
-
-  /**
    * Updates the flexbox state with the newly selected flexbox.
    */
   updateFlexbox(flexbox) {
     return {
       type: UPDATE_FLEXBOX,
       flexbox,
     };
   },
--- a/devtools/client/inspector/flexbox/actions/index.js
+++ b/devtools/client/inspector/flexbox/actions/index.js
@@ -6,19 +6,16 @@
 
 const { createEnum } = require("devtools/client/shared/enum");
 
 createEnum([
 
   // Clears the flexbox state by resetting it back to the initial flexbox state.
   "CLEAR_FLEXBOX",
 
-  // Toggles the display of flex item sizing information shown.
-  "TOGGLE_FLEX_ITEM_SHOWN",
-
   // Updates the flexbox state with the newly selected flexbox.
   "UPDATE_FLEXBOX",
 
   // Updates the color used for the overlay of a flexbox.
   "UPDATE_FLEXBOX_COLOR",
 
   // Updates the flexbox highlighted state.
   "UPDATE_FLEXBOX_HIGHLIGHTED",
--- a/devtools/client/inspector/flexbox/components/FlexContainer.js
+++ b/devtools/client/inspector/flexbox/components/FlexContainer.js
@@ -7,28 +7,30 @@
 const {
   createElement,
   createRef,
   Fragment,
   PureComponent,
 } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
 
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 const ElementNode = REPS.ElementNode;
 
 const Types = require("../types");
 
 class FlexContainer extends PureComponent {
   static get propTypes() {
     return {
-      flexbox: PropTypes.shape(Types.flexbox).isRequired,
+      color: PropTypes.string.isRequired,
+      flexContainer: PropTypes.shape(Types.flexContainer).isRequired,
       getSwatchColorPickerTooltip: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
@@ -38,63 +40,54 @@ class FlexContainer extends PureComponen
     this.colorValueEl = createRef();
     this.swatchEl = createRef();
 
     this.onFlexboxInspectIconClick = this.onFlexboxInspectIconClick.bind(this);
     this.setFlexboxColor = this.setFlexboxColor.bind(this);
   }
 
   componentDidMount() {
-    const {
-      flexbox,
-      getSwatchColorPickerTooltip,
-      onSetFlexboxOverlayColor,
-    } = this.props;
-
-    const tooltip = getSwatchColorPickerTooltip();
+    const tooltip = this.props.getSwatchColorPickerTooltip();
 
     let previousColor;
     tooltip.addSwatch(this.swatchEl.current, {
       onCommit: this.setFlexboxColor,
       onPreview: this.setFlexboxColor,
       onRevert: () => {
-        onSetFlexboxOverlayColor(previousColor);
+        this.props.onSetFlexboxOverlayColor(previousColor);
       },
       onShow: () => {
-        previousColor = flexbox.color;
+        previousColor = this.props.color;
       },
     });
   }
 
   componentWillUnMount() {
     const tooltip = this.props.getSwatchColorPickerTooltip();
     tooltip.removeSwatch(this.swatchEl.current);
   }
 
   setFlexboxColor() {
     const color = this.colorValueEl.current.textContent;
     this.props.onSetFlexboxOverlayColor(color);
   }
 
   onFlexboxInspectIconClick(nodeFront) {
-    const { setSelectedNode } = this.props;
-    setSelectedNode(nodeFront, { reason: "layout-panel" });
+    this.props.setSelectedNode(nodeFront, { reason: "layout-panel" });
     nodeFront.scrollIntoView().catch(e => console.error(e));
   }
 
   render() {
     const {
-      flexbox,
+      color,
+      flexContainer,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
     } = this.props;
-    const {
-      color,
-      nodeFront,
-    } = flexbox;
+    const { nodeFront } = flexContainer;
 
     return createElement(Fragment, null,
       Rep({
         defaultRep: ElementNode,
         mode: MODE.TINY,
         object: translateNodeFrontToGrip(nodeFront),
         onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
         onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
@@ -118,9 +111,15 @@ class FlexContainer extends PureComponen
           ref: this.colorValueEl,
         },
         color
       )
     );
   }
 }
 
-module.exports = FlexContainer;
+const mapStateToProps = state => {
+  return {
+    color: state.flexbox.color,
+  };
+};
+
+module.exports = connect(mapStateToProps)(FlexContainer);
--- a/devtools/client/inspector/flexbox/components/FlexItem.js
+++ b/devtools/client/inspector/flexbox/components/FlexItem.js
@@ -18,33 +18,29 @@ loader.lazyGetter(this, "MODE", function
 loader.lazyRequireGetter(this, "translateNodeFrontToGrip", "devtools/client/inspector/shared/utils", true);
 
 const Types = require("../types");
 
 class FlexItem extends PureComponent {
   static get propTypes() {
     return {
       flexItem: PropTypes.shape(Types.flexItem).isRequired,
-      onToggleFlexItemShown: PropTypes.func.isRequired,
+      setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   render() {
-    const {
-      flexItem,
-      onToggleFlexItemShown,
-    } = this.props;
-    const { nodeFront } = flexItem;
+    const { nodeFront } = this.props.flexItem;
 
     return (
       dom.li({},
         dom.button(
           {
             className: "devtools-button devtools-monospace",
-            onClick: () => onToggleFlexItemShown(nodeFront),
+            onClick: () => this.props.setSelectedNode(nodeFront),
           },
           Rep({
             defaultRep: Rep.ElementNode,
             mode: MODE.TINY,
             object: translateNodeFrontToGrip(nodeFront),
           })
         )
       )
--- a/devtools/client/inspector/flexbox/components/FlexItemList.js
+++ b/devtools/client/inspector/flexbox/components/FlexItemList.js
@@ -11,32 +11,32 @@ const PropTypes = require("devtools/clie
 const FlexItem = createFactory(require(("./FlexItem")));
 
 const Types = require("../types");
 
 class FlexItemList extends PureComponent {
   static get propTypes() {
     return {
       flexItems: PropTypes.arrayOf(PropTypes.shape(Types.flexItem)).isRequired,
-      onToggleFlexItemShown: PropTypes.func.isRequired,
+      setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   render() {
     const {
       flexItems,
-      onToggleFlexItemShown,
+      setSelectedNode,
     } = this.props;
 
     return (
       dom.ol(
         { className: "flex-item-list" },
         flexItems.map(flexItem => FlexItem({
           key: flexItem.actorID,
           flexItem,
-          onToggleFlexItemShown,
+          setSelectedNode,
         }))
       )
     );
   }
 }
 
 module.exports = FlexItemList;
--- a/devtools/client/inspector/flexbox/components/FlexItemSelector.js
+++ b/devtools/client/inspector/flexbox/components/FlexItemSelector.js
@@ -20,40 +20,40 @@ const Types = require("../types");
 
 loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
 
 class FlexItemSelector extends PureComponent {
   static get propTypes() {
     return {
       flexItem: PropTypes.shape(Types.flexItem).isRequired,
       flexItems: PropTypes.arrayOf(PropTypes.shape(Types.flexItem)).isRequired,
-      onToggleFlexItemShown: PropTypes.func.isRequired,
+      setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
     this.onShowFlexItemMenu = this.onShowFlexItemMenu.bind(this);
   }
 
   onShowFlexItemMenu(event) {
     const {
       flexItem,
       flexItems,
-      onToggleFlexItemShown,
+      setSelectedNode,
     } = this.props;
     const menuItems = [];
 
     for (const item of flexItems) {
       const grip = translateNodeFrontToGrip(item.nodeFront);
       menuItems.push({
         label: getSelectorFromGrip(grip),
         type: "checkbox",
         checked: item === flexItem,
-        click: () => onToggleFlexItemShown(item.nodeFront),
+        click: () => setSelectedNode(item.nodeFront),
       });
     }
 
     showMenu(menuItems, {
       button: event.target,
     });
   }
 
--- a/devtools/client/inspector/flexbox/components/Flexbox.js
+++ b/devtools/client/inspector/flexbox/components/Flexbox.js
@@ -22,99 +22,102 @@ loader.lazyGetter(this, "Header", functi
   return createFactory(require("./Header"));
 });
 
 const Types = require("../types");
 
 class Flexbox extends PureComponent {
   static get propTypes() {
     return {
-      flexbox: PropTypes.shape(Types.flexbox).isRequired,
+      flexContainer: PropTypes.shape(Types.flexContainer).isRequired,
       getSwatchColorPickerTooltip: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       onToggleFlexboxHighlighter: PropTypes.func.isRequired,
-      onToggleFlexItemShown: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
-  renderFlexItemList() {
-    const {
-      flexbox,
-      onToggleFlexItemShown,
-    } = this.props;
-    const {
-      flexItems,
-      flexItemShown,
-    } = flexbox;
-
-    if (flexItemShown || !flexItems.length) {
+  renderFlexContainerProperties() {
+    // Don't show the flex container properties for the parent flex container of the
+    // selected element.
+    if (this.props.flexContainer.isFlexItemContainer) {
       return null;
     }
 
-    return FlexItemList({
-      flexItems,
-      onToggleFlexItemShown,
+    return FlexContainerProperties({
+      properties: this.props.flexContainer.properties,
     });
   }
 
-  renderFlexItemSizingProperties() {
-    const { flexbox } = this.props;
+  renderFlexItemList() {
+    const { setSelectedNode } = this.props;
+    const { flexItems } = this.props.flexContainer;
+
+    return FlexItemList({
+      flexItems,
+      setSelectedNode,
+    });
+  }
+
+  renderFlexItemSizing() {
     const {
       flexItems,
       flexItemShown,
-    } = flexbox;
+      properties,
+    } = this.props.flexContainer;
 
-    if (!flexItemShown) {
+    const flexItem = flexItems.find(item => item.nodeFront.actorID === flexItemShown);
+    if (!flexItem) {
       return null;
     }
 
     return FlexItemSizingProperties({
-      flexDirection: flexbox.properties["flex-direction"],
-      flexItem: flexItems.find(item => item.nodeFront.actorID === flexItemShown),
+      flexDirection: properties["flex-direction"],
+      flexItem,
     });
   }
 
   render() {
     const {
-      flexbox,
+      flexContainer,
       getSwatchColorPickerTooltip,
       onHideBoxModelHighlighter,
       onSetFlexboxOverlayColor,
       onShowBoxModelHighlighterForNode,
       onToggleFlexboxHighlighter,
-      onToggleFlexItemShown,
       setSelectedNode,
     } = this.props;
 
-    if (!flexbox.actorID) {
+    if (!flexContainer.actorID) {
       return (
         dom.div({ className: "devtools-sidepanel-no-result" },
           getStr("flexbox.noFlexboxeOnThisPage")
         )
       );
     }
 
+    const {
+      flexItems,
+      flexItemShown,
+    } = flexContainer;
+
     return (
       dom.div({ id: "layout-flexbox-container" },
         Header({
-          flexbox,
+          flexContainer,
           getSwatchColorPickerTooltip,
           onHideBoxModelHighlighter,
           onSetFlexboxOverlayColor,
           onShowBoxModelHighlighterForNode,
           onToggleFlexboxHighlighter,
-          onToggleFlexItemShown,
           setSelectedNode,
         }),
-        this.renderFlexItemList(),
-        this.renderFlexItemSizingProperties(),
-        FlexContainerProperties({
-          properties: flexbox.properties,
-        })
+        !flexItemShown && flexItems.length > 0 ? this.renderFlexItemList() : null,
+        flexItemShown ? this.renderFlexItemSizing() : null,
+        this.renderFlexContainerProperties()
       )
     );
   }
 }
 
 module.exports = Flexbox;
--- a/devtools/client/inspector/flexbox/components/Header.js
+++ b/devtools/client/inspector/flexbox/components/Header.js
@@ -1,128 +1,147 @@
 /* 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";
 
-const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const {
+  createElement,
+  createFactory,
+  Fragment,
+  PureComponent,
+} = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 const FlexContainer = createFactory(require("./FlexContainer"));
 const FlexItemSelector = createFactory(require("./FlexItemSelector"));
 
 const Types = require("../types");
 
 class Header extends PureComponent {
   static get propTypes() {
     return {
-      flexbox: PropTypes.shape(Types.flexbox).isRequired,
+      flexContainer: PropTypes.shape(Types.flexContainer).isRequired,
       getSwatchColorPickerTooltip: PropTypes.func.isRequired,
+      highlighted: PropTypes.bool.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       onToggleFlexboxHighlighter: PropTypes.func.isRequired,
-      onToggleFlexItemShown: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
     this.onFlexboxCheckboxClick = this.onFlexboxCheckboxClick.bind(this);
   }
 
   onFlexboxCheckboxClick() {
-    const {
-      flexbox,
-      onToggleFlexboxHighlighter,
-    } = this.props;
+    this.props.onToggleFlexboxHighlighter(this.props.flexContainer.nodeFront);
+  }
+
+  renderFlexboxHighlighterToggle() {
+    // Don't show the flexbox highlighter toggle for the parent flex container of the
+    // selected element.
+    if (this.props.flexContainer.isFlexItemContainer) {
+      return null;
+    }
 
-    onToggleFlexboxHighlighter(flexbox.nodeFront);
+    return createElement(Fragment, null,
+      dom.div({ className: "devtools-separator" }),
+      dom.input({
+        className: "devtools-checkbox-toggle",
+        checked: this.props.highlighted,
+        onChange: this.onFlexboxCheckboxClick,
+        type: "checkbox",
+      })
+    );
   }
 
   renderFlexContainer() {
-    if (this.props.flexbox.flexItemShown) {
+    if (this.props.flexContainer.flexItemShown) {
       return null;
     }
 
     const {
-      flexbox,
+      flexContainer,
       getSwatchColorPickerTooltip,
       onHideBoxModelHighlighter,
       onSetFlexboxOverlayColor,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
     } = this.props;
 
     return FlexContainer({
-      flexbox,
+      flexContainer,
       getSwatchColorPickerTooltip,
       onHideBoxModelHighlighter,
       onSetFlexboxOverlayColor,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
     });
   }
 
   renderFlexItemSelector() {
-    if (!this.props.flexbox.flexItemShown) {
+    if (!this.props.flexContainer.flexItemShown) {
       return null;
     }
 
     const {
-      flexbox,
-      onToggleFlexItemShown,
+      flexContainer,
+      setSelectedNode,
     } = this.props;
     const {
       flexItems,
       flexItemShown,
-    } = flexbox;
+    } = flexContainer;
 
     return FlexItemSelector({
       flexItem: flexItems.find(item => item.nodeFront.actorID === flexItemShown),
       flexItems,
-      onToggleFlexItemShown,
+      setSelectedNode,
     });
   }
 
   render() {
     const {
-      flexbox,
-      onToggleFlexItemShown,
+      flexContainer,
+      setSelectedNode,
     } = this.props;
     const {
       flexItemShown,
-      highlighted,
-    } = flexbox;
+      nodeFront,
+    } = flexContainer;
 
     return (
       dom.div({ className: "flex-header devtools-monospace" },
         flexItemShown ?
           dom.button({
             className: "flex-header-button-prev devtools-button",
-            onClick: () => onToggleFlexItemShown(),
+            onClick: () => setSelectedNode(nodeFront),
           })
           :
           null,
         dom.div(
           {
             className: "flex-header-content" +
                        (flexItemShown ? " flex-item-shown" : "")
           },
           this.renderFlexContainer(),
           this.renderFlexItemSelector()
         ),
-        dom.div({ className: "devtools-separator" }),
-        dom.input({
-          className: "devtools-checkbox-toggle",
-          checked: highlighted,
-          onChange: this.onFlexboxCheckboxClick,
-          type: "checkbox",
-        })
+        this.renderFlexboxHighlighterToggle()
       )
     );
   }
 }
 
-module.exports = Header;
+const mapStateToProps = state => {
+  return {
+    highlighted: state.flexbox.highlighted,
+  };
+};
+
+module.exports = connect(mapStateToProps)(Header);
--- a/devtools/client/inspector/flexbox/flexbox.js
+++ b/devtools/client/inspector/flexbox/flexbox.js
@@ -4,17 +4,16 @@
 
 "use strict";
 
 const flags = require("devtools/shared/flags");
 const { throttle } = require("devtools/shared/throttle");
 
 const {
   clearFlexbox,
-  toggleFlexItemShown,
   updateFlexbox,
   updateFlexboxColor,
   updateFlexboxHighlighted,
 } = require("./actions/flexbox");
 
 loader.lazyRequireGetter(this, "parseURL", "devtools/client/shared/source-utils", true);
 loader.lazyRequireGetter(this, "asyncStorage", "devtools/shared/async-storage");
 
@@ -30,17 +29,16 @@ class FlexboxInspector {
 
     this.onHighlighterShown = this.onHighlighterShown.bind(this);
     this.onHighlighterHidden = this.onHighlighterHidden.bind(this);
     this.onNavigate = this.onNavigate.bind(this);
     this.onReflow = throttle(this.onReflow, 500, this);
     this.onSetFlexboxOverlayColor = this.onSetFlexboxOverlayColor.bind(this);
     this.onSidebarSelect = this.onSidebarSelect.bind(this);
     this.onToggleFlexboxHighlighter = this.onToggleFlexboxHighlighter.bind(this);
-    this.onToggleFlexItemShown = this.onToggleFlexItemShown.bind(this);
     this.onUpdatePanel = this.onUpdatePanel.bind(this);
 
     this.init();
   }
 
   // Get the highlighters overlay from the Inspector.
   get highlighters() {
     if (!this._highlighters) {
@@ -100,21 +98,65 @@ class FlexboxInspector {
     this.hasGetCurrentFlexbox = null;
     this.inspector = null;
     this.layoutInspector = null;
     this.selection = null;
     this.store = null;
     this.walker = null;
   }
 
+  /**
+   * If the current selected node is a flex container, check if it is also a flex item of
+   * a parent flex container and get its parent flex container if any and returns an
+   * object that consists of the parent flex container's items and properties.
+   *
+   * @param  {NodeFront} containerNodeFront
+   *         The current flex container of the selected node.
+   * @return {Object} consiting of the parent flex container's flex items and properties.
+   */
+  async getAsFlexItem(containerNodeFront) {
+    // If the current selected node is not a flex container, we know it is a flex item.
+    // No need to look for the parent flex container.
+    if (containerNodeFront !== this.selection.nodeFront) {
+      return null;
+    }
+
+    const flexboxFront = await this.layoutInspector.getCurrentFlexbox(
+      this.selection.nodeFront, true);
+
+    if (!flexboxFront) {
+      return null;
+    }
+
+    containerNodeFront = flexboxFront.containerNodeFront;
+    if (!containerNodeFront) {
+      containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
+        ["containerEl"]);
+    }
+
+    let flexItemContainer = null;
+    if (flexboxFront) {
+      const flexItems = await this.getFlexItems(flexboxFront);
+      flexItemContainer = {
+        actorID: flexboxFront.actorID,
+        flexItems,
+        flexItemShown: this.selection.nodeFront.actorID,
+        isFlexItemContainer: true,
+        nodeFront: containerNodeFront,
+        properties: flexboxFront.properties,
+      };
+    }
+
+    return flexItemContainer;
+  }
+
   getComponentProps() {
     return {
       onSetFlexboxOverlayColor: this.onSetFlexboxOverlayColor,
       onToggleFlexboxHighlighter: this.onToggleFlexboxHighlighter,
-      onToggleFlexItemShown: this.onToggleFlexItemShown,
     };
   }
 
   /**
    * Returns an object containing the custom flexbox colors for different hosts.
    *
    * @return {Object} that maps a host name to a custom flexbox color for a given host.
    */
@@ -225,17 +267,18 @@ class FlexboxInspector {
    *          If the change is to highlight or hide the overlay.
    * @param  {NodeFront} nodeFront
    *         The NodeFront of the flex container element for which the flexbox
    *         highlighter is shown for.
    */
   onHighlighterChange(highlighted, nodeFront) {
     const { flexbox } = this.store.getState();
 
-    if (flexbox.nodeFront === nodeFront && flexbox.highlighted !== highlighted) {
+    if (flexbox.flexContainer.nodeFront === nodeFront &&
+        flexbox.highlighted !== highlighted) {
       this.store.dispatch(updateFlexboxHighlighted(highlighted));
     }
   }
 
   /**
    * Handler for the "new-root" event fired by the inspector. Clears the cached overlay
    * color for the flexbox highlighter and updates the panel.
    */
@@ -337,34 +380,16 @@ class FlexboxInspector {
    */
   onToggleFlexboxHighlighter(node) {
     this.highlighters.toggleFlexboxHighlighter(node);
     this.store.dispatch(updateFlexboxHighlighted(node !==
       this.highlighters.flexboxHighlighterShow));
   }
 
   /**
-   * Handler for a change in the input checkbox in the FlexItem and Header component.
-   * Toggles on/off the flex item highlighter for the provided flex item element and
-   * changes the selection to the given node.
-   *
-   * @param  {NodeFront|null} node
-   *         The NodeFront of the flex item element for which the flex item is toggled
-   *         on/off for.
-   */
-  onToggleFlexItemShown(node) {
-    this.highlighters.toggleFlexItemHighlighter(node);
-    this.store.dispatch(toggleFlexItemShown(node));
-
-    if (node) {
-      this.selection.setNodeFront(node);
-    }
-  }
-
-  /**
    * Handler for "new-root" event fired by the inspector and "new-node-front" event fired
    * by the inspector selection. Updates the flexbox panel if it is visible.
    */
   onUpdatePanel() {
     if (!this.isPanelVisible()) {
       return;
     }
 
@@ -407,33 +432,38 @@ class FlexboxInspector {
       // then get it from the walker. This happens when the walker hasn't seen this
       // particular DOM Node in the tree yet or when we are connected to an older server.
       let containerNodeFront = flexboxFront.containerNodeFront;
       if (!containerNodeFront) {
         containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
           ["containerEl"]);
       }
 
+      const flexItemContainer = await this.getAsFlexItem(containerNodeFront);
       const flexItems = await this.getFlexItems(flexboxFront);
       // If the current selected node is a flex item, display its flex item sizing
       // properties.
       const flexItemShown = flexItems.find(item =>
         item.nodeFront === this.selection.nodeFront);
       const highlighted = this._highlighters &&
         containerNodeFront == this.highlighters.flexboxHighlighterShown;
       const color = await this.getOverlayColor();
 
       this.store.dispatch(updateFlexbox({
-        actorID: flexboxFront.actorID,
         color,
-        flexItems,
-        flexItemShown: flexItemShown ? flexItemShown.nodeFront.actorID : null,
+        flexContainer: {
+          actorID: flexboxFront.actorID,
+          flexItems,
+          flexItemShown: flexItemShown ? flexItemShown.nodeFront.actorID : null,
+          isFlexItemContainer: false,
+          nodeFront: containerNodeFront,
+          properties: flexboxFront.properties,
+        },
+        flexItemContainer,
         highlighted,
-        nodeFront: containerNodeFront,
-        properties: flexboxFront.properties,
       }));
     } catch (e) {
       // This call might fail if called asynchrously after the toolbox is finished
       // closing.
     }
   }
 }
 
--- a/devtools/client/inspector/flexbox/reducers/flexbox.js
+++ b/devtools/client/inspector/flexbox/reducers/flexbox.js
@@ -1,73 +1,85 @@
 /* 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";
 
 const {
   CLEAR_FLEXBOX,
-  TOGGLE_FLEX_ITEM_SHOWN,
   UPDATE_FLEXBOX,
   UPDATE_FLEXBOX_COLOR,
   UPDATE_FLEXBOX_HIGHLIGHTED,
 } = require("../actions/index");
 
 const INITIAL_FLEXBOX = {
-  // The actor ID of the flex container.
-  actorID: null,
   // The color of the flexbox highlighter overlay.
   color: "",
-  // An array of flex items belonging to the current flex container.
-  flexItems: [],
-  // The NodeFront actor ID  of the flex item to display the flex item sizing properties.
-  flexItemShown: null,
+  // The flex container of the selected element.
+  flexContainer: {
+    // The actor ID of the selected flex container.
+    actorID: "",
+    // An array of flex items belonging to the selected flex container.
+    flexItems: [],
+    // The NodeFront actor ID of the flex item to display in the flex item sizing
+    // properties.
+    flexItemShown: null,
+    // This flag specifies that the flex container data represents the selected flex
+    // container.
+    isFlexItemContainer: false,
+    // The NodeFront of the selected flex container.
+    nodeFront: null,
+    // The computed style properties of the selected flex container.
+    properties: null,
+  },
+  // The selected flex container can also be a flex item. This object contains the
+  // parent flex container properties of the selected element.
+  flexItemContainer: {
+    // The actor ID of the parent flex container.
+    actorID: "",
+    // An array of flex items belonging to the parent flex container.
+    flexItems: [],
+    // The NodeFront actor ID of the flex item to display in the flex item sizing
+    // properties.
+    flexItemShown: null,
+    // This flag specifies that the flex container data represents the parent flex
+    // container of the selected element.
+    isFlexItemContainer: true,
+    // The NodeFront of the parent flex container.
+    nodeFront: null,
+    // The computed styles properties of the parent flex container.
+    properties: null,
+  },
   // Whether or not the flexbox highlighter is highlighting the flex container.
   highlighted: false,
-  // The NodeFront of the flex container.
-  nodeFront: null,
-  // The computed style properties of the flex container.
-  properties: {},
 };
 
 const reducers = {
 
   [CLEAR_FLEXBOX](flexbox, _) {
     return INITIAL_FLEXBOX;
   },
 
-  [TOGGLE_FLEX_ITEM_SHOWN](flexbox, { nodeFront }) {
-    let flexItemShown = null;
-
-    // Get the NodeFront actor ID of the flex item.
-    if (nodeFront) {
-      const flexItem = flexbox.flexItems.find(item => item.nodeFront === nodeFront);
-      flexItemShown = flexItem.nodeFront.actorID;
-    }
-
-    return Object.assign({}, flexbox, {
-      flexItemShown,
-    });
-  },
-
   [UPDATE_FLEXBOX](_, { flexbox }) {
     return flexbox;
   },
 
   [UPDATE_FLEXBOX_COLOR](flexbox, { color }) {
-    return Object.assign({}, flexbox, {
+    return {
+      ...flexbox,
       color,
-    });
+    };
   },
 
   [UPDATE_FLEXBOX_HIGHLIGHTED](flexbox, { highlighted }) {
-    return Object.assign({}, flexbox, {
+    return {
+      ...flexbox,
       highlighted,
-    });
+    };
   },
 
 };
 
 module.exports = function(flexbox = INITIAL_FLEXBOX, action) {
   const reducer = reducers[action.type];
   if (!reducer) {
     return flexbox;
--- a/devtools/client/inspector/flexbox/types.js
+++ b/devtools/client/inspector/flexbox/types.js
@@ -103,32 +103,52 @@ const flexContainerProperties = exports.
   // The computed value of justify-content.
   "justify-content": PropTypes.string,
 
 };
 
 /**
  * A flex container data.
  */
-exports.flexbox = {
+const flexContainer = exports.flexContainer = {
 
   // The actor ID of the flex container.
   actorID: PropTypes.string,
 
-  // The color of the flexbox highlighter overlay.
-  color: PropTypes.string,
-
-  // Array of flex container's flex items.
+  // An array of flex items belonging to the flex container.
   flexItems: PropTypes.arrayOf(PropTypes.shape(flexItem)),
 
-  // The NodeFront actor ID of the flex item to display the flex item sizing properties.
-  flexItemShown: PropTypes.string,
+  // Whether or not the flex container data represents the selected flex container
+  // or the parent flex container. This is true if the flex container data represents
+  // the parent flex container.
+  isFlexItemContainer: PropTypes.bool,
 
-  // Whether or not the flexbox highlighter is highlighting the flex container.
-  highlighted: PropTypes.bool,
+  // The NodeFront actor ID of the flex item to display in the flex item sizing
+  // properties.
+  flexItemShown: PropTypes.string,
 
   // The NodeFront of the flex container.
   nodeFront: PropTypes.object,
 
   // The computed style properties of the flex container.
   properties: PropTypes.shape(flexContainerProperties),
 
 };
+
+/**
+ * The Flexbox UI state.
+ */
+exports.flexbox = {
+
+  // The color of the flexbox highlighter overlay.
+  color: PropTypes.string,
+
+  // The selected flex container.
+  flexContainer: PropTypes.shape(flexContainer),
+
+  // The selected flex container can also be a flex item. This object contains the
+  // parent flex container properties.
+  flexItemContainer: PropTypes.shape(flexContainer),
+
+  // Whether or not the flexbox highlighter is highlighting the flex container.
+  highlighted: PropTypes.bool,
+
+};
--- a/devtools/client/inspector/layout/components/LayoutApp.js
+++ b/devtools/client/inspector/layout/components/LayoutApp.js
@@ -46,44 +46,41 @@ class LayoutApp extends PureComponent {
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onSetGridOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelEditor: PropTypes.func.isRequired,
       onShowBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       onShowGridOutlineHighlight: PropTypes.func.isRequired,
       onToggleFlexboxHighlighter: PropTypes.func.isRequired,
-      onToggleFlexItemShown: PropTypes.func.isRequired,
       onToggleGeometryEditor: PropTypes.func.isRequired,
       onToggleGridHighlighter: PropTypes.func.isRequired,
       onToggleShowGridAreas: PropTypes.func.isRequired,
       onToggleShowGridLineNumbers: PropTypes.func.isRequired,
       onToggleShowInfiniteLines: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       showBoxModelProperties: PropTypes.bool.isRequired,
     };
   }
 
-  getFlexboxHeader() {
-    const { flexbox } = this.props;
-
-    if (!flexbox.actorID) {
+  getFlexboxHeader(flexContainer) {
+    if (!flexContainer.actorID) {
       // No flex container or flex item selected.
       return LAYOUT_L10N.getStr("flexbox.header");
-    } else if (!flexbox.flexItemShown) {
+    } else if (!flexContainer.flexItemShown) {
       // No flex item selected.
       return LAYOUT_L10N.getStr("flexbox.flexContainer");
     }
 
-    const grip = translateNodeFrontToGrip(flexbox.nodeFront);
+    const grip = translateNodeFrontToGrip(flexContainer.nodeFront);
     return LAYOUT_L10N.getFormatStr("flexbox.flexItemOf", getSelectorFromGrip(grip));
   }
 
   render() {
-    let items = [
+    const items = [
       {
         component: Grid,
         componentProps: this.props,
         header: LAYOUT_L10N.getStr("layout.header"),
         opened: Services.prefs.getBoolPref(GRID_OPENED_PREF),
         onToggled: () => {
           const opened = Services.prefs.getBoolPref(GRID_OPENED_PREF);
           Services.prefs.setBoolPref(GRID_OPENED_PREF, !opened);
@@ -97,29 +94,53 @@ class LayoutApp extends PureComponent {
         onToggled: () => {
           const opened = Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF);
           Services.prefs.setBoolPref(BOXMODEL_OPENED_PREF, !opened);
         }
       },
     ];
 
     if (Services.prefs.getBoolPref(FLEXBOX_ENABLED_PREF)) {
-      items = [
-        {
+      // Since the flexbox panel is hidden behind a pref. We insert the flexbox container
+      // to the first index of the accordion item list.
+      items.splice(0, 0, {
+        component: Flexbox,
+        componentProps: {
+          ...this.props,
+          flexContainer: this.props.flexbox.flexContainer,
+        },
+        header: this.getFlexboxHeader(this.props.flexbox.flexContainer),
+        opened: Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF),
+        onToggled: () => {
+          const opened =  Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF);
+          Services.prefs.setBoolPref(FLEXBOX_OPENED_PREF, !opened);
+        }
+      });
+
+      // If the current selected node is both a flex container and flex item. Render
+      // an accordion with another Flexbox component where the flexbox to show is the
+      // parent flex container of the current selected node.
+      if (this.props.flexbox.flexItemContainer &&
+          this.props.flexbox.flexItemContainer.actorID) {
+        // Insert the parent flex container to the second index of the accordion item
+        // list.
+        items.splice(1, 0, {
           component: Flexbox,
-          componentProps: this.props,
-          header: this.getFlexboxHeader(),
+          componentProps: {
+            ...this.props,
+            flexContainer: this.props.flexbox.flexItemContainer,
+          },
+          header: this.getFlexboxHeader(this.props.flexbox.flexItemContainer),
           opened: Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF),
           onToggled: () => {
             const opened =  Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF);
             Services.prefs.setBoolPref(FLEXBOX_OPENED_PREF, !opened);
           }
-        },
-        ...items
-      ];
+        });
+      }
     }
 
     return (
       dom.div({ id: "layout-container" },
         Accordion({ items })
       )
     );
   }
--- a/devtools/client/inspector/layout/layout.js
+++ b/devtools/client/inspector/layout/layout.js
@@ -42,17 +42,16 @@ class LayoutView {
       onShowBoxModelHighlighter,
       onToggleGeometryEditor,
     } = this.inspector.getPanel("boxmodel").getComponentProps();
 
     this.flexboxInspector = new FlexboxInspector(this.inspector, this.inspector.panelWin);
     const {
       onSetFlexboxOverlayColor,
       onToggleFlexboxHighlighter,
-      onToggleFlexItemShown,
     } = this.flexboxInspector.getComponentProps();
 
     this.gridInspector = new GridInspector(this.inspector, this.inspector.panelWin);
     const {
       onSetGridOverlayColor,
       onShowGridOutlineHighlight,
       onToggleGridHighlighter,
       onToggleShowGridAreas,
@@ -65,17 +64,16 @@ class LayoutView {
       onHideBoxModelHighlighter,
       onSetFlexboxOverlayColor,
       onSetGridOverlayColor,
       onShowBoxModelEditor,
       onShowBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       onShowGridOutlineHighlight,
       onToggleFlexboxHighlighter,
-      onToggleFlexItemShown,
       onToggleGeometryEditor,
       onToggleGridHighlighter,
       onToggleShowGridAreas,
       onToggleShowGridLineNumbers,
       onToggleShowInfiniteLines,
       setSelectedNode,
       /**
        * Shows the box model properties under the box model if true, otherwise, hidden by
--- a/devtools/server/actors/layout.js
+++ b/devtools/server/actors/layout.js
@@ -7,16 +7,17 @@
 const { Cu } = require("chrome");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const {
   flexboxSpec,
   flexItemSpec,
   gridSpec,
   layoutSpec,
 } = require("devtools/shared/specs/layout");
+const { ELEMENT_NODE } = require("devtools/shared/dom-node-constants");
 const { SHOW_ELEMENT } = require("devtools/shared/dom-node-filter-constants");
 const { getStringifiableFragments } =
   require("devtools/server/actors/utils/css-grid-utils");
 
 loader.lazyRequireGetter(this, "CssLogic", "devtools/server/actors/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants");
 
 /**
@@ -97,16 +98,20 @@ const FlexboxActor = ActorClassWithSpec(
     if (!flex) {
       return [];
     }
 
     const flexItemActors = [];
 
     for (const line of flex.getLines()) {
       for (const item of line.getItems()) {
+        if (item.node.nodeType !== ELEMENT_NODE) {
+          continue;
+        }
+
         flexItemActors.push(new FlexItemActor(this, item.node, {
           crossMaxSize: item.crossMaxSize,
           crossMinSize: item.crossMinSize,
           mainBaseSize: item.mainBaseSize,
           mainDeltaSize: item.mainDeltaSize,
           mainMaxSize: item.mainMaxSize,
           mainMinSize: item.mainMinSize,
         }));
@@ -147,38 +152,41 @@ const FlexItemActor = ActorClassWithSpec
     this.walker = null;
   },
 
   form(detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
-    const { flexDirection } = CssLogic.getComputedStyle(this.containerEl);
-    const styles = CssLogic.getComputedStyle(this.element);
-    const clientRect = this.element.getBoundingClientRect();
-    const dimension = flexDirection.startsWith("row") ? "width" : "height";
-
     const form = {
       actor: this.actorID,
       // The flex item sizing data.
       flexItemSizing: this.flexItemSizing,
+    };
+
+    if (this.element.nodeType === ELEMENT_NODE) {
+      const { flexDirection } = CssLogic.getComputedStyle(this.containerEl);
+      const styles = CssLogic.getComputedStyle(this.element);
+      const clientRect = this.element.getBoundingClientRect();
+      const dimension = flexDirection.startsWith("row") ? "width" : "height";
+
       // The computed style properties of the flex item.
-      properties: {
+      form.properties = {
         "flex-basis": styles.flexBasis,
         "flex-grow": styles.flexGrow,
         "flex-shrink": styles.flexShrink,
         // min-width/height computed style.
         [`min-${dimension}`]: styles[`min-${dimension}`],
         // max-width/height computed style.
         [`max-${dimension}`]: styles[`max-${dimension}`],
         // Computed width/height of the flex item element.
         [dimension]: parseFloat(clientRect[dimension.toLowerCase()].toPrecision(6)),
-      },
-    };
+      };
+    }
 
     // If the WalkerActor already knows the flex item element, then also return its
     // ActorID so we avoid the client from doing another round trip to get it in many
     // cases.
     if (this.walker.hasNode(this.element)) {
       form.nodeActorID = this.walker.getNode(this.element).actorID;
     }
 
@@ -256,25 +264,25 @@ const LayoutActor = ActorClassWithSpec(l
   destroy() {
     Actor.prototype.destroy.call(this);
 
     this.targetActor = null;
     this.walker = null;
   },
 
   /**
-   * Helper function for getCurrentGrid and getCurrentFlexbox. Returns the grid or
-   * flex container (whichever is requested) found by iterating on the given selected
-   * node. The current node can be a grid/flex container or grid/flex item. If it is a
-   * grid/flex item, returns the parent grid/flex container. Otherwise, returns null
-   * if the current or parent node is not a grid/flex container.
+   * Helper function for getAsFlexItem, getCurrentGrid and getCurrentFlexbox. Returns the
+   * grid or flex container (whichever is requested) found by iterating on the given
+   * selected node. The current node can be a grid/flex container or grid/flex item.
+   * If it is a grid/flex item, returns the parent grid/flex container. Otherwise, returns
+   * null if the current or parent node is not a grid/flex container.
    *
    * @param  {Node|NodeActor} node
    *         The node to start iterating at.
-   * @param {String} type
+   * @param  {String} type
    *         Can be "grid" or "flex", the display type we are searching for.
    * @return {GridActor|FlexboxActor|null} The GridActor or FlexboxActor of the
    * grid/flex container of the give node. Otherwise, returns null.
    */
   getCurrentDisplay(node, type) {
     if (isNodeDead(node)) {
       return null;
     }
@@ -295,17 +303,18 @@ const LayoutActor = ActorClassWithSpec(l
     if (type == "flex" &&
         (displayType == "inline-flex" || displayType == "flex")) {
       return new FlexboxActor(this, currentNode);
     } else if (type == "grid" &&
                (displayType == "inline-grid" || displayType == "grid")) {
       return new GridActor(this, currentNode);
     }
 
-    // Otherwise, check if this is a flex item or the parent node is a flex container.
+    // Otherwise, check if this is a flex/grid item or the parent node is a flex/grid
+    // container.
     while ((currentNode = treeWalker.parentNode())) {
       if (!currentNode) {
         break;
       }
 
       displayType = this.walker.getNode(currentNode).displayType;
 
       if (type == "flex" &&
@@ -328,35 +337,41 @@ const LayoutActor = ActorClassWithSpec(l
   /**
    * Returns the grid container found by iterating on the given selected node. The current
    * node can be a grid container or grid item. If it is a grid item, returns the parent
    * grid container. Otherwise, return null if the current or parent node is not a grid
    * container.
    *
    * @param  {Node|NodeActor} node
    *         The node to start iterating at.
-   * @return {GridActor|null} The GridActor of the grid container of the give node.
+   * @return {GridActor|null} The GridActor of the grid container of the given node.
    * Otherwise, returns null.
    */
   getCurrentGrid(node) {
     return this.getCurrentDisplay(node, "grid");
   },
 
   /**
    * Returns the flex container found by iterating on the given selected node. The current
    * node can be a flex container or flex item. If it is a flex item, returns the parent
    * flex container. Otherwise, return null if the current or parent node is not a flex
    * container.
    *
    * @param  {Node|NodeActor} node
    *         The node to start iterating at.
-   * @return {FlexboxActor|null} The FlexboxActor of the flex container of the give node.
+   * @param  {Boolean|null} onlyLookAtParents
+   *         Whether or not to only consider the parent node of the given node.
+   * @return {FlexboxActor|null} The FlexboxActor of the flex container of the given node.
    * Otherwise, returns null.
    */
-  getCurrentFlexbox(node) {
+  getCurrentFlexbox(node, onlyLookAtParents) {
+    if (onlyLookAtParents) {
+      node = node.rawNode.parentNode;
+    }
+
     return this.getCurrentDisplay(node, "flex");
   },
 
   /**
    * Returns an array of GridActor objects for all the grid elements contained in the
    * given root node.
    *
    * @param  {Node|NodeActor} node
--- a/devtools/shared/specs/layout.js
+++ b/devtools/shared/specs/layout.js
@@ -33,16 +33,17 @@ const gridSpec = generateActorSpec({
 
 const layoutSpec = generateActorSpec({
   typeName: "layout",
 
   methods: {
     getCurrentFlexbox: {
       request: {
         node: Arg(0, "domnode"),
+        onlyLookAtParents: Arg(1, "nullable:boolean"),
       },
       response: {
         flexbox: RetVal("nullable:flexbox")
       }
     },
 
     getCurrentGrid: {
       request: {
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -7515,16 +7515,20 @@ nsGlobalWindowInner::GetSidebar(OwningEx
 #else
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 #endif
 }
 
 void
 nsGlobalWindowInner::ClearDocumentDependentSlots(JSContext* aCx)
 {
+  if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(GetWrapperPreserveColor())) {
+    MOZ_CRASH("Looks like bug 1488480/1405521, with ClearDocumentDependentSlots in a bogus compartment");
+  }
+
   // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
   if (!Window_Binding::ClearCachedDocumentValue(aCx, this) ||
       !Window_Binding::ClearCachedPerformanceValue(aCx, this)) {
     MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
   }
 }
 
 /* static */
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -4181,16 +4181,20 @@ JS::Handle<JSObject*>
 GetPerInterfaceObjectHandle(JSContext* aCx,
                             size_t aSlotId,
                             CreateInterfaceObjectsMethod aCreator,
                             bool aDefineOnGlobal)
 {
   /* Make sure our global is sane.  Hopefully we can remove this sometime */
   JSObject* global = JS::CurrentGlobalOrNull(aCx);
   if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
+    if (aSlotId == prototypes::id::HTMLDocument ||
+        aSlotId == prototypes::id::Document) {
+      MOZ_CRASH("Looks like bug 1488480/1405521, with a non-DOM global in GetPerInterfaceObjectHandle");
+    }
     return nullptr;
   }
 
   /* Check to see whether the interface objects are already installed */
   ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
   if (!protoAndIfaceCache.HasEntryInSlot(aSlotId)) {
     JS::Rooted<JSObject*> rootedGlobal(aCx, global);
     aCreator(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
@@ -4205,16 +4209,24 @@ GetPerInterfaceObjectHandle(JSContext* a
    *
    * Calling address() avoids the read barrier that does gray unmarking, but
    * it's not possible for the object to be gray here.
    */
 
   const JS::Heap<JSObject*>& entrySlot =
     protoAndIfaceCache.EntrySlotMustExist(aSlotId);
   MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
+
+  if (!entrySlot) {
+    if (aSlotId == prototypes::id::HTMLDocument ||
+        aSlotId == prototypes::id::Document) {
+      MOZ_CRASH("Looks like bug 1488480/1405521, with aCreator failing to create the per-interface object");
+    }
+  }
+
   return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
 }
 
 namespace binding_detail {
 bool
 IsGetterEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
                 JSJitGetterOp aGetter,
                 const Prefable<const JSPropertySpec>* aAttributes)
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -65,17 +65,17 @@ FullscreenDeniedContainerNotAllowed=Request for fullscreen was denied because at least one of the document’s containing elements is not an iframe or does not have an “allowfullscreen” attribute.
 FullscreenDeniedNotInputDriven=Request for fullscreen was denied because Element.requestFullscreen() was not called from inside a short running user-generated event handler.
 FullscreenDeniedNotHTMLSVGOrMathML=Request for fullscreen was denied because requesting element is not <svg>, <math>, or an HTML element.
 FullscreenDeniedNotInDocument=Request for fullscreen was denied because requesting element is no longer in its document.
 FullscreenDeniedMovedDocument=Request for fullscreen was denied because requesting element has moved document.
 FullscreenDeniedLostWindow=Request for fullscreen was denied because we no longer have a window.
 FullscreenDeniedSubDocFullscreen=Request for fullscreen was denied because a subdocument of the document requesting fullscreen is already fullscreen.
 FullscreenDeniedNotDescendant=Request for fullscreen was denied because requesting element is not a descendant of the current fullscreen element.
 FullscreenDeniedNotFocusedTab=Request for fullscreen was denied because requesting element is not in the currently focused tab.
-FullscreenDeniedFeaturePolicy=Request for fullscreen was denied because of FeturePolicy directives.
+FullscreenDeniedFeaturePolicy=Request for fullscreen was denied because of FeaturePolicy directives.
 RemovedFullscreenElement=Exited fullscreen because fullscreen element was removed from document.
 FocusedWindowedPluginWhileFullscreen=Exited fullscreen because windowed plugin was focused.
 PointerLockDeniedDisabled=Request for pointer lock was denied because Pointer Lock API is disabled by user preference.
 PointerLockDeniedInUse=Request for pointer lock was denied because the pointer is currently controlled by a different document.
 PointerLockDeniedNotInDocument=Request for pointer lock was denied because the requesting element is not in a document.
 PointerLockDeniedSandboxed=Request for pointer lock was denied because Pointer Lock API is restricted via sandbox.
 PointerLockDeniedHidden=Request for pointer lock was denied because the document is not visible.
 PointerLockDeniedNotFocused=Request for pointer lock was denied because the document is not focused.
--- a/dom/media/systemservices/CamerasChild.h
+++ b/dom/media/systemservices/CamerasChild.h
@@ -9,17 +9,16 @@
 
 #include "mozilla/Move.h"
 #include "mozilla/Pair.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/camera/PCamerasChild.h"
 #include "mozilla/camera/PCamerasParent.h"
 #include "mozilla/media/DeviceChangeCallback.h"
 #include "mozilla/Mutex.h"
-#include "base/singleton.h"
 #include "nsCOMPtr.h"
 
 // conflicts with #include of scoped_ptr.h
 #undef FF
 #include "webrtc/modules/video_capture/video_capture_defines.h"
 
 namespace mozilla {
 
@@ -65,48 +64,51 @@ template <class T> class LockAndDispatch
 // async messaging. We dispatch the messages to another thread to send them
 // async and hold a Monitor to wait for the result to be asynchronously received
 // again. The requirement for async messaging originates on the parent side:
 // it's not reasonable to block all PBackground IPC there while waiting for
 // something like device enumeration to complete.
 
 class CamerasSingleton {
 public:
-  CamerasSingleton();
-  ~CamerasSingleton();
-
   static OffTheBooksMutex& Mutex() {
-    return Singleton<mozilla::camera::CamerasSingleton>::get()->mCamerasMutex;
+    return singleton().mCamerasMutex;
   }
 
   static CamerasChild*& Child() {
     Mutex().AssertCurrentThreadOwns();
-    return Singleton<mozilla::camera::CamerasSingleton>::get()->mCameras;
+    return singleton().mCameras;
   }
 
   static nsCOMPtr<nsIThread>& Thread() {
     Mutex().AssertCurrentThreadOwns();
-    return Singleton<mozilla::camera::CamerasSingleton>::get()->mCamerasChildThread;
+    return singleton().mCamerasChildThread;
   }
 
   static nsCOMPtr<nsIThread>& FakeDeviceChangeEventThread() {
     Mutex().AssertCurrentThreadOwns();
-    return Singleton<mozilla::camera::CamerasSingleton>::get()->mFakeDeviceChangeEventThread;
+    return singleton().mFakeDeviceChangeEventThread;
   }
 
   static bool InShutdown() {
-    return gTheInstance.get()->mInShutdown;
+    return singleton().mInShutdown;
   }
 
   static void StartShutdown() {
-    gTheInstance.get()->mInShutdown = true;
+    singleton().mInShutdown = true;
   }
 
 private:
-  static Singleton<CamerasSingleton> gTheInstance;
+  CamerasSingleton();
+  ~CamerasSingleton();
+
+  static CamerasSingleton& singleton() {
+    static CamerasSingleton camera;
+    return camera;
+  }
 
   // Reinitializing CamerasChild will change the pointers below.
   // We don't want this to happen in the middle of preparing IPC.
   // We will be alive on destruction, so this needs to be off the books.
   mozilla::OffTheBooksMutex mCamerasMutex;
 
   // This is owned by the IPC code, and the same code controls the lifetime.
   // It will set and clear this pointer as appropriate in setup/teardown.
deleted file mode 100644
--- a/ipc/chromium/atomics/moz.build
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-Library('chromium_atomics')
-
-# This test is copied from ../moz.build for atomicops_internals_mutex.cc
-if not CONFIG['INTEL_ARCHITECTURE'] and CONFIG['CPU_ARCH'] not in ('arm', 'aarch64', 'mips32', 'mips64', 'ppc', 'ppc64'):
-    SOURCES += [
-        '../src/base/atomicops_internals_mutex.cc',
-        '../src/base/lock_impl_posix.cc',
-    ]
--- a/ipc/chromium/moz.build
+++ b/ipc/chromium/moz.build
@@ -89,24 +89,22 @@ if os_macosx:
     SOURCES += [
         # This file cannot be built in unified mode because of the redefinition
         # of NoOp.
         'src/base/platform_thread_mac.mm',
     ]
 
 if os_bsd:
     SOURCES += [
-        'src/base/atomicops_internals_x86_gcc.cc',
         'src/base/process_util_linux.cc',
         'src/base/time_posix.cc',
     ]
 
 if os_linux:
     SOURCES += [
-        'src/base/atomicops_internals_x86_gcc.cc',
         'src/base/process_util_linux.cc',
         'src/base/time_posix.cc',
     ]
     if CONFIG['OS_TARGET'] == 'Android':
         UNIFIED_SOURCES += [
             'src/base/message_pump_android.cc',
         ]
         DEFINES['ANDROID'] = True
@@ -115,36 +113,26 @@ if os_linux:
 if os_bsd or os_linux:
     if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
         SOURCES += [
             'src/base/message_pump_glib.cc',
         ]
 
 if os_solaris:
     SOURCES += [
-        'src/base/atomicops_internals_x86_gcc.cc',
         'src/base/process_util_linux.cc',
         'src/base/time_posix.cc',
     ]
 
-if not CONFIG['INTEL_ARCHITECTURE'] and CONFIG['CPU_ARCH'] not in ('arm', 'aarch64', 'mips32', 'mips64', 'ppc', 'ppc64'):
-    SOURCES += [
-        'src/base/atomicops_internals_mutex.cc',
-    ]
-
 CXXFLAGS += CONFIG['TK_CFLAGS']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
-DIRS += [
-    'atomics',
-]
-
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
 
 # Add libFuzzer configuration directives
 include('/tools/fuzzing/libfuzzer-config.mozbuild')
 
 if CONFIG['CC_TYPE'] == 'clang-cl':
     AllowCompilerWarnings()  # workaround for bug 1090497
deleted file mode 100644
--- a/ipc/chromium/src/base/atomic_sequence_num.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
-#define BASE_ATOMIC_SEQUENCE_NUM_H_
-
-#include "base/atomicops.h"
-#include "base/basictypes.h"
-
-namespace base {
-
-class AtomicSequenceNumber;
-
-// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or
-// non-function scope) ONLY. This implementation does not generate any static
-// initializer.  Note that it does not implement any constructor which means
-// that its fields are not initialized except when it is stored in the global
-// data section (.data in ELF). If you want to allocate an atomic sequence
-// number on the stack (or heap), please use the AtomicSequenceNumber class
-// declared below.
-class StaticAtomicSequenceNumber {
- public:
-  inline int GetNext() {
-    return static_cast<int>(
-        base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
-  }
-
- private:
-  friend class AtomicSequenceNumber;
-
-  inline void Reset() {
-    base::subtle::Release_Store(&seq_, 0);
-  }
-
-  base::subtle::Atomic32 seq_;
-};
-
-// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are
-// always initialized as opposed to StaticAtomicSequenceNumber declared above).
-// Please use StaticAtomicSequenceNumber if you want to declare an atomic
-// sequence number in the global scope.
-class AtomicSequenceNumber {
- public:
-  AtomicSequenceNumber() {
-    seq_.Reset();
-  }
-
-  inline int GetNext() {
-    return seq_.GetNext();
-  }
-
- private:
-  StaticAtomicSequenceNumber seq_;
-  DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
-};
-
-}  // namespace base
-
-#endif  // BASE_ATOMIC_SEQUENCE_NUM_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// For atomic operations on reference counts, see atomic_refcount.h.
-// For atomic operations on sequence numbers, see atomic_sequence_num.h.
-
-// The routines exported by this module are subtle.  If you use them, even if
-// you get the code right, it will depend on careful reasoning about atomicity
-// and memory ordering; it will be less readable, and harder to maintain.  If
-// you plan to use these routines, you should have a good reason, such as solid
-// evidence that performance would otherwise suffer, or there being no
-// alternative.  You should assume only properties explicitly guaranteed by the
-// specifications in this file.  You are almost certainly _not_ writing code
-// just for the x86; if you assume x86 semantics, x86 hardware bugs and
-// implementations on other archtectures will cause your code to break.  If you
-// do not know what you are doing, avoid these routines, and use a Mutex.
-//
-// It is incorrect to make direct assignments to/from an atomic variable.
-// You should use one of the Load or Store routines.  The NoBarrier
-// versions are provided when no barriers are needed:
-//   NoBarrier_Store()
-//   NoBarrier_Load()
-// Although there are currently no compiler enforcement, you are encouraged
-// to use these.
-//
-
-#ifndef BASE_ATOMICOPS_H_
-#define BASE_ATOMICOPS_H_
-
-#include "base/basictypes.h"
-#include "base/port.h"
-
-namespace base {
-namespace subtle {
-
-// Bug 1308991.  We need this for /Wp64, to mark it safe for AtomicWord casting.
-#ifndef OS_WIN
-#define __w64
-#endif
-typedef __w64 int32_t Atomic32;
-#ifdef ARCH_CPU_64_BITS
-typedef int64_t Atomic64;
-#endif
-
-// Use AtomicWord for a machine-sized pointer.  It will use the Atomic32 or
-// Atomic64 routines below, depending on your architecture.
-#ifdef OS_OPENBSD
-#ifdef ARCH_CPU_64_BITS
-typedef Atomic64 AtomicWord;
-#else
-typedef Atomic32 AtomicWord;
-#endif // ARCH_CPU_64_BITS
-#else
-typedef intptr_t AtomicWord;
-#endif // OS_OPENBSD
-
-// Atomically execute:
-//      result = *ptr;
-//      if (*ptr == old_value)
-//        *ptr = new_value;
-//      return result;
-//
-// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
-// Always return the old value of "*ptr"
-//
-// This routine implies no memory barriers.
-Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                  Atomic32 old_value,
-                                  Atomic32 new_value);
-
-// Atomically store new_value into *ptr, returning the previous value held in
-// *ptr.  This routine implies no memory barriers.
-Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
-
-// Atomically increment *ptr by "increment".  Returns the new value of
-// *ptr with the increment applied.  This routine implies no memory barriers.
-Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
-
-Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                 Atomic32 increment);
-
-// These following lower-level operations are typically useful only to people
-// implementing higher-level synchronization operations like spinlocks,
-// mutexes, and condition-variables.  They combine CompareAndSwap(), a load, or
-// a store with appropriate memory-ordering instructions.  "Acquire" operations
-// ensure that no later memory access can be reordered ahead of the operation.
-// "Release" operations ensure that no previous memory access can be reordered
-// after the operation.  "Barrier" operations have both "Acquire" and "Release"
-// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
-// access.
-Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                Atomic32 old_value,
-                                Atomic32 new_value);
-Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                Atomic32 old_value,
-                                Atomic32 new_value);
-
-// On AArch64 Windows, MemoryBarrier is defined as:
-//
-// #define MemoryBarrier()             __dmb(_ARM_BARRIER_SY)
-//
-// which wreaks havoc with the declaration below.  Capture the definition
-// before undefining the macro.
-#if defined(_M_ARM64) && defined(MemoryBarrier)
-static inline void
-MemoryBarrierARM64()
-{
-  MemoryBarrier();
-}
-#undef MemoryBarrier
-#endif
-void MemoryBarrier();
-void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
-void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
-void Release_Store(volatile Atomic32* ptr, Atomic32 value);
-
-Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
-Atomic32 Acquire_Load(volatile const Atomic32* ptr);
-Atomic32 Release_Load(volatile const Atomic32* ptr);
-
-// 64-bit atomic operations (only available on 64-bit processors).
-#ifdef ARCH_CPU_64_BITS
-Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                  Atomic64 old_value,
-                                  Atomic64 new_value);
-Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
-Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
-Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
-
-Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                Atomic64 old_value,
-                                Atomic64 new_value);
-Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                Atomic64 old_value,
-                                Atomic64 new_value);
-void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
-void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
-void Release_Store(volatile Atomic64* ptr, Atomic64 value);
-Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
-Atomic64 Acquire_Load(volatile const Atomic64* ptr);
-Atomic64 Release_Load(volatile const Atomic64* ptr);
-#endif  // CPU_ARCH_64_BITS
-
-}  // namespace base::subtle
-}  // namespace base
-
-// Include our platform specific implementation.
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_FAMILY)
-#include "base/atomicops_internals_x86_msvc.h"
-#elif defined(OS_WIN) && defined(ARCH_CPU_ARM64)
-// Works just fine, separate case in case we need to change things.
-#include "base/atomicops_internals_x86_msvc.h"
-#elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY)
-#include "base/atomicops_internals_x86_macosx.h"
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
-#include "base/atomicops_internals_x86_gcc.h"
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
-#include "base/atomicops_internals_arm_gcc.h"
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
-#include "base/atomicops_internals_arm64_gcc.h"
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS)
-#include "base/atomicops_internals_mips_gcc.h"
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_PPC_FAMILY)
-#include "base/atomicops_internals_ppc_gcc.h"
-#else
-#include "base/atomicops_internals_mutex.h"
-#endif
-
-#endif  // BASE_ATOMICOPS_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_arm64_gcc.h
+++ /dev/null
@@ -1,362 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-
-// TODO(rmcilroy): Investigate whether we can use __sync__ intrinsics instead of
-//                 the hand coded assembly without introducing perf regressions.
-// TODO(rmcilroy): Investigate whether we can use acquire / release versions of
-//                 exclusive load / store assembly instructions and do away with
-//                 the barriers.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
-
-#if defined(OS_QNX)
-#include <sys/cpuinline.h>
-#endif
-
-namespace base {
-namespace subtle {
-
-inline void MemoryBarrier() {
-  __asm__ __volatile__ (  // NOLINT
-    "dmb ish                                  \n\t"  // Data memory barrier.
-    ::: "memory"
-  );  // NOLINT
-}
-
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %w[prev], %[ptr]                 \n\t"  // Load the previous value.
-    "cmp %w[prev], %w[old_value]           \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
-    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
-    "1:                                    \n\t"
-    "clrex                                 \n\t"  // In case we didn't swap.
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"r" (old_value),
-      [new_value]"r" (new_value)
-    : "memory", "cc"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %w[result], %[ptr]               \n\t"  // Load the previous value.
-    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
-    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [new_value]"r" (new_value)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                       \n\t"
-    "ldxr %w[result], %[ptr]                  \n\t"  // Load the previous value.
-    "add %w[result], %w[result], %w[increment]\n\t"
-    "stxr %w[temp], %w[result], %[ptr]        \n\t"  // Try to store the result.
-    "cbnz %w[temp], 0b                        \n\t"  // Retry on failure.
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [increment]"r" (increment)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  MemoryBarrier();
-  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-
-  return result;
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 prev;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %w[prev], %[ptr]                 \n\t"  // Load the previous value.
-    "cmp %w[prev], %w[old_value]           \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
-    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
-    "dmb ish                               \n\t"  // Data memory barrier.
-    "1:                                    \n\t"
-    // If the compare failed the 'dmb' is unnecessary, but we still need a
-    // 'clrex'.
-    "clrex                                 \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"r" (old_value),
-      [new_value]"r" (new_value)
-    : "memory", "cc"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 prev;
-  int32_t temp;
-
-  MemoryBarrier();
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %w[prev], %[ptr]                 \n\t"  // Load the previous value.
-    "cmp %w[prev], %w[old_value]           \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
-    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
-    "1:                                    \n\t"
-    // If the compare failed the we still need a 'clrex'.
-    "clrex                                 \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"r" (old_value),
-      [new_value]"r" (new_value)
-    : "memory", "cc"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-// 64-bit versions of the operations.
-// See the 32-bit versions for comments.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %[prev], %[ptr]                  \n\t"
-    "cmp %[prev], %[old_value]             \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
-    "cbnz %w[temp], 0b                     \n\t"
-    "1:                                    \n\t"
-    "clrex                                 \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"r" (old_value),
-      [new_value]"r" (new_value)
-    : "memory", "cc"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  Atomic64 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %[result], %[ptr]                \n\t"
-    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
-    "cbnz %w[temp], 0b                     \n\t"
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [new_value]"r" (new_value)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  Atomic64 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                     \n\t"
-    "ldxr %[result], %[ptr]                 \n\t"
-    "add %[result], %[result], %[increment] \n\t"
-    "stxr %w[temp], %[result], %[ptr]       \n\t"
-    "cbnz %w[temp], 0b                      \n\t"
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [increment]"r" (increment)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  MemoryBarrier();
-  Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-
-  return result;
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 prev;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %[prev], %[ptr]                  \n\t"
-    "cmp %[prev], %[old_value]             \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
-    "cbnz %w[temp], 0b                     \n\t"
-    "dmb ish                               \n\t"
-    "1:                                    \n\t"
-    "clrex                                 \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"r" (old_value),
-      [new_value]"r" (new_value)
-    : "memory", "cc"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 prev;
-  int32_t temp;
-
-  MemoryBarrier();
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %[prev], %[ptr]                  \n\t"
-    "cmp %[prev], %[old_value]             \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
-    "cbnz %w[temp], 0b                     \n\t"
-    "1:                                    \n\t"
-    "clrex                                 \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"r" (old_value),
-      [new_value]"r" (new_value)
-    : "memory", "cc"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-}  // namespace base::subtle
-}  // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_arm_gcc.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-//
-// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
-
-namespace base {
-namespace subtle {
-
-// 0xffff0fc0 is the hard coded address of a function provided by
-// the kernel which implements an atomic compare-exchange. On older
-// ARM architecture revisions (pre-v6) this may be implemented using
-// a syscall. This address is stable, and in active use (hard coded)
-// by at least glibc-2.7 and the Android C library.
-typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
-                                           Atomic32 new_value,
-                                           volatile Atomic32* ptr);
-LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
-    (LinuxKernelCmpxchgFunc) 0xffff0fc0;
-
-typedef void (*LinuxKernelMemoryBarrierFunc)(void);
-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
-    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
-
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev_value = *ptr;
-  do {
-    if (!pLinuxKernelCmpxchg(old_value, new_value,
-                             const_cast<Atomic32*>(ptr))) {
-      return old_value;
-    }
-    prev_value = *ptr;
-  } while (prev_value == old_value);
-  return prev_value;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 old_value;
-  do {
-    old_value = *ptr;
-  } while (pLinuxKernelCmpxchg(old_value, new_value,
-                               const_cast<Atomic32*>(ptr)));
-  return old_value;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  for (;;) {
-    // Atomic exchange the old value with an incremented one.
-    Atomic32 old_value = *ptr;
-    Atomic32 new_value = old_value + increment;
-    if (pLinuxKernelCmpxchg(old_value, new_value,
-                            const_cast<Atomic32*>(ptr)) == 0) {
-      // The exchange took place as expected.
-      return new_value;
-    }
-    // Otherwise, *ptr changed mid-loop and we need to retry.
-  }
-
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void MemoryBarrier() {
-  pLinuxKernelMemoryBarrier();
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-} // namespace base::subtle
-} // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_mips_gcc.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// 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.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// 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
-// OWNER 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.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-//
-// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
-
-#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
-#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
-
-namespace base {
-namespace subtle {
-
-// Atomically execute:
-//      result = *ptr;
-//      if (*ptr == old_value)
-//        *ptr = new_value;
-//      return result;
-//
-// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
-// Always return the old value of "*ptr"
-//
-// This routine implies no memory barriers.
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev, tmp;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "ll %0, %5\n"  // prev = *ptr
-                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
-                       "move %2, %4\n"  // tmp = new_value
-                       "sc %2, %1\n"  // *ptr = tmp (with atomic check)
-                       "beqz %2, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       "2:\n"
-                       ".set pop\n"
-                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
-                       : "r" (old_value), "r" (new_value), "m" (*ptr)
-                       : "memory");
-  return prev;
-}
-
-// Atomically store new_value into *ptr, returning the previous value held in
-// *ptr.  This routine implies no memory barriers.
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 temp, old;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "ll %1, %4\n"  // old = *ptr
-                       "move %0, %3\n"  // temp = new_value
-                       "sc %0, %2\n"  // *ptr = temp (with atomic check)
-                       "beqz %0, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
-                       : "r" (new_value), "m" (*ptr)
-                       : "memory");
-
-  return old;
-}
-
-// Atomically increment *ptr by "increment".  Returns the new value of
-// *ptr with the increment applied.  This routine implies no memory barriers.
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 temp, temp2;
-
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "ll %0, %4\n"  // temp = *ptr
-                       "addu %1, %0, %3\n"  // temp2 = temp + increment
-                       "sc %1, %2\n"  // *ptr = temp2 (with atomic check)
-                       "beqz %1, 1b\n"  // start again on atomic error
-                       "addu %1, %0, %3\n"  // temp2 = temp + increment
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
-                       : "Ir" (increment), "m" (*ptr)
-                       : "memory");
-  // temp2 now holds the final value.
-  return temp2;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  MemoryBarrier();
-  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-  return res;
-}
-
-// "Acquire" operations
-// ensure that no later memory access can be reordered ahead of the operation.
-// "Release" operations ensure that no previous memory access can be reordered
-// after the operation.  "Barrier" operations have both "Acquire" and "Release"
-// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
-// access.
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-  return res;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  MemoryBarrier();
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void MemoryBarrier() {
-  __asm__ __volatile__("sync" : : : "memory");
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#if defined(__LP64__)
-// 64-bit versions of the atomic ops.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev, tmp;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "lld %0, %5\n"  // prev = *ptr
-                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
-                       "move %2, %4\n"  // tmp = new_value
-                       "scd %2, %1\n"  // *ptr = tmp (with atomic check)
-                       "beqz %2, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       "2:\n"
-                       ".set pop\n"
-                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
-                       : "r" (old_value), "r" (new_value), "m" (*ptr)
-                       : "memory");
-  return prev;
-}
-
-// Atomically store new_value into *ptr, returning the previous value held in
-// *ptr.  This routine implies no memory barriers.
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  Atomic64 temp, old;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "lld %1, %4\n"  // old = *ptr
-                       "move %0, %3\n"  // temp = new_value
-                       "scd %0, %2\n"  // *ptr = temp (with atomic check)
-                       "beqz %0, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
-                       : "r" (new_value), "m" (*ptr)
-                       : "memory");
-
-  return old;
-}
-
-// Atomically increment *ptr by "increment".  Returns the new value of
-// *ptr with the increment applied.  This routine implies no memory barriers.
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  Atomic64 temp, temp2;
-
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "lld %0, %4\n"  // temp = *ptr
-                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
-                       "scd %1, %2\n"  // *ptr = temp2 (with atomic check)
-                       "beqz %1, 1b\n"  // start again on atomic error
-                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
-                       : "Ir" (increment), "m" (*ptr)
-                       : "memory");
-  // temp2 now holds the final value.
-  return temp2;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  MemoryBarrier();
-  Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-  return res;
-}
-
-// "Acquire" operations
-// ensure that no later memory access can be reordered ahead of the operation.
-// "Release" operations ensure that no previous memory access can be reordered
-// after the operation.  "Barrier" operations have both "Acquire" and "Release"
-// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
-// access.
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-  return res;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  MemoryBarrier();
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-#endif
-
-} // namespace base::subtle
-} // namespace base
-
-#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_mutex.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "base/atomicops.h"
-
-namespace base {
-namespace subtle {
-
-Lock gAtomicsMutex;
-
-}  // namespace subtle
-}  // namespace base
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_mutex.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This file is an internal atomic implementation, use
-// base/atomicops.h instead.
-//
-// This is a very slow fallback implementation of atomic operations
-// that uses a mutex instead of atomic instructions.
-//
-// (NB: a small "optimization" here would be using a spinlock instead
-// of a blocking mutex, but it's probably not worth the time.)
-
-#ifndef base_atomicops_internals_mutex_h
-#define base_atomicops_internals_mutex_h
-
-#include "base/lock.h"
-
-namespace base {
-namespace subtle {
-
-extern Lock gAtomicsMutex;
-
-template<typename T>
-T Locked_CAS(volatile T* ptr, T old_value, T new_value) {
-  AutoLock _(gAtomicsMutex);
-
-  T current_value = *ptr;
-  if (current_value == old_value)
-    *ptr = new_value;
-
-  return current_value;
-}
-
-template<typename T>
-T Locked_AtomicExchange(volatile T* ptr, T new_value) {
-  AutoLock _(gAtomicsMutex);
-
-  T current_value = *ptr;
-  *ptr = new_value;
-  return current_value;
-}
-
-template<typename T>
-T Locked_AtomicIncrement(volatile T* ptr, T increment) {
-  AutoLock _(gAtomicsMutex);
-  return *ptr += increment;
-}
-
-template<typename T>
-void Locked_Store(volatile T* ptr, T value) {
-  AutoLock _(gAtomicsMutex);
-  *ptr = value;
-}
-
-template<typename T>
-T Locked_Load(volatile const T* ptr) {
-  AutoLock _(gAtomicsMutex);
-  return *ptr;
-}
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  return Locked_AtomicExchange(ptr, new_value);
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  return Locked_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  return Locked_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  return Locked_Store(ptr, value);
-}
-
-inline void MemoryBarrier() {
-  AutoLock _(gAtomicsMutex);
-  // lock/unlock work as a barrier here
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  return Locked_Store(ptr, value);
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  return Locked_Store(ptr, value);
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return Locked_Load(ptr);
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  return NoBarrier_Load(ptr);
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  return Locked_Load(ptr);
-}
-
-#ifdef ARCH_CPU_64_BITS
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  return Locked_AtomicExchange(ptr, new_value);
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  return Locked_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  return Locked_AtomicIncrement(ptr, increment);
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  return Locked_Store(ptr, value);
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  return Locked_Store(ptr, value);
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  return Locked_Store(ptr, value);
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return Locked_Load(ptr);
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  return Locked_Load(ptr);
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  return Locked_Load(ptr);
-}
-
-#endif  // ARCH_CPU_64_BITS
-
-#ifdef OS_MACOSX
-// From atomicops_internals_x86_macosx.h:
-//
-//   MacOS uses long for intptr_t, AtomicWord and Atomic32 are always
-//   different on the Mac, even when they are the same size.  We need
-//   to explicitly cast from AtomicWord to Atomic32/64 to implement
-//   the AtomicWord interface.
-
-inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
-                                           AtomicWord old_value,
-                                           AtomicWord new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
-                                           AtomicWord new_value) {
-  return Locked_AtomicExchange(ptr, new_value);
-}
-
-inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
-                                            AtomicWord increment) {
-  return Locked_AtomicIncrement(ptr, increment);
-}
-
-inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
-                                          AtomicWord increment) {
-  return Locked_AtomicIncrement(ptr, increment);
-}
-
-inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
-                                         AtomicWord old_value,
-                                         AtomicWord new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
-                                         AtomicWord old_value,
-                                         AtomicWord new_value) {
-  return Locked_CAS(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
-  return Locked_Store(ptr, value);
-}
-
-inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
-  return Locked_Store(ptr, value);
-}
-
-inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
-  return Locked_Store(ptr, value);
-}
-
-inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
-  return Locked_Load(ptr);
-}
-
-inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
-  return Locked_Load(ptr);
-}
-
-inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
-  return Locked_Load(ptr);
-}
-
-#endif  // OS_MACOSX
-
-}  // namespace subtle
-}  // namespace base
-
-#endif  // base_atomicops_internals_mutex_h
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_ppc_gcc.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// This file is an internal atomic implementation, use atomicops.h instead.
-//
-#ifndef BASE_ATOMICOPS_INTERNALS_PPC_H_
-#define BASE_ATOMICOPS_INTERNALS_PPC_H_
-namespace base {
-namespace subtle {
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  return (__sync_val_compare_and_swap(ptr, old_value, new_value));
-}
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 old_value;
-  do {
-    old_value = *ptr;
-  } while (__sync_bool_compare_and_swap(ptr, old_value, new_value) == false);
-  return old_value;
-}
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  for (;;) {
-    Atomic32 old_value = *ptr;
-    Atomic32 new_value = old_value + increment;
-    if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
-      return new_value;
-      // The exchange took place as expected.
-    }
-    // Otherwise, *ptr changed mid-loop and we need to retry.
-  }
-}
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value, Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value, Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-inline void MemoryBarrier() {
-  __asm__ __volatile__("sync" : : : "memory"); }
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-#ifdef ARCH_CPU_PPC64
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  return (__sync_val_compare_and_swap(ptr, old_value, new_value));
-}
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  Atomic64 old_value;
-  do {
-    old_value = *ptr;
-  } while (__sync_bool_compare_and_swap(ptr, old_value, new_value) == false);
-  return old_value;
-}
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  for (;;) {
-    Atomic64 old_value = *ptr;
-    Atomic64 new_value = old_value + increment;
-    if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
-      return new_value;
-      // The exchange took place as expected.
-    }
-    // Otherwise, *ptr changed mid-loop and we need to retry.
-  }
-}
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value, Atomic64 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value, Atomic64 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { return *ptr; }
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-#endif
-}  // namespace base::subtle
-}  // namespace base
-#endif  // BASE_ATOMICOPS_INTERNALS_PPC_GCC_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_x86_gcc.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This module gets enough CPU information to optimize the
-// atomicops module on x86.
-
-#include <string.h>
-
-#include "base/atomicops.h"
-#include "base/basictypes.h"
-
-// This file only makes sense with atomicops_internals_x86_gcc.h -- it
-// depends on structs that are defined in that file.  If atomicops.h
-// doesn't sub-include that file, then we aren't needed, and shouldn't
-// try to do anything.
-#ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
-
-// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
-// of the global offset table.  To avoid breaking such executables, this code
-// must preserve that register's value across cpuid instructions.
-#if defined(__i386__)
-#define cpuid(a, b, c, d, inp) \
-  asm ("mov %%ebx, %%edi\n"    \
-       "cpuid\n"               \
-       "xchg %%edi, %%ebx\n"   \
-       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
-#elif defined (__x86_64__)
-#define cpuid(a, b, c, d, inp) \
-  asm ("mov %%rbx, %%rdi\n"    \
-       "cpuid\n"               \
-       "xchg %%rdi, %%rbx\n"   \
-       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
-#endif
-
-#if defined(cpuid)        // initialize the struct only on x86
-
-// Set the flags so that code will run correctly and conservatively, so even
-// if we haven't been initialized yet, we're probably single threaded, and our
-// default values should hopefully be pretty safe.
-struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
-  false,          // bug can't exist before process spawns multiple threads
-  false,          // no SSE2
-};
-
-// Initialize the AtomicOps_Internalx86CPUFeatures struct.
-static void AtomicOps_Internalx86CPUFeaturesInit() {
-  uint32_t eax;
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-
-  // Get vendor string (issue CPUID with eax = 0)
-  cpuid(eax, ebx, ecx, edx, 0);
-  char vendor[13];
-  memcpy(vendor, &ebx, 4);
-  memcpy(vendor + 4, &edx, 4);
-  memcpy(vendor + 8, &ecx, 4);
-  vendor[12] = 0;
-
-  // get feature flags in ecx/edx, and family/model in eax
-  cpuid(eax, ebx, ecx, edx, 1);
-
-  int family = (eax >> 8) & 0xf;        // family and model fields
-  int model = (eax >> 4) & 0xf;
-  if (family == 0xf) {                  // use extended family and model fields
-    family += (eax >> 20) & 0xff;
-    model += ((eax >> 16) & 0xf) << 4;
-  }
-
-  // Opteron Rev E has a bug in which on very rare occasions a locked
-  // instruction doesn't act as a read-acquire barrier if followed by a
-  // non-locked read-modify-write instruction.  Rev F has this bug in
-  // pre-release versions, but not in versions released to customers,
-  // so we test only for Rev E, which is family 15, model 32..63 inclusive.
-  if (strcmp(vendor, "AuthenticAMD") == 0 &&       // AMD
-      family == 15 &&
-      32 <= model && model <= 63) {
-    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
-  } else {
-    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
-  }
-
-  // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
-  AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
-}
-
-namespace {
-
-class AtomicOpsx86Initializer {
- public:
-  AtomicOpsx86Initializer() {
-    AtomicOps_Internalx86CPUFeaturesInit();
-  }
-};
-
-// A global to get use initialized on startup via static initialization :/
-AtomicOpsx86Initializer g_initer;
-
-}  // namespace
-
-#endif  // if x86
-
-#endif  // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_x86_gcc.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
-
-// This struct is not part of the public API of this module; clients may not
-// use it.
-// Features of this x86.  Values may not be correct before main() is run,
-// but are set conservatively.
-struct AtomicOps_x86CPUFeatureStruct {
-  bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
-                            // after acquire compare-and-swap.
-  bool has_sse2;            // Processor has SSE2.
-};
-extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
-
-#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
-
-namespace base {
-namespace subtle {
-
-// 32-bit low-level operations on any platform.
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev;
-  __asm__ __volatile__("lock; cmpxchgl %1,%2"
-                       : "=a" (prev)
-                       : "q" (new_value), "m" (*ptr), "0" (old_value)
-                       : "memory");
-  return prev;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
-                       : "=r" (new_value)
-                       : "m" (*ptr), "0" (new_value)
-                       : "memory");
-  return new_value;  // Now it's the previous value.
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 temp = increment;
-  __asm__ __volatile__("lock; xaddl %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now holds the old value of *ptr
-  return temp + increment;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  Atomic32 temp = increment;
-  __asm__ __volatile__("lock; xaddl %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now holds the old value of *ptr
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return temp + increment;
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return x;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-#if defined(__x86_64__)
-
-// 64-bit implementations of memory barrier can be simpler, because it
-// "mfence" is guaranteed to exist.
-inline void MemoryBarrier() {
-  __asm__ __volatile__("mfence" : : : "memory");
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-#else
-
-inline void MemoryBarrier() {
-  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
-    __asm__ __volatile__("mfence" : : : "memory");
-  } else { // mfence is faster but not present on PIII
-    Atomic32 x = 0;
-    NoBarrier_AtomicExchange(&x, 0);  // acts as a barrier on PIII
-  }
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
-    *ptr = value;
-    __asm__ __volatile__("mfence" : : : "memory");
-  } else {
-    NoBarrier_AtomicExchange(ptr, value);
-                          // acts as a barrier on PIII
-  }
-}
-#endif
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  ATOMICOPS_COMPILER_BARRIER();
-  *ptr = value; // An x86 store acts as a release barrier.
-  // See comments in Atomic64 version of Release_Store(), below.
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
-  // See comments in Atomic64 version of Release_Store(), below.
-  ATOMICOPS_COMPILER_BARRIER();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#if defined(__x86_64__)
-
-// 64-bit low-level operations on 64-bit platform.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev;
-  __asm__ __volatile__("lock; cmpxchgq %1,%2"
-                       : "=a" (prev)
-                       : "q" (new_value), "m" (*ptr), "0" (old_value)
-                       : "memory");
-  return prev;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
-                       : "=r" (new_value)
-                       : "m" (*ptr), "0" (new_value)
-                       : "memory");
-  return new_value;  // Now it's the previous value.
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  Atomic64 temp = increment;
-  __asm__ __volatile__("lock; xaddq %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now contains the previous value of *ptr
-  return temp + increment;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  Atomic64 temp = increment;
-  __asm__ __volatile__("lock; xaddq %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now contains the previous value of *ptr
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return temp + increment;
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  /* XXX/cjones: no idea if this is necessary... */
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return x;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  ATOMICOPS_COMPILER_BARRIER();
-
-  *ptr = value; // An x86 store acts as a release barrier
-                // for current AMD/Intel chips as of Jan 2008.
-                // See also Acquire_Load(), below.
-
-  // When new chips come out, check:
-  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
-  //  System Programming Guide, Chatper 7: Multiple-processor management,
-  //  Section 7.2, Memory Ordering.
-  // Last seen at:
-  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
-  //
-  // x86 stores/loads fail to act as barriers for a few instructions (clflush
-  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
-  // not generated by the compiler, and are rare.  Users of these instructions
-  // need to know about cache behaviour in any case since all of these involve
-  // either flushing cache lines or non-temporal cache hints.
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
-                         // for current AMD/Intel chips as of Jan 2008.
-                         // See also Release_Store(), above.
-  ATOMICOPS_COMPILER_BARRIER();
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-#endif  // defined(__x86_64__)
-
-} // namespace base::subtle
-} // namespace base
-
-#undef ATOMICOPS_COMPILER_BARRIER
-
-#endif  // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_x86_macosx.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
-#define BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
-
-#include <libkern/OSAtomic.h>
-
-namespace base {
-namespace subtle {
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev_value;
-  do {
-    if (OSAtomicCompareAndSwap32(old_value, new_value,
-                                 const_cast<Atomic32*>(ptr))) {
-      return old_value;
-    }
-    prev_value = *ptr;
-  } while (prev_value == old_value);
-  return prev_value;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
-                                         Atomic32 new_value) {
-  Atomic32 old_value;
-  do {
-    old_value = *ptr;
-  } while (!OSAtomicCompareAndSwap32(old_value, new_value,
-                                     const_cast<Atomic32*>(ptr)));
-  return old_value;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
-                                          Atomic32 increment) {
-  return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
-                                          Atomic32 increment) {
-  return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
-}
-
-inline void MemoryBarrier() {
-  OSMemoryBarrier();
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 prev_value;
-  do {
-    if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
-                                        const_cast<Atomic32*>(ptr))) {
-      return old_value;
-    }
-    prev_value = *ptr;
-  } while (prev_value == old_value);
-  return prev_value;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return Acquire_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#ifdef __LP64__
-
-// 64-bit implementation on 64-bit platform
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev_value;
-  do {
-    if (OSAtomicCompareAndSwap64(old_value, new_value,
-                                 const_cast<Atomic64*>(ptr))) {
-      return old_value;
-    }
-    prev_value = *ptr;
-  } while (prev_value == old_value);
-  return prev_value;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
-                                         Atomic64 new_value) {
-  Atomic64 old_value;
-  do {
-    old_value = *ptr;
-  } while (!OSAtomicCompareAndSwap64(old_value, new_value,
-                                     const_cast<Atomic64*>(ptr)));
-  return old_value;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
-                                          Atomic64 increment) {
-  return OSAtomicAdd64(increment, const_cast<Atomic64*>(ptr));
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
-                                        Atomic64 increment) {
-  return OSAtomicAdd64Barrier(increment, const_cast<Atomic64*>(ptr));
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 prev_value;
-  do {
-    if (OSAtomicCompareAndSwap64Barrier(old_value, new_value,
-                                        const_cast<Atomic64*>(ptr))) {
-      return old_value;
-    }
-    prev_value = *ptr;
-  } while (prev_value == old_value);
-  return prev_value;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  // The lib kern interface does not distinguish between
-  // Acquire and Release memory barriers; they are equivalent.
-  return Acquire_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
-  Atomic64 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#endif  // defined(__LP64__)
-
-// MacOS uses long for intptr_t, AtomicWord and Atomic32 are always different
-// on the Mac, even when they are the same size.  We need to explicitly cast
-// from AtomicWord to Atomic32/64 to implement the AtomicWord interface.
-#ifdef __LP64__
-#define AtomicWordCastType Atomic64
-#else
-#define AtomicWordCastType Atomic32
-#endif
-
-inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
-                                           AtomicWord old_value,
-                                           AtomicWord new_value) {
-  return NoBarrier_CompareAndSwap(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr),
-      old_value, new_value);
-}
-
-inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
-                                           AtomicWord new_value) {
-  return NoBarrier_AtomicExchange(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr), new_value);
-}
-
-inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
-                                            AtomicWord increment) {
-  return NoBarrier_AtomicIncrement(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr), increment);
-}
-
-inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
-                                          AtomicWord increment) {
-  return Barrier_AtomicIncrement(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr), increment);
-}
-
-inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
-                                         AtomicWord old_value,
-                                         AtomicWord new_value) {
-  return base::subtle::Acquire_CompareAndSwap(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr),
-      old_value, new_value);
-}
-
-inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
-                                         AtomicWord old_value,
-                                         AtomicWord new_value) {
-  return base::subtle::Release_CompareAndSwap(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr),
-      old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
-  NoBarrier_Store(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
-}
-
-inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
-  return base::subtle::Acquire_Store(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
-}
-
-inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
-  return base::subtle::Release_Store(
-      reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
-}
-
-inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
-  return NoBarrier_Load(
-      reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
-}
-
-inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
-  return base::subtle::Acquire_Load(
-      reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
-}
-
-inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
-  return base::subtle::Release_Load(
-      reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
-}
-
-#undef AtomicWordCastType
-
-}   // namespace base::subtle
-}   // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/atomicops_internals_x86_msvc.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
-#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
-
-#include <windows.h>
-
-namespace base {
-namespace subtle {
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  LONG result = InterlockedCompareExchange(
-      reinterpret_cast<volatile LONG*>(ptr),
-      static_cast<LONG>(new_value),
-      static_cast<LONG>(old_value));
-  return static_cast<Atomic32>(result);
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  LONG result = InterlockedExchange(
-      reinterpret_cast<volatile LONG*>(ptr),
-      static_cast<LONG>(new_value));
-  return static_cast<Atomic32>(result);
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  return InterlockedExchangeAdd(
-      reinterpret_cast<volatile LONG*>(ptr),
-      static_cast<LONG>(increment)) + increment;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-
-inline void MemoryBarrier() {
-  // We use MemoryBarrier from WinNT.h, except for AArch64.
-  // See the comment in atomicops.h.
-#if defined(_M_ARM64)
-  MemoryBarrierARM64();
-#else
-  ::MemoryBarrier();
-#endif
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  NoBarrier_AtomicExchange(ptr, value);
-              // acts as a barrier in this implementation
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
-  // See comments in Atomic64 version of Release_Store() below.
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#if defined(_WIN64)
-
-// 64-bit low-level operations on 64-bit platform.
-
-COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  PVOID result = InterlockedCompareExchangePointer(
-    reinterpret_cast<volatile PVOID*>(ptr),
-    reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
-  return reinterpret_cast<Atomic64>(result);
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  PVOID result = InterlockedExchangePointer(
-    reinterpret_cast<volatile PVOID*>(ptr),
-    reinterpret_cast<PVOID>(new_value));
-  return reinterpret_cast<Atomic64>(result);
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  return InterlockedExchangeAdd64(
-      reinterpret_cast<volatile LONGLONG*>(ptr),
-      static_cast<LONGLONG>(increment)) + increment;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  NoBarrier_AtomicExchange(ptr, value);
-              // acts as a barrier in this implementation
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
-
-  // When new chips come out, check:
-  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
-  //  System Programming Guide, Chatper 7: Multiple-processor management,
-  //  Section 7.2, Memory Ordering.
-  // Last seen at:
-  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr;
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#endif  // defined(_WIN64)
-
-}  // namespace base::subtle
-}  // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
--- a/ipc/chromium/src/base/command_line.cc
+++ b/ipc/chromium/src/base/command_line.cc
@@ -9,17 +9,16 @@
 #if defined(OS_WIN)
 #include <windows.h>
 #include <shellapi.h>
 #endif
 
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/singleton.h"
 #include "base/string_piece.h"
 #include "base/string_util.h"
 #include "base/sys_string_conversions.h"
 
 CommandLine* CommandLine::current_process_commandline_ = NULL;
 
 // Since we use a lazy match, make sure that longer versions (like L"--")
 // are listed before shorter versions (like L"-") of similar prefixes.
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -534,113 +534,113 @@ void Pickle::EndWrite(uint32_t length) {
       kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
     };
     buffers_.WriteBytes(padding_data, padding);
   }
 }
 
 bool Pickle::WriteBool(bool value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzBool(&value);
+  mozilla::ipc::Faulty::instance().FuzzBool(&value);
 #endif
   return WriteInt(value ? 1 : 0);
 }
 
 bool Pickle::WriteInt16(int16_t value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzInt16(&value);
+  mozilla::ipc::Faulty::instance().FuzzInt16(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteUInt16(uint16_t value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt16(&value);
+  mozilla::ipc::Faulty::instance().FuzzUInt16(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteInt(int value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
+  mozilla::ipc::Faulty::instance().FuzzInt(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteLong(long value) {
   // Always written as a 64-bit value since the size for this type can
   // differ between architectures.
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzLong(&value);
+  mozilla::ipc::Faulty::instance().FuzzLong(&value);
 #endif
   return WriteInt64(int64_t(value));
 }
 
 bool Pickle::WriteULong(unsigned long value) {
   // Always written as a 64-bit value since the size for this type can
   // differ between architectures.
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzULong(&value);
+  mozilla::ipc::Faulty::instance().FuzzULong(&value);
 #endif
   return WriteUInt64(uint64_t(value));
 }
 
 bool Pickle::WriteSize(size_t value) {
   // Always written as a 64-bit value since the size for this type can
   // differ between architectures.
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzSize(&value);
+  mozilla::ipc::Faulty::instance().FuzzSize(&value);
 #endif
   return WriteUInt64(uint64_t(value));
 }
 
 bool Pickle::WriteInt32(int32_t value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
+  mozilla::ipc::Faulty::instance().FuzzInt(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteUInt32(uint32_t value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt32(&value);
+  mozilla::ipc::Faulty::instance().FuzzUInt32(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteInt64(int64_t value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzInt64(&value);
+  mozilla::ipc::Faulty::instance().FuzzInt64(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteUInt64(uint64_t value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt64(&value);
+  mozilla::ipc::Faulty::instance().FuzzUInt64(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteDouble(double value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzDouble(&value);
+  mozilla::ipc::Faulty::instance().FuzzDouble(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteIntPtr(intptr_t value) {
   // Always written as a 64-bit value since the size for this type can
   // differ between architectures.
   return WriteInt64(int64_t(value));
 }
 
 bool Pickle::WriteUnsignedChar(unsigned char value) {
 #ifdef FUZZING
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzUChar(&value);
+  mozilla::ipc::Faulty::instance().FuzzUChar(&value);
 #endif
   return WriteBytes(&value, sizeof(value));
 }
 
 bool Pickle::WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity) {
 
   BeginWrite(data_len, sizeof(memberAlignmentType));
 
@@ -660,33 +660,33 @@ bool Pickle::WriteBytes(const void* data
 
   EndWrite(data_len);
   return true;
 }
 
 bool Pickle::WriteString(const std::string& value) {
 #ifdef FUZZING
   std::string v(value);
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzString(v);
+  mozilla::ipc::Faulty::instance().FuzzString(v);
   if (!WriteInt(static_cast<int>(v.size())))
     return false;
 
   return WriteBytes(v.data(), static_cast<int>(v.size()));
 #else
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(), static_cast<int>(value.size()));
 #endif
 }
 
 bool Pickle::WriteWString(const std::wstring& value) {
 #ifdef FUZZING
   std::wstring v(value);
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzWString(v);
+  mozilla::ipc::Faulty::instance().FuzzWString(v);
   if (!WriteInt(static_cast<int>(v.size())))
     return false;
 
   return WriteBytes(v.data(),
                     static_cast<int>(v.size() * sizeof(wchar_t)));
 #else
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -13,17 +13,16 @@
 #include "base/logging.h"
 #include "base/string16.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/BufferList.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/TimeStamp.h"
 #ifdef FUZZING
-#include "base/singleton.h"
 #include "mozilla/ipc/Faulty.h"
 #endif
 #if !defined(FUZZING) && (!defined(RELEASE_OR_BETA) || defined(DEBUG))
 #define MOZ_PICKLE_SENTINEL_CHECKING
 #endif
 class Pickle;
 class PickleIterator {
 public:
deleted file mode 100644
--- a/ipc/chromium/src/base/singleton.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_SINGLETON_H_
-#define BASE_SINGLETON_H_
-
-#include "base/at_exit.h"
-#include "base/atomicops.h"
-#include "base/platform_thread.h"
-
-// Default traits for Singleton<Type>. Calls operator new and operator delete on
-// the object. Registers automatic deletion at process exit.
-// Overload if you need arguments or another memory allocation function.
-template<typename Type>
-struct DefaultSingletonTraits {
-  // Allocates the object.
-  static Type* New() {
-    // The parenthesis is very important here; it forces POD type
-    // initialization.
-    return new Type();
-  }
-
-  // Destroys the object.
-  static void Delete(Type* x) {
-    delete x;
-  }
-
-  // Set to true to automatically register deletion of the object on process
-  // exit. See below for the required call that makes this happen.
-  static const bool kRegisterAtExit = true;
-};
-
-
-// Alternate traits for use with the Singleton<Type>.  Identical to
-// DefaultSingletonTraits except that the Singleton will not be cleaned up
-// at exit.
-template<typename Type>
-struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
-  static const bool kRegisterAtExit = false;
-};
-
-
-// The Singleton<Type, Traits, DifferentiatingType> class manages a single
-// instance of Type which will be created on first use and will be destroyed at
-// normal process exit). The Trait::Delete function will not be called on
-// abnormal process exit.
-//
-// DifferentiatingType is used as a key to differentiate two different
-// singletons having the same memory allocation functions but serving a
-// different purpose. This is mainly used for Locks serving different purposes.
-//
-// Example usages: (none are preferred, they all result in the same code)
-//   1. FooClass* ptr = Singleton<FooClass>::get();
-//      ptr->Bar();
-//   2. Singleton<FooClass>()->Bar();
-//   3. Singleton<FooClass>::get()->Bar();
-//
-// Singleton<> has no non-static members and doesn't need to actually be
-// instantiated. It does no harm to instantiate it and use it as a class member
-// or at global level since it is acting as a POD type.
-//
-// This class is itself thread-safe. The underlying Type must of course be
-// thread-safe if you want to use it concurrently. Two parameters may be tuned
-// depending on the user's requirements.
-//
-// Glossary:
-//   RAE = kRegisterAtExit
-//
-// On every platform, if Traits::RAE is true, the singleton will be destroyed at
-// process exit. More precisely it uses base::AtExitManager which requires an
-// object of this type to be instanciated. AtExitManager mimics the semantics
-// of atexit() such as LIFO order but under Windows is safer to call. For more
-// information see at_exit.h.
-//
-// If Traits::RAE is false, the singleton will not be freed at process exit,
-// thus the singleton will be leaked if it is ever accessed. Traits::RAE
-// shouldn't be false unless absolutely necessary. Remember that the heap where
-// the object is allocated may be destroyed by the CRT anyway.
-//
-// If you want to ensure that your class can only exist as a singleton, make
-// its constructors private, and make DefaultSingletonTraits<> a friend:
-//
-//   #include "base/singleton.h"
-//   class FooClass {
-//    public:
-//     void Bar() { ... }
-//    private:
-//     FooClass() { ... }
-//     friend struct DefaultSingletonTraits<FooClass>;
-//
-//     DISALLOW_EVIL_CONSTRUCTORS(FooClass);
-//   };
-//
-// Caveats:
-// (a) Every call to get(), operator->() and operator*() incurs some overhead
-//     (16ns on my P4/2.8GHz) to check whether the object has already been
-//     initialized.  You may wish to cache the result of get(); it will not
-//     change.
-//
-// (b) Your factory function must never throw an exception. This class is not
-//     exception-safe.
-//
-template <typename Type,
-          typename Traits = DefaultSingletonTraits<Type>,
-          typename DifferentiatingType = Type>
-class Singleton {
- public:
-  // This class is safe to be constructed and copy-constructed since it has no
-  // member.
-
-  // Return a pointer to the one true instance of the class.
-  static Type* get() {
-    // Our AtomicWord doubles as a spinlock, where a value of
-    // kBeingCreatedMarker means the spinlock is being held for creation.
-    static const base::subtle::AtomicWord kBeingCreatedMarker = 1;
-
-    base::subtle::AtomicWord value = base::subtle::NoBarrier_Load(&instance_);
-    if (value != 0 && value != kBeingCreatedMarker)
-      return reinterpret_cast<Type*>(value);
-
-    // Object isn't created yet, maybe we will get to create it, let's try...
-    if (base::subtle::Acquire_CompareAndSwap(&instance_,
-                                             0,
-                                             kBeingCreatedMarker) == 0) {
-      // instance_ was NULL and is now kBeingCreatedMarker.  Only one thread
-      // will ever get here.  Threads might be spinning on us, and they will
-      // stop right after we do this store.
-      Type* newval = Traits::New();
-      base::subtle::Release_Store(
-          &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
-
-      if (Traits::kRegisterAtExit)
-        base::AtExitManager::RegisterCallback(OnExit, NULL);
-
-      return newval;
-    }
-
-    // We hit a race.  Another thread beat us and either:
-    // - Has the object in BeingCreated state
-    // - Already has the object created...
-    // We know value != NULL.  It could be kBeingCreatedMarker, or a valid ptr.
-    // Unless your constructor can be very time consuming, it is very unlikely
-    // to hit this race.  When it does, we just spin and yield the thread until
-    // the object has been created.
-    while (true) {
-      value = base::subtle::NoBarrier_Load(&instance_);
-      if (value != kBeingCreatedMarker)
-        break;
-      PlatformThread::YieldCurrentThread();
-    }
-
-    return reinterpret_cast<Type*>(value);
-  }
-
-  // Shortcuts.
-  Type& operator*() {
-    return *get();
-  }
-
-  Type* operator->() {
-    return get();
-  }
-
- private:
-  // Adapter function for use with AtExit().  This should be called single
-  // threaded, but we might as well take the precautions anyway.
-  static void OnExit(void* unused) {
-    // AtExit should only ever be register after the singleton instance was
-    // created.  We should only ever get here with a valid instance_ pointer.
-    Traits::Delete(reinterpret_cast<Type*>(
-        base::subtle::NoBarrier_AtomicExchange(&instance_, 0)));
-  }
-  static base::subtle::AtomicWord instance_;
-};
-
-template <typename Type, typename Traits, typename DifferentiatingType>
-base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
-    instance_ = 0;
-
-#endif  // BASE_SINGLETON_H_
deleted file mode 100644
--- a/ipc/chromium/src/base/singleton_objc.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-// Copyright (c) 2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Support for using the Singleton<T> pattern with Objective-C objects.  A
-// SingletonObjC is the same as a Singleton, except the default traits are
-// appropriate for Objective-C objects.  A typical Objective-C object of type
-// NSExampleType can be maintained as a singleton and accessed with:
-//
-//   NSExampleType* exampleSingleton = SingletonObjC<NSExampleType>::get();
-//
-// The first time this is used, it will create exampleSingleton as the result
-// of [[NSExampleType alloc] init].  Subsequent calls will return the same
-// NSExampleType* object.  The object will be released by calling
-// -[NSExampleType release] when Singleton's atexit routines run
-// (see singleton.h).
-//
-// For Objective-C objects initialized through means other than the
-// no-parameter -init selector, DefaultSingletonObjCTraits may be extended
-// as needed:
-//
-//   struct FooSingletonTraits : public DefaultSingletonObjCTraits<Foo> {
-//     static Foo* New() {
-//       return [[Foo alloc] initWithName:@"selecty"];
-//     }
-//   }
-//   ...
-//   Foo* widgetSingleton = SingletonObjC<Foo, FooSingletonTraits>::get();
-
-#ifndef BASE_SINGLETON_OBJC_H_
-#define BASE_SINGLETON_OBJC_H_
-
-#import <Foundation/Foundation.h>
-#include "base/singleton.h"
-
-// Singleton traits usable to manage traditional Objective-C objects, which
-// are instantiated by sending |alloc| and |init| messages, and are deallocated
-// in a memory-managed environment when their retain counts drop to 0 by
-// sending |release| messages.
-template<typename Type>
-struct DefaultSingletonObjCTraits : public DefaultSingletonTraits<Type> {
-  static Type* New() {
-    return [[Type alloc] init];
-  }
-
-  static void Delete(Type* object) {
-    [object release];
-  }
-};
-
-// Exactly like Singleton, but without the DefaultSingletonObjCTraits as the
-// default trait class.  This makes it straightforward for Objective-C++ code
-// to hold Objective-C objects as singletons.
-template<typename Type,
-         typename Traits = DefaultSingletonObjCTraits<Type>,
-         typename DifferentiatingType = Type>
-class SingletonObjC : public Singleton<Type, Traits, DifferentiatingType> {
-};
-
-#endif  // BASE_SINGLETON_OBJC_H_
--- a/ipc/chromium/src/base/string_util.cc
+++ b/ipc/chromium/src/base/string_util.cc
@@ -19,17 +19,16 @@
 #include <wchar.h>
 #include <wctype.h>
 
 #include <algorithm>
 #include <vector>
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/singleton.h"
 
 namespace {
 
 // Hack to convert any char-like type to its unsigned counterpart.
 // For example, it will convert char, signed char and unsigned char to unsigned
 // char.
 template<typename T>
 struct ToUnsigned {
--- a/ipc/chromium/src/base/time_win.cc
+++ b/ipc/chromium/src/base/time_win.cc
@@ -42,17 +42,16 @@
 #pragma comment(lib, "winmm.lib")
 #endif
 #include <windows.h>
 #include <mmsystem.h>
 
 #include "base/basictypes.h"
 #include "base/lock.h"
 #include "base/logging.h"
-#include "base/singleton.h"
 #include "mozilla/Casting.h"
 
 using base::Time;
 using base::TimeDelta;
 using base::TimeTicks;
 using mozilla::BitwiseCast;
 
 namespace {
@@ -244,16 +243,21 @@ class NowSingleton {
     // we keep our last_seen_ stay correctly in sync.
     DWORD now = tick_function();
     if (now < last_seen_)
       rollover_ += TimeDelta::FromMilliseconds(GG_LONGLONG(0x100000000));  // ~49.7 days.
     last_seen_ = now;
     return TimeDelta::FromMilliseconds(now) + rollover_;
   }
 
+  static NowSingleton& instance() {
+    static NowSingleton now;
+    return now;
+  }
+
  private:
   Lock lock_;  // To protected last_seen_ and rollover_.
   TimeDelta rollover_;  // Accumulation of time lost due to rollover.
   DWORD last_seen_;  // The last timeGetTime value we saw, to detect rollover.
 
   DISALLOW_COPY_AND_ASSIGN(NowSingleton);
 };
 
@@ -264,10 +268,10 @@ TimeTicks::TickFunctionType TimeTicks::S
     TickFunctionType ticker) {
   TickFunctionType old = tick_function;
   tick_function = ticker;
   return old;
 }
 
 // static
 TimeTicks TimeTicks::Now() {
-  return TimeTicks() + Singleton<NowSingleton>::get()->Now();
+  return TimeTicks() + NowSingleton::instance().Now();
 }
--- a/ipc/chromium/src/base/win_util.cc
+++ b/ipc/chromium/src/base/win_util.cc
@@ -5,17 +5,16 @@
 // found in the LICENSE file.
 
 #include "base/win_util.h"
 
 #include <map>
 #include <sddl.h>
 
 #include "base/logging.h"
-#include "base/singleton.h"
 #include "base/string_util.h"
 
 namespace win_util {
 
 std::wstring FormatMessage(unsigned messageid) {
   wchar_t* string_buffer = NULL;
   unsigned string_length = ::FormatMessage(
       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
--- a/ipc/chromium/src/chrome/common/child_process_host.cc
+++ b/ipc/chromium/src/chrome/common/child_process_host.cc
@@ -5,17 +5,16 @@
 // found in the LICENSE file.
 
 #include "chrome/common/child_process_host.h"
 
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/message_loop.h"
 #include "base/process_util.h"
-#include "base/singleton.h"
 #include "base/waitable_event.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/ipc/Transport.h"
 typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
 #include "chrome/common/process_watcher.h"
 
 using mozilla::ipc::FileDescriptor;
--- a/ipc/chromium/src/chrome/common/ipc_channel.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel.cc
@@ -3,25 +3,26 @@
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chrome/common/ipc_channel.h"
 
 #include <limits>
 
-#include "base/atomic_sequence_num.h"
 #include "base/process_util.h"
 #include "base/rand_util.h"
 #include "base/string_util.h"
 
+#include "mozilla/Atomics.h"
+
 namespace {
 
 // Global atomic used to guarantee channel IDs are unique.
-base::StaticAtomicSequenceNumber g_last_id;
+mozilla::Atomic<int> g_last_id;
 
 }  // namespace
 
 namespace IPC {
 
 // static
 std::wstring Channel::GenerateUniqueRandomChannelID() {
   // Note: the string must start with the current process id, this is how
@@ -29,13 +30,13 @@ std::wstring Channel::GenerateUniqueRand
   //
   // This is composed of a unique incremental identifier, the process ID of
   // the creator, an identifier for the child instance, and a strong random
   // component. The strong random component prevents other processes from
   // hijacking or squatting on predictable channel names.
 
   return StringPrintf(L"%d.%u.%d",
       base::GetCurrentProcId(),
-      g_last_id.GetNext(),
+      g_last_id++,
       base::RandInt(0, std::numeric_limits<int32_t>::max()));
 }
 
-}  // namespace IPC
\ No newline at end of file
+}  // namespace IPC
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -24,17 +24,16 @@
 #include <map>
 
 #include "base/command_line.h"
 #include "base/eintr_wrapper.h"
 #include "base/lock.h"
 #include "base/logging.h"
 #include "base/process_util.h"
 #include "base/string_util.h"
-#include "base/singleton.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/file_descriptor_set_posix.h"
 #include "chrome/common/ipc_message_utils.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/UniquePtr.h"
 
 #ifdef FUZZING
 #include "mozilla/ipc/Faulty.h"
@@ -135,17 +134,25 @@ class PipeMap {
 
     ChannelToFDMap::const_iterator i = map_.find(channel_id);
     CHECK(i == map_.end()) << "Creating second IPC server for '"
                            << channel_id
                            << "' while first still exists";
     map_[channel_id] = fd;
   }
 
+  static PipeMap& instance() {
+    static PipeMap map;
+    return map;
+  }
+
  private:
+  PipeMap() = default;
+  ~PipeMap() = default;
+
   Lock lock_;
   typedef std::map<std::string, int> ChannelToFDMap;
   ChannelToFDMap map_;
 };
 
 // This is the file descriptor number that a client process expects to find its
 // IPC socket.
 static int gClientChannelFd =
@@ -155,17 +162,17 @@ static int gClientChannelFd =
 #else
 3
 #endif // defined(MOZ_WIDGET_ANDROID)
 ;
 
 // Used to map a channel name to the equivalent FD # in the client process.
 int ChannelNameToClientFD(const std::string& channel_id) {
   // See the large block comment above PipeMap for the reasoning here.
-  const int fd = Singleton<PipeMap>()->Lookup(channel_id);
+  const int fd = PipeMap::instance().Lookup(channel_id);
   if (fd != -1)
     return dup(fd);
 
   // If we don't find an entry, we assume that the correct value has been
   // inserted in the magic slot.
   return gClientChannelFd;
 }
 
@@ -270,17 +277,17 @@ bool Channel::ChannelImpl::CreatePipe(co
       IGNORE_EINTR(close(pipe_fds[1]));
       return false;
     }
 
     pipe_ = pipe_fds[0];
     client_pipe_ = pipe_fds[1];
 
     if (pipe_name_.length()) {
-      Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
+      PipeMap::instance().Insert(pipe_name_, client_pipe_);
     }
   } else {
     pipe_ = ChannelNameToClientFD(pipe_name_);
     DCHECK(pipe_ > 0);
     waiting_connect_ = false;
   }
 
   return true;
@@ -359,17 +366,17 @@ bool Channel::ChannelImpl::ProcessIncomi
     } else if (bytes_read == 0) {
       // The pipe has closed...
       Close();
       return false;
     }
     DCHECK(bytes_read);
 
     if (client_pipe_ != -1) {
-      Singleton<PipeMap>()->Remove(pipe_name_);
+      PipeMap::instance().Remove(pipe_name_);
       IGNORE_EINTR(close(client_pipe_));
       client_pipe_ = -1;
     }
 
     // a pointer to an array of |num_wire_fds| file descriptors from the read
     const int* wire_fds = NULL;
     unsigned num_wire_fds = 0;
 
@@ -606,17 +613,17 @@ bool Channel::ChannelImpl::ProcessOutgoi
 
   if (pipe_ == -1)
     return false;
 
   // Write out all the messages we can till the write blocks or there are no
   // more outgoing messages.
   while (!output_queue_.empty()) {
 #ifdef FUZZING
-    Singleton<mozilla::ipc::Faulty>::get()->MaybeCollectAndClosePipe(pipe_);
+    mozilla::ipc::Faulty::instance().MaybeCollectAndClosePipe(pipe_);
 #endif
     Message* msg = output_queue_.front();
 
     struct msghdr msgh = {0};
 
     static const int tmp = CMSG_SPACE(sizeof(
         int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
     char buf[tmp];
@@ -770,17 +777,17 @@ bool Channel::ChannelImpl::ProcessOutgoi
 bool Channel::ChannelImpl::Send(Message* message) {
 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   DLOG(INFO) << "sending message @" << message << " on channel @" << this
              << " with type " << message->type()
              << " (" << output_queue_.size() << " in queue)";
 #endif
 
 #ifdef FUZZING
-  message = Singleton<mozilla::ipc::Faulty>::get()->MutateIPCMessage("Channel::ChannelImpl::Send", message);
+  message = mozilla::ipc::Faulty::instance().MutateIPCMessage("Channel::ChannelImpl::Send", message);
 #endif
 
   // If the channel has been closed, ProcessOutgoingMessages() is never going
   // to pop anything off output_queue; output_queue will only get emptied when
   // the channel is destructed.  We might as well delete message now, instead
   // of waiting for the channel to be destructed.
   if (closed_) {
     if (mozilla::ipc::LoggingEnabled()) {
@@ -806,17 +813,17 @@ void Channel::ChannelImpl::GetClientFile
                                                           int *dest_fd) const {
   DCHECK(mode_ == MODE_SERVER);
   *src_fd = client_pipe_;
   *dest_fd = gClientChannelFd;
 }
 
 void Channel::ChannelImpl::CloseClientFileDescriptor() {
   if (client_pipe_ != -1) {
-    Singleton<PipeMap>()->Remove(pipe_name_);
+    PipeMap::instance().Remove(pipe_name_);
     IGNORE_EINTR(close(client_pipe_));
     client_pipe_ = -1;
   }
 }
 
 // Called by libevent when we can read from th pipe without blocking.
 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
   if (!waiting_connect_ && fd == pipe_) {
@@ -881,17 +888,17 @@ void Channel::ChannelImpl::Close() {
   // Unregister libevent for the FIFO and close it.
   read_watcher_.StopWatchingFileDescriptor();
   write_watcher_.StopWatchingFileDescriptor();
   if (pipe_ != -1) {
     IGNORE_EINTR(close(pipe_));
     pipe_ = -1;
   }
   if (client_pipe_ != -1) {
-    Singleton<PipeMap>()->Remove(pipe_name_);
+    PipeMap::instance().Remove(pipe_name_);
     IGNORE_EINTR(close(client_pipe_));
     client_pipe_ = -1;
   }
 
   while (!output_queue_.empty()) {
     Message* m = output_queue_.front();
     OutputQueuePop();
     delete m;
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -49,16 +49,17 @@
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/Opcodes.h"
 #include "vm/Printer.h"
 #include "vm/RegExpObject.h"
 #include "vm/RegExpStatics.h"
 #include "vm/SelfHosting.h"
 
+#include "vm/InlineCharBuffer-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/StringType-inl.h"
 #include "vm/TypeInference-inl.h"
 
 using namespace js;
 
 using JS::Symbol;
@@ -83,150 +84,16 @@ ArgToLinearString(JSContext* cx, const C
     JSString* str = ToString<CanGC>(cx, args[argno]);
     if (!str) {
         return nullptr;
     }
 
     return str->ensureLinear(cx);
 }
 
-template <typename CharT> struct MaximumInlineLength;
-
-template<> struct MaximumInlineLength<Latin1Char> {
-    static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
-};
-
-template<> struct MaximumInlineLength<char16_t> {
-    static constexpr size_t value = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
-};
-
-// Character buffer class used for ToLowerCase and ToUpperCase operations, as
-// well as other string operations where the final string length is known in
-// advance.
-//
-// Case conversion operations normally return a string with the same length as
-// the input string. To avoid over-allocation, we optimistically allocate an
-// array with same size as the input string and only when we detect special
-// casing characters, which can change the output string length, we reallocate
-// the output buffer to the final string length.
-//
-// As a further mean to improve runtime performance, the character buffer
-// contains an inline storage, so we don't need to heap-allocate an array when
-// a JSInlineString will be used for the output string.
-//
-// Why not use mozilla::Vector instead? mozilla::Vector doesn't provide enough
-// fine-grained control to avoid over-allocation when (re)allocating for exact
-// buffer sizes. This led to visible performance regressions in µ-benchmarks.
-template <typename CharT>
-class MOZ_NON_PARAM InlineCharBuffer
-{
-    static constexpr size_t InlineCapacity = MaximumInlineLength<CharT>::value;
-
-    CharT inlineStorage[InlineCapacity];
-    UniquePtr<CharT[], JS::FreePolicy> heapStorage;
-
-#ifdef DEBUG
-    // In debug mode, we keep track of the requested string lengths to ensure
-    // all character buffer methods are called in the correct order and with
-    // the expected argument values.
-    size_t lastRequestedLength = 0;
-
-    void assertValidRequest(size_t expectedLastLength, size_t length) {
-        MOZ_ASSERT(length >= expectedLastLength, "cannot shrink requested length");
-        MOZ_ASSERT(lastRequestedLength == expectedLastLength);
-        lastRequestedLength = length;
-    }
-#else
-    void assertValidRequest(size_t expectedLastLength, size_t length) {}
-#endif
-
-  public:
-    CharT* get()
-    {
-        return heapStorage ? heapStorage.get() : inlineStorage;
-    }
-
-    bool maybeAlloc(JSContext* cx, size_t length)
-    {
-        assertValidRequest(0, length);
-
-        if (length <= InlineCapacity) {
-            return true;
-        }
-
-        MOZ_ASSERT(!heapStorage, "heap storage already allocated");
-        heapStorage = cx->make_pod_array<CharT>(length + 1);
-        return !!heapStorage;
-    }
-
-    bool maybeRealloc(JSContext* cx, size_t oldLength, size_t newLength)
-    {
-        assertValidRequest(oldLength, newLength);
-
-        if (newLength <= InlineCapacity) {
-            return true;
-        }
-
-        if (!heapStorage) {
-            heapStorage = cx->make_pod_array<CharT>(newLength + 1);
-            if (!heapStorage) {
-                return false;
-            }
-
-            MOZ_ASSERT(oldLength <= InlineCapacity);
-            PodCopy(heapStorage.get(), inlineStorage, oldLength);
-            return true;
-        }
-
-        CharT* oldChars = heapStorage.release();
-        CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
-        if (!newChars) {
-            js_free(oldChars);
-            return false;
-        }
-
-        heapStorage.reset(newChars);
-        return true;
-    }
-
-    JSString* toStringDontDeflate(JSContext* cx, size_t length)
-    {
-        MOZ_ASSERT(length == lastRequestedLength);
-
-        if (JSInlineString::lengthFits<CharT>(length)) {
-            MOZ_ASSERT(!heapStorage,
-                       "expected only inline storage when length fits in inline string");
-
-            return NewStringCopyNDontDeflate<CanGC>(cx, inlineStorage, length);
-        }
-
-        MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
-
-        heapStorage.get()[length] = '\0'; // Null-terminate
-        return NewStringDontDeflate<CanGC>(cx, std::move(heapStorage), length);
-    }
-
-    JSString* toString(JSContext* cx, size_t length)
-    {
-        MOZ_ASSERT(length == lastRequestedLength);
-
-        if (JSInlineString::lengthFits<CharT>(length)) {
-            MOZ_ASSERT(!heapStorage,
-                       "expected only inline storage when length fits in inline string");
-
-            return NewStringCopyN<CanGC>(cx, inlineStorage, length);
-        }
-
-        MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
-
-        heapStorage.get()[length] = '\0'; // Null-terminate
-        return NewString<CanGC>(cx, std::move(heapStorage), length);
-    }
-};
-
 /*
  * Forward declarations for URI encode/decode and helper routines
  */
 static bool
 str_decodeURI(JSContext* cx, unsigned argc, Value* vp);
 
 static bool
 str_decodeURI_Component(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/ctypes/libffi/src/aarch64/ffitarget.h
+++ b/js/src/ctypes/libffi/src/aarch64/ffitarget.h
@@ -22,18 +22,24 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #ifndef LIBFFI_TARGET_H
 #define LIBFFI_TARGET_H
 
 #ifndef LIBFFI_H
 #error "Please do not include ffitarget.h directly into your source.  Use ffi.h instead."
 #endif
 
 #ifndef LIBFFI_ASM
+#ifdef _MSC_VER
+typedef unsigned long long ffi_arg;
+typedef signed long long ffi_sarg;
+#define FFI_SIZEOF_ARG 8
+#else
 typedef unsigned long ffi_arg;
 typedef signed long ffi_sarg;
+#endif
 
 typedef enum ffi_abi
   {
     FFI_FIRST_ABI = 0,
     FFI_SYSV,
     FFI_LAST_ABI,
     FFI_DEFAULT_ABI = FFI_SYSV
   } ffi_abi;
copy from js/src/builtin/String.cpp
copy to js/src/vm/InlineCharBuffer-inl.h
--- a/js/src/builtin/String.cpp
+++ b/js/src/vm/InlineCharBuffer-inl.h
@@ -1,97 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "builtin/String.h"
-
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/CheckedInt.h"
-#include "mozilla/FloatingPoint.h"
-#include "mozilla/PodOperations.h"
-#include "mozilla/Range.h"
-#include "mozilla/TypeTraits.h"
-#include "mozilla/Unused.h"
-
-#include <ctype.h>
-#include <limits>
-#include <string.h>
-
-#include "jsapi.h"
-#include "jsnum.h"
-#include "jstypes.h"
-#include "jsutil.h"
+#ifndef vm_InlineCharBuffer_inl_h
+#define vm_InlineCharBuffer_inl_h
 
-#include "builtin/Array.h"
-#include "builtin/Boolean.h"
-#include "builtin/intl/CommonFunctions.h"
-#include "builtin/intl/ICUStubs.h"
-#include "builtin/RegExp.h"
-#include "jit/InlinableNatives.h"
-#include "js/Conversions.h"
-#if !EXPOSE_INTL_API
-#include "js/LocaleSensitive.h"
-#endif
-#include "js/StableStringChars.h"
-#include "js/UniquePtr.h"
-#if ENABLE_INTL_API
-# include "unicode/uchar.h"
-# include "unicode/unorm2.h"
-#endif
-#include "util/StringBuffer.h"
-#include "util/Unicode.h"
-#include "vm/BytecodeUtil.h"
-#include "vm/GlobalObject.h"
-#include "vm/Interpreter.h"
-#include "vm/JSAtom.h"
-#include "vm/JSContext.h"
-#include "vm/JSObject.h"
-#include "vm/Opcodes.h"
-#include "vm/Printer.h"
-#include "vm/RegExpObject.h"
-#include "vm/RegExpStatics.h"
-#include "vm/SelfHosting.h"
+#include "vm/StringType-inl.h"
 
-#include "vm/Interpreter-inl.h"
-#include "vm/StringObject-inl.h"
-#include "vm/StringType-inl.h"
-#include "vm/TypeInference-inl.h"
-
-using namespace js;
-
-using JS::Symbol;
-using JS::SymbolCode;
-
-using mozilla::CheckedInt;
-using mozilla::IsNaN;
-using mozilla::IsSame;
-using mozilla::PodCopy;
-using mozilla::RangedPtr;
-
-using JS::AutoCheckCannotGC;
-using JS::AutoStableStringChars;
-
-static JSLinearString*
-ArgToLinearString(JSContext* cx, const CallArgs& args, unsigned argno)
-{
-    if (argno >= args.length()) {
-        return cx->names().undefined;
-    }
-
-    JSString* str = ToString<CanGC>(cx, args[argno]);
-    if (!str) {
-        return nullptr;
-    }
-
-    return str->ensureLinear(cx);
-}
+namespace js {
 
 template <typename CharT> struct MaximumInlineLength;
 
 template<> struct MaximumInlineLength<Latin1Char> {
     static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
 };
 
 template<> struct MaximumInlineLength<char16_t> {
@@ -167,17 +90,17 @@ class MOZ_NON_PARAM InlineCharBuffer
 
         if (!heapStorage) {
             heapStorage = cx->make_pod_array<CharT>(newLength + 1);
             if (!heapStorage) {
                 return false;
             }
 
             MOZ_ASSERT(oldLength <= InlineCapacity);
-            PodCopy(heapStorage.get(), inlineStorage, oldLength);
+            mozilla::PodCopy(heapStorage.get(), inlineStorage, oldLength);
             return true;
         }
 
         CharT* oldChars = heapStorage.release();
         CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
         if (!newChars) {
             js_free(oldChars);
             return false;
@@ -190,17 +113,22 @@ class MOZ_NON_PARAM InlineCharBuffer
     JSString* toStringDontDeflate(JSContext* cx, size_t length)
     {
         MOZ_ASSERT(length == lastRequestedLength);
 
         if (JSInlineString::lengthFits<CharT>(length)) {
             MOZ_ASSERT(!heapStorage,
                        "expected only inline storage when length fits in inline string");
 
-            return NewStringCopyNDontDeflate<CanGC>(cx, inlineStorage, length);
+            if (JSString* str = TryEmptyOrStaticString(cx, inlineStorage, length)) {
+                return str;
+            }
+
+            mozilla::Range<const CharT> range(inlineStorage, length);
+            return NewInlineString<CanGC>(cx, range);
         }
 
         MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
 
         heapStorage.get()[length] = '\0'; // Null-terminate
         return NewStringDontDeflate<CanGC>(cx, std::move(heapStorage), length);
     }
 
@@ -217,4310 +145,11 @@ class MOZ_NON_PARAM InlineCharBuffer
 
         MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
 
         heapStorage.get()[length] = '\0'; // Null-terminate
         return NewString<CanGC>(cx, std::move(heapStorage), length);
     }
 };
 
-/*
- * Forward declarations for URI encode/decode and helper routines
- */
-static bool
-str_decodeURI(JSContext* cx, unsigned argc, Value* vp);
-
-static bool
-str_decodeURI_Component(JSContext* cx, unsigned argc, Value* vp);
-
-static bool
-str_encodeURI(JSContext* cx, unsigned argc, Value* vp);
-
-static bool
-str_encodeURI_Component(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Global string methods
- */
-
-
-/* ES5 B.2.1 */
-template <typename CharT>
-static bool
-Escape(JSContext* cx, const CharT* chars, uint32_t length, InlineCharBuffer<Latin1Char>& newChars,
-       uint32_t* newLengthOut)
-{
-    static const uint8_t shouldPassThrough[128] = {
-         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-         0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,       /*    !"#$%&'()*+,-./  */
-         1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,       /*   0123456789:;<=>?  */
-         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /*   @ABCDEFGHIJKLMNO  */
-         1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,       /*   PQRSTUVWXYZ[\]^_  */
-         0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /*   `abcdefghijklmno  */
-         1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,       /*   pqrstuvwxyz{\}~  DEL */
-    };
-
-    /* Take a first pass and see how big the result string will need to be. */
-    uint32_t newLength = length;
-    for (size_t i = 0; i < length; i++) {
-        char16_t ch = chars[i];
-        if (ch < 128 && shouldPassThrough[ch]) {
-            continue;
-        }
-
-        /* The character will be encoded as %XX or %uXXXX. */
-        newLength += (ch < 256) ? 2 : 5;
-
-        /*
-         * newlength is incremented by at most 5 on each iteration, so worst
-         * case newlength == length * 6. This can't overflow.
-         */
-        static_assert(JSString::MAX_LENGTH < UINT32_MAX / 6,
-                      "newlength must not overflow");
-    }
-
-    if (newLength == length) {
-        *newLengthOut = newLength;
-        return true;
-    }
-
-    if (!newChars.maybeAlloc(cx, newLength)) {
-        return false;
-    }
-
-    static const char digits[] = "0123456789ABCDEF";
-
-    Latin1Char* rawNewChars = newChars.get();
-    size_t i, ni;
-    for (i = 0, ni = 0; i < length; i++) {
-        char16_t ch = chars[i];
-        if (ch < 128 && shouldPassThrough[ch]) {
-            rawNewChars[ni++] = ch;
-        } else if (ch < 256) {
-            rawNewChars[ni++] = '%';
-            rawNewChars[ni++] = digits[ch >> 4];
-            rawNewChars[ni++] = digits[ch & 0xF];
-        } else {
-            rawNewChars[ni++] = '%';
-            rawNewChars[ni++] = 'u';
-            rawNewChars[ni++] = digits[ch >> 12];
-            rawNewChars[ni++] = digits[(ch & 0xF00) >> 8];
-            rawNewChars[ni++] = digits[(ch & 0xF0) >> 4];
-            rawNewChars[ni++] = digits[ch & 0xF];
-        }
-    }
-    MOZ_ASSERT(ni == newLength);
-
-    *newLengthOut = newLength;
-    return true;
-}
-
-static bool
-str_escape(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedLinearString str(cx, ArgToLinearString(cx, args, 0));
-    if (!str) {
-        return false;
-    }
-
-    InlineCharBuffer<Latin1Char> newChars;
-    uint32_t newLength = 0;  // initialize to silence GCC warning
-    if (str->hasLatin1Chars()) {
-        AutoCheckCannotGC nogc;
-        if (!Escape(cx, str->latin1Chars(nogc), str->length(), newChars, &newLength)) {
-            return false;
-        }
-    } else {
-        AutoCheckCannotGC nogc;
-        if (!Escape(cx, str->twoByteChars(nogc), str->length(), newChars, &newLength)) {
-            return false;
-        }
-    }
-
-    // Return input if no characters need to be escaped.
-    if (newLength == str->length()) {
-        args.rval().setString(str);
-        return true;
-    }
-
-    JSString* res = newChars.toString(cx, newLength);
-    if (!res) {
-        return false;
-    }
-
-    args.rval().setString(res);
-    return true;
-}
-
-template <typename CharT>
-static inline bool
-Unhex4(const RangedPtr<const CharT> chars, char16_t* result)
-{
-    char16_t a = chars[0],
-             b = chars[1],
-             c = chars[2],
-             d = chars[3];
-
-    if (!(JS7_ISHEX(a) && JS7_ISHEX(b) && JS7_ISHEX(c) && JS7_ISHEX(d))) {
-        return false;
-    }
-
-    *result = (((((JS7_UNHEX(a) << 4) + JS7_UNHEX(b)) << 4) + JS7_UNHEX(c)) << 4) + JS7_UNHEX(d);
-    return true;
-}
-
-template <typename CharT>
-static inline bool
-Unhex2(const RangedPtr<const CharT> chars, char16_t* result)
-{
-    char16_t a = chars[0],
-             b = chars[1];
-
-    if (!(JS7_ISHEX(a) && JS7_ISHEX(b))) {
-        return false;
-    }
-
-    *result = (JS7_UNHEX(a) << 4) + JS7_UNHEX(b);
-    return true;
-}
-
-template <typename CharT>
-static bool
-Unescape(StringBuffer& sb, const mozilla::Range<const CharT> chars)
-{
-    // Step 2.
-    uint32_t length = chars.length();
-
-    /*
-     * Note that the spec algorithm has been optimized to avoid building
-     * a string in the case where no escapes are present.
-     */
-    bool building = false;
-
-#define ENSURE_BUILDING                                      \
-        do {                                                 \
-            if (!building) {                                 \
-                building = true;                             \
-                if (!sb.reserve(length))                     \
-                    return false;                            \
-                sb.infallibleAppend(chars.begin().get(), k); \
-            }                                                \
-        } while(false);
-
-    // Step 4.
-    uint32_t k = 0;
-
-    // Step 5.
-    while (k < length) {
-        // Step 5.a.
-        char16_t c = chars[k];
-
-        // Step 5.b.
-        if (c == '%') {
-            static_assert(JSString::MAX_LENGTH < UINT32_MAX - 6,
-                          "String length is not near UINT32_MAX");
-
-            // Steps 5.b.i-ii.
-            if (k + 6 <= length && chars[k + 1] == 'u') {
-                if (Unhex4(chars.begin() + k + 2, &c)) {
-                    ENSURE_BUILDING
-                    k += 5;
-                }
-            } else if (k + 3 <= length) {
-                if (Unhex2(chars.begin() + k + 1, &c)) {
-                    ENSURE_BUILDING
-                    k += 2;
-                }
-            }
-        }
-
-        // Step 5.c.
-        if (building && !sb.append(c)) {
-            return false;
-        }
-
-        // Step 5.d.
-        k += 1;
-    }
-
-    return true;
-#undef ENSURE_BUILDING
-}
-
-// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
-// B.2.1.2 unescape ( string )
-static bool
-str_unescape(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Step 1.
-    RootedLinearString str(cx, ArgToLinearString(cx, args, 0));
-    if (!str) {
-        return false;
-    }
-
-    // Step 3.
-    StringBuffer sb(cx);
-    if (str->hasTwoByteChars() && !sb.ensureTwoByteChars()) {
-        return false;
-    }
-
-    // Steps 2, 4-5.
-    if (str->hasLatin1Chars()) {
-        AutoCheckCannotGC nogc;
-        if (!Unescape(sb, str->latin1Range(nogc))) {
-            return false;
-        }
-    } else {
-        AutoCheckCannotGC nogc;
-        if (!Unescape(sb, str->twoByteRange(nogc))) {
-            return false;
-        }
-    }
-
-    // Step 6.
-    JSLinearString* result;
-    if (!sb.empty()) {
-        result = sb.finishString();
-        if (!result) {
-            return false;
-        }
-    } else {
-        result = str;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-static bool
-str_uneval(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    JSString* str = ValueToSource(cx, args.get(0));
-    if (!str) {
-        return false;
-    }
-
-    args.rval().setString(str);
-    return true;
-}
-
-static const JSFunctionSpec string_functions[] = {
-    JS_FN(js_escape_str,             str_escape,                1, JSPROP_RESOLVING),
-    JS_FN(js_unescape_str,           str_unescape,              1, JSPROP_RESOLVING),
-    JS_FN(js_uneval_str,             str_uneval,                1, JSPROP_RESOLVING),
-    JS_FN(js_decodeURI_str,          str_decodeURI,             1, JSPROP_RESOLVING),
-    JS_FN(js_encodeURI_str,          str_encodeURI,             1, JSPROP_RESOLVING),
-    JS_FN(js_decodeURIComponent_str, str_decodeURI_Component,   1, JSPROP_RESOLVING),
-    JS_FN(js_encodeURIComponent_str, str_encodeURI_Component,   1, JSPROP_RESOLVING),
-
-    JS_FS_END
-};
-
-static const unsigned STRING_ELEMENT_ATTRS = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
-
-static bool
-str_enumerate(JSContext* cx, HandleObject obj)
-{
-    RootedString str(cx, obj->as<StringObject>().unbox());
-    js::StaticStrings& staticStrings = cx->staticStrings();
-
-    RootedValue value(cx);
-    for (size_t i = 0, length = str->length(); i < length; i++) {
-        JSString* str1 = staticStrings.getUnitStringForElement(cx, str, i);
-        if (!str1) {
-            return false;
-        }
-        value.setString(str1);
-        if (!DefineDataElement(cx, obj, i, value, STRING_ELEMENT_ATTRS | JSPROP_RESOLVING)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-static bool
-str_mayResolve(const JSAtomState&, jsid id, JSObject*)
-{
-    // str_resolve ignores non-integer ids.
-    return JSID_IS_INT(id);
-}
-
-static bool
-str_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
-{
-    if (!JSID_IS_INT(id)) {
-        return true;
-    }
-
-    RootedString str(cx, obj->as<StringObject>().unbox());
-
-    int32_t slot = JSID_TO_INT(id);
-    if ((size_t)slot < str->length()) {
-        JSString* str1 = cx->staticStrings().getUnitStringForElement(cx, str, size_t(slot));
-        if (!str1) {
-            return false;
-        }
-        RootedValue value(cx, StringValue(str1));
-        if (!DefineDataElement(cx, obj, uint32_t(slot), value,
-                               STRING_ELEMENT_ATTRS | JSPROP_RESOLVING))
-        {
-            return false;
-        }
-        *resolvedp = true;
-    }
-    return true;
-}
-
-static const ClassOps StringObjectClassOps = {
-    nullptr, /* addProperty */
-    nullptr, /* delProperty */
-    str_enumerate,
-    nullptr, /* newEnumerate */
-    str_resolve,
-    str_mayResolve
-};
-
-const Class StringObject::class_ = {
-    js_String_str,
-    JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_String),
-    &StringObjectClassOps
-};
-
-/*
- * Perform the initial |RequireObjectCoercible(thisv)| and |ToString(thisv)|
- * from nearly all String.prototype.* functions.
- */
-static MOZ_ALWAYS_INLINE JSString*
-ToStringForStringFunction(JSContext* cx, HandleValue thisv)
-{
-    if (!CheckRecursionLimit(cx)) {
-        return nullptr;
-    }
-
-    if (thisv.isString()) {
-        return thisv.toString();
-    }
-
-    if (thisv.isObject()) {
-        RootedObject obj(cx, &thisv.toObject());
-        if (obj->is<StringObject>()) {
-            StringObject* nobj = &obj->as<StringObject>();
-            // We have to make sure that the ToPrimitive call from ToString
-            // would be unobservable.
-            if (HasNoToPrimitiveMethodPure(nobj, cx) &&
-                HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx))
-            {
-                return nobj->unbox();
-            }
-        }
-    } else if (thisv.isNullOrUndefined()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
-                                  thisv.isNull() ? "null" : "undefined", "object");
-        return nullptr;
-    }
-
-    return ToStringSlow<CanGC>(cx, thisv);
-}
-
-MOZ_ALWAYS_INLINE bool
-IsString(HandleValue v)
-{
-    return v.isString() || (v.isObject() && v.toObject().is<StringObject>());
-}
-
-MOZ_ALWAYS_INLINE bool
-str_toSource_impl(JSContext* cx, const CallArgs& args)
-{
-    MOZ_ASSERT(IsString(args.thisv()));
-
-    JSString* str = ToString<CanGC>(cx, args.thisv());
-    if (!str) {
-        return false;
-    }
-
-    UniqueChars quoted = QuoteString(cx, str, '"');
-    if (!quoted) {
-        return false;
-    }
-
-    StringBuffer sb(cx);
-    if (!sb.append("(new String(") ||
-        !sb.append(quoted.get(), strlen(quoted.get())) ||
-        !sb.append("))"))
-    {
-        return false;
-    }
-
-    JSString* result = sb.finishString();
-    if (!result) {
-        return false;
-    }
-    args.rval().setString(result);
-    return true;
-}
-
-static bool
-str_toSource(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsString, str_toSource_impl>(cx, args);
-}
-
-MOZ_ALWAYS_INLINE bool
-str_toString_impl(JSContext* cx, const CallArgs& args)
-{
-    MOZ_ASSERT(IsString(args.thisv()));
-
-    args.rval().setString(args.thisv().isString()
-                              ? args.thisv().toString()
-                              : args.thisv().toObject().as<StringObject>().unbox());
-    return true;
-}
-
-bool
-js::str_toString(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsString, str_toString_impl>(cx, args);
-}
-
-/*
- * Java-like string native methods.
- */
-
-JSString*
-js::SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt)
-{
-    MOZ_ASSERT(0 <= beginInt);
-    MOZ_ASSERT(0 <= lengthInt);
-    MOZ_ASSERT(uint32_t(beginInt) <= str->length());
-    MOZ_ASSERT(uint32_t(lengthInt) <= str->length() - beginInt);
-
-    uint32_t begin = beginInt;
-    uint32_t len = lengthInt;
-
-    /*
-     * Optimization for one level deep ropes.
-     * This is common for the following pattern:
-     *
-     * while() {
-     *   text = text.substr(0, x) + "bla" + text.substr(x)
-     *   test.charCodeAt(x + 1)
-     * }
-     */
-    if (str->isRope()) {
-        JSRope* rope = &str->asRope();
-
-        /* Substring is totally in leftChild of rope. */
-        if (begin + len <= rope->leftChild()->length()) {
-            return NewDependentString(cx, rope->leftChild(), begin, len);
-        }
-
-        /* Substring is totally in rightChild of rope. */
-        if (begin >= rope->leftChild()->length()) {
-            begin -= rope->leftChild()->length();
-            return NewDependentString(cx, rope->rightChild(), begin, len);
-        }
-
-        /*
-         * Requested substring is partly in the left and partly in right child.
-         * Create a rope of substrings for both childs.
-         */
-        MOZ_ASSERT(begin < rope->leftChild()->length() &&
-                   begin + len > rope->leftChild()->length());
-
-        size_t lhsLength = rope->leftChild()->length() - begin;
-        size_t rhsLength = begin + len - rope->leftChild()->length();
-
-        Rooted<JSRope*> ropeRoot(cx, rope);
-        RootedString lhs(cx, NewDependentString(cx, ropeRoot->leftChild(), begin, lhsLength));
-        if (!lhs) {
-            return nullptr;
-        }
-
-        RootedString rhs(cx, NewDependentString(cx, ropeRoot->rightChild(), 0, rhsLength));
-        if (!rhs) {
-            return nullptr;
-        }
-
-        return JSRope::new_<CanGC>(cx, lhs, rhs, len);
-    }
-
-    return NewDependentString(cx, str, begin, len);
-}
-
-/**
- * U+03A3 GREEK CAPITAL LETTER SIGMA has two different lower case mappings
- * depending on its context:
- * When it's preceded by a cased character and not followed by another cased
- * character, its lower case form is U+03C2 GREEK SMALL LETTER FINAL SIGMA.
- * Otherwise its lower case mapping is U+03C3 GREEK SMALL LETTER SIGMA.
- *
- * Unicode 9.0, §3.13 Default Case Algorithms
- */
-static char16_t
-Final_Sigma(const char16_t* chars, size_t length, size_t index)
-{
-    MOZ_ASSERT(index < length);
-    MOZ_ASSERT(chars[index] == unicode::GREEK_CAPITAL_LETTER_SIGMA);
-    MOZ_ASSERT(unicode::ToLowerCase(unicode::GREEK_CAPITAL_LETTER_SIGMA) ==
-               unicode::GREEK_SMALL_LETTER_SIGMA);
-
-#if ENABLE_INTL_API
-    // Tell the analysis the BinaryProperty.contains function pointer called by
-    // u_hasBinaryProperty cannot GC.
-    JS::AutoSuppressGCAnalysis nogc;
-
-    bool precededByCased = false;
-    for (size_t i = index; i > 0; ) {
-        char16_t c = chars[--i];
-        uint32_t codePoint = c;
-        if (unicode::IsTrailSurrogate(c) && i > 0) {
-            char16_t lead = chars[i - 1];
-            if (unicode::IsLeadSurrogate(lead)) {
-                codePoint = unicode::UTF16Decode(lead, c);
-                i--;
-            }
-        }
-
-        // Ignore any characters with the property Case_Ignorable.
-        // NB: We need to skip over all Case_Ignorable characters, even when
-        // they also have the Cased binary property.
-        if (u_hasBinaryProperty(codePoint, UCHAR_CASE_IGNORABLE)) {
-            continue;
-        }
-
-        precededByCased = u_hasBinaryProperty(codePoint, UCHAR_CASED);
-        break;
-    }
-    if (!precededByCased) {
-        return unicode::GREEK_SMALL_LETTER_SIGMA;
-    }
-
-    bool followedByCased = false;
-    for (size_t i = index + 1; i < length; ) {
-        char16_t c = chars[i++];
-        uint32_t codePoint = c;
-        if (unicode::IsLeadSurrogate(c) && i < length) {
-            char16_t trail = chars[i];
-            if (unicode::IsTrailSurrogate(trail)) {
-                codePoint = unicode::UTF16Decode(c, trail);
-                i++;
-            }
-        }
-
-        // Ignore any characters with the property Case_Ignorable.
-        // NB: We need to skip over all Case_Ignorable characters, even when
-        // they also have the Cased binary property.
-        if (u_hasBinaryProperty(codePoint, UCHAR_CASE_IGNORABLE)) {
-            continue;
-        }
-
-        followedByCased = u_hasBinaryProperty(codePoint, UCHAR_CASED);
-        break;
-    }
-    if (!followedByCased) {
-        return unicode::GREEK_SMALL_LETTER_FINAL_SIGMA;
-    }
-#endif
-
-    return unicode::GREEK_SMALL_LETTER_SIGMA;
-}
-
-static Latin1Char
-Final_Sigma(const Latin1Char* chars, size_t length, size_t index)
-{
-    MOZ_ASSERT_UNREACHABLE("U+03A3 is not a Latin-1 character");
-    return 0;
-}
-
-// If |srcLength == destLength| is true, the destination buffer was allocated
-// with the same size as the source buffer. When we append characters which
-// have special casing mappings, we test |srcLength == destLength| to decide
-// if we need to back out and reallocate a sufficiently large destination
-// buffer. Otherwise the destination buffer was allocated with the correct
-// size to hold all lower case mapped characters, i.e.
-// |destLength == ToLowerCaseLength(srcChars, 0, srcLength)| is true.
-template <typename CharT>
-static size_t
-ToLowerCaseImpl(CharT* destChars, const CharT* srcChars, size_t startIndex, size_t srcLength,
-                size_t destLength)
-{
-    MOZ_ASSERT(startIndex < srcLength);
-    MOZ_ASSERT(srcLength <= destLength);
-    MOZ_ASSERT_IF((IsSame<CharT, Latin1Char>::value), srcLength == destLength);
-
-    size_t j = startIndex;
-    for (size_t i = startIndex; i < srcLength; i++) {
-        char16_t c = srcChars[i];
-        if (!IsSame<CharT, Latin1Char>::value) {
-            if (unicode::IsLeadSurrogate(c) && i + 1 < srcLength) {
-                char16_t trail = srcChars[i + 1];
-                if (unicode::IsTrailSurrogate(trail)) {
-                    trail = unicode::ToLowerCaseNonBMPTrail(c, trail);
-                    destChars[j++] = c;
-                    destChars[j++] = trail;
-                    i++;
-                    continue;
-                }
-            }
-
-            // Special case: U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
-            // lowercases to <U+0069 U+0307>.
-            if (c == unicode::LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) {
-                // Return if the output buffer is too small.
-                if (srcLength == destLength) {
-                    return i;
-                }
-
-                destChars[j++] = CharT('i');
-                destChars[j++] = CharT(unicode::COMBINING_DOT_ABOVE);
-                continue;
-            }
-
-            // Special case: U+03A3 GREEK CAPITAL LETTER SIGMA lowercases to
-            // one of two codepoints depending on context.
-            if (c == unicode::GREEK_CAPITAL_LETTER_SIGMA) {
-                destChars[j++] = Final_Sigma(srcChars, srcLength, i);
-                continue;
-            }
-        }
-
-        c = unicode::ToLowerCase(c);
-        MOZ_ASSERT_IF((IsSame<CharT, Latin1Char>::value), c <= JSString::MAX_LATIN1_CHAR);
-        destChars[j++] = c;
-    }
-
-    MOZ_ASSERT(j == destLength);
-    return srcLength;
-}
-
-static size_t
-ToLowerCaseLength(const char16_t* chars, size_t startIndex, size_t length)
-{
-    size_t lowerLength = length;
-    for (size_t i = startIndex; i < length; i++) {
-        char16_t c = chars[i];
-
-        // U+0130 is lowercased to the two-element sequence <U+0069 U+0307>.
-        if (c == unicode::LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) {
-            lowerLength += 1;
-        }
-    }
-    return lowerLength;
-}
-
-static size_t
-ToLowerCaseLength(const Latin1Char* chars, size_t startIndex, size_t length)
-{
-    MOZ_ASSERT_UNREACHABLE("never called for Latin-1 strings");
-    return 0;
-}
-
-template <typename CharT>
-static JSString*
-ToLowerCase(JSContext* cx, JSLinearString* str)
-{
-    // Unlike toUpperCase, toLowerCase has the nice invariant that if the
-    // input is a Latin-1 string, the output is also a Latin-1 string.
-
-    InlineCharBuffer<CharT> newChars;
-
-    const size_t length = str->length();
-    size_t resultLength;
-    {
-        AutoCheckCannotGC nogc;
-        const CharT* chars = str->chars<CharT>(nogc);
-
-        // We don't need extra special casing checks in the loop below,
-        // because U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE and U+03A3
-        // GREEK CAPITAL LETTER SIGMA already have simple lower case mappings.
-        MOZ_ASSERT(unicode::ChangesWhenLowerCased(unicode::LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE),
-                   "U+0130 has a simple lower case mapping");
-        MOZ_ASSERT(unicode::ChangesWhenLowerCased(unicode::GREEK_CAPITAL_LETTER_SIGMA),
-                   "U+03A3 has a simple lower case mapping");
-
-        // One element Latin-1 strings can be directly retrieved from the
-        // static strings cache.
-        if (IsSame<CharT, Latin1Char>::value) {
-            if (length == 1) {
-                char16_t lower = unicode::ToLowerCase(chars[0]);
-                MOZ_ASSERT(lower <= JSString::MAX_LATIN1_CHAR);
-                MOZ_ASSERT(StaticStrings::hasUnit(lower));
-
-                return cx->staticStrings().getUnit(lower);
-            }
-        }
-
-        // Look for the first character that changes when lowercased.
-        size_t i = 0;
-        for (; i < length; i++) {
-            CharT c = chars[i];
-            if (!IsSame<CharT, Latin1Char>::value) {
-                if (unicode::IsLeadSurrogate(c) && i + 1 < length) {
-                    CharT trail = chars[i + 1];
-                    if (unicode::IsTrailSurrogate(trail)) {
-                        if (unicode::ChangesWhenLowerCasedNonBMP(c, trail)) {
-                            break;
-                        }
-
-                        i++;
-                        continue;
-                    }
-                }
-            }
-            if (unicode::ChangesWhenLowerCased(c)) {
-                break;
-            }
-        }
-
-        // If no character needs to change, return the input string.
-        if (i == length) {
-            return str;
-        }
-
-        resultLength = length;
-        if (!newChars.maybeAlloc(cx, resultLength)) {
-            return nullptr;
-        }
-
-        PodCopy(newChars.get(), chars, i);
-
-        size_t readChars = ToLowerCaseImpl(newChars.get(), chars, i, length, resultLength);
-        if (readChars < length) {
-            MOZ_ASSERT((!IsSame<CharT, Latin1Char>::value),
-                       "Latin-1 strings don't have special lower case mappings");
-            resultLength = ToLowerCaseLength(chars, readChars, length);
-
-            if (!newChars.maybeRealloc(cx, length, resultLength)) {
-                return nullptr;
-            }
-
-            MOZ_ALWAYS_TRUE(length ==
-                ToLowerCaseImpl(newChars.get(), chars, readChars, length, resultLength));
-        }
-    }
-
-    return newChars.toStringDontDeflate(cx, resultLength);
-}
-
-JSString*
-js::StringToLowerCase(JSContext* cx, HandleString string)
-{
-    JSLinearString* linear = string->ensureLinear(cx);
-    if (!linear) {
-        return nullptr;
-    }
-
-    if (linear->hasLatin1Chars()) {
-        return ToLowerCase<Latin1Char>(cx, linear);
-    }
-    return ToLowerCase<char16_t>(cx, linear);
-}
-
-bool
-js::str_toLowerCase(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    JSString* result = StringToLowerCase(cx, str);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-static const char*
-CaseMappingLocale(JSContext* cx, JSString* str)
-{
-    JSLinearString* locale = str->ensureLinear(cx);
-    if (!locale) {
-        return nullptr;
-    }
-
-    MOZ_ASSERT(locale->length() >= 2, "locale is a valid language tag");
-
-    // Lithuanian, Turkish, and Azeri have language dependent case mappings.
-    static const char languagesWithSpecialCasing[][3] = { "lt", "tr", "az" };
-
-    // All strings in |languagesWithSpecialCasing| are of length two, so we
-    // only need to compare the first two characters to find a matching locale.
-    // ES2017 Intl, §9.2.2 BestAvailableLocale
-    if (locale->length() == 2 || locale->latin1OrTwoByteChar(2) == '-') {
-        for (const auto& language : languagesWithSpecialCasing) {
-            if (locale->latin1OrTwoByteChar(0) == language[0] &&
-                locale->latin1OrTwoByteChar(1) == language[1])
-            {
-                return language;
-            }
-        }
-    }
-
-    return ""; // ICU root locale
-}
-
-bool
-js::intl_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].isString());
-    MOZ_ASSERT(args[1].isString());
-
-    RootedString string(cx, args[0].toString());
-
-    const char* locale = CaseMappingLocale(cx, args[1].toString());
-    if (!locale) {
-        return false;
-    }
-
-    // Call String.prototype.toLowerCase() for language independent casing.
-    if (intl::StringsAreEqual(locale, "")) {
-        JSString* str = StringToLowerCase(cx, string);
-        if (!str) {
-            return false;
-        }
-
-        args.rval().setString(str);
-        return true;
-    }
-
-    AutoStableStringChars inputChars(cx);
-    if (!inputChars.initTwoByte(cx, string)) {
-        return false;
-    }
-    mozilla::Range<const char16_t> input = inputChars.twoByteRange();
-
-    // Maximum case mapping length is three characters.
-    static_assert(JSString::MAX_LENGTH < INT32_MAX / 3,
-                  "Case conversion doesn't overflow int32_t indices");
-
-    static const size_t INLINE_CAPACITY = js::intl::INITIAL_CHAR_BUFFER_SIZE;
-
-    Vector<char16_t, INLINE_CAPACITY> chars(cx);
-    if (!chars.resize(Max(INLINE_CAPACITY, input.length()))) {
-        return false;
-    }
-
-    int32_t size =
-        intl::CallICU(cx, [&input, locale](UChar* chars, int32_t size, UErrorCode* status) {
-            return u_strToLower(chars, size, input.begin().get(), input.length(), locale, status);
-        }, chars);
-    if (size < 0) {
-        return false;
-    }
-
-    JSString* result = NewStringCopyN<CanGC>(cx, chars.begin(), size);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-#if EXPOSE_INTL_API
-
-// String.prototype.toLocaleLowerCase is self-hosted when Intl is exposed,
-// with core functionality performed by the intrinsic above.
-
-#else
-
-bool
-js::str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    /*
-     * Forcefully ignore the first (or any) argument and return toLowerCase(),
-     * ECMA has reserved that argument, presumably for defining the locale.
-     */
-    if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToLowerCase) {
-        RootedValue result(cx);
-        if (!cx->runtime()->localeCallbacks->localeToLowerCase(cx, str, &result)) {
-            return false;
-        }
-
-        args.rval().set(result);
-        return true;
-    }
-
-    RootedLinearString linear(cx, str->ensureLinear(cx));
-    if (!linear) {
-        return false;
-    }
-
-    JSString* result = StringToLowerCase(cx, linear);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-#endif // EXPOSE_INTL_API
-
-static inline bool
-ToUpperCaseHasSpecialCasing(Latin1Char charCode)
-{
-    // U+00DF LATIN SMALL LETTER SHARP S is the only Latin-1 code point with
-    // special casing rules, so detect it inline.
-    bool hasUpperCaseSpecialCasing = charCode == unicode::LATIN_SMALL_LETTER_SHARP_S;
-    MOZ_ASSERT(hasUpperCaseSpecialCasing == unicode::ChangesWhenUpperCasedSpecialCasing(charCode));
-
-    return hasUpperCaseSpecialCasing;
-}
-
-static inline bool
-ToUpperCaseHasSpecialCasing(char16_t charCode)
-{
-    return unicode::ChangesWhenUpperCasedSpecialCasing(charCode);
-}
-
-static inline size_t
-ToUpperCaseLengthSpecialCasing(Latin1Char charCode)
-{
-    // U+00DF LATIN SMALL LETTER SHARP S is uppercased to two 'S'.
-    MOZ_ASSERT(charCode == unicode::LATIN_SMALL_LETTER_SHARP_S);
-
-    return 2;
-}
-
-static inline size_t
-ToUpperCaseLengthSpecialCasing(char16_t charCode)
-{
-    MOZ_ASSERT(ToUpperCaseHasSpecialCasing(charCode));
-
-    return unicode::LengthUpperCaseSpecialCasing(charCode);
-}
-
-static inline void
-ToUpperCaseAppendUpperCaseSpecialCasing(char16_t charCode, Latin1Char* elements, size_t* index)
-{
-    // U+00DF LATIN SMALL LETTER SHARP S is uppercased to two 'S'.
-    MOZ_ASSERT(charCode == unicode::LATIN_SMALL_LETTER_SHARP_S);
-    static_assert('S' <= JSString::MAX_LATIN1_CHAR, "'S' is a Latin-1 character");
-
-    elements[(*index)++] = 'S';
-    elements[(*index)++] = 'S';
-}
-
-static inline void
-ToUpperCaseAppendUpperCaseSpecialCasing(char16_t charCode, char16_t* elements, size_t* index)
-{
-    unicode::AppendUpperCaseSpecialCasing(charCode, elements, index);
-}
-
-// See ToLowerCaseImpl for an explanation of the parameters.
-template <typename DestChar, typename SrcChar>
-static size_t
-ToUpperCaseImpl(DestChar* destChars, const SrcChar* srcChars, size_t startIndex, size_t srcLength,
-                size_t destLength)
-{
-    static_assert(IsSame<SrcChar, Latin1Char>::value || !IsSame<DestChar, Latin1Char>::value,
-                  "cannot write non-Latin-1 characters into Latin-1 string");
-    MOZ_ASSERT(startIndex < srcLength);
-    MOZ_ASSERT(srcLength <= destLength);
-
-    size_t j = startIndex;
-    for (size_t i = startIndex; i < srcLength; i++) {
-        char16_t c = srcChars[i];
-        if (!IsSame<DestChar, Latin1Char>::value) {
-            if (unicode::IsLeadSurrogate(c) && i + 1 < srcLength) {
-                char16_t trail = srcChars[i + 1];
-                if (unicode::IsTrailSurrogate(trail)) {
-                    trail = unicode::ToUpperCaseNonBMPTrail(c, trail);
-                    destChars[j++] = c;
-                    destChars[j++] = trail;
-                    i++;
-                    continue;
-                }
-            }
-        }
-
-        if (MOZ_UNLIKELY(c > 0x7f && ToUpperCaseHasSpecialCasing(static_cast<SrcChar>(c)))) {
-            // Return if the output buffer is too small.
-            if (srcLength == destLength) {
-                return i;
-            }
-
-            ToUpperCaseAppendUpperCaseSpecialCasing(c, destChars, &j);
-            continue;
-        }
-
-        c = unicode::ToUpperCase(c);
-        MOZ_ASSERT_IF((IsSame<DestChar, Latin1Char>::value), c <= JSString::MAX_LATIN1_CHAR);
-        destChars[j++] = c;
-    }
-
-    MOZ_ASSERT(j == destLength);
-    return srcLength;
-}
-
-// Explicit instantiation so we don't hit the static_assert from above.
-static bool
-ToUpperCaseImpl(Latin1Char* destChars, const char16_t* srcChars, size_t startIndex,
-                size_t srcLength, size_t destLength)
-{
-    MOZ_ASSERT_UNREACHABLE("cannot write non-Latin-1 characters into Latin-1 string");
-    return false;
-}
-
-template <typename CharT>
-static size_t
-ToUpperCaseLength(const CharT* chars, size_t startIndex, size_t length)
-{
-    size_t upperLength = length;
-    for (size_t i = startIndex; i < length; i++) {
-        char16_t c = chars[i];
-
-        if (c > 0x7f && ToUpperCaseHasSpecialCasing(static_cast<CharT>(c))) {
-            upperLength += ToUpperCaseLengthSpecialCasing(static_cast<CharT>(c)) - 1;
-        }
-    }
-    return upperLength;
-}
-
-template <typename DestChar, typename SrcChar>
-static inline void
-CopyChars(DestChar* destChars, const SrcChar* srcChars, size_t length)
-{
-    static_assert(!IsSame<DestChar, SrcChar>::value, "PodCopy is used for the same type case");
-    for (size_t i = 0; i < length; i++) {
-        destChars[i] = srcChars[i];
-    }
-}
-
-template <typename CharT>
-static inline void
-CopyChars(CharT* destChars, const CharT* srcChars, size_t length)
-{
-    PodCopy(destChars, srcChars, length);
-}
-
-template <typename DestChar, typename SrcChar>
-static inline bool
-ToUpperCase(JSContext* cx, InlineCharBuffer<DestChar>& newChars, const SrcChar* chars,
-            size_t startIndex, size_t length, size_t* resultLength)
-{
-    MOZ_ASSERT(startIndex < length);
-
-    *resultLength = length;
-    if (!newChars.maybeAlloc(cx, length)) {
-        return false;
-    }
-
-    CopyChars(newChars.get(), chars, startIndex);
-
-    size_t readChars = ToUpperCaseImpl(newChars.get(), chars, startIndex, length, length);
-    if (readChars < length) {
-        size_t actualLength = ToUpperCaseLength(chars, readChars, length);
-
-        *resultLength = actualLength;
-        if (!newChars.maybeRealloc(cx, length, actualLength)) {
-            return false;
-        }
-
-        MOZ_ALWAYS_TRUE(length ==
-            ToUpperCaseImpl(newChars.get(), chars, readChars, length, actualLength));
-    }
-
-    return true;
-}
-
-template <typename CharT>
-static JSString*
-ToUpperCase(JSContext* cx, JSLinearString* str)
-{
-    using Latin1Buffer = InlineCharBuffer<Latin1Char>;
-    using TwoByteBuffer = InlineCharBuffer<char16_t>;
-
-    mozilla::MaybeOneOf<Latin1Buffer, TwoByteBuffer> newChars;
-    const size_t length = str->length();
-    size_t resultLength;
-    {
-        AutoCheckCannotGC nogc;
-        const CharT* chars = str->chars<CharT>(nogc);
-
-        // Most one element Latin-1 strings can be directly retrieved from the
-        // static strings cache.
-        if (IsSame<CharT, Latin1Char>::value) {
-            if (length == 1) {
-                Latin1Char c = chars[0];
-                if (c != unicode::MICRO_SIGN &&
-                    c != unicode::LATIN_SMALL_LETTER_Y_WITH_DIAERESIS &&
-                    c != unicode::LATIN_SMALL_LETTER_SHARP_S)
-                {
-                    char16_t upper = unicode::ToUpperCase(c);
-                    MOZ_ASSERT(upper <= JSString::MAX_LATIN1_CHAR);
-                    MOZ_ASSERT(StaticStrings::hasUnit(upper));
-
-                    return cx->staticStrings().getUnit(upper);
-                }
-
-                MOZ_ASSERT(unicode::ToUpperCase(c) > JSString::MAX_LATIN1_CHAR ||
-                           ToUpperCaseHasSpecialCasing(c));
-            }
-        }
-
-        // Look for the first character that changes when uppercased.
-        size_t i = 0;
-        for (; i < length; i++) {
-            CharT c = chars[i];
-            if (!IsSame<CharT, Latin1Char>::value) {
-                if (unicode::IsLeadSurrogate(c) && i + 1 < length) {
-                    CharT trail = chars[i + 1];
-                    if (unicode::IsTrailSurrogate(trail)) {
-                        if (unicode::ChangesWhenUpperCasedNonBMP(c, trail)) {
-                            break;
-                        }
-
-                        i++;
-                        continue;
-                    }
-                }
-            }
-            if (unicode::ChangesWhenUpperCased(c)) {
-                break;
-            }
-            if (MOZ_UNLIKELY(c > 0x7f && ToUpperCaseHasSpecialCasing(c))) {
-                break;
-            }
-        }
-
-        // If no character needs to change, return the input string.
-        if (i == length) {
-            return str;
-        }
-
-        // The string changes when uppercased, so we must create a new string.
-        // Can it be Latin-1?
-        //
-        // If the original string is Latin-1, it can -- unless the string
-        // contains U+00B5 MICRO SIGN or U+00FF SMALL LETTER Y WITH DIAERESIS,
-        // the only Latin-1 codepoints that don't uppercase within Latin-1.
-        // Search for those codepoints to decide whether the new string can be
-        // Latin-1.
-        // If the original string is a two-byte string, its uppercase form is
-        // so rarely Latin-1 that we don't even consider creating a new
-        // Latin-1 string.
-        bool resultIsLatin1;
-        if (IsSame<CharT, Latin1Char>::value) {
-            resultIsLatin1 = true;
-            for (size_t j = i; j < length; j++) {
-                Latin1Char c = chars[j];
-                if (c == unicode::MICRO_SIGN ||
-                    c == unicode::LATIN_SMALL_LETTER_Y_WITH_DIAERESIS)
-                {
-                    MOZ_ASSERT(unicode::ToUpperCase(c) > JSString::MAX_LATIN1_CHAR);
-                    resultIsLatin1 = false;
-                    break;
-                } else {
-                    MOZ_ASSERT(unicode::ToUpperCase(c) <= JSString::MAX_LATIN1_CHAR);
-                }
-            }
-        } else {
-            resultIsLatin1 = false;
-        }
-
-        if (resultIsLatin1) {
-            newChars.construct<Latin1Buffer>();
-
-            if (!ToUpperCase(cx, newChars.ref<Latin1Buffer>(), chars, i, length, &resultLength)) {
-                return nullptr;
-            }
-        } else {
-            newChars.construct<TwoByteBuffer>();
-
-            if (!ToUpperCase(cx, newChars.ref<TwoByteBuffer>(), chars, i, length, &resultLength)) {
-                return nullptr;
-            }
-        }
-    }
-
-    return newChars.constructed<Latin1Buffer>()
-           ? newChars.ref<Latin1Buffer>().toStringDontDeflate(cx, resultLength)
-           : newChars.ref<TwoByteBuffer>().toStringDontDeflate(cx, resultLength);
-}
-
-JSString*
-js::StringToUpperCase(JSContext* cx, HandleString string)
-{
-    JSLinearString* linear = string->ensureLinear(cx);
-    if (!linear) {
-        return nullptr;
-    }
-
-    if (linear->hasLatin1Chars()) {
-        return ToUpperCase<Latin1Char>(cx, linear);
-    }
-    return ToUpperCase<char16_t>(cx, linear);
-}
-
-bool
-js::str_toUpperCase(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    JSString* result = StringToUpperCase(cx, str);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-bool
-js::intl_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].isString());
-    MOZ_ASSERT(args[1].isString());
-
-    RootedString string(cx, args[0].toString());
-
-    const char* locale = CaseMappingLocale(cx, args[1].toString());
-    if (!locale) {
-        return false;
-    }
-
-    // Call String.prototype.toUpperCase() for language independent casing.
-    if (intl::StringsAreEqual(locale, "")) {
-        JSString* str = js::StringToUpperCase(cx, string);
-        if (!str) {
-            return false;
-        }
-
-        args.rval().setString(str);
-        return true;
-    }
-
-    AutoStableStringChars inputChars(cx);
-    if (!inputChars.initTwoByte(cx, string)) {
-        return false;
-    }
-    mozilla::Range<const char16_t> input = inputChars.twoByteRange();
-
-    // Maximum case mapping length is three characters.
-    static_assert(JSString::MAX_LENGTH < INT32_MAX / 3,
-                  "Case conversion doesn't overflow int32_t indices");
-
-    static const size_t INLINE_CAPACITY = js::intl::INITIAL_CHAR_BUFFER_SIZE;
-
-    Vector<char16_t, INLINE_CAPACITY> chars(cx);
-    if (!chars.resize(Max(INLINE_CAPACITY, input.length()))) {
-        return false;
-    }
-
-    int32_t size =
-        intl::CallICU(cx, [&input, locale](UChar* chars, int32_t size, UErrorCode* status) {
-            return u_strToUpper(chars, size, input.begin().get(), input.length(), locale, status);
-        }, chars);
-    if (size < 0) {
-        return false;
-    }
-
-    JSString* result = NewStringCopyN<CanGC>(cx, chars.begin(), size);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-#if EXPOSE_INTL_API
-
-// String.prototype.toLocaleLowerCase is self-hosted when Intl is exposed,
-// with core functionality performed by the intrinsic above.
-
-#else
-
-bool
-js::str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    /*
-     * Forcefully ignore the first (or any) argument and return toUpperCase(),
-     * ECMA has reserved that argument, presumably for defining the locale.
-     */
-    if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUpperCase) {
-        RootedValue result(cx);
-        if (!cx->runtime()->localeCallbacks->localeToUpperCase(cx, str, &result)) {
-            return false;
-        }
-
-        args.rval().set(result);
-        return true;
-    }
-
-    RootedLinearString linear(cx, str->ensureLinear(cx));
-    if (!linear) {
-        return false;
-    }
-
-    JSString* result = StringToUpperCase(cx, linear);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-#endif // EXPOSE_INTL_API
-
-#if EXPOSE_INTL_API
-
-// String.prototype.localeCompare is self-hosted when Intl is exposed.
-
-#else
-
-bool
-js::str_localeCompare(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    RootedString thatStr(cx, ToString<CanGC>(cx, args.get(0)));
-    if (!thatStr) {
-        return false;
-    }
-
-    if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeCompare) {
-        RootedValue result(cx);
-        if (!cx->runtime()->localeCallbacks->localeCompare(cx, str, thatStr, &result)) {
-            return false;
-        }
-
-        args.rval().set(result);
-        return true;
-    }
-
-    int32_t result;
-    if (!CompareStrings(cx, str, thatStr, &result)) {
-        return false;
-    }
-
-    args.rval().setInt32(result);
-    return true;
-}
-
-#endif // EXPOSE_INTL_API
-
-#if EXPOSE_INTL_API
-
-// ES2017 draft rev 45e890512fd77add72cc0ee742785f9f6f6482de
-// 21.1.3.12 String.prototype.normalize ( [ form ] )
-bool
-js::str_normalize(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1-2.
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    enum NormalizationForm {
-        NFC, NFD, NFKC, NFKD
-    };
-
-    NormalizationForm form;
-    if (!args.hasDefined(0)) {
-        // Step 3.
-        form = NFC;
-    } else {
-        // Step 4.
-        JSLinearString* formStr = ArgToLinearString(cx, args, 0);
-        if (!formStr) {
-            return false;
-        }
-
-        // Step 5.
-        if (EqualStrings(formStr, cx->names().NFC)) {
-            form = NFC;
-        } else if (EqualStrings(formStr, cx->names().NFD)) {
-            form = NFD;
-        } else if (EqualStrings(formStr, cx->names().NFKC)) {
-            form = NFKC;
-        } else if (EqualStrings(formStr, cx->names().NFKD)) {
-            form = NFKD;
-        } else {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INVALID_NORMALIZE_FORM);
-            return false;
-        }
-    }
-
-    // Latin-1 strings are already in Normalization Form C.
-    if (form == NFC && str->hasLatin1Chars()) {
-        // Step 7.
-        args.rval().setString(str);
-        return true;
-    }
-
-    // Step 6.
-    AutoStableStringChars stableChars(cx);
-    if (!stableChars.initTwoByte(cx, str)) {
-        return false;
-    }
-
-    mozilla::Range<const char16_t> srcChars = stableChars.twoByteRange();
-
-    // The unorm2_getXXXInstance() methods return a shared instance which must
-    // not be deleted.
-    UErrorCode status = U_ZERO_ERROR;
-    const UNormalizer2* normalizer;
-    if (form == NFC) {
-        normalizer = unorm2_getNFCInstance(&status);
-    } else if (form == NFD) {
-        normalizer = unorm2_getNFDInstance(&status);
-    } else if (form == NFKC) {
-        normalizer = unorm2_getNFKCInstance(&status);
-    } else {
-        MOZ_ASSERT(form == NFKD);
-        normalizer = unorm2_getNFKDInstance(&status);
-    }
-    if (U_FAILURE(status)) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
-        return false;
-    }
-
-    int32_t spanLengthInt = unorm2_spanQuickCheckYes(normalizer,
-                                                     srcChars.begin().get(), srcChars.length(),
-                                                     &status);
-    if (U_FAILURE(status)) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
-        return false;
-    }
-    MOZ_ASSERT(0 <= spanLengthInt && size_t(spanLengthInt) <= srcChars.length());
-    size_t spanLength = size_t(spanLengthInt);
-
-    // Return if the input string is already normalized.
-    if (spanLength == srcChars.length()) {
-        // Step 7.
-        args.rval().setString(str);
-        return true;
-    }
-
-    static const size_t INLINE_CAPACITY = js::intl::INITIAL_CHAR_BUFFER_SIZE;
-
-    Vector<char16_t, INLINE_CAPACITY> chars(cx);
-    if (!chars.resize(Max(INLINE_CAPACITY, srcChars.length()))) {
-        return false;
-    }
-
-    // Copy the already normalized prefix.
-    if (spanLength > 0) {
-        PodCopy(chars.begin(), srcChars.begin().get(), spanLength);
-    }
-
-    int32_t size =
-        intl::CallICU(cx, [normalizer, &srcChars, spanLength](UChar* chars, uint32_t size,
-                                                              UErrorCode* status)
-        {
-            mozilla::RangedPtr<const char16_t> remainingStart = srcChars.begin() + spanLength;
-            size_t remainingLength = srcChars.length() - spanLength;
-
-            return unorm2_normalizeSecondAndAppend(normalizer, chars, spanLength, size,
-                                                   remainingStart.get(), remainingLength, status);
-        }, chars);
-    if (size < 0) {
-        return false;
-    }
-
-    JSString* ns = NewStringCopyN<CanGC>(cx, chars.begin(), size);
-    if (!ns) {
-        return false;
-    }
-
-    // Step 7.
-    args.rval().setString(ns);
-    return true;
-}
-
-#endif // EXPOSE_INTL_API
-
-bool
-js::str_charAt(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedString str(cx);
-    size_t i;
-    if (args.thisv().isString() && args.length() != 0 && args[0].isInt32()) {
-        str = args.thisv().toString();
-        i = size_t(args[0].toInt32());
-        if (i >= str->length()) {
-            goto out_of_range;
-        }
-    } else {
-        str = ToStringForStringFunction(cx, args.thisv());
-        if (!str) {
-            return false;
-        }
-
-        double d = 0.0;
-        if (args.length() > 0 && !ToInteger(cx, args[0], &d)) {
-            return false;
-        }
-
-        if (d < 0 || str->length() <= d) {
-            goto out_of_range;
-        }
-        i = size_t(d);
-    }
-
-    str = cx->staticStrings().getUnitStringForElement(cx, str, i);
-    if (!str) {
-        return false;
-    }
-    args.rval().setString(str);
-    return true;
-
-  out_of_range:
-    args.rval().setString(cx->runtime()->emptyString);
-    return true;
-}
-
-bool
-js::str_charCodeAt_impl(JSContext* cx, HandleString string, HandleValue index, MutableHandleValue res)
-{
-    size_t i;
-    if (index.isInt32()) {
-        i = index.toInt32();
-        if (i >= string->length()) {
-            goto out_of_range;
-        }
-    } else {
-        double d = 0.0;
-        if (!ToInteger(cx, index, &d)) {
-            return false;
-        }
-        // check whether d is negative as size_t is unsigned
-        if (d < 0 || string->length() <= d ) {
-            goto out_of_range;
-        }
-        i = size_t(d);
-    }
-    char16_t c;
-    if (!string->getChar(cx, i , &c)) {
-        return false;
-    }
-    res.setInt32(c);
-    return true;
-
-out_of_range:
-    res.setNaN();
-    return true;
-}
-
-bool
-js::str_charCodeAt(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedString str(cx);
-    RootedValue index(cx);
-    if (args.thisv().isString()) {
-        str = args.thisv().toString();
-    } else {
-        str = ToStringForStringFunction(cx, args.thisv());
-        if (!str) {
-            return false;
-        }
-    }
-    if (args.length() != 0) {
-        index = args[0];
-    } else {
-        index.setInt32(0);
-    }
-
-    return js::str_charCodeAt_impl(cx, str, index, args.rval());
-}
-
-/*
- * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen.
- * The patlen argument must be positive and no greater than sBMHPatLenMax.
- *
- * Return the index of pat in text, or -1 if not found.
- */
-static const uint32_t sBMHCharSetSize = 256; /* ISO-Latin-1 */
-static const uint32_t sBMHPatLenMax   = 255; /* skip table element is uint8_t */
-static const int      sBMHBadPattern  = -2;  /* return value if pat is not ISO-Latin-1 */
-
-template <typename TextChar, typename PatChar>
-static int
-BoyerMooreHorspool(const TextChar* text, uint32_t textLen, const PatChar* pat, uint32_t patLen)
-{
-    MOZ_ASSERT(0 < patLen && patLen <= sBMHPatLenMax);
-
-    uint8_t skip[sBMHCharSetSize];
-    for (uint32_t i = 0; i < sBMHCharSetSize; i++) {
-        skip[i] = uint8_t(patLen);
-    }
-
-    uint32_t patLast = patLen - 1;
-    for (uint32_t i = 0; i < patLast; i++) {
-        char16_t c = pat[i];
-        if (c >= sBMHCharSetSize) {
-            return sBMHBadPattern;
-        }
-        skip[c] = uint8_t(patLast - i);
-    }
-
-    for (uint32_t k = patLast; k < textLen; ) {
-        for (uint32_t i = k, j = patLast; ; i--, j--) {
-            if (text[i] != pat[j]) {
-                break;
-            }
-            if (j == 0) {
-                return static_cast<int>(i);  /* safe: max string size */
-            }
-        }
-
-        char16_t c = text[k];
-        k += (c >= sBMHCharSetSize) ? patLen : skip[c];
-    }
-    return -1;
-}
-
-template <typename TextChar, typename PatChar>
-struct MemCmp {
-    typedef uint32_t Extent;
-    static MOZ_ALWAYS_INLINE Extent computeExtent(const PatChar*, uint32_t patLen) {
-        return (patLen - 1) * sizeof(PatChar);
-    }
-    static MOZ_ALWAYS_INLINE bool match(const PatChar* p, const TextChar* t, Extent extent) {
-        MOZ_ASSERT(sizeof(TextChar) == sizeof(PatChar));
-        return memcmp(p, t, extent) == 0;
-    }
-};
-
-template <typename TextChar, typename PatChar>
-struct ManualCmp {
-    typedef const PatChar* Extent;
-    static MOZ_ALWAYS_INLINE Extent computeExtent(const PatChar* pat, uint32_t patLen) {
-        return pat + patLen;
-    }
-    static MOZ_ALWAYS_INLINE bool match(const PatChar* p, const TextChar* t, Extent extent) {
-        for (; p != extent; ++p, ++t) {
-            if (*p != *t) {
-                return false;
-            }
-        }
-        return true;
-    }
-};
-
-template <typename TextChar, typename PatChar>
-static const TextChar*
-FirstCharMatcherUnrolled(const TextChar* text, uint32_t n, const PatChar pat)
-{
-    const TextChar* textend = text + n;
-    const TextChar* t = text;
-
-    switch ((textend - t) & 7) {
-        case 0: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 7: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 6: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 5: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 4: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 3: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 2: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
-        case 1: if (*t++ == pat) return t - 1;
-    }
-    while (textend != t) {
-        if (t[0] == pat) return t;
-        if (t[1] == pat) return t + 1;
-        if (t[2] == pat) return t + 2;
-        if (t[3] == pat) return t + 3;
-        if (t[4] == pat) return t + 4;
-        if (t[5] == pat) return t + 5;
-        if (t[6] == pat) return t + 6;
-        if (t[7] == pat) return t + 7;
-        t += 8;
-    }
-    return nullptr;
-}
-
-static const char*
-FirstCharMatcher8bit(const char* text, uint32_t n, const char pat)
-{
-    return reinterpret_cast<const char*>(memchr(text, pat, n));
-}
-
-template <class InnerMatch, typename TextChar, typename PatChar>
-static int
-Matcher(const TextChar* text, uint32_t textlen, const PatChar* pat, uint32_t patlen)
-{
-    MOZ_ASSERT(patlen > 0);
-
-    if (sizeof(TextChar) == 1 && sizeof(PatChar) > 1 && pat[0] > 0xff) {
-        return -1;
-    }
-
-    const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen);
-
-    uint32_t i = 0;
-    uint32_t n = textlen - patlen + 1;
-    while (i < n) {
-        const TextChar* pos;
-
-        if (sizeof(TextChar) == 1) {
-            MOZ_ASSERT(pat[0] <= 0xff);
-            pos = (TextChar*) FirstCharMatcher8bit((char*) text + i, n - i, pat[0]);
-        } else {
-            pos = FirstCharMatcherUnrolled(text + i, n - i, char16_t(pat[0]));
-        }
-
-        if (pos == nullptr) {
-            return -1;
-        }
-
-        i = static_cast<uint32_t>(pos - text);
-        if (InnerMatch::match(pat + 1, text + i + 1, extent)) {
-            return i;
-        }
-
-        i += 1;
-     }
-     return -1;
- }
-
-
-template <typename TextChar, typename PatChar>
-static MOZ_ALWAYS_INLINE int
-StringMatch(const TextChar* text, uint32_t textLen, const PatChar* pat, uint32_t patLen)
-{
-    if (patLen == 0) {
-        return 0;
-    }
-    if (textLen < patLen) {
-        return -1;
-    }
-
-#if defined(__i386__) || defined(_M_IX86) || defined(__i386)
-    /*
-     * Given enough registers, the unrolled loop below is faster than the
-     * following loop. 32-bit x86 does not have enough registers.
-     */
-    if (patLen == 1) {
-        const PatChar p0 = *pat;
-        const TextChar* end = text + textLen;
-        for (const TextChar* c = text; c != end; ++c) {
-            if (*c == p0) {
-                return c - text;
-            }
-        }
-        return -1;
-    }
-#endif
-
-    /*
-     * If the text or pattern string is short, BMH will be more expensive than
-     * the basic linear scan due to initialization cost and a more complex loop
-     * body. While the correct threshold is input-dependent, we can make a few
-     * conservative observations:
-     *  - When |textLen| is "big enough", the initialization time will be
-     *    proportionally small, so the worst-case slowdown is minimized.
-     *  - When |patLen| is "too small", even the best case for BMH will be
-     *    slower than a simple scan for large |textLen| due to the more complex
-     *    loop body of BMH.
-     * From this, the values for "big enough" and "too small" are determined
-     * empirically. See bug 526348.
-     */
-    if (textLen >= 512 && patLen >= 11 && patLen <= sBMHPatLenMax) {
-        int index = BoyerMooreHorspool(text, textLen, pat, patLen);
-        if (index != sBMHBadPattern) {
-            return index;
-        }
-    }
-
-    /*
-     * For big patterns with large potential overlap we want the SIMD-optimized
-     * speed of memcmp. For small patterns, a simple loop is faster. We also can't
-     * use memcmp if one of the strings is TwoByte and the other is Latin-1.
-     */
-    return (patLen > 128 && IsSame<TextChar, PatChar>::value)
-           ? Matcher<MemCmp<TextChar, PatChar>, TextChar, PatChar>(text, textLen, pat, patLen)
-           : Matcher<ManualCmp<TextChar, PatChar>, TextChar, PatChar>(text, textLen, pat, patLen);
-}
-
-static int32_t
-StringMatch(JSLinearString* text, JSLinearString* pat, uint32_t start = 0)
-{
-    MOZ_ASSERT(start <= text->length());
-    uint32_t textLen = text->length() - start;
-    uint32_t patLen = pat->length();
-
-    int match;
-    AutoCheckCannotGC nogc;
-    if (text->hasLatin1Chars()) {
-        const Latin1Char* textChars = text->latin1Chars(nogc) + start;
-        if (pat->hasLatin1Chars()) {
-            match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
-        } else {
-            match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
-        }
-    } else {
-        const char16_t* textChars = text->twoByteChars(nogc) + start;
-        if (pat->hasLatin1Chars()) {
-            match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
-        } else {
-            match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
-        }
-    }
-
-    return (match == -1) ? -1 : start + match;
-}
-
-static const size_t sRopeMatchThresholdRatioLog2 = 4;
-
-int
-js::StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start)
-{
-    return StringMatch(text, pat, start);
-}
-
-// When an algorithm does not need a string represented as a single linear
-// array of characters, this range utility may be used to traverse the string a
-// sequence of linear arrays of characters. This avoids flattening ropes.
-class StringSegmentRange
-{
-    // If malloc() shows up in any profiles from this vector, we can add a new
-    // StackAllocPolicy which stashes a reusable freed-at-gc buffer in the cx.
-    using StackVector = JS::GCVector<JSString*, 16>;
-    Rooted<StackVector> stack;
-    RootedLinearString cur;
-
-    bool settle(JSString* str) {
-        while (str->isRope()) {
-            JSRope& rope = str->asRope();
-            if (!stack.append(rope.rightChild())) {
-                return false;
-            }
-            str = rope.leftChild();
-        }
-        cur = &str->asLinear();
-        return true;
-    }
-
-  public:
-    explicit StringSegmentRange(JSContext* cx)
-      : stack(cx, StackVector(cx)), cur(cx)
-    {}
-
-    MOZ_MUST_USE bool init(JSString* str) {
-        MOZ_ASSERT(stack.empty());
-        return settle(str);
-    }
-
-    bool empty() const {
-        return cur == nullptr;
-    }
-
-    JSLinearString* front() const {
-        MOZ_ASSERT(!cur->isRope());
-        return cur;
-    }
-
-    MOZ_MUST_USE bool popFront() {
-        MOZ_ASSERT(!empty());
-        if (stack.empty()) {
-            cur = nullptr;
-            return true;
-        }
-        return settle(stack.popCopy());
-    }
-};
-
-typedef Vector<JSLinearString*, 16, SystemAllocPolicy> LinearStringVector;
-
-template <typename TextChar, typename PatChar>
-static int
-RopeMatchImpl(const AutoCheckCannotGC& nogc, LinearStringVector& strings,
-              const PatChar* pat, size_t patLen)
-{
-    /* Absolute offset from the beginning of the logical text string. */
-    int pos = 0;
-
-    for (JSLinearString** outerp = strings.begin(); outerp != strings.end(); ++outerp) {
-        /* Try to find a match within 'outer'. */
-        JSLinearString* outer = *outerp;
-        const TextChar* chars = outer->chars<TextChar>(nogc);
-        size_t len = outer->length();
-        int matchResult = StringMatch(chars, len, pat, patLen);
-        if (matchResult != -1) {
-            /* Matched! */
-            return pos + matchResult;
-        }
-
-        /* Try to find a match starting in 'outer' and running into other nodes. */
-        const TextChar* const text = chars + (patLen > len ? 0 : len - patLen + 1);
-        const TextChar* const textend = chars + len;
-        const PatChar p0 = *pat;
-        const PatChar* const p1 = pat + 1;
-        const PatChar* const patend = pat + patLen;
-        for (const TextChar* t = text; t != textend; ) {
-            if (*t++ != p0) {
-                continue;
-            }
-
-            JSLinearString** innerp = outerp;
-            const TextChar* ttend = textend;
-            const TextChar* tt = t;
-            for (const PatChar* pp = p1; pp != patend; ++pp, ++tt) {
-                while (tt == ttend) {
-                    if (++innerp == strings.end()) {
-                        return -1;
-                    }
-
-                    JSLinearString* inner = *innerp;
-                    tt = inner->chars<TextChar>(nogc);
-                    ttend = tt + inner->length();
-                }
-                if (*pp != *tt) {
-                    goto break_continue;
-                }
-            }
-
-            /* Matched! */
-            return pos + (t - chars) - 1;  /* -1 because of *t++ above */
-
-          break_continue:;
-        }
-
-        pos += len;
-    }
-
-    return -1;
-}
-
-/*
- * RopeMatch takes the text to search and the pattern to search for in the text.
- * RopeMatch returns false on OOM and otherwise returns the match index through
- * the 'match' outparam (-1 for not found).
- */
-static bool
-RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match)
-{
-    uint32_t patLen = pat->length();
-    if (patLen == 0) {
-        *match = 0;
-        return true;
-    }
-    if (text->length() < patLen) {
-        *match = -1;
-        return true;
-    }
-
-    /*
-     * List of leaf nodes in the rope. If we run out of memory when trying to
-     * append to this list, we can still fall back to StringMatch, so use the
-     * system allocator so we don't report OOM in that case.
-     */
-    LinearStringVector strings;
-
-    /*
-     * We don't want to do rope matching if there is a poor node-to-char ratio,
-     * since this means spending a lot of time in the match loop below. We also
-     * need to build the list of leaf nodes. Do both here: iterate over the
-     * nodes so long as there are not too many.
-     *
-     * We also don't use rope matching if the rope contains both Latin-1 and
-     * TwoByte nodes, to simplify the match algorithm.
-     */
-    {
-        size_t threshold = text->length() >> sRopeMatchThresholdRatioLog2;
-        StringSegmentRange r(cx);
-        if (!r.init(text)) {
-            return false;
-        }
-
-        bool textIsLatin1 = text->hasLatin1Chars();
-        while (!r.empty()) {
-            if (threshold-- == 0 ||
-                r.front()->hasLatin1Chars() != textIsLatin1 ||
-                !strings.append(r.front()))
-            {
-                JSLinearString* linear = text->ensureLinear(cx);
-                if (!linear) {
-                    return false;
-                }
-
-                *match = StringMatch(linear, pat);
-                return true;
-            }
-            if (!r.popFront()) {
-                return false;
-            }
-        }
-    }
-
-    AutoCheckCannotGC nogc;
-    if (text->hasLatin1Chars()) {
-        if (pat->hasLatin1Chars()) {
-            *match = RopeMatchImpl<Latin1Char>(nogc, strings, pat->latin1Chars(nogc), patLen);
-        } else {
-            *match = RopeMatchImpl<Latin1Char>(nogc, strings, pat->twoByteChars(nogc), patLen);
-        }
-    } else {
-        if (pat->hasLatin1Chars()) {
-            *match = RopeMatchImpl<char16_t>(nogc, strings, pat->latin1Chars(nogc), patLen);
-        } else {
-            *match = RopeMatchImpl<char16_t>(nogc, strings, pat->twoByteChars(nogc), patLen);
-        }
-    }
-
-    return true;
-}
-
-static MOZ_ALWAYS_INLINE bool
-ReportErrorIfFirstArgIsRegExp(JSContext* cx, const CallArgs& args)
-{
-    // Only call IsRegExp if the first argument is definitely an object, so we
-    // don't pay the cost of an additional function call in the common case.
-    if (args.length() == 0 || !args[0].isObject()) {
-        return true;
-    }
-
-    bool isRegExp;
-    if (!IsRegExp(cx, args[0], &isRegExp)) {
-        return false;
-    }
-
-    if (isRegExp) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
-                                  "first", "", "Regular Expression");
-        return false;
-    }
-    return true;
-}
-
-// ES2018 draft rev de77aaeffce115deaf948ed30c7dbe4c60983c0c
-// 21.1.3.7 String.prototype.includes ( searchString [ , position ] )
-bool
-js::str_includes(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1-2.
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    // Steps 3-4.
-    if (!ReportErrorIfFirstArgIsRegExp(cx, args)) {
-        return false;
-    }
-
-    // Step 5.
-    RootedLinearString searchStr(cx, ArgToLinearString(cx, args, 0));
-    if (!searchStr) {
-        return false;
-    }
-
-    // Step 6.
-    uint32_t pos = 0;
-    if (args.hasDefined(1)) {
-        if (args[1].isInt32()) {
-            int i = args[1].toInt32();
-            pos = (i < 0) ? 0U : uint32_t(i);
-        } else {
-            double d;
-            if (!ToInteger(cx, args[1], &d)) {
-                return false;
-            }
-            pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
-        }
-    }
+} /* namespace js */
 
-    // Step 7.
-    uint32_t textLen = str->length();
-
-    // Step 8.
-    uint32_t start = Min(Max(pos, 0U), textLen);
-
-    // Steps 9-10.
-    JSLinearString* text = str->ensureLinear(cx);
-    if (!text) {
-        return false;
-    }
-
-    args.rval().setBoolean(StringMatch(text, searchStr, start) != -1);
-    return true;
-}
-
-/* ES6 20120927 draft 15.5.4.7. */
-bool
-js::str_indexOf(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1, 2, and 3
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    // Steps 4 and 5
-    RootedLinearString searchStr(cx, ArgToLinearString(cx, args, 0));
-    if (!searchStr) {
-        return false;
-    }
-
-    // Steps 6 and 7
-    uint32_t pos = 0;
-    if (args.hasDefined(1)) {
-        if (args[1].isInt32()) {
-            int i = args[1].toInt32();
-            pos = (i < 0) ? 0U : uint32_t(i);
-        } else {
-            double d;
-            if (!ToInteger(cx, args[1], &d)) {
-                return false;
-            }
-            pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
-        }
-    }
-
-   // Step 8
-    uint32_t textLen = str->length();
-
-    // Step 9
-    uint32_t start = Min(Max(pos, 0U), textLen);
-
-    if (str == searchStr) {
-        // AngularJS often invokes "false".indexOf("false"). This check should
-        // be cheap enough to not hurt anything else.
-        args.rval().setInt32(start == 0 ? 0 : -1);
-        return true;
-    }
-
-    // Steps 10 and 11
-    JSLinearString* text = str->ensureLinear(cx);
-    if (!text) {
-        return false;
-    }
-
-    args.rval().setInt32(StringMatch(text, searchStr, start));
-    return true;
-}
-
-template <typename TextChar, typename PatChar>
-static int32_t
-LastIndexOfImpl(const TextChar* text, size_t textLen, const PatChar* pat, size_t patLen,
-                size_t start)
-{
-    MOZ_ASSERT(patLen > 0);
-    MOZ_ASSERT(patLen <= textLen);
-    MOZ_ASSERT(start <= textLen - patLen);
-
-    const PatChar p0 = *pat;
-    const PatChar* patNext = pat + 1;
-    const PatChar* patEnd = pat + patLen;
-
-    for (const TextChar* t = text + start; t >= text; --t) {
-        if (*t == p0) {
-            const TextChar* t1 = t + 1;
-            for (const PatChar* p1 = patNext; p1 < patEnd; ++p1, ++t1) {
-                if (*t1 != *p1) {
-                    goto break_continue;
-                }
-            }
-
-            return static_cast<int32_t>(t - text);
-        }
-      break_continue:;
-    }
-
-    return -1;
-}
-
-// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
-// 21.1.3.9 String.prototype.lastIndexOf ( searchString [ , position ] )
-bool
-js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1-2.
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    // Step 3.
-    RootedLinearString searchStr(cx, ArgToLinearString(cx, args, 0));
-    if (!searchStr) {
-        return false;
-    }
-
-    // Step 6.
-    size_t len = str->length();
-
-    // Step 8.
-    size_t searchLen = searchStr->length();
-
-    // Steps 4-5, 7.
-    int start = len - searchLen; // Start searching here
-    if (args.hasDefined(1)) {
-        if (args[1].isInt32()) {
-            int i = args[1].toInt32();
-            if (i <= 0) {
-                start = 0;
-            } else if (i < start) {
-                start = i;
-            }
-        } else {
-            double d;
-            if (!ToNumber(cx, args[1], &d)) {
-                return false;
-            }
-            if (!IsNaN(d)) {
-                d = JS::ToInteger(d);
-                if (d <= 0) {
-                    start = 0;
-                } else if (d < start) {
-                    start = int(d);
-                }
-            }
-        }
-    }
-
-    if (str == searchStr) {
-        args.rval().setInt32(0);
-        return true;
-    }
-
-    if (searchLen > len) {
-        args.rval().setInt32(-1);
-        return true;
-    }
-
-    if (searchLen == 0) {
-        args.rval().setInt32(start);
-        return true;
-    }
-    MOZ_ASSERT(0 <= start && size_t(start) < len);
-
-    JSLinearString* text = str->ensureLinear(cx);
-    if (!text) {
-        return false;
-    }
-
-    // Step 9.
-    int32_t res;
-    AutoCheckCannotGC nogc;
-    if (text->hasLatin1Chars()) {
-        const Latin1Char* textChars = text->latin1Chars(nogc);
-        if (searchStr->hasLatin1Chars()) {
-            res = LastIndexOfImpl(textChars, len, searchStr->latin1Chars(nogc), searchLen, start);
-        } else {
-            res = LastIndexOfImpl(textChars, len, searchStr->twoByteChars(nogc), searchLen, start);
-        }
-    } else {
-        const char16_t* textChars = text->twoByteChars(nogc);
-        if (searchStr->hasLatin1Chars()) {
-            res = LastIndexOfImpl(textChars, len, searchStr->latin1Chars(nogc), searchLen, start);
-        } else {
-            res = LastIndexOfImpl(textChars, len, searchStr->twoByteChars(nogc), searchLen, start);
-        }
-    }
-
-    args.rval().setInt32(res);
-    return true;
-}
-
-// ES2018 draft rev de77aaeffce115deaf948ed30c7dbe4c60983c0c
-// 21.1.3.20 String.prototype.startsWith ( searchString [ , position ] )
-bool
-js::str_startsWith(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1-2.
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    // Steps 3-4.
-    if (!ReportErrorIfFirstArgIsRegExp(cx, args)) {
-        return false;
-    }
-
-    // Step 5.
-    RootedLinearString searchStr(cx, ArgToLinearString(cx, args, 0));
-    if (!searchStr) {
-        return false;
-    }
-
-    // Step 6.
-    uint32_t pos = 0;
-    if (args.hasDefined(1)) {
-        if (args[1].isInt32()) {
-            int i = args[1].toInt32();
-            pos = (i < 0) ? 0U : uint32_t(i);
-        } else {
-            double d;
-            if (!ToInteger(cx, args[1], &d)) {
-                return false;
-            }
-            pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
-        }
-    }
-
-    // Step 7.
-    uint32_t textLen = str->length();
-
-    // Step 8.
-    uint32_t start = Min(Max(pos, 0U), textLen);
-
-    // Step 9.
-    uint32_t searchLen = searchStr->length();
-
-    // Step 10.
-    if (searchLen + start < searchLen || searchLen + start > textLen) {
-        args.rval().setBoolean(false);
-        return true;
-    }
-
-    // Steps 11-12.
-    JSLinearString* text = str->ensureLinear(cx);
-    if (!text) {
-        return false;
-    }
-
-    args.rval().setBoolean(HasSubstringAt(text, searchStr, start));
-    return true;
-}
-
-// ES2018 draft rev de77aaeffce115deaf948ed30c7dbe4c60983c0c
-// 21.1.3.6 String.prototype.endsWith ( searchString [ , endPosition ] )
-bool
-js::str_endsWith(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1-2.
-    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!str) {
-        return false;
-    }
-
-    // Steps 3-4.
-    if (!ReportErrorIfFirstArgIsRegExp(cx, args)) {
-        return false;
-    }
-
-    // Step 5.
-    RootedLinearString searchStr(cx, ArgToLinearString(cx, args, 0));
-    if (!searchStr) {
-        return false;
-    }
-
-    // Step 6.
-    uint32_t textLen = str->length();
-
-    // Step 7.
-    uint32_t pos = textLen;
-    if (args.hasDefined(1)) {
-        if (args[1].isInt32()) {
-            int i = args[1].toInt32();
-            pos = (i < 0) ? 0U : uint32_t(i);
-        } else {
-            double d;
-            if (!ToInteger(cx, args[1], &d)) {
-                return false;
-            }
-            pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
-        }
-    }
-
-    // Step 8.
-    uint32_t end = Min(Max(pos, 0U), textLen);
-
-    // Step 9.
-    uint32_t searchLen = searchStr->length();
-
-    // Step 11 (reordered).
-    if (searchLen > end) {
-        args.rval().setBoolean(false);
-        return true;
-    }
-
-    // Step 10.
-    uint32_t start = end - searchLen;
-
-    // Steps 12-13.
-    JSLinearString* text = str->ensureLinear(cx);
-    if (!text) {
-        return false;
-    }
-
-    args.rval().setBoolean(HasSubstringAt(text, searchStr, start));
-    return true;
-}
-
-template <typename CharT>
-static void
-TrimString(const CharT* chars, bool trimStart, bool trimEnd, size_t length,
-           size_t* pBegin, size_t* pEnd)
-{
-    size_t begin = 0, end = length;
-
-    if (trimStart) {
-        while (begin < length && unicode::IsSpace(chars[begin])) {
-            ++begin;
-        }
-    }
-
-    if (trimEnd) {
-        while (end > begin && unicode::IsSpace(chars[end - 1])) {
-            --end;
-        }
-    }
-
-    *pBegin = begin;
-    *pEnd = end;
-}
-
-static bool
-TrimString(JSContext* cx, const CallArgs& args, bool trimStart, bool trimEnd)
-{
-    JSString* str = ToStringForStringFunction(cx, args.thisv());
-    if (!str) {
-        return false;
-    }
-
-    JSLinearString* linear = str->ensureLinear(cx);
-    if (!linear) {
-        return false;
-    }
-
-    size_t length = linear->length();
-    size_t begin, end;
-    if (linear->hasLatin1Chars()) {
-        AutoCheckCannotGC nogc;
-        TrimString(linear->latin1Chars(nogc), trimStart, trimEnd, length, &begin, &end);
-    } else {
-        AutoCheckCannotGC nogc;
-        TrimString(linear->twoByteChars(nogc), trimStart, trimEnd, length, &begin, &end);
-    }
-
-    JSLinearString* result = NewDependentString(cx, linear, begin, end - begin);
-    if (!result) {
-        return false;
-    }
-
-    args.rval().setString(result);
-    return true;
-}
-
-bool
-js::str_trim(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return TrimString(cx, args, true, true);
-}
-
-bool
-js::str_trimStart(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return TrimString(cx, args, true, false);
-}
-
-bool
-js::str_trimEnd(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return TrimString(cx, args, false, true);
-}
-
-// Utility for building a rope (lazy concatenation) of strings.
-class RopeBuilder
-{
-    JSContext* cx;
-    RootedString res;
-
-    RopeBuilder(const RopeBuilder& other) = delete;
-    void operator=(const RopeBuilder& other) = delete;
-
-  public:
-    explicit RopeBuilder(JSContext* cx)
-      : cx(cx), res(cx, cx->runtime()->emptyString)
-    {}
-
-    inline bool append(HandleString str) {
-        res = ConcatStrings<CanGC>(cx, res, str);
-        return !!res;
-    }
-
-    inline JSString* result() {
-        return res;
-    }
-};
-
-namespace {
-
-template <typename CharT>
-static uint32_t
-FindDollarIndex(const CharT* chars, size_t length)
-{
-    if (const CharT* p = js_strchr_limit(chars, '$', chars + length)) {
-        uint32_t dollarIndex = p - chars;
-        MOZ_ASSERT(dollarIndex < length);
-        return dollarIndex;
-    }
-    return UINT32_MAX;
-}
-
-} /* anonymous namespace */
-
-/*
- * Constructs a result string that looks like:
- *
- *      newstring = string[:matchStart] + repstr + string[matchEnd:]
- */
-static JSString*
-BuildFlatReplacement(JSContext* cx, HandleString textstr, HandleLinearString repstr,
-                     size_t matchStart, size_t patternLength)
-{
-    size_t matchEnd = matchStart + patternLength;
-
-    RootedString resultStr(cx, NewDependentString(cx, textstr, 0, matchStart));
-    if (!resultStr) {
-        return nullptr;
-    }
-
-    resultStr = ConcatStrings<CanGC>(cx, resultStr, repstr);
-    if (!resultStr) {
-        return nullptr;
-    }
-
-    MOZ_ASSERT(textstr->length() >= matchEnd);
-    RootedString rest(cx, NewDependentString(cx, textstr, matchEnd, textstr->length() - matchEnd));
-    if (!rest) {
-        return nullptr;
-    }
-
-    return ConcatStrings<CanGC>(cx, resultStr, rest);
-}
-
-static JSString*
-BuildFlatRopeReplacement(JSContext* cx, HandleString textstr, HandleLinearString repstr,
-                         size_t match, size_t patternLength)
-{
-    MOZ_ASSERT(textstr->isRope());
-
-    size_t matchEnd = match + patternLength;
-
-    /*
-     * If we are replacing over a rope, avoid flattening it by iterating
-     * through it, building a new rope.
-     */
-    StringSegmentRange r(cx);
-    if (!r.init(textstr)) {
-        return nullptr;
-    }
-
-    RopeBuilder builder(cx);
-    size_t pos = 0;
-    while (!r.empty()) {
-        RootedString str(cx, r.front());
-        size_t len = str->length();
-        size_t strEnd = pos + len;
-        if (pos < matchEnd && strEnd > match) {
-            /*
-             * We need to special-case any part of the rope that overlaps
-             * with the replacement string.
-             */
-            if (match >= pos) {
-                /*
-                 * If this part of the rope overlaps with the left side of
-                 * the pattern, then it must be the only one to overlap with
-                 * the first character in the pattern, so we include the
-                 * replacement string here.
-                 */
-                RootedString leftSide(cx, NewDependentString(cx, str, 0, match - pos));
-                if (!leftSide ||
-                    !builder.append(leftSide) ||
-                    !builder.append(repstr))
-                {
-                    return nullptr;
-                }
-            }
-
-            /*
-             * If str runs off the end of the matched string, append the
-             * last part of str.
-             */
-            if (strEnd > matchEnd) {
-                RootedString rightSide(cx, NewDependentString(cx, str, matchEnd - pos,
-                                                              strEnd - matchEnd));
-                if (!rightSide || !builder.append(rightSide)) {
-                    return nullptr;
-                }
-            }
-        } else {
-            if (!builder.append(str)) {
-                return nullptr;
-            }
-        }
-        pos += str->length();
-        if (!r.popFront()) {
-            return nullptr;
-        }
-    }
-
-    return builder.result();
-}
-
-template <typename CharT>
-static bool
-AppendDollarReplacement(StringBuffer& newReplaceChars, size_t firstDollarIndex,
-                        size_t matchStart, size_t matchLimit, JSLinearString* text,
-                        const CharT* repChars, size_t repLength)
-{
-    MOZ_ASSERT(firstDollarIndex < repLength);
-
-    /* Move the pre-dollar chunk in bulk. */
-    newReplaceChars.infallibleAppend(repChars, firstDollarIndex);
-
-    /* Move the rest char-by-char, interpreting dollars as we encounter them. */
-    const CharT* repLimit = repChars + repLength;
-    for (const CharT* it = repChars + firstDollarIndex; it < repLimit; ++it) {
-        if (*it != '$' || it == repLimit - 1) {
-            if (!newReplaceChars.append(*it)) {
-                return false;
-            }
-            continue;
-        }
-
-        switch (*(it + 1)) {
-          case '$': /* Eat one of the dollars. */
-            if (!newReplaceChars.append(*it)) {
-                return false;
-            }
-            break;
-          case '&':
-            if (!newReplaceChars.appendSubstring(text, matchStart, matchLimit - matchStart)) {
-                return false;
-            }
-            break;
-          case '`':
-            if (!newReplaceChars.appendSubstring(text, 0, matchStart)) {
-                return false;
-            }
-            break;
-          case '\'':
-            if (!newReplaceChars.appendSubstring(text, matchLimit, text->length() - matchLimit)) {
-                return false;
-            }
-            break;
-          default: /* The dollar we saw was not special (no matter what its mother told it). */
-            if (!newReplaceChars.append(*it)) {
-                return false;
-            }
-            continue;
-        }
-        ++it; /* We always eat an extra char in the above switch. */
-    }
-
-    return true;
-}
-
-/*
- * Perform a linear-scan dollar substitution on the replacement text.
- */
-static JSLinearString*
-InterpretDollarReplacement(JSContext* cx, HandleString textstrArg, HandleLinearString repstr,
-                           uint32_t firstDollarIndex, size_t matchStart, size_t patternLength)
-{
-    RootedLinearString textstr(cx, textstrArg->ensureLinear(cx));
-    if (!textstr) {
-        return nullptr;
-    }
-
-    size_t matchLimit = matchStart + patternLength;
-
-    /*
-     * Most probably:
-     *
-     *      len(newstr) >= len(orig) - len(match) + len(replacement)
-     *
-     * Note that dollar vars _could_ make the resulting text smaller than this.
-     */
-    StringBuffer newReplaceChars(cx);
-    if (repstr->hasTwoByteChars() && !newReplaceChars.ensureTwoByteChars()) {
-        return nullptr;
-    }
-
-    if (!newReplaceChars.reserve(textstr->length() - patternLength + repstr->length())) {
-        return nullptr;
-    }
-
-    bool res;
-    if (repstr->hasLatin1Chars()) {
-        AutoCheckCannotGC nogc;
-        res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, matchStart, matchLimit,
-                                      textstr, repstr->latin1Chars(nogc), repstr->length());
-    } else {
-        AutoCheckCannotGC nogc;
-        res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, matchStart, matchLimit,
-                                      textstr, repstr->twoByteChars(nogc), repstr->length());
-    }
-    if (!res) {
-        return nullptr;
-    }
-
-    return newReplaceChars.finishString();
-}
-
-template <typename StrChar, typename RepChar>
-static bool
-StrFlatReplaceGlobal(JSContext* cx, JSLinearString* str, JSLinearString* pat, JSLinearString* rep,
-                     StringBuffer& sb)
-{
-    MOZ_ASSERT(str->length() > 0);
-
-    AutoCheckCannotGC nogc;
-    const StrChar* strChars = str->chars<StrChar>(nogc);
-    const RepChar* repChars = rep->chars<RepChar>(nogc);
-
-    // The pattern is empty, so we interleave the replacement string in-between
-    // each character.
-    if (!pat->length()) {
-        CheckedInt<uint32_t> strLength(str->length());
-        CheckedInt<uint32_t> repLength(rep->length());
-        CheckedInt<uint32_t> length = repLength * (strLength - 1) + strLength;
-        if (!length.isValid()) {
-            ReportAllocationOverflow(cx);
-            return false;
-        }
-
-        if (!sb.reserve(length.value())) {
-            return false;
-        }
-
-        for (unsigned i = 0; i < str->length() - 1; ++i, ++strChars) {
-            sb.infallibleAppend(*strChars);
-            sb.infallibleAppend(repChars, rep->length());
-        }
-        sb.infallibleAppend(*strChars);
-        return true;
-    }
-
-    // If it's true, we are sure that the result's length is, at least, the same
-    // length as |str->length()|.
-    if (rep->length() >= pat->length()) {
-        if (!sb.reserve(str->length())) {
-            return false;
-        }
-    }
-
-    uint32_t start = 0;
-    for (;;) {
-        int match = StringMatch(str, pat, start);
-        if (match < 0) {
-            break;
-        }
-        if (!sb.append(strChars + start, match - start)) {
-            return false;
-        }
-        if (!sb.append(repChars, rep->length())) {
-            return false;
-        }
-        start = match + pat->length();
-    }
-
-    if (!sb.append(strChars + start, str->length() - start)) {
-        return false;
-    }
-
-    return true;
-}
-
-// This is identical to "str.split(pattern).join(replacement)" except that we
-// do some deforestation optimization in Ion.
-JSString*
-js::str_flat_replace_string(JSContext* cx, HandleString string, HandleString pattern,
-                            HandleString replacement)
-{
-    MOZ_ASSERT(string);
-    MOZ_ASSERT(pattern);
-    MOZ_ASSERT(replacement);
-
-    if (!string->length()) {
-        return string;
-    }
-
-    RootedLinearString linearRepl(cx, replacement->ensureLinear(cx));
-    if (!linearRepl) {
-        return nullptr;
-    }
-
-    RootedLinearString linearPat(cx, pattern->ensureLinear(cx));
-    if (!linearPat) {
-        return nullptr;
-    }
-
-    RootedLinearString linearStr(cx, string->ensureLinear(cx));
-    if (!linearStr) {
-        return nullptr;
-    }
-
-    StringBuffer sb(cx);
-    if (linearStr->hasTwoByteChars()) {
-        if (!sb.ensureTwoByteChars()) {
-            return nullptr;
-        }
-        if (linearRepl->hasTwoByteChars()) {
-            if (!StrFlatReplaceGlobal<char16_t, char16_t>(cx, linearStr, linearPat, linearRepl, sb)) {
-                return nullptr;
-            }
-        } else {
-            if (!StrFlatReplaceGlobal<char16_t, Latin1Char>(cx, linearStr, linearPat, linearRepl, sb)) {
-                return nullptr;
-            }
-        }
-    } else {
-        if (linearRepl->hasTwoByteChars()) {
-            if (!sb.ensureTwoByteChars()) {
-                return nullptr;
-            }
-            if (!StrFlatReplaceGlobal<Latin1Char, char16_t>(cx, linearStr, linearPat, linearRepl, sb)) {
-                return nullptr;
-            }
-        } else {
-            if (!StrFlatReplaceGlobal<Latin1Char, Latin1Char>(cx, linearStr, linearPat, linearRepl, sb)) {
-                return nullptr;
-            }
-        }
-    }
-
-    return sb.finishString();
-}
-
-JSString*
-js::str_replace_string_raw(JSContext* cx, HandleString string, HandleString pattern,
-                           HandleString replacement)
-{
-    RootedLinearString repl(cx, replacement->ensureLinear(cx));
-    if (!repl) {
-        return nullptr;
-    }
-
-    RootedLinearString pat(cx, pattern->ensureLinear(cx));
-    if (!pat) {
-        return nullptr;
-    }
-
-    size_t patternLength = pat->length();
-    int32_t match;
-    uint32_t dollarIndex;
-
-    {
-        AutoCheckCannotGC nogc;
-        dollarIndex = repl->hasLatin1Chars()
-                      ? FindDollarIndex(repl->latin1Chars(nogc), repl->length())
-                      : FindDollarIndex(repl->twoByteChars(nogc), repl->length());
-    }
-
-    /*
-     * |string| could be a rope, so we want to avoid flattening it for as
-     * long as possible.
-     */
-    if (string->isRope()) {
-        if (!RopeMatch(cx, &string->asRope(), pat, &match)) {
-            return nullptr;
-        }
-    } else {
-        match = StringMatch(&string->asLinear(), pat, 0);
-    }
-
-    if (match < 0) {
-        return string;
-    }
-
-    if (dollarIndex != UINT32_MAX) {
-        repl = InterpretDollarReplacement(cx, string, repl, dollarIndex, match, patternLength);
-        if (!repl) {
-            return nullptr;
-        }
-    } else if (string->isRope()) {
-        return BuildFlatRopeReplacement(cx, string, repl, match, patternLength);
-    }
-    return BuildFlatReplacement(cx, string, repl, match, patternLength);
-}
-
-static ArrayObject*
-NewFullyAllocatedStringArray(JSContext* cx, HandleObjectGroup group, uint32_t length)
-{
-    ArrayObject* array = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
-    if (!array) {
-        return nullptr;
-    }
-
-    // Only string values will be added to this array. Inform TI early about
-    // the element type, so we can directly initialize all elements using
-    // NativeObject::initDenseElement() instead of the slightly more expensive
-    // NativeObject::initDenseElementWithType() method.
-    // Since this function is never called to create a zero-length array, it's
-    // always necessary and correct to call AddTypePropertyId here.
-    MOZ_ASSERT(length > 0);
-    AddTypePropertyId(cx, array, JSID_VOID, TypeSet::StringType());
-
-    return array;
-}
-
-static ArrayObject*
-SingleElementStringArray(JSContext* cx, HandleObjectGroup group, HandleLinearString str)
-{
-    ArrayObject* array = NewFullyAllocatedStringArray(cx, group, 1);
-    if (!array) {
-        return nullptr;
-    }
-    array->setDenseInitializedLength(1);
-    array->initDenseElement(0, StringValue(str));
-    return array;
-}
-
-// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
-static ArrayObject*
-SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearString sep,
-            HandleObjectGroup group)
-{
-    size_t strLength = str->length();
-    size_t sepLength = sep->length();
-    MOZ_ASSERT(sepLength != 0);
-
-    // Step 12.
-    if (strLength == 0) {
-        // Step 12.a.
-        int match = StringMatch(str, sep, 0);
-
-        // Step 12.b.
-        if (match != -1) {
-            return NewFullyAllocatedArrayTryUseGroup(cx, group, 0);
-        }
-
-        // Steps 12.c-e.
-        return SingleElementStringArray(cx, group, str);
-    }
-
-    // Step 3 (reordered).
-    AutoValueVector splits(cx);
-
-    // Step 8 (reordered).
-    size_t lastEndIndex = 0;
-
-    // Step 13.
-    size_t index = 0;
-
-    // Step 14.
-    while (index != strLength) {
-        // Step 14.a.
-        int match = StringMatch(str, sep, index);
-
-        // Step 14.b.
-        //
-        // Our match algorithm differs from the spec in that it returns the
-        // next index at which a match happens.  If no match happens we're
-        // done.
-        //
-        // But what if the match is at the end of the string (and the string is
-        // not empty)?  Per 14.c.i this shouldn't be a match, so we have to
-        // specially exclude it.  Thus this case should hold:
-        //
-        //   var a = "abc".split(/\b/);
-        //   assertEq(a.length, 1);
-        //   assertEq(a[0], "abc");
-        if (match == -1) {
-            break;
-        }
-
-        // Step 14.c.
-        size_t endIndex = match + sepLength;
-
-        // Step 14.c.i.
-        if (endIndex == lastEndIndex) {
-            index++;
-            continue;
-        }
-
-        // Step 14.c.ii.
-        MOZ_ASSERT(lastEndIndex < endIndex);
-        MOZ_ASSERT(sepLength <= strLength);
-        MOZ_ASSERT(lastEndIndex + sepLength <= endIndex);
-
-        // Step 14.c.ii.1.
-        size_t subLength = size_t(endIndex - sepLength - lastEndIndex);
-        JSString* sub = NewDependentString(cx, str, lastEndIndex, subLength);
-
-        // Steps 14.c.ii.2-4.
-        if (!sub || !splits.append(StringValue(sub))) {
-            return nullptr;
-        }
-
-        // Step 14.c.ii.5.
-        if (splits.length() == limit) {
-            return NewCopiedArrayTryUseGroup(cx, group, splits.begin(), splits.length());
-        }
-
-        // Step 14.c.ii.6.
-        index = endIndex;
-
-        // Step 14.c.ii.7.
-        lastEndIndex = index;
-    }
-
-    // Step 15.
-    JSString* sub = NewDependentString(cx, str, lastEndIndex, strLength - lastEndIndex);
-
-    // Steps 16-17.
-    if (!sub || !splits.append(StringValue(sub))) {
-        return nullptr;
-    }
-
-    // Step 18.
-    return NewCopiedArrayTryUseGroup(cx, group, splits.begin(), splits.length());
-}
-
-// Fast-path for splitting a string into a character array via split("").
-static ArrayObject*
-CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObjectGroup group)
-{
-    size_t strLength = str->length();
-    if (strLength == 0) {
-        return NewFullyAllocatedArrayTryUseGroup(cx, group, 0);
-    }
-
-    js::StaticStrings& staticStrings = cx->staticStrings();
-    uint32_t resultlen = (limit < strLength ? limit : strLength);
-    MOZ_ASSERT(limit > 0 && resultlen > 0,
-               "Neither limit nor strLength is zero, so resultlen is greater than zero.");
-
-    RootedArrayObject splits(cx, NewFullyAllocatedStringArray(cx, group, resultlen));
-    if (!splits) {
-        return nullptr;
-    }
-
-    if (str->hasLatin1Chars()) {
-        splits->setDenseInitializedLength(resultlen);
-
-        JS::AutoCheckCannotGC nogc;
-        const Latin1Char* latin1Chars = str->latin1Chars(nogc);
-        for (size_t i = 0; i < resultlen; ++i) {
-            Latin1Char c = latin1Chars[i];
-            MOZ_ASSERT(staticStrings.hasUnit(c));
-            splits->initDenseElement(i, StringValue(staticStrings.getUnit(c)));
-        }
-    } else {
-        splits->ensureDenseInitializedLength(cx, 0, resultlen);
-
-        for (size_t i = 0; i < resultlen; ++i) {
-            JSString* sub = staticStrings.getUnitStringForElement(cx, str, i);
-            if (!sub) {
-                return nullptr;
-            }
-            splits->initDenseElement(i, StringValue(sub));
-        }
-    }
-
-    return splits;
-}
-
-template <typename TextChar>
-static MOZ_ALWAYS_INLINE ArrayObject*
-SplitSingleCharHelper(JSContext* cx, HandleLinearString str, const TextChar* text,
-                      uint32_t textLen, char16_t patCh, HandleObjectGroup group)
-{
-    // Count the number of occurrences of patCh within text.
-    uint32_t count = 0;
-    for (size_t index = 0; index < textLen; index++) {
-        if (static_cast<char16_t>(text[index]) == patCh) {
-            count++;
-        }
-    }
-
-    // Handle zero-occurrence case - return input string in an array.
-    if (count == 0) {
-        return SingleElementStringArray(cx, group, str);
-    }
-
-    // Create the result array for the substring values.
-    RootedArrayObject splits(cx, NewFullyAllocatedStringArray(cx, group, count + 1));
-    if (!splits) {
-        return nullptr;
-    }
-    splits->ensureDenseInitializedLength(cx, 0, count + 1);
-
-    // Add substrings.
-    uint32_t splitsIndex = 0;
-    size_t lastEndIndex = 0;
-    for (size_t index = 0; index < textLen; index++) {
-        if (static_cast<char16_t>(text[index]) == patCh) {
-            size_t subLength = size_t(index - lastEndIndex);
-            JSString* sub = NewDependentString(cx, str, lastEndIndex, subLength);
-            if (!sub) {
-                return nullptr;
-            }
-            splits->initDenseElement(splitsIndex++, StringValue(sub));
-            lastEndIndex = index + 1;
-        }
-    }
-
-    // Add substring for tail of string (after last match).
-    JSString* sub = NewDependentString(cx, str, lastEndIndex, textLen - lastEndIndex);
-    if (!sub) {
-        return nullptr;
-    }
-    splits->initDenseElement(splitsIndex++, StringValue(sub));
-
-    return splits;
-}
-
-// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
-static ArrayObject*
-SplitSingleCharHelper(JSContext* cx, HandleLinearString str, char16_t ch, HandleObjectGroup group)
-{
-    // Step 12.
-    size_t strLength = str->length();
-
-    AutoStableStringChars linearChars(cx);
-    if (!linearChars.init(cx, str)) {
-        return nullptr;
-    }
-
-    if (linearChars.isLatin1()) {
-        return SplitSingleCharHelper(cx, str, linearChars.latin1Chars(), strLength, ch, group);
-    }
-
-    return SplitSingleCharHelper(cx, str, linearChars.twoByteChars(), strLength, ch, group);
-}
-
-// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
-ArrayObject*
-js::str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep,
-                     uint32_t limit)
-{
-    MOZ_ASSERT(limit > 0, "Only called for strictly positive limit.");
-
-    RootedLinearString linearStr(cx, str->ensureLinear(cx));
-    if (!linearStr) {
-        return nullptr;
-    }
-
-    RootedLinearString linearSep(cx, sep->ensureLinear(cx));
-    if (!linearSep) {
-        return nullptr;
-    }
-
-    if (linearSep->length() == 0) {
-        return CharSplitHelper(cx, linearStr, limit, group);
-    }
-
-    if (linearSep->length() == 1 && limit >= static_cast<uint32_t>(INT32_MAX)) {
-        char16_t ch = linearSep->latin1OrTwoByteChar(0);
-        return SplitSingleCharHelper(cx, linearStr, ch, group);
-    }
-
-    return SplitHelper(cx, linearStr, limit, linearSep, group);
-}
-
-/*
- * Python-esque sequence operations.
- */
-bool
-js::str_concat(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    JSString* str = ToStringForStringFunction(cx, args.thisv());
-    if (!str) {
-        return false;
-    }
-
-    for (unsigned i = 0; i < args.length(); i++) {
-        JSString* argStr = ToString<NoGC>(cx, args[i]);
-        if (!argStr) {
-            RootedString strRoot(cx, str);
-            argStr = ToString<CanGC>(cx, args[i]);
-            if (!argStr) {
-                return false;
-            }
-            str = strRoot;
-        }
-
-        JSString* next = ConcatStrings<NoGC>(cx, str, argStr);
-        if (next) {
-            str = next;
-        } else {
-            RootedString strRoot(cx, str), argStrRoot(cx, argStr);
-            str = ConcatStrings<CanGC>(cx, strRoot, argStrRoot);
-            if (!str) {
-                return false;
-            }
-        }
-    }
-
-    args.rval().setString(str);
-    return true;
-}
-
-static const JSFunctionSpec string_methods[] = {
-    JS_FN(js_toSource_str,     str_toSource,          0,0),
-
-    /* Java-like methods. */
-    JS_FN(js_toString_str,     str_toString,          0,0),
-    JS_FN(js_valueOf_str,      str_toString,          0,0),
-    JS_INLINABLE_FN("toLowerCase", str_toLowerCase,   0,0, StringToLowerCase),
-    JS_INLINABLE_FN("toUpperCase", str_toUpperCase,   0,0, StringToUpperCase),
-    JS_INLINABLE_FN("charAt",  str_charAt,            1,0, StringCharAt),
-    JS_INLINABLE_FN("charCodeAt", str_charCodeAt,     1,0, StringCharCodeAt),
-    JS_SELF_HOSTED_FN("substring", "String_substring", 2,0),
-    JS_SELF_HOSTED_FN("padStart", "String_pad_start", 2,0),
-    JS_SELF_HOSTED_FN("padEnd", "String_pad_end", 2,0),
-    JS_SELF_HOSTED_FN("codePointAt", "String_codePointAt", 1,0),
-    JS_FN("includes",          str_includes,          1,0),
-    JS_FN("indexOf",           str_indexOf,           1,0),
-    JS_FN("lastIndexOf",       str_lastIndexOf,       1,0),
-    JS_FN("startsWith",        str_startsWith,        1,0),
-    JS_FN("endsWith",          str_endsWith,          1,0),
-    JS_FN("trim",              str_trim,              0,0),
-    JS_FN("trimStart",         str_trimStart,         0,0),
-    JS_FN("trimEnd",           str_trimEnd,           0,0),
-#if EXPOSE_INTL_API
-    JS_SELF_HOSTED_FN("toLocaleLowerCase", "String_toLocaleLowerCase", 0,0),
-    JS_SELF_HOSTED_FN("toLocaleUpperCase", "String_toLocaleUpperCase", 0,0),
-    JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0),
-#else
-    JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0),
-    JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0),
-    JS_FN("localeCompare",     str_localeCompare,     1,0),
-#endif
-    JS_SELF_HOSTED_FN("repeat", "String_repeat",      1,0),
-#if EXPOSE_INTL_API
-    JS_FN("normalize",         str_normalize,         0,0),
-#endif
-
-    /* Perl-ish methods (search is actually Python-esque). */
-    JS_SELF_HOSTED_FN("match", "String_match",        1,0),
-    JS_SELF_HOSTED_FN("search", "String_search",      1,0),
-    JS_SELF_HOSTED_FN("replace", "String_replace",    2,0),
-    JS_SELF_HOSTED_FN("split",  "String_split",       2,0),
-    JS_SELF_HOSTED_FN("substr", "String_substr",      2,0),
-
-    /* Python-esque sequence methods. */
-    JS_FN("concat",            str_concat,            1,0),
-    JS_SELF_HOSTED_FN("slice", "String_slice",        2,0),
-
-    /* HTML string methods. */
-    JS_SELF_HOSTED_FN("bold",     "String_bold",       0,0),
-    JS_SELF_HOSTED_FN("italics",  "String_italics",    0,0),
-    JS_SELF_HOSTED_FN("fixed",    "String_fixed",      0,0),
-    JS_SELF_HOSTED_FN("strike",   "String_strike",     0,0),
-    JS_SELF_HOSTED_FN("small",    "String_small",      0,0),
-    JS_SELF_HOSTED_FN("big",      "String_big",        0,0),
-    JS_SELF_HOSTED_FN("blink",    "String_blink",      0,0),
-    JS_SELF_HOSTED_FN("sup",      "String_sup",        0,0),
-    JS_SELF_HOSTED_FN("sub",      "String_sub",        0,0),
-    JS_SELF_HOSTED_FN("anchor",   "String_anchor",     1,0),
-    JS_SELF_HOSTED_FN("link",     "String_link",       1,0),
-    JS_SELF_HOSTED_FN("fontcolor","String_fontcolor",  1,0),
-    JS_SELF_HOSTED_FN("fontsize", "String_fontsize",   1,0),
-
-    JS_SELF_HOSTED_SYM_FN(iterator, "String_iterator", 0,0),
-    JS_FS_END
-};
-
-// ES6 rev 27 (2014 Aug 24) 21.1.1
-bool
-js::StringConstructor(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    RootedString str(cx);
-    if (args.length() > 0) {
-        if (!args.isConstructing() && args[0].isSymbol()) {
-            return js::SymbolDescriptiveString(cx, args[0].toSymbol(), args.rval());
-        }
-
-        str = ToString<CanGC>(cx, args[0]);
-        if (!str) {
-            return false;
-        }
-    } else {
-        str = cx->runtime()->emptyString;
-    }
-
-    if (args.isConstructing()) {
-        RootedObject proto(cx);
-        if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
-            return false;
-        }
-
-        StringObject* strobj = StringObject::create(cx, str, proto);
-        if (!strobj) {
-            return false;
-        }
-        args.rval().setObject(*strobj);
-        return true;
-    }
-
-    args.rval().setString(str);
-    return true;
-}
-
-bool
-js::str_fromCharCode(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
-
-    // Optimize the single-char case.
-    if (args.length() == 1) {
-        return str_fromCharCode_one_arg(cx, args[0], args.rval());
-    }
-
-    // Optimize the case where the result will definitely fit in an inline
-    // string (thin or fat) and so we don't need to malloc the chars. (We could
-    // cover some cases where args.length() goes up to
-    // JSFatInlineString::MAX_LENGTH_LATIN1 if we also checked if the chars are
-    // all Latin-1, but it doesn't seem worth the effort.)
-    InlineCharBuffer<char16_t> chars;
-    if (!chars.maybeAlloc(cx, args.length())) {
-        return false;
-    }
-
-    char16_t* rawChars = chars.get();
-    for (unsigned i = 0; i < args.length(); i++) {
-        uint16_t code;
-        if (!ToUint16(cx, args[i], &code)) {
-            return false;
-        }
-
-        rawChars[i] = char16_t(code);
-    }
-
-    JSString* str = chars.toString(cx, args.length());
-    if (!str) {
-        return false;
-    }
-
-    args.rval().setString(str);
-    return true;
-}
-
-static inline bool
-CodeUnitToString(JSContext* cx, uint16_t ucode, MutableHandleValue rval)
-{
-    if (StaticStrings::hasUnit(ucode)) {
-        rval.setString(cx->staticStrings().getUnit(ucode));
-        return true;
-    }
-
-    char16_t c = char16_t(ucode);
-    JSString* str = NewStringCopyNDontDeflate<CanGC>(cx, &c, 1);
-    if (!str) {
-        return false;
-    }
-
-    rval.setString(str);
-    return true;
-}
-
-bool
-js::str_fromCharCode_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval)
-{
-    uint16_t ucode;
-
-    if (!ToUint16(cx, code, &ucode)) {
-        return false;
-    }
-
-    return CodeUnitToString(cx, ucode, rval);
-}
-
-static MOZ_ALWAYS_INLINE bool
-ToCodePoint(JSContext* cx, HandleValue code, uint32_t* codePoint)
-{
-    // String.fromCodePoint, Steps 5.a-b.
-
-    // Fast path for the common case - the input is already an int32.
-    if (code.isInt32()) {
-        int32_t nextCP = code.toInt32();
-        if (nextCP >= 0 && nextCP <= int32_t(unicode::NonBMPMax)) {
-            *codePoint = uint32_t(nextCP);
-            return true;
-        }
-    }
-
-    double nextCP;
-    if (!ToNumber(cx, code, &nextCP)) {
-        return false;
-    }
-
-    // String.fromCodePoint, Steps 5.c-d.
-    if (JS::ToInteger(nextCP) != nextCP || nextCP < 0 || nextCP > unicode::NonBMPMax) {
-        ToCStringBuf cbuf;
-        if (const char* numStr = NumberToCString(cx, &cbuf, nextCP)) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_A_CODEPOINT, numStr);
-        }
-        return false;
-    }
-
-    *codePoint = uint32_t(nextCP);
-    return true;
-}
-
-bool
-js::str_fromCodePoint_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval)
-{
-    // Steps 1-4 (omitted).
-
-    // Steps 5.a-d.
-    uint32_t codePoint;
-    if (!ToCodePoint(cx, code, &codePoint)) {
-        return false;
-    }
-
-    // Steps 5.e, 6.
-    if (!unicode::IsSupplementary(codePoint)) {
-        return CodeUnitToString(cx, uint16_t(codePoint), rval);
-    }
-
-    char16_t chars[] = { unicode::LeadSurrogate(codePoint), unicode::TrailSurrogate(codePoint) };
-    JSString* str = NewStringCopyNDontDeflate<CanGC>(cx, chars, 2);
-    if (!str) {
-        return false;
-    }
-
-    rval.setString(str);
-    return true;
-}
-
-static bool
-str_fromCodePoint_few_args(JSContext* cx, const CallArgs& args)
-{
-    MOZ_ASSERT(args.length() <= JSFatInlineString::MAX_LENGTH_TWO_BYTE / 2);
-
-    // Steps 1-2 (omitted).
-
-    // Step 3.
-    char16_t elements[JSFatInlineString::MAX_LENGTH_TWO_BYTE];
-
-    // Steps 4-5.
-    unsigned length = 0;
-    for (unsigned nextIndex = 0; nextIndex < args.length(); nextIndex++) {
-        // Steps 5.a-d.
-        uint32_t codePoint;
-        if (!ToCodePoint(cx, args[nextIndex], &codePoint)) {
-            return false;
-        }
-
-        // Step 5.e.
-        unicode::UTF16Encode(codePoint, elements, &length);
-    }
-
-    // Step 6.
-    JSString* str = NewStringCopyN<CanGC>(cx, elements, length);
-    if (!str) {
-        return false;
-    }
-
-    args.rval().setString(str);
-    return true;
-}
-
-// ES2017 draft rev 40edb3a95a475c1b251141ac681b8793129d9a6d
-// 21.1.2.2 String.fromCodePoint(...codePoints)
-bool
-js::str_fromCodePoint(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Optimize the single code-point case.
-    if (args.length() == 1) {
-        return str_fromCodePoint_one_arg(cx, args[0], args.rval());
-    }
-
-    // Optimize the case where the result will definitely fit in an inline
-    // string (thin or fat) and so we don't need to malloc the chars. (We could
-    // cover some cases where |args.length()| goes up to
-    // JSFatInlineString::MAX_LENGTH_LATIN1 / 2 if we also checked if the chars
-    // are all Latin-1, but it doesn't seem worth the effort.)
-    if (args.length() <= JSFatInlineString::MAX_LENGTH_TWO_BYTE / 2) {
-        return str_fromCodePoint_few_args(cx, args);
-    }
-
-    // Steps 1-2 (omitted).
-
-    // Step 3.
-    static_assert(ARGS_LENGTH_MAX < std::numeric_limits<decltype(args.length())>::max() / 2,
-                  "|args.length() * 2 + 1| does not overflow");
-    auto elements = cx->make_pod_array<char16_t>(args.length() * 2 + 1);
-    if (!elements) {
-        return false;
-    }
-
-    // Steps 4-5.
-    unsigned length = 0;
-    for (unsigned nextIndex = 0; nextIndex < args.length(); nextIndex++) {
-        // Steps 5.a-d.
-        uint32_t codePoint;
-        if (!ToCodePoint(cx, args[nextIndex], &codePoint)) {
-            return false;
-        }
-
-        // Step 5.e.
-        unicode::UTF16Encode(codePoint, elements.get(), &length);
-    }
-    elements[length] = 0;
-
-    // Step 6.
-    JSString* str = NewString<CanGC>(cx, std::move(elements), length);
-    if (!str) {
-        return false;
-    }
-
-    args.rval().setString(str);
-    return true;
-}
-
-static const JSFunctionSpec string_static_methods[] = {
-    JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
-    JS_INLINABLE_FN("fromCodePoint", js::str_fromCodePoint, 1, 0, StringFromCodePoint),
-
-    JS_SELF_HOSTED_FN("raw",             "String_static_raw",           1,0),
-    JS_SELF_HOSTED_FN("substring",       "String_static_substring",     3,0),
-    JS_SELF_HOSTED_FN("substr",          "String_static_substr",        3,0),
-    JS_SELF_HOSTED_FN("slice",           "String_static_slice",         3,0),
-
-    JS_SELF_HOSTED_FN("match",           "String_generic_match",        2,0),
-    JS_SELF_HOSTED_FN("replace",         "String_generic_replace",      3,0),
-    JS_SELF_HOSTED_FN("search",          "String_generic_search",       2,0),
-    JS_SELF_HOSTED_FN("split",           "String_generic_split",        3,0),
-
-    JS_SELF_HOSTED_FN("toLowerCase",     "String_static_toLowerCase",   1,0),
-    JS_SELF_HOSTED_FN("toUpperCase",     "String_static_toUpperCase",   1,0),
-    JS_SELF_HOSTED_FN("charAt",          "String_static_charAt",        2,0),
-    JS_SELF_HOSTED_FN("charCodeAt",      "String_static_charCodeAt",    2,0),
-    JS_SELF_HOSTED_FN("includes",        "String_static_includes",      2,0),
-    JS_SELF_HOSTED_FN("indexOf",         "String_static_indexOf",       2,0),
-    JS_SELF_HOSTED_FN("lastIndexOf",     "String_static_lastIndexOf",   2,0),
-    JS_SELF_HOSTED_FN("startsWith",      "String_static_startsWith",    2,0),
-    JS_SELF_HOSTED_FN("endsWith",        "String_static_endsWith",      2,0),
-    JS_SELF_HOSTED_FN("trim",            "String_static_trim",          1,0),
-    JS_SELF_HOSTED_FN("trimLeft",        "String_static_trimLeft",      1,0),
-    JS_SELF_HOSTED_FN("trimRight",       "String_static_trimRight",     1,0),
-    JS_SELF_HOSTED_FN("toLocaleLowerCase","String_static_toLocaleLowerCase",1,0),
-    JS_SELF_HOSTED_FN("toLocaleUpperCase","String_static_toLocaleUpperCase",1,0),
-#if EXPOSE_INTL_API
-    JS_SELF_HOSTED_FN("normalize",       "String_static_normalize",     1,0),
-#endif
-    JS_SELF_HOSTED_FN("concat",          "String_static_concat",        2,0),
-
-    JS_SELF_HOSTED_FN("localeCompare",   "String_static_localeCompare", 2,0),
-    JS_FS_END
-};
-
-/* static */ Shape*
-StringObject::assignInitialShape(JSContext* cx, Handle<StringObject*> obj)
-{
-    MOZ_ASSERT(obj->empty());
-
-    return NativeObject::addDataProperty(cx, obj, cx->names().length, LENGTH_SLOT,
-                                         JSPROP_PERMANENT | JSPROP_READONLY);
-}
-
-JSObject*
-js::InitStringClass(JSContext* cx, Handle<GlobalObject*> global)
-{
-    Rooted<JSString*> empty(cx, cx->runtime()->emptyString);
-    Rooted<StringObject*> proto(cx, GlobalObject::createBlankPrototype<StringObject>(cx, global));
-    if (!proto) {
-        return nullptr;
-    }
-    if (!StringObject::init(cx, proto, empty)) {
-        return nullptr;
-    }
-
-    /* Now create the String function. */
-    RootedFunction ctor(cx);
-    ctor = GlobalObject::createConstructor(cx, StringConstructor, cx->names().String, 1,
-                                           gc::AllocKind::FUNCTION, &jit::JitInfo_String);
-    if (!ctor) {
-        return nullptr;
-    }
-
-    if (!LinkConstructorAndPrototype(cx, ctor, proto)) {
-        return nullptr;
-    }
-
-    if (!DefinePropertiesAndFunctions(cx, proto, nullptr, string_methods) ||
-        !DefinePropertiesAndFunctions(cx, ctor, nullptr, string_static_methods))
-    {
-        return nullptr;
-    }
-
-    // Create "trimLeft" as an alias for "trimStart".
-    RootedValue trimFn(cx);
-    RootedId trimId(cx, NameToId(cx->names().trimStart));
-    RootedId trimAliasId(cx, NameToId(cx->names().trimLeft));
-    if (!NativeGetProperty(cx, proto, trimId, &trimFn) ||
-        !NativeDefineDataProperty(cx, proto, trimAliasId, trimFn, 0))
-    {
-        return nullptr;
-    }
-
-    // Create "trimRight" as an alias for "trimEnd".
-    trimId = NameToId(cx->names().trimEnd);
-    trimAliasId = NameToId(cx->names().trimRight);
-    if (!NativeGetProperty(cx, proto, trimId, &trimFn) ||
-        !NativeDefineDataProperty(cx, proto, trimAliasId, trimFn, 0))
-    {
-        return nullptr;
-    }
-
-    /*
-     * Define escape/unescape, the URI encode/decode functions, and maybe
-     * uneval on the global object.
-     */
-    if (!JS_DefineFunctions(cx, global, string_functions)) {
-        return nullptr;
-    }
-
-    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto)) {
-        return nullptr;
-    }
-
-    return proto;
-}
-
-#define ____ false
-
-/*
- * Uri reserved chars + #:
- * - 35: #
- * - 36: $
- * - 38: &
- * - 43: +
- * - 44: ,
- * - 47: /
- * - 58: :
- * - 59: ;
- * - 61: =
- * - 63: ?
- * - 64: @
- */
-static const bool js_isUriReservedPlusPound[] = {
-/*       0     1     2     3     4     5     6     7     8     9  */
-/*  0 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  1 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  2 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  3 */ ____, ____, ____, ____, ____, true, true, ____, true, ____,
-/*  4 */ ____, ____, ____, true, true, ____, ____, true, ____, ____,
-/*  5 */ ____, ____, ____, ____, ____, ____, ____, ____, true, true,
-/*  6 */ ____, true, ____, true, true, ____, ____, ____, ____, ____,
-/*  7 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  8 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  9 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/* 10 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/* 11 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/* 12 */ ____, ____, ____, ____, ____, ____, ____, ____
-};
-
-/*
- * Uri unescaped chars:
- * -      33: !
- * -      39: '
- * -      40: (
- * -      41: )
- * -      42: *
- * -      45: -
- * -      46: .
- * -  48..57: 0-9
- * -  65..90: A-Z
- * -      95: _
- * - 97..122: a-z
- * -     126: ~
- */
-static const bool js_isUriUnescaped[] = {
-/*       0     1     2     3     4     5     6     7     8     9  */
-/*  0 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  1 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  2 */ ____, ____, ____, ____, ____, ____, ____, ____, ____, ____,
-/*  3 */ ____, ____, ____, true, ____, ____, ____, ____, ____, true,
-/*  4 */ true, true, true, ____, ____, true, true, ____, true, true,
-/*  5 */ true, true, true, true, true, true, true, true, ____, ____,
-/*  6 */ ____, ____, ____, ____, ____, true, true, true, true, true,
-/*  7 */ true, true, true, true, true, true, true, true, true, true,
-/*  8 */ true, true, true, true, true, true, true, true, true, true,
-/*  9 */ true, ____, ____, ____, ____, true, ____, true, true, true,
-/* 10 */ true, true, true, true, true, true, true, true, true, true,
-/* 11 */ true, true, true, true, true, true, true, true, true, true,
-/* 12 */ true, true, true, ____, ____, ____, true, ____
-};
-
-#undef ____
-
-static inline bool
-TransferBufferToString(StringBuffer& sb, JSString* str, MutableHandleValue rval)
-{
-    if (!sb.empty()) {
-        str = sb.finishString();
-        if (!str) {
-            return false;
-        }
-    }
-    rval.setString(str);
-    return true;
-}
-
-/*
- * ECMA 3, 15.1.3 URI Handling Function Properties
- *
- * The following are implementations of the algorithms
- * given in the ECMA specification for the hidden functions
- * 'Encode' and 'Decode'.
- */
-enum EncodeResult { Encode_Failure, Encode_BadUri, Encode_Success };
-
-// Bug 1403318: GCC sometimes inlines this Encode function rather than the
-// caller Encode function. Annotate both functions with MOZ_NEVER_INLINE resp.
-// MOZ_ALWAYS_INLINE to ensure we get the desired inlining behavior.
-template <typename CharT>
-static MOZ_NEVER_INLINE EncodeResult
-Encode(StringBuffer& sb, const CharT* chars, size_t length, const bool* unescapedSet)
-{
-    Latin1Char hexBuf[3];
-    hexBuf[0] = '%';
-
-    auto appendEncoded = [&sb, &hexBuf](Latin1Char c) {
-        static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
-
-        hexBuf[1] = HexDigits[c >> 4];
-        hexBuf[2] = HexDigits[c & 0xf];
-        return sb.append(hexBuf, 3);
-    };
-
-    auto appendRange = [&sb, chars, length](size_t start, size_t end) {
-        MOZ_ASSERT(start <= end);
-
-        if (start < end) {
-            if (start == 0) {
-                if (!sb.reserve(length)) {
-                    return false;
-                }
-            }
-            return sb.append(chars + start, chars + end);
-        }
-        return true;
-    };
-
-    size_t startAppend = 0;
-    for (size_t k = 0; k < length; k++) {
-        CharT c = chars[k];
-        if (c < 128 && (js_isUriUnescaped[c] || (unescapedSet && unescapedSet[c]))) {
-            continue;
-        } else {
-            if (!appendRange(startAppend, k)) {
-                return Encode_Failure;
-            }
-
-            if (mozilla::IsSame<CharT, Latin1Char>::value) {
-                if (c < 0x80) {
-                    if (!appendEncoded(c)) {
-                        return Encode_Failure;
-                    }
-                } else {
-                    if (!appendEncoded(0xC0 | (c >> 6)) || !appendEncoded(0x80 | (c & 0x3F))) {
-                        return Encode_Failure;
-                    }
-                }
-            } else {
-                if (unicode::IsTrailSurrogate(c)) {
-                    return Encode_BadUri;
-                }
-
-                uint32_t v;
-                if (!unicode::IsLeadSurrogate(c)) {
-                    v = c;
-                } else {
-                    k++;
-                    if (k == length) {
-                        return Encode_BadUri;
-                    }
-
-                    char16_t c2 = chars[k];
-                    if (!unicode::IsTrailSurrogate(c2)) {
-                        return Encode_BadUri;
-                    }
-
-                    v = unicode::UTF16Decode(c, c2);
-                }
-
-                uint8_t utf8buf[4];
-                size_t L = OneUcs4ToUtf8Char(utf8buf, v);
-                for (size_t j = 0; j < L; j++) {
-                    if (!appendEncoded(utf8buf[j])) {
-                        return Encode_Failure;
-                    }
-                }
-            }
-
-            startAppend = k + 1;
-        }
-    }
-
-    if (startAppend > 0) {
-        if (!appendRange(startAppend, length)) {
-            return Encode_Failure;
-        }
-    }
-
-    return Encode_Success;
-}
-
-static MOZ_ALWAYS_INLINE bool
-Encode(JSContext* cx, HandleLinearString str, const bool* unescapedSet, MutableHandleValue rval)
-{
-    size_t length = str->length();
-    if (length == 0) {
-        rval.setString(cx->runtime()->emptyString);
-        return true;
-    }
-
-    StringBuffer sb(cx);
-
-    EncodeResult res;
-    if (str->hasLatin1Chars()) {
-        AutoCheckCannotGC nogc;
-        res = Encode(sb, str->latin1Chars(nogc), str->length(), unescapedSet);
-    } else {
-        AutoCheckCannotGC nogc;
-        res = Encode(sb, str->twoByteChars(nogc), str->length(), unescapedSet);
-    }
-
-    if (res == Encode_Failure) {
-        return false;
-    }
-
-    if (res == Encode_BadUri) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_URI);
-        return false;
-    }
-
-    MOZ_ASSERT(res == Encode_Success);
-    return TransferBufferToString(sb, str, rval);
-}
-
-enum DecodeResult { Decode_Failure, Decode_BadUri, Decode_Success };
-
-template <typename CharT>
-static DecodeResult
-Decode(StringBuffer& sb, const CharT* chars, size_t length, const bool* reservedSet)
-{
-    auto appendRange = [&sb, chars](size_t start, size_t end) {
-        MOZ_ASSERT(start <= end);
-
-        if (start < end) {
-            return sb.append(chars + start, chars + end);
-        }
-        return true;
-    };
-
-    size_t startAppend = 0;
-    for (size_t k = 0; k < length; k++) {
-        CharT c = chars[k];
-        if (c == '%') {
-            size_t start = k;
-            if ((k + 2) >= length) {
-                return Decode_BadUri;
-            }
-
-            if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2])) {
-                return Decode_BadUri;
-            }
-
-            uint32_t B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
-            k += 2;
-            if (B < 128) {
-                Latin1Char ch = Latin1Char(B);
-                if (reservedSet && reservedSet[ch]) {
-                    continue;
-                }
-
-                if (!appendRange(startAppend, start)) {
-                    return Decode_Failure;
-                }
-                if (!sb.append(ch)) {
-                    return Decode_Failure;
-                }
-            } else {
-                int n = 1;
-                while (B & (0x80 >> n)) {
-                    n++;
-                }
-
-                if (n == 1 || n > 4) {
-                    return Decode_BadUri;
-                }
-
-                uint8_t octets[4];
-                octets[0] = (uint8_t)B;
-                if (k + 3 * (n - 1) >= length) {
-                    return Decode_BadUri;
-                }
-
-                for (int j = 1; j < n; j++) {
-                    k++;
-                    if (chars[k] != '%') {
-                        return Decode_BadUri;
-                    }
-
-                    if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2])) {
-                        return Decode_BadUri;
-                    }
-
-                    B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
-                    if ((B & 0xC0) != 0x80) {
-                        return Decode_BadUri;
-                    }
-
-                    k += 2;
-                    octets[j] = char(B);
-                }
-
-                if (!appendRange(startAppend, start)) {
-                    return Decode_Failure;
-                }
-
-                uint32_t v = JS::Utf8ToOneUcs4Char(octets, n);
-                MOZ_ASSERT(v >= 128);
-                if (v >= unicode::NonBMPMin) {
-                    if (v > unicode::NonBMPMax) {
-                        return Decode_BadUri;
-                    }
-
-                    if (!sb.append(unicode::LeadSurrogate(v))) {
-                        return Decode_Failure;
-                    }
-                    if (!sb.append(unicode::TrailSurrogate(v))) {
-                        return Decode_Failure;
-                    }
-                } else {
-                    if (!sb.append(char16_t(v))) {
-                        return Decode_Failure;
-                    }
-                }
-            }
-
-            startAppend = k + 1;
-        }
-    }
-
-    if (startAppend > 0) {
-        if (!appendRange(startAppend, length)) {
-            return Decode_Failure;
-        }
-    }
-
-    return Decode_Success;
-}
-
-static bool
-Decode(JSContext* cx, HandleLinearString str, const bool* reservedSet, MutableHandleValue rval)
-{
-    size_t length = str->length();
-    if (length == 0) {
-        rval.setString(cx->runtime()->emptyString);
-        return true;
-    }
-
-    StringBuffer sb(cx);
-
-    DecodeResult res;
-    if (str->hasLatin1Chars()) {
-        AutoCheckCannotGC nogc;
-        res = Decode(sb, str->latin1Chars(nogc), str->length(), reservedSet);
-    } else {
-        AutoCheckCannotGC nogc;
-        res = Decode(sb, str->twoByteChars(nogc), str->length(), reservedSet);
-    }
-
-    if (res == Decode_Failure) {
-        return false;
-    }
-
-    if (res == Decode_BadUri) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_URI);
-        return false;
-    }
-
-    MOZ_ASSERT(res == Decode_Success);
-    return TransferBufferToString(sb, str, rval);
-}
-
-static bool
-str_decodeURI(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedLinearString str(cx, ArgToLinearString(cx, args, 0));
-    if (!str) {
-        return false;
-    }
-
-    return Decode(cx, str, js_isUriReservedPlusPound, args.rval());
-}
-
-static bool
-str_decodeURI_Component(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedLinearString str(cx, ArgToLinearString(cx, args, 0));
-    if (!str) {
-        return false;
-    }
-
-    return Decode(cx, str, nullptr, args.rval());
-}
-
-static bool
-str_encodeURI(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedLinearString str(cx, ArgToLinearString(cx, args, 0));
-    if (!str) {
-        return false;
-    }
-
-    return Encode(cx, str, js_isUriReservedPlusPound, args.rval());
-}
-
-static bool
-str_encodeURI_Component(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedLinearString str(cx, ArgToLinearString(cx, args, 0));
-    if (!str) {
-        return false;
-    }
-
-    return Encode(cx, str, nullptr, args.rval());
-}
-
-JSString*
-js::EncodeURI(JSContext* cx, const char* chars, size_t length)
-{
-    StringBuffer sb(cx);
-    EncodeResult result = Encode(sb, reinterpret_cast<const Latin1Char*>(chars), length,
-                                 js_isUriReservedPlusPound);
-    if (result == EncodeResult::Encode_Failure) {
-        return nullptr;
-    }
-    if (result == EncodeResult::Encode_BadUri) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_URI);
-        return nullptr;
-    }
-    if (sb.empty()) {
-        return NewStringCopyN<CanGC>(cx, chars, length);
-    }
-    return sb.finishString();
-}
-
-static bool
-FlatStringMatchHelper(JSContext* cx, HandleString str, HandleString pattern, bool* isFlat, int32_t* match)
-{
-    RootedLinearString linearPattern(cx, pattern->ensureLinear(cx));
-    if (!linearPattern) {
-        return false;
-    }
-
-    static const size_t MAX_FLAT_PAT_LEN = 256;
-    if (linearPattern->length() > MAX_FLAT_PAT_LEN || StringHasRegExpMetaChars(linearPattern)) {
-        *isFlat = false;
-        return true;
-    }
-
-    *isFlat = true;
-    if (str->isRope()) {
-        if (!RopeMatch(cx, &str->asRope(), linearPattern, match)) {
-            return false;
-        }
-    } else {
-        *match = StringMatch(&str->asLinear(), linearPattern);
-    }
-
-    return true;
-}
-
-static bool
-BuildFlatMatchArray(JSContext* cx, HandleString str, HandleString pattern, int32_t match,
-                    MutableHandleValue rval)
-{
-    if (match < 0) {
-        rval.setNull();
-        return true;
-    }
-
-    /* Get the templateObject that defines the shape and type of the output object */
-    JSObject* templateObject = cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
-    if (!templateObject) {
-        return false;
-    }
-
-    RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject));
-    if (!arr) {
-        return false;
-    }
-
-    /* Store a Value for each pair. */
-    arr->setDenseInitializedLength(1);
-    arr->initDenseElement(0, StringValue(pattern));
-
-    /* Set the |index| property. (TemplateObject positions it in slot 0) */
-    arr->setSlot(0, Int32Value(match));
-
-    /* Set the |input| property. (TemplateObject positions it in slot 1) */
-    arr->setSlot(1, StringValue(str));
-
-#ifdef DEBUG
-    RootedValue test(cx);
-    RootedId id(cx, NameToId(cx->names().index));
-    if (!NativeGetProperty(cx, arr, id, &test)) {
-        return false;
-    }
-    MOZ_ASSERT(test == arr->getSlot(0));
-    id = NameToId(cx->names().input);
-    if (!NativeGetProperty(cx, arr, id, &test)) {
-        return false;
-    }
-    MOZ_ASSERT(test == arr->getSlot(1));
-#endif
-
-    rval.setObject(*arr);
-    return true;
-}
-
-#ifdef DEBUG
-static bool
-CallIsStringOptimizable(JSContext* cx, const char* name, bool* result)
-{
-    FixedInvokeArgs<0> args(cx);
-
-    RootedValue rval(cx);
-    if (!CallSelfHostedFunction(cx, name, UndefinedHandleValue, args, &rval)) {
-        return false;
-    }
-
-    *result = rval.toBoolean();
-    return true;
-}
-#endif
-
-bool
-js::FlatStringMatch(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].isString());
-    MOZ_ASSERT(args[1].isString());
-#ifdef DEBUG
-    bool isOptimizable = false;
-    if (!CallIsStringOptimizable(cx, "IsStringMatchOptimizable", &isOptimizable)) {
-        return false;
-    }
-    MOZ_ASSERT(isOptimizable);
-#endif
-
-    RootedString str(cx, args[0].toString());
-    RootedString pattern(cx, args[1].toString());
-
-    bool isFlat = false;
-    int32_t match = 0;
-    if (!FlatStringMatchHelper(cx, str, pattern, &isFlat, &match)) {
-        return false;
-    }
-
-    if (!isFlat) {
-        args.rval().setUndefined();
-        return true;
-    }
-
-    return BuildFlatMatchArray(cx, str, pattern, match, args.rval());
-}
-
-bool
-js::FlatStringSearch(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].isString());
-    MOZ_ASSERT(args[1].isString());
-#ifdef DEBUG
-    bool isOptimizable = false;
-    if (!CallIsStringOptimizable(cx, "IsStringSearchOptimizable", &isOptimizable)) {
-        return false;
-    }
-    MOZ_ASSERT(isOptimizable);
-#endif
-
-    RootedString str(cx, args[0].toString());
-    RootedString pattern(cx, args[1].toString());
-
-    bool isFlat = false;
-    int32_t match = 0;
-    if (!FlatStringMatchHelper(cx, str, pattern, &isFlat, &match)) {
-        return false;
-    }
-
-    if (!isFlat) {
-        args.rval().setInt32(-2);
-        return true;
-    }
-
-    args.rval().setInt32(match);
-    return true;
-}
+#endif /* vm_InlineCharBuffer_inl_h */
--- a/js/src/vm/StringType-inl.h
+++ b/js/src/vm/StringType-inl.h
@@ -83,16 +83,36 @@ NewInlineString(JSContext* cx, HandleLin
     }
 
     JS::AutoCheckCannotGC nogc;
     mozilla::PodCopy(chars, base->chars<CharT>(nogc) + start, length);
     chars[length] = 0;
     return s;
 }
 
+template <typename CharT>
+static MOZ_ALWAYS_INLINE JSFlatString*
+TryEmptyOrStaticString(JSContext* cx, const CharT* chars, size_t n)
+{
+    // Measurements on popular websites indicate empty strings are pretty common
+    // and most strings with length 1 or 2 are in the StaticStrings table. For
+    // length 3 strings that's only about 1%, so we check n <= 2.
+    if (n <= 2) {
+        if (n == 0) {
+            return cx->emptyString();
+        }
+
+        if (JSFlatString* str = cx->staticStrings().lookup(chars, n)) {
+            return str;
+        }
+    }
+
+    return nullptr;
+}
+
 } /* namespace js */
 
 MOZ_ALWAYS_INLINE bool
 JSString::validateLength(JSContext* maybecx, size_t length)
 {
     if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
         js::ReportAllocationOverflow(maybecx);
         return false;
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -1580,36 +1580,16 @@ NewInlineStringDeflated(JSContext* cx, m
     for (size_t i = 0; i < len; i++) {
         MOZ_ASSERT(chars[i] <= JSString::MAX_LATIN1_CHAR);
         storage[i] = Latin1Char(chars[i]);
     }
     storage[len] = '\0';
     return str;
 }
 
-template <typename CharT>
-static MOZ_ALWAYS_INLINE JSFlatString*
-TryEmptyOrStaticString(JSContext* cx, const CharT* chars, size_t n)
-{
-    // Measurements on popular websites indicate empty strings are pretty common
-    // and most strings with length 1 or 2 are in the StaticStrings table. For
-    // length 3 strings that's only about 1%, so we check n <= 2.
-    if (n <= 2) {
-        if (n == 0) {
-            return cx->emptyString();
-        }
-
-        if (JSFlatString* str = cx->staticStrings().lookup(chars, n)) {
-            return str;
-        }
-    }
-
-    return nullptr;
-}
-
 template <AllowGC allowGC>
 static JSFlatString*
 NewStringDeflated(JSContext* cx, const char16_t* s, size_t n)
 {
     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n)) {
         return str;
     }
 
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -51,16 +51,17 @@
 #include "vm/JSContext.h"
 #include "vm/RegExpObject.h"
 #include "vm/SavedFrame.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 #include "wasm/WasmJS.h"
 
+#include "vm/InlineCharBuffer-inl.h"
 #include "vm/JSContext-inl.h"
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 
 using mozilla::BitwiseCast;
 using mozilla::NativeEndian;
 using mozilla::NumbersAreIdentical;
@@ -2160,21 +2161,22 @@ template <typename CharT>
 JSString*
 JSStructuredCloneReader::readStringImpl(uint32_t nchars)
 {
     if (nchars > JSString::MAX_LENGTH) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "string length");
         return nullptr;
     }
-    UniquePtr<CharT[], JS::FreePolicy> chars = AllocateChars<CharT>(context(), nchars);
-    if (!chars || !in.readChars(chars.get(), nchars)) {
+
+    InlineCharBuffer<CharT> chars;
+    if (!chars.maybeAlloc(context(), nchars) || !in.readChars(chars.get(), nchars)) {
         return nullptr;
     }
-    return NewString<CanGC>(context(), std::move(chars), nchars);
+    return chars.toStringDontDeflate(context(), nchars);
 }
 
 JSString*
 JSStructuredCloneReader::readString(uint32_t data)
 {
     uint32_t nchars = data & JS_BITMASK(31);
     bool latin1 = data & (1 << 31);
     return latin1 ? readStringImpl<Latin1Char>(nchars) : readStringImpl<char16_t>(nchars);
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1178783-1.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+*
+{
+    margin: 0;
+    padding: 0;
+}
+html
+{
+    height: 100%;
+    display: flex;
+    flex-flow: row nowrap;
+}
+body
+{
+    flex: 1 1 0px;
+    min-width: 0;
+    display: flex;
+    flex-flow: row nowrap;
+}
+ul
+{
+    list-style: none;
+}
+.vertical
+{
+    flex: 1 1 0px;
+    min-width: 0;
+    display: flex;
+    flex-flow: column nowrap;
+}
+.vertical > li:first-child
+{
+    flex: 1 1 0px;
+    min-height: 0;
+    background-color: #0ff;
+}
+.vertical > li:last-child
+{
+    flex: 0 0 0px;
+    min-height: 0;
+    background-color: #f0f;
+    display: flex;
+    flex-flow: row nowrap;
+}
+.horizontal-separator
+{
+    flex: 0 0 5px;
+    cursor: row-resize;
+    background-color: #fff;
+}
+  </style>
+</head>
+<body>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+  <ul class="vertical">
+    <li></li>
+    <li class="horizontal-separator"></li>
+    <li>
+<!-- ... etc ... -->
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -606,16 +606,17 @@ load 1146107.html
 load 1146114.html
 asserts(0-20) load 1153478.html # bug 1144852
 load 1153695.html
 load 1156222.html
 load 1156257.html
 load 1157011.html
 load 1169420-1.html
 load 1169420-2.html
+load 1178783-1.html
 load 1183431.html
 load 1186147-1.html
 load 1221112-1.html
 load 1221112-2.html
 load 1221874-1.html
 load 1221904.html
 load 1222783.xhtml
 load 1223522.xhtml
--- a/media/webrtc/trunk/gtest/moz.build
+++ b/media/webrtc/trunk/gtest/moz.build
@@ -26,17 +26,16 @@ LOCAL_INCLUDES += [
     '/media/libopus/include',
     '/media/libopus/src',
     '/media/libyuv/libyuv/include',
 ]
 
 USE_LIBS += [
     '/media/webrtc/trunk/third_party/gflags/gflags_gflags/gflags',
     '/testing/gtest/gtest',
-    'chromium_atomics',
     'media_libopus',
     'mozglue',
     'speex',
     'webrtc',
     'webrtc_common_gn',
     'webrtc_gn',
     'webrtc_i420_gn',
     'webrtc_vp8_gn',
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -8,16 +8,17 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
 
 #include <algorithm>
 #include <utility>
 
+#include "webrtc/base/arraysize.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/rate_limiter.h"
 #include "webrtc/base/trace_event.h"
 #include "webrtc/base/timeutils.h"
 #include "webrtc/call/call.h"
 #include "webrtc/logging/rtc_event_log/rtc_event_log.h"
 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
--- a/media/webrtc/trunk/webrtc/modules/video_capture/windows/device_info_ds.h
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/windows/device_info_ds.h
@@ -8,17 +8,16 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_DEVICE_INFO_DS_H_
 #define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_DEVICE_INFO_DS_H_
 
 #include "webrtc/modules/video_capture/device_info_impl.h"
 #include "webrtc/modules/video_capture/video_capture_impl.h"
-#include "base/singleton.h"
 
 #include <dshow.h>
 #include <windows.h>
 
 namespace webrtc
 {
 namespace videocapturemodule
 {
--- a/media/webrtc/trunk/webrtc/system_wrappers/include/static_instance.h
+++ b/media/webrtc/trunk/webrtc/system_wrappers/include/static_instance.h
@@ -8,21 +8,16 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_
 #define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_
 
 #include <assert.h>
 
-#if defined(WEBRTC_ANDROID)
-#define OS_LINUX
-#endif
-#include "base/singleton.h"
-
 namespace webrtc {
 
 enum CountOperation {
   kRelease,
   kAddRef,
   kAddRefNoCreate
 };
 enum CreateOperation {
@@ -31,14 +26,15 @@ enum CreateOperation {
   kDestroy
 };
 
 template <class T>
 // Construct On First Use idiom. Avoids
 // "static initialization order fiasco".
 static T* GetStaticInstance(CountOperation count_operation) {
   // Simple solution since we don't use this for large objects anymore
-  return Singleton<T>::get();
+  static T instance;
+  return &instance;
 }
 
 }  // namspace webrtc
 
 #endif  // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_
--- a/security/manager/ssl/nsNSSCertificate.cpp
+++ b/security/manager/ssl/nsNSSCertificate.cpp
@@ -886,16 +886,20 @@ nsNSSCertList*
 nsNSSCertList::GetCertList()
 {
   return this;
 }
 
 NS_IMETHODIMP
 nsNSSCertList::AddCert(nsIX509Cert* aCert)
 {
+  if (!aCert) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
   // We need an owning handle when calling nsIX509Cert::GetCert().
   UniqueCERTCertificate cert(aCert->GetCert());
   if (!cert) {
     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
     return NS_ERROR_FAILURE;
   }
   mCerts.push_back(std::move(cert));
   return NS_OK;
@@ -1037,27 +1041,29 @@ nsNSSCertList::Read(nsIObjectInputStream
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   for (uint32_t i = 0; i < certListLen; ++i) {
     nsCOMPtr<nsISupports> certSupports;
     rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
     if (NS_FAILED(rv)) {
-      break;
+      return rv;
     }
-
     nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
+    if (!cert) {
+      return NS_ERROR_UNEXPECTED;
+    }
     rv = AddCert(cert);
     if (NS_FAILED(rv)) {
-      break;
+      return rv;
     }
   }
 
-  return rv;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
 {
   nsCOMPtr<nsISimpleEnumerator> enumerator(new nsNSSCertListEnumerator(mCerts));
   enumerator.forget(_retval);
   return NS_OK;
--- a/security/manager/ssl/tests/unit/test_cert_chains.js
+++ b/security/manager/ssl/tests/unit/test_cert_chains.js
@@ -16,19 +16,40 @@ function test_cert_equals() {
   ok(certA.equals(certB),
      "equals() on cert objects constructed from the same cert file should" +
      " return true");
   ok(!certA.equals(certC),
      "equals() on cert objects constructed from files for different certs" +
      " should return false");
 }
 
+function test_bad_cert_list_serialization() {
+  // Normally the serialization of an nsIX509CertList consists of some header
+  // junk (IIDs and whatnot), 4 bytes representing how many nsIX509Cert follow,
+  // and then the serialization of each nsIX509Cert. This serialization consists
+  // of the header junk for an nsIX509CertList with 1 "nsIX509Cert", but then
+  // instead of an nsIX509Cert, the subsequent bytes represent the serialization
+  // of another nsIX509CertList (with 0 nsIX509Cert). This test ensures that
+  // nsIX509CertList safely handles this unexpected input when deserializing.
+  const badCertListSerialization =
+    "lZ+xZWUXSH+rm9iRO+UxlwAAAAAAAAAAwAAAAAAAAEYAAAABlZ+xZWUXSH+rm9iRO+UxlwAAAAAA" +
+    "AAAAwAAAAAAAAEYAAAAA";
+  let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
+                    .getService(Ci.nsISerializationHelper);
+  throws(() => serHelper.deserializeObject(badCertListSerialization),
+         /NS_ERROR_UNEXPECTED/,
+         "deserializing a bogus nsIX509CertList should throw NS_ERROR_UNEXPECTED");
+}
+
 function test_cert_list_serialization() {
   let certList = build_cert_chain(["default-ee", "expired-ee"]);
 
+  throws(() => certList.addCert(null), /NS_ERROR_ILLEGAL_VALUE/,
+         "trying to add a null cert to an nsIX509CertList should throw");
+
   // Serialize the cert list to a string
   let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
                     .getService(Ci.nsISerializationHelper);
   certList.QueryInterface(Ci.nsISerializable);
   let serialized = serHelper.serializeToString(certList);
 
   // Deserialize from the string and compare to the original object
   let deserialized = serHelper.deserializeObject(serialized);
@@ -195,16 +216,21 @@ function run_test() {
   add_tls_server_setup("BadCertServer", "bad_certs");
 
   // Test nsIX509Cert.equals
   add_test(function() {
     test_cert_equals();
     run_next_test();
   });
 
+  add_test(function() {
+    test_bad_cert_list_serialization();
+    run_next_test();
+  });
+
   // Test serialization of nsIX509CertList
   add_test(function() {
     test_cert_list_serialization();
     run_next_test();
   });
 
   add_test(function() {
     test_cert_pkcs7_export();
--- a/storage/mozStorageService.cpp
+++ b/storage/mozStorageService.cpp
@@ -614,18 +614,20 @@ Service::OpenAsyncDatabase(nsIVariant *a
   rv = aDatabaseStore->GetAsISupports(getter_AddRefs(dbStore));
   if (NS_SUCCEEDED(rv)) {
     // Generally, aDatabaseStore holds the database nsIFile.
     storageFile = do_QueryInterface(dbStore, &rv);
     if (NS_FAILED(rv)) {
       return NS_ERROR_INVALID_ARG;
     }
 
-    rv = storageFile->Clone(getter_AddRefs(storageFile));
+    nsCOMPtr<nsIFile> cloned;
+    rv = storageFile->Clone(getter_AddRefs(cloned));
     MOZ_ASSERT(NS_SUCCEEDED(rv));
+    storageFile = cloned.forget();
 
     if (!readOnly) {
       // Ensure that SQLITE_OPEN_CREATE is passed in for compatibility reasons.
       flags |= SQLITE_OPEN_CREATE;
     }
 
     // Apply the shared-cache option.
     flags |= shared ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE;
--- a/tools/fuzzing/faulty/Faulty.cpp
+++ b/tools/fuzzing/faulty/Faulty.cpp
@@ -346,16 +346,24 @@ Faulty::MutationFactor()
     if (n != 0) {
       sPropValue = n;
       return sPropValue;
     }
   }
   return sPropValue;
 }
 
+// static
+Faulty&
+Faulty::instance()
+{
+  static Faulty faulty;
+  return faulty;
+}
+
 //
 // Strategy: Pipes
 //
 
 void
 Faulty::MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability)
 {
   if (!mFuzzPipes) {
--- a/tools/fuzzing/faulty/Faulty.h
+++ b/tools/fuzzing/faulty/Faulty.h
@@ -6,17 +6,16 @@
 
 #ifndef mozilla_ipc_Faulty_h
 #define mozilla_ipc_Faulty_h
 
 #include <set>
 #include <string>
 #include <vector>
 #include "base/string16.h"
-#include "base/singleton.h"
 #include "nsDebug.h"
 #include "nsTArray.h"
 
 #define FAULTY_DEFAULT_PROBABILITY 1000
 #define FAULTY_DEFAULT_MUTATION_FACTOR 10
 #define FAULTY_LOG(fmt, args...) \
   if (mozilla::ipc::Faulty::IsLoggingEnabled()) { \
     printf_stderr("[Faulty] (%10u) " fmt "\n", getpid(), ## args); \
@@ -39,16 +38,18 @@ class Faulty
     static unsigned int DefaultProbability(void);
     static bool Logging(void);
     static bool IsLoggingEnabled(void) { return sIsLoggingEnabled; }
     static std::vector<uint8_t> GetDataFromIPCMessage(IPC::Message* aMsg);
     static nsresult CreateOutputDirectory(const char *aPathname);
     static nsresult ReadFile(const char* aPathname, nsTArray<nsCString> &aArray);
     static void CopyFDs(IPC::Message* aDstMsg, IPC::Message* aSrcMsg);
 
+    static Faulty& instance();
+
     // Fuzzing methods for Pickle.
     void FuzzBool(bool* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzChar(char* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUChar(unsigned char* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt16(int16_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt16(uint16_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt(int* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt32(uint32_t* aValue, unsigned int aProbability=sDefaultProbability);
@@ -87,17 +88,16 @@ class Faulty
     const char* mMessagePath;
     const char* mBlacklistPath;
 
     size_t sMsgCounter;
 
     static const bool sIsLoggingEnabled;
 
     Faulty();
-    friend struct DefaultSingletonTraits<Faulty>;
     DISALLOW_EVIL_CONSTRUCTORS(Faulty);
 
     static bool IsValidProcessType(void);
     static uint32_t MutationFactor();
 
     // Fuzzing methods for Pickle
     void MutateBool(bool* aValue);
     void MutateChar(char* aValue);