зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to central, a=merge
MozReview-Commit-ID: KWDF34vWlBx
This commit is contained in:
Коммит
a7c590aa9c
|
@ -155,9 +155,13 @@ XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function() {
|
|||
try {
|
||||
// Hide all notifications while the URL is being edited and the address bar
|
||||
// has focus, including the virtual focus in the results popup.
|
||||
// We also have to hide notifications explicitly when the window is
|
||||
// minimized because of the effects of the "noautohide" attribute on Linux.
|
||||
// This can be removed once bug 545265 and bug 1320361 are fixed.
|
||||
let shouldSuppress = () => {
|
||||
return gURLBar.getAttribute("pageproxystate") != "valid" &&
|
||||
gURLBar.focused;
|
||||
return window.windowState == window.STATE_MINIMIZED ||
|
||||
(gURLBar.getAttribute("pageproxystate") != "valid" &&
|
||||
gURLBar.focused);
|
||||
};
|
||||
return new tmp.PopupNotifications(gBrowser,
|
||||
document.getElementById("notification-popup"),
|
||||
|
@ -1500,6 +1504,15 @@ var gBrowserInit = {
|
|||
|
||||
gExtensionsNotifications.init();
|
||||
|
||||
let wasMinimized = window.windowState == window.STATE_MINIMIZED;
|
||||
window.addEventListener("sizemodechange", () => {
|
||||
let isMinimized = window.windowState == window.STATE_MINIMIZED;
|
||||
if (wasMinimized != isMinimized) {
|
||||
wasMinimized = isMinimized;
|
||||
UpdatePopupNotificationsVisibility();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("mousemove", MousePosTracker);
|
||||
window.addEventListener("dragover", MousePosTracker);
|
||||
|
||||
|
|
|
@ -2,26 +2,6 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
|||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
if test `uname -s` = Darwin; then
|
||||
# The toolchain installed on our OSX 10.7 build machines is too old to support
|
||||
# MachO LC_DATA_IN_CODE load command, which newer LLVM generates, so we need to
|
||||
# use a newer toolchain that we build.
|
||||
#
|
||||
# Unfortunately setting $PATH is not enough, because the build system hardcodes
|
||||
# the default values for some of the build tools, which we also need to
|
||||
# override below. The default value for host ar and host ranlib is also
|
||||
# hardcoded so we need to override those separately.
|
||||
CCTOOLS_DIR="$topsrcdir/cctools/bin"
|
||||
export PATH="$CCTOOLS_DIR:$PATH"
|
||||
export AR="$CCTOOLS_DIR/ar"
|
||||
export HOST_AR="$CCTOOLS_DIR/ar"
|
||||
export RANLIB="$CCTOOLS_DIR/ranlib"
|
||||
export HOST_RANLIB="$CCTOOLS_DIR/ranlib"
|
||||
export LIPO="$CCTOOLS_DIR/lipo"
|
||||
export OTOOL="$CCTOOLS_DIR/otool"
|
||||
export STRIP="$CCTOOLS_DIR/strip"
|
||||
fi
|
||||
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --enable-debug
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/shared/widgets/color-widget.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/inspector.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/rules.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/computed.css"/>
|
||||
|
|
|
@ -108,7 +108,7 @@ TextPropertyEditor.prototype = {
|
|||
this.element._textPropertyEditor = this;
|
||||
|
||||
this.container = createChild(this.element, "div", {
|
||||
class: "ruleview-propertycontainer"
|
||||
class: "ruleview-propertycontainer inline-tooltip-container"
|
||||
});
|
||||
|
||||
// The enable checkbox will disable or enable the rule.
|
||||
|
|
|
@ -40,102 +40,18 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
|||
function ColorWidget(parentEl, rgb) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.element = parentEl.ownerDocument.createElementNS(XHTML_NS, "div");
|
||||
this.parentEl = parentEl;
|
||||
|
||||
this.element.className = "colorwidget-container";
|
||||
this.element.innerHTML = `
|
||||
<div class="colorwidget-top">
|
||||
<div class="colorwidget-fill"></div>
|
||||
<div class="colorwidget-top-inner">
|
||||
<div class="colorwidget-color colorwidget-box">
|
||||
<div class="colorwidget-sat">
|
||||
<div class="colorwidget-val">
|
||||
<div class="colorwidget-dragger"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-hue colorwidget-box">
|
||||
<div class="colorwidget-slider colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-alpha colorwidget-checker colorwidget-box">
|
||||
<div class="colorwidget-alpha-inner">
|
||||
<div class="colorwidget-alpha-handle colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-value">
|
||||
<select class="colorwidget-select">
|
||||
<option value="hex">Hex</option>
|
||||
<option value="rgba">RGBA</option>
|
||||
<option value="hsla">HSLA</option>
|
||||
</select>
|
||||
<div class="colorwidget-hex">
|
||||
<input class="colorwidget-hex-input"/>
|
||||
</div>
|
||||
<div class="colorwidget-rgba colorwidget-hidden">
|
||||
<input class="colorwidget-rgba-r" data-id="r" />
|
||||
<input class="colorwidget-rgba-g" data-id="g" />
|
||||
<input class="colorwidget-rgba-b" data-id="b" />
|
||||
<input class="colorwidget-rgba-a" data-id="a" />
|
||||
</div>
|
||||
<div class="colorwidget-hsla colorwidget-hidden">
|
||||
<input class="colorwidget-hsla-h" data-id="h" />
|
||||
<input class="colorwidget-hsla-s" data-id="s" />
|
||||
<input class="colorwidget-hsla-l" data-id="l" />
|
||||
<input class="colorwidget-hsla-a" data-id="a" />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.onSelectValueChange = this.onSelectValueChange.bind(this);
|
||||
this.onHexInputChange = this.onHexInputChange.bind(this);
|
||||
this.onRgbaInputChange = this.onRgbaInputChange.bind(this);
|
||||
this.onHslaInputChange = this.onHslaInputChange.bind(this);
|
||||
|
||||
this.onAlphaSliderMove = this.onAlphaSliderMove.bind(this);
|
||||
this.onElementClick = this.onElementClick.bind(this);
|
||||
this.element.addEventListener("click", this.onElementClick);
|
||||
this.onDraggerMove = this.onDraggerMove.bind(this);
|
||||
this.onHexInputChange = this.onHexInputChange.bind(this);
|
||||
this.onHslaInputChange = this.onHslaInputChange.bind(this);
|
||||
this.onRgbaInputChange = this.onRgbaInputChange.bind(this);
|
||||
this.onSelectValueChange = this.onSelectValueChange.bind(this);
|
||||
this.onSliderMove = this.onSliderMove.bind(this);
|
||||
|
||||
this.parentEl.appendChild(this.element);
|
||||
|
||||
this.slider = this.element.querySelector(".colorwidget-hue");
|
||||
this.slideHelper = this.element.querySelector(".colorwidget-slider");
|
||||
ColorWidget.draggable(this.slider, this.onSliderMove.bind(this));
|
||||
|
||||
this.dragger = this.element.querySelector(".colorwidget-color");
|
||||
this.dragHelper = this.element.querySelector(".colorwidget-dragger");
|
||||
ColorWidget.draggable(this.dragger, this.onDraggerMove.bind(this));
|
||||
|
||||
this.alphaSlider = this.element.querySelector(".colorwidget-alpha");
|
||||
this.alphaSliderInner = this.element.querySelector(".colorwidget-alpha-inner");
|
||||
this.alphaSliderHelper = this.element.querySelector(".colorwidget-alpha-handle");
|
||||
ColorWidget.draggable(this.alphaSliderInner, this.onAlphaSliderMove.bind(this));
|
||||
|
||||
this.colorSelect = this.element.querySelector(".colorwidget-select");
|
||||
this.colorSelect.addEventListener("change", this.onSelectValueChange);
|
||||
|
||||
this.hexValue = this.element.querySelector(".colorwidget-hex");
|
||||
this.hexValueInput = this.element.querySelector(".colorwidget-hex-input");
|
||||
this.hexValueInput.addEventListener("input", this.onHexInputChange);
|
||||
|
||||
this.rgbaValue = this.element.querySelector(".colorwidget-rgba");
|
||||
this.rgbaValueInputs = {
|
||||
r: this.element.querySelector(".colorwidget-rgba-r"),
|
||||
g: this.element.querySelector(".colorwidget-rgba-g"),
|
||||
b: this.element.querySelector(".colorwidget-rgba-b"),
|
||||
a: this.element.querySelector(".colorwidget-rgba-a"),
|
||||
};
|
||||
this.rgbaValue.addEventListener("input", this.onRgbaInputChange);
|
||||
|
||||
this.hslaValue = this.element.querySelector(".colorwidget-hsla");
|
||||
this.hslaValueInputs = {
|
||||
h: this.element.querySelector(".colorwidget-hsla-h"),
|
||||
s: this.element.querySelector(".colorwidget-hsla-s"),
|
||||
l: this.element.querySelector(".colorwidget-hsla-l"),
|
||||
a: this.element.querySelector(".colorwidget-hsla-a"),
|
||||
};
|
||||
this.hslaValue.addEventListener("input", this.onHslaInputChange);
|
||||
this.initializeColorWidget();
|
||||
|
||||
if (rgb) {
|
||||
this.rgb = rgb;
|
||||
|
@ -291,7 +207,101 @@ ColorWidget.prototype = {
|
|||
rgb[3] + ")";
|
||||
},
|
||||
|
||||
initializeColorWidget: function () {
|
||||
this.parentEl.innerHTML = "";
|
||||
this.element = this.parentEl.ownerDocument.createElementNS(XHTML_NS, "div");
|
||||
|
||||
this.element.className = "colorwidget-container";
|
||||
this.element.innerHTML = `
|
||||
<div class="colorwidget-top">
|
||||
<div class="colorwidget-fill"></div>
|
||||
<div class="colorwidget-top-inner">
|
||||
<div class="colorwidget-color colorwidget-box">
|
||||
<div class="colorwidget-sat">
|
||||
<div class="colorwidget-val">
|
||||
<div class="colorwidget-dragger"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-hue colorwidget-box">
|
||||
<div class="colorwidget-slider colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-alpha colorwidget-checker colorwidget-box">
|
||||
<div class="colorwidget-alpha-inner">
|
||||
<div class="colorwidget-alpha-handle colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-value">
|
||||
<select class="colorwidget-select">
|
||||
<option value="hex">Hex</option>
|
||||
<option value="rgba">RGBA</option>
|
||||
<option value="hsla">HSLA</option>
|
||||
</select>
|
||||
<div class="colorwidget-hex">
|
||||
<input class="colorwidget-hex-input"/>
|
||||
</div>
|
||||
<div class="colorwidget-rgba colorwidget-hidden">
|
||||
<input class="colorwidget-rgba-r" data-id="r" />
|
||||
<input class="colorwidget-rgba-g" data-id="g" />
|
||||
<input class="colorwidget-rgba-b" data-id="b" />
|
||||
<input class="colorwidget-rgba-a" data-id="a" />
|
||||
</div>
|
||||
<div class="colorwidget-hsla colorwidget-hidden">
|
||||
<input class="colorwidget-hsla-h" data-id="h" />
|
||||
<input class="colorwidget-hsla-s" data-id="s" />
|
||||
<input class="colorwidget-hsla-l" data-id="l" />
|
||||
<input class="colorwidget-hsla-a" data-id="a" />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.element.addEventListener("click", this.onElementClick);
|
||||
|
||||
this.parentEl.appendChild(this.element);
|
||||
|
||||
this.slider = this.element.querySelector(".colorwidget-hue");
|
||||
this.slideHelper = this.element.querySelector(".colorwidget-slider");
|
||||
ColorWidget.draggable(this.slider, this.onSliderMove);
|
||||
|
||||
this.dragger = this.element.querySelector(".colorwidget-color");
|
||||
this.dragHelper = this.element.querySelector(".colorwidget-dragger");
|
||||
ColorWidget.draggable(this.dragger, this.onDraggerMove);
|
||||
|
||||
this.alphaSlider = this.element.querySelector(".colorwidget-alpha");
|
||||
this.alphaSliderInner = this.element.querySelector(".colorwidget-alpha-inner");
|
||||
this.alphaSliderHelper = this.element.querySelector(".colorwidget-alpha-handle");
|
||||
ColorWidget.draggable(this.alphaSliderInner, this.onAlphaSliderMove);
|
||||
|
||||
this.colorSelect = this.element.querySelector(".colorwidget-select");
|
||||
this.colorSelect.addEventListener("change", this.onSelectValueChange);
|
||||
|
||||
this.hexValue = this.element.querySelector(".colorwidget-hex");
|
||||
this.hexValueInput = this.element.querySelector(".colorwidget-hex-input");
|
||||
this.hexValueInput.addEventListener("input", this.onHexInputChange);
|
||||
|
||||
this.rgbaValue = this.element.querySelector(".colorwidget-rgba");
|
||||
this.rgbaValueInputs = {
|
||||
r: this.element.querySelector(".colorwidget-rgba-r"),
|
||||
g: this.element.querySelector(".colorwidget-rgba-g"),
|
||||
b: this.element.querySelector(".colorwidget-rgba-b"),
|
||||
a: this.element.querySelector(".colorwidget-rgba-a"),
|
||||
};
|
||||
this.rgbaValue.addEventListener("input", this.onRgbaInputChange);
|
||||
|
||||
this.hslaValue = this.element.querySelector(".colorwidget-hsla");
|
||||
this.hslaValueInputs = {
|
||||
h: this.element.querySelector(".colorwidget-hsla-h"),
|
||||
s: this.element.querySelector(".colorwidget-hsla-s"),
|
||||
l: this.element.querySelector(".colorwidget-hsla-l"),
|
||||
a: this.element.querySelector(".colorwidget-hsla-a"),
|
||||
};
|
||||
this.hslaValue.addEventListener("input", this.onHslaInputChange);
|
||||
},
|
||||
|
||||
show: function () {
|
||||
this.initializeColorWidget();
|
||||
this.element.classList.add("colorwidget-show");
|
||||
|
||||
this.slideHeight = this.slider.offsetHeight;
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/* 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 EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
/**
|
||||
* The InlineTooltip can display widgets for the CSS Rules view in an
|
||||
* inline container.
|
||||
*
|
||||
* @param {Document} doc
|
||||
* The toolbox document to attach the InlineTooltip container.
|
||||
*/
|
||||
function InlineTooltip(doc) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.doc = doc;
|
||||
|
||||
this.panel = this.doc.createElement("div");
|
||||
|
||||
this.topWindow = this._getTopWindow();
|
||||
}
|
||||
|
||||
InlineTooltip.prototype = {
|
||||
/**
|
||||
* Show the tooltip. It might be wise to append some content first if you
|
||||
* don't want the tooltip to be empty.
|
||||
*
|
||||
* @param {Node} anchor
|
||||
* Which node below which the tooltip should be shown.
|
||||
*/
|
||||
show(anchor) {
|
||||
anchor.parentNode.insertBefore(this.panel, anchor.nextSibling);
|
||||
|
||||
this.emit("shown");
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the current tooltip.
|
||||
*/
|
||||
hide() {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.panel.parentNode.remove(this.panel);
|
||||
|
||||
this.emit("hidden");
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the tooltip is currently displayed.
|
||||
*
|
||||
* @return {Boolean} true if the tooltip is visible
|
||||
*/
|
||||
isVisible() {
|
||||
return typeof this.panel.parentNode !== "undefined" && this.panel.parentNode !== null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the HTML content of the tooltip panel
|
||||
*/
|
||||
clear() {
|
||||
this.panel.innerHTML = "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the content of this tooltip. Will first clear the tooltip and then
|
||||
* append the new content element.
|
||||
*
|
||||
* @param {DOMNode} content
|
||||
* A node that can be appended in the tooltip
|
||||
*/
|
||||
setContent(content) {
|
||||
this.clear();
|
||||
|
||||
this.panel.appendChild(content);
|
||||
},
|
||||
|
||||
get content() {
|
||||
return this.panel.firstChild;
|
||||
},
|
||||
|
||||
_getTopWindow: function () {
|
||||
return this.doc.defaultView;
|
||||
},
|
||||
|
||||
destroy() {
|
||||
this.hide();
|
||||
this.doc = null;
|
||||
this.panel = null;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = InlineTooltip;
|
|
@ -7,6 +7,9 @@
|
|||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
|
||||
const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
|
||||
const InlineTooltip = require("devtools/client/shared/widgets/tooltip/InlineTooltip");
|
||||
|
||||
const INLINE_TOOLTIP_CLASS = "inline-tooltip-container";
|
||||
|
||||
/**
|
||||
* Base class for all (color, gradient, ...)-swatch based value editors inside
|
||||
|
@ -16,19 +19,30 @@ const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLToolti
|
|||
* The document to attach the SwatchBasedEditorTooltip. This is either the toolbox
|
||||
* document if the tooltip is a popup tooltip or the panel's document if it is an
|
||||
* inline editor.
|
||||
* @param {String} stylesheet
|
||||
* The stylesheet to be used for the HTMLTooltip.
|
||||
* @param {Boolean} useInline
|
||||
* A boolean flag representing whether or not the InlineTooltip should be used.
|
||||
*/
|
||||
function SwatchBasedEditorTooltip(document, stylesheet) {
|
||||
function SwatchBasedEditorTooltip(document, stylesheet, useInline) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.useInline = useInline;
|
||||
|
||||
// Creating a tooltip instance
|
||||
// This one will consume outside clicks as it makes more sense to let the user
|
||||
// close the tooltip by clicking out
|
||||
// It will also close on <escape> and <enter>
|
||||
this.tooltip = new HTMLTooltip(document, {
|
||||
type: "arrow",
|
||||
consumeOutsideClicks: true,
|
||||
useXulWrapper: true,
|
||||
stylesheet
|
||||
});
|
||||
if (useInline) {
|
||||
this.tooltip = new InlineTooltip(document);
|
||||
} else {
|
||||
// This one will consume outside clicks as it makes more sense to let the user
|
||||
// close the tooltip by clicking out
|
||||
// It will also close on <escape> and <enter>
|
||||
this.tooltip = new HTMLTooltip(document, {
|
||||
type: "arrow",
|
||||
consumeOutsideClicks: true,
|
||||
useXulWrapper: true,
|
||||
stylesheet
|
||||
});
|
||||
}
|
||||
|
||||
// By default, swatch-based editor tooltips revert value change on <esc> and
|
||||
// commit value change on <enter>
|
||||
|
@ -73,9 +87,13 @@ SwatchBasedEditorTooltip.prototype = {
|
|||
* immediately if there is no currently active swatch.
|
||||
*/
|
||||
show: function () {
|
||||
if (this.activeSwatch) {
|
||||
let tooltipAnchor = this.useInline ?
|
||||
this.activeSwatch.closest(`.${INLINE_TOOLTIP_CLASS}`) :
|
||||
this.activeSwatch;
|
||||
|
||||
if (tooltipAnchor) {
|
||||
let onShown = this.tooltip.once("shown");
|
||||
this.tooltip.show(this.activeSwatch, "topcenter bottomleft");
|
||||
this.tooltip.show(tooltipAnchor, "topcenter bottomleft");
|
||||
|
||||
// When the tooltip is closed by clicking outside the panel we want to
|
||||
// commit any changes.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
const Services = require("Services");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget");
|
||||
const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
|
||||
const SwatchBasedEditorTooltip = require("devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip");
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
|
@ -38,9 +39,10 @@ function SwatchColorPickerTooltip(document,
|
|||
inspector,
|
||||
{supportsCssColor4ColorFunction}) {
|
||||
let stylesheet = NEW_COLOR_WIDGET ?
|
||||
"chrome://devtools/content/shared/widgets/color-widget.css" :
|
||||
null :
|
||||
"chrome://devtools/content/shared/widgets/spectrum.css";
|
||||
SwatchBasedEditorTooltip.call(this, document, stylesheet);
|
||||
let tooltipDocument = NEW_COLOR_WIDGET ? inspector.panelDoc : document;
|
||||
SwatchBasedEditorTooltip.call(this, tooltipDocument, stylesheet, NEW_COLOR_WIDGET);
|
||||
|
||||
this.inspector = inspector;
|
||||
|
||||
|
@ -62,9 +64,20 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||
|
||||
let container = doc.createElementNS(XHTML_NS, "div");
|
||||
container.id = "spectrum-tooltip";
|
||||
let spectrumNode = doc.createElementNS(XHTML_NS, "div");
|
||||
spectrumNode.id = "spectrum";
|
||||
container.appendChild(spectrumNode);
|
||||
|
||||
let widget;
|
||||
let node = doc.createElementNS(XHTML_NS, "div");
|
||||
|
||||
if (NEW_COLOR_WIDGET) {
|
||||
node.id = "colorwidget";
|
||||
container.appendChild(node);
|
||||
widget = new ColorWidget(node, color);
|
||||
} else {
|
||||
node.id = "spectrum";
|
||||
container.appendChild(node);
|
||||
widget = new Spectrum(node, color);
|
||||
}
|
||||
|
||||
let eyedropper = doc.createElementNS(XHTML_NS, "button");
|
||||
eyedropper.id = "eyedropper-button";
|
||||
eyedropper.className = "devtools-button";
|
||||
|
@ -74,23 +87,15 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||
eyedropper.style.pointerEvents = "auto";
|
||||
container.appendChild(eyedropper);
|
||||
|
||||
let spectrum;
|
||||
if (NEW_COLOR_WIDGET) {
|
||||
this.tooltip.setContent(container, { width: 218, height: 271 });
|
||||
const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget");
|
||||
spectrum = new ColorWidget(spectrumNode, color);
|
||||
} else {
|
||||
this.tooltip.setContent(container, { width: 218, height: 224 });
|
||||
spectrum = new Spectrum(spectrumNode, color);
|
||||
}
|
||||
this.tooltip.setContent(container, { width: 218, height: 224 });
|
||||
|
||||
// Wait for the tooltip to be shown before calling spectrum.show
|
||||
// Wait for the tooltip to be shown before calling widget.show
|
||||
// as it expect to be visible in order to compute DOM element sizes.
|
||||
this.tooltip.once("shown", () => {
|
||||
spectrum.show();
|
||||
widget.show();
|
||||
});
|
||||
|
||||
return spectrum;
|
||||
return widget;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -100,6 +105,7 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||
show: Task.async(function* () {
|
||||
// Call then parent class' show function
|
||||
yield SwatchBasedEditorTooltip.prototype.show.call(this);
|
||||
|
||||
// Then set spectrum's color and listen to color changes to preview them
|
||||
if (this.activeSwatch) {
|
||||
this.currentSwatchColor = this.activeSwatch.nextSibling;
|
||||
|
|
|
@ -9,6 +9,7 @@ DevToolsModules(
|
|||
'EventTooltipHelper.js',
|
||||
'HTMLTooltip.js',
|
||||
'ImageTooltipHelper.js',
|
||||
'InlineTooltip.js',
|
||||
'SwatchBasedEditorTooltip.js',
|
||||
'SwatchColorPickerTooltip.js',
|
||||
'SwatchCubicBezierTooltip.js',
|
||||
|
|
|
@ -5,16 +5,19 @@
|
|||
/* CSS Variables specific to this panel that aren't defined by the themes */
|
||||
.theme-light {
|
||||
--rule-highlight-background-color: #ffee99;
|
||||
--rule-overridden-item-border-color: var(--theme-content-color3);
|
||||
}
|
||||
|
||||
.theme-dark {
|
||||
--rule-highlight-background-color: #594724;
|
||||
--rule-overridden-item-border-color: var(--theme-content-color1);
|
||||
}
|
||||
|
||||
.theme-firebug {
|
||||
--rule-highlight-background-color: #ffee99;
|
||||
--rule-property-name: darkgreen;
|
||||
--rule-property-value: darkblue;
|
||||
--rule-overridden-item-border-color: var(--theme-content-color2);
|
||||
}
|
||||
|
||||
/* Rule View Tabpanel */
|
||||
|
@ -428,9 +431,9 @@
|
|||
top: 0px;
|
||||
content: '';
|
||||
display: block;
|
||||
border-left: 1px solid var(--theme-highlight-gray);
|
||||
height: 0.7em;
|
||||
border-bottom: 1px solid var(--theme-highlight-gray);
|
||||
border-left: 0.5px solid var(--rule-overridden-item-border-color);
|
||||
height: 0.8em;
|
||||
border-bottom: 0.5px solid var(--rule-overridden-item-border-color);
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
|
@ -440,7 +443,7 @@
|
|||
bottom: -7px;
|
||||
content: '';
|
||||
display: block;
|
||||
border-left: 1px solid var(--theme-highlight-gray);
|
||||
border-left: 0.5px solid var(--rule-overridden-item-border-color);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
|
|
@ -988,13 +988,6 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
|
|||
|
||||
if (aValue.IsDirectory()) {
|
||||
Directory* directory = aValue.GetAsDirectory();
|
||||
|
||||
if (closure->mHolder->CloneScope() !=
|
||||
StructuredCloneHolder::StructuredCloneScope::SameProcessSameThread &&
|
||||
!directory->ClonableToDifferentThreadOrProcess()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WriteDirectory(closure->mWriter, directory);
|
||||
}
|
||||
|
||||
|
@ -1114,11 +1107,6 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
|
|||
{
|
||||
Directory* directory = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, aObj, directory))) {
|
||||
if (mStructuredCloneScope != StructuredCloneScope::SameProcessSameThread &&
|
||||
!directory->ClonableToDifferentThreadOrProcess()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WriteDirectory(aWriter, directory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ void
|
|||
CleanupChild(CacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
// fds cleaned up by mStreamCleanupList
|
||||
// PSendStream actors cleaned up by mStreamCleanupList
|
||||
// PChildToParentStream actors cleaned up by mStreamCleanupList
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/SendStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -20,7 +19,6 @@ namespace cache {
|
|||
|
||||
using mozilla::ipc::FileDescriptorSetParent;
|
||||
using mozilla::ipc::PBackgroundParent;
|
||||
using mozilla::ipc::SendStreamParent;
|
||||
|
||||
CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager, CacheId aCacheId,
|
||||
const CacheOpArgs& aOpArgs)
|
||||
|
@ -220,7 +218,7 @@ CacheOpParent::DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid
|
|||
}
|
||||
|
||||
// Option 2: A stream was serialized using normal methods or passed
|
||||
// as a PSendStream actor. Use the standard method for
|
||||
// as a PChildToParentStream actor. Use the standard method for
|
||||
// extracting the resulting stream.
|
||||
return DeserializeIPCStream(readStream.stream());
|
||||
}
|
||||
|
|
|
@ -60,8 +60,11 @@ CacheStreamControlParent::SerializeStream(CacheReadStream* aReadStreamOut,
|
|||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStream);
|
||||
|
||||
UniquePtr<AutoIPCStream> autoStream(new AutoIPCStream(aReadStreamOut->stream()));
|
||||
autoStream->Serialize(aStream, Manager());
|
||||
bool ok = autoStream->Serialize(aStream, Manager());
|
||||
MOZ_DIAGNOSTIC_ASSERT(ok);
|
||||
|
||||
aStreamCleanupList.AppendElement(Move(autoStream));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
include protocol PCache;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include IPCStream;
|
||||
include ChannelInfo;
|
||||
include PBackgroundSharedTypes;
|
||||
|
|
|
@ -7,7 +7,8 @@ include protocol PBlob; // FIXME: bug 792908
|
|||
include protocol PCacheOp;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
|
||||
include CacheTypes;
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ include protocol PCache;
|
|||
include protocol PCacheStorage;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
|
||||
include CacheTypes;
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ include protocol PCache;
|
|||
include protocol PCacheOp;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
|
||||
include CacheTypes;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/SendStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace mozilla {
|
|||
|
||||
namespace ipc {
|
||||
class PBackgroundChild;
|
||||
class SendStreamChild;
|
||||
class AutoIPCStream;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,9 +80,9 @@ InternalResponse::~InternalResponse()
|
|||
}
|
||||
|
||||
template void
|
||||
InternalResponse::ToIPC<PContentParent>
|
||||
InternalResponse::ToIPC<nsIContentParent>
|
||||
(IPCInternalResponse* aIPCResponse,
|
||||
PContentParent* aManager,
|
||||
nsIContentParent* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
|
||||
template void
|
||||
InternalResponse::ToIPC<nsIContentChild>
|
||||
|
@ -127,7 +127,8 @@ InternalResponse::ToIPC(IPCInternalResponse* aIPCResponse,
|
|||
|
||||
if (body) {
|
||||
aAutoStream.reset(new mozilla::ipc::AutoIPCStream(aIPCResponse->body()));
|
||||
aAutoStream->Serialize(body, aManager);
|
||||
bool ok = aAutoStream->Serialize(body, aManager);
|
||||
MOZ_DIAGNOSTIC_ASSERT(ok);
|
||||
} else {
|
||||
aIPCResponse->body() = void_t();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ include protocol PBlobStream;
|
|||
include protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
|
||||
include BlobTypes;
|
||||
include DOMTypes;
|
||||
|
|
|
@ -239,18 +239,5 @@ Directory::GetFileSystem(ErrorResult& aRv)
|
|||
return mFileSystem;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Directory::ClonableToDifferentThreadOrProcess() const
|
||||
{
|
||||
// If we don't have a fileSystem we are going to create a OSFileSystem that is
|
||||
// clonable everywhere.
|
||||
if (!mFileSystem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mFileSystem->ClonableToDifferentThreadOrProcess();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -96,9 +96,6 @@ public:
|
|||
FileSystemBase*
|
||||
GetFileSystem(ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
ClonableToDifferentThreadOrProcess() const;
|
||||
|
||||
nsIFile*
|
||||
GetInternalNsIFile() const
|
||||
{
|
||||
|
|
|
@ -72,18 +72,6 @@ public:
|
|||
bool
|
||||
GetRealPath(BlobImpl* aFile, nsIFile** aPath) const;
|
||||
|
||||
// IPC initialization
|
||||
// See how these 2 methods are used in FileSystemTaskChildBase.
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const { return false; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() { return NS_ERROR_FAILURE; }
|
||||
|
||||
virtual bool
|
||||
ClonableToDifferentThreadOrProcess() const { return false; }
|
||||
|
||||
// CC methods
|
||||
virtual void Unlink() {}
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {}
|
||||
|
|
|
@ -256,12 +256,6 @@ FileSystemTaskParentBase::Start()
|
|||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (NeedToGoToMainThread()) {
|
||||
DebugOnly<nsresult> rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
|
||||
return;
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rv = DispatchToIOThread(this);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchToIOThread failed");
|
||||
}
|
||||
|
@ -305,52 +299,12 @@ FileSystemTaskParentBase::SetError(const nsresult& aErrorValue)
|
|||
mErrorValue = FileSystemErrorFromNsError(aErrorValue);
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemTaskParentBase::NeedToGoToMainThread() const
|
||||
{
|
||||
return mFileSystem->NeedToGoToMainThread();
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileSystemTaskParentBase::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mFileSystem->MainThreadWork();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileSystemTaskParentBase::Run()
|
||||
{
|
||||
// This method can run in 3 different threads. Here why:
|
||||
// 1. if we are on the main-thread it's because the task must do something
|
||||
// here. If no errors are returned we go the step 2.
|
||||
// 2. We can be here directly if the task doesn't have nothing to do on the
|
||||
// main-thread. We are are on the I/O thread and we call IOWork().
|
||||
// 3. Both step 1 (in case of error) and step 2 end up here where return the
|
||||
// value back to the PBackground thread.
|
||||
if (NS_IsMainThread()) {
|
||||
MOZ_ASSERT(NeedToGoToMainThread());
|
||||
|
||||
nsresult rv = MainThreadWork();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
SetError(rv);
|
||||
|
||||
// Something when wrong. Let's go to the Background thread directly
|
||||
// skipping the I/O thread step.
|
||||
rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Next step must happen on the I/O thread.
|
||||
rv = DispatchToIOThread(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
// This method can run in 2 different threads. Here why:
|
||||
// 1. We are are on the I/O thread and we call IOWork().
|
||||
// 2. After step 1, it returns back to the PBackground thread.
|
||||
|
||||
// Run I/O thread tasks
|
||||
if (!IsOnBackgroundThread()) {
|
||||
|
|
|
@ -225,17 +225,6 @@ public:
|
|||
void
|
||||
HandleResult();
|
||||
|
||||
// If this task must do something on the main-thread before IOWork(), it must
|
||||
// overwrite this method. Otherwise it returns true if the FileSystem must be
|
||||
// initialized on the main-thread. It's called from the Background thread.
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const;
|
||||
|
||||
// This method is called only if NeedToGoToMainThread() returns true.
|
||||
// Of course, it runs on the main-thread.
|
||||
virtual nsresult
|
||||
MainThreadWork();
|
||||
|
||||
bool
|
||||
HasError() const { return NS_FAILED(mErrorValue); }
|
||||
|
||||
|
|
|
@ -46,9 +46,6 @@ public:
|
|||
virtual void
|
||||
SerializeDOMPath(nsAString& aOutput) const override;
|
||||
|
||||
virtual bool
|
||||
ClonableToDifferentThreadOrProcess() const override { return true; }
|
||||
|
||||
// CC methods
|
||||
virtual void Unlink() override;
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PContent;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PTransportProvider;
|
||||
include FetchTypes;
|
||||
|
|
|
@ -90,10 +90,10 @@ ContentBridgeChild::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD)
|
|||
return PContentBridgeChild::SendPFileDescriptorSetConstructor(aFD);
|
||||
}
|
||||
|
||||
PSendStreamChild*
|
||||
ContentBridgeChild::SendPSendStreamConstructor(PSendStreamChild* aActor)
|
||||
PChildToParentStreamChild*
|
||||
ContentBridgeChild::SendPChildToParentStreamConstructor(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
return PContentBridgeChild::SendPSendStreamConstructor(aActor);
|
||||
return PContentBridgeChild::SendPChildToParentStreamConstructor(aActor);
|
||||
}
|
||||
|
||||
// This implementation is identical to ContentChild::GetCPOWManager but we can't
|
||||
|
@ -168,16 +168,28 @@ ContentBridgeChild::DeallocPBlobChild(PBlobChild* aActor)
|
|||
return nsIContentChild::DeallocPBlobChild(aActor);
|
||||
}
|
||||
|
||||
PSendStreamChild*
|
||||
ContentBridgeChild::AllocPSendStreamChild()
|
||||
PChildToParentStreamChild*
|
||||
ContentBridgeChild::AllocPChildToParentStreamChild()
|
||||
{
|
||||
return nsIContentChild::AllocPSendStreamChild();
|
||||
return nsIContentChild::AllocPChildToParentStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeChild::DeallocPSendStreamChild(PSendStreamChild* aActor)
|
||||
ContentBridgeChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
return nsIContentChild::DeallocPSendStreamChild(aActor);
|
||||
return nsIContentChild::DeallocPChildToParentStreamChild(aActor);
|
||||
}
|
||||
|
||||
PParentToChildStreamChild*
|
||||
ContentBridgeChild::AllocPParentToChildStreamChild()
|
||||
{
|
||||
return nsIContentChild::AllocPParentToChildStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
|
||||
{
|
||||
return nsIContentChild::DeallocPParentToChildStreamChild(aActor);
|
||||
}
|
||||
|
||||
PFileDescriptorSetChild*
|
||||
|
|
|
@ -48,8 +48,8 @@ public:
|
|||
virtual mozilla::ipc::PFileDescriptorSetChild*
|
||||
SendPFileDescriptorSetConstructor(const mozilla::ipc::FileDescriptor&) override;
|
||||
|
||||
virtual mozilla::ipc::PSendStreamChild*
|
||||
SendPSendStreamConstructor(mozilla::ipc::PSendStreamChild*) override;
|
||||
virtual mozilla::ipc::PChildToParentStreamChild*
|
||||
SendPChildToParentStreamConstructor(mozilla::ipc::PChildToParentStreamChild*) override;
|
||||
|
||||
FORWARD_SHMEM_ALLOCATOR_TO(PContentBridgeChild)
|
||||
|
||||
|
@ -75,10 +75,16 @@ protected:
|
|||
virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams) override;
|
||||
virtual bool DeallocPBlobChild(PBlobChild*) override;
|
||||
|
||||
virtual mozilla::ipc::PSendStreamChild* AllocPSendStreamChild() override;
|
||||
virtual mozilla::ipc::PChildToParentStreamChild*
|
||||
AllocPChildToParentStreamChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPSendStreamChild(mozilla::ipc::PSendStreamChild* aActor) override;
|
||||
DeallocPChildToParentStreamChild(mozilla::ipc::PChildToParentStreamChild* aActor) override;
|
||||
|
||||
virtual PParentToChildStreamChild* AllocPParentToChildStreamChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor) override;
|
||||
|
||||
virtual PFileDescriptorSetChild*
|
||||
AllocPFileDescriptorSetChild(const mozilla::ipc::FileDescriptor& aFD) override;
|
||||
|
|
|
@ -110,6 +110,12 @@ ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
|
|||
aIsForBrowser);
|
||||
}
|
||||
|
||||
PParentToChildStreamParent*
|
||||
ContentBridgeParent::SendPParentToChildStreamConstructor(PParentToChildStreamParent* aActor)
|
||||
{
|
||||
return PContentBridgeParent::SendPParentToChildStreamConstructor(aActor);
|
||||
}
|
||||
|
||||
PBlobParent*
|
||||
ContentBridgeParent::AllocPBlobParent(const BlobConstructorParams& aParams)
|
||||
{
|
||||
|
@ -186,6 +192,12 @@ ContentBridgeParent::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PFileDescriptorSetParent*
|
||||
ContentBridgeParent::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD)
|
||||
{
|
||||
return PContentBridgeParent::SendPFileDescriptorSetConstructor(aFD);
|
||||
}
|
||||
|
||||
PFileDescriptorSetParent*
|
||||
ContentBridgeParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD)
|
||||
{
|
||||
|
@ -198,16 +210,28 @@ ContentBridgeParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* a
|
|||
return nsIContentParent::DeallocPFileDescriptorSetParent(aActor);
|
||||
}
|
||||
|
||||
PSendStreamParent*
|
||||
ContentBridgeParent::AllocPSendStreamParent()
|
||||
PChildToParentStreamParent*
|
||||
ContentBridgeParent::AllocPChildToParentStreamParent()
|
||||
{
|
||||
return nsIContentParent::AllocPSendStreamParent();
|
||||
return nsIContentParent::AllocPChildToParentStreamParent();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeParent::DeallocPSendStreamParent(PSendStreamParent* aActor)
|
||||
ContentBridgeParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
|
||||
{
|
||||
return nsIContentParent::DeallocPSendStreamParent(aActor);
|
||||
return nsIContentParent::DeallocPChildToParentStreamParent(aActor);
|
||||
}
|
||||
|
||||
PParentToChildStreamParent*
|
||||
ContentBridgeParent::AllocPParentToChildStreamParent()
|
||||
{
|
||||
return nsIContentParent::AllocPParentToChildStreamParent();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
|
||||
{
|
||||
return nsIContentParent::DeallocPParentToChildStreamParent(aActor);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -45,6 +45,9 @@ public:
|
|||
const ContentParentId& aCpID,
|
||||
const bool& aIsForBrowser) override;
|
||||
|
||||
virtual PFileDescriptorSetParent*
|
||||
SendPFileDescriptorSetConstructor(const FileDescriptor&) override;
|
||||
|
||||
FORWARD_SHMEM_ALLOCATOR_TO(PContentBridgeParent)
|
||||
|
||||
jsipc::CPOWManager* GetCPOWManager() override;
|
||||
|
@ -63,6 +66,9 @@ public:
|
|||
return -1;
|
||||
}
|
||||
|
||||
virtual mozilla::ipc::PParentToChildStreamParent*
|
||||
SendPParentToChildStreamConstructor(mozilla::ipc::PParentToChildStreamParent*) override;
|
||||
|
||||
protected:
|
||||
virtual ~ContentBridgeParent();
|
||||
|
||||
|
@ -114,9 +120,16 @@ protected:
|
|||
|
||||
virtual bool DeallocPBlobParent(PBlobParent*) override;
|
||||
|
||||
virtual PSendStreamParent* AllocPSendStreamParent() override;
|
||||
virtual PChildToParentStreamParent* AllocPChildToParentStreamParent() override;
|
||||
|
||||
virtual bool DeallocPSendStreamParent(PSendStreamParent* aActor) override;
|
||||
virtual bool
|
||||
DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::PParentToChildStreamParent*
|
||||
AllocPParentToChildStreamParent() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamParent(mozilla::ipc::PParentToChildStreamParent* aActor) override;
|
||||
|
||||
virtual PFileDescriptorSetParent*
|
||||
AllocPFileDescriptorSetParent(const mozilla::ipc::FileDescriptor&) override;
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/ipc/ProcessChild.h"
|
||||
#include "mozilla/ipc/PSendStreamChild.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamChild.h"
|
||||
#include "mozilla/ipc/TestShellChild.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/layers/APZChild.h"
|
||||
|
@ -1713,26 +1713,38 @@ ContentChild::DeallocPPrintingChild(PPrintingChild* printing)
|
|||
return true;
|
||||
}
|
||||
|
||||
PSendStreamChild*
|
||||
ContentChild::SendPSendStreamConstructor(PSendStreamChild* aActor)
|
||||
PChildToParentStreamChild*
|
||||
ContentChild::SendPChildToParentStreamConstructor(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
if (IsShuttingDown()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return PContentChild::SendPSendStreamConstructor(aActor);
|
||||
return PContentChild::SendPChildToParentStreamConstructor(aActor);
|
||||
}
|
||||
|
||||
PSendStreamChild*
|
||||
ContentChild::AllocPSendStreamChild()
|
||||
PChildToParentStreamChild*
|
||||
ContentChild::AllocPChildToParentStreamChild()
|
||||
{
|
||||
return nsIContentChild::AllocPSendStreamChild();
|
||||
return nsIContentChild::AllocPChildToParentStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPSendStreamChild(PSendStreamChild* aActor)
|
||||
ContentChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
return nsIContentChild::DeallocPSendStreamChild(aActor);
|
||||
return nsIContentChild::DeallocPChildToParentStreamChild(aActor);
|
||||
}
|
||||
|
||||
PParentToChildStreamChild*
|
||||
ContentChild::AllocPParentToChildStreamChild()
|
||||
{
|
||||
return nsIContentChild::AllocPParentToChildStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
|
||||
{
|
||||
return nsIContentChild::DeallocPParentToChildStreamChild(aActor);
|
||||
}
|
||||
|
||||
PScreenManagerChild*
|
||||
|
|
|
@ -233,11 +233,14 @@ public:
|
|||
|
||||
virtual bool DeallocPPrintingChild(PPrintingChild*) override;
|
||||
|
||||
virtual PSendStreamChild*
|
||||
SendPSendStreamConstructor(PSendStreamChild*) override;
|
||||
virtual PChildToParentStreamChild*
|
||||
SendPChildToParentStreamConstructor(PChildToParentStreamChild*) override;
|
||||
|
||||
virtual PSendStreamChild* AllocPSendStreamChild() override;
|
||||
virtual bool DeallocPSendStreamChild(PSendStreamChild*) override;
|
||||
virtual PChildToParentStreamChild* AllocPChildToParentStreamChild() override;
|
||||
virtual bool DeallocPChildToParentStreamChild(PChildToParentStreamChild*) override;
|
||||
|
||||
virtual PParentToChildStreamChild* AllocPParentToChildStreamChild() override;
|
||||
virtual bool DeallocPParentToChildStreamChild(PParentToChildStreamChild*) override;
|
||||
|
||||
virtual PScreenManagerChild*
|
||||
AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||
#include "mozilla/ipc/PSendStreamParent.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamParent.h"
|
||||
#include "mozilla/ipc/TestShellParent.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
|
@ -3176,16 +3176,34 @@ ContentParent::GetPrintingParent()
|
|||
}
|
||||
#endif
|
||||
|
||||
PSendStreamParent*
|
||||
ContentParent::AllocPSendStreamParent()
|
||||
PChildToParentStreamParent*
|
||||
ContentParent::AllocPChildToParentStreamParent()
|
||||
{
|
||||
return nsIContentParent::AllocPSendStreamParent();
|
||||
return nsIContentParent::AllocPChildToParentStreamParent();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPSendStreamParent(PSendStreamParent* aActor)
|
||||
ContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
|
||||
{
|
||||
return nsIContentParent::DeallocPSendStreamParent(aActor);
|
||||
return nsIContentParent::DeallocPChildToParentStreamParent(aActor);
|
||||
}
|
||||
|
||||
PParentToChildStreamParent*
|
||||
ContentParent::SendPParentToChildStreamConstructor(PParentToChildStreamParent* aActor)
|
||||
{
|
||||
return PContentParent::SendPParentToChildStreamConstructor(aActor);
|
||||
}
|
||||
|
||||
PParentToChildStreamParent*
|
||||
ContentParent::AllocPParentToChildStreamParent()
|
||||
{
|
||||
return nsIContentParent::AllocPParentToChildStreamParent();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
|
||||
{
|
||||
return nsIContentParent::DeallocPParentToChildStreamParent(aActor);
|
||||
}
|
||||
|
||||
PScreenManagerParent*
|
||||
|
@ -3921,7 +3939,10 @@ ContentParent::RecvKeywordToURI(const nsCString& aKeyword,
|
|||
info->GetKeywordProviderName(*aProviderName);
|
||||
|
||||
AutoIPCStream autoStream;
|
||||
autoStream.Serialize(postData, this);
|
||||
if (NS_WARN_IF(!autoStream.Serialize(postData, this))) {
|
||||
NS_ENSURE_SUCCESS(NS_ERROR_FAILURE, IPC_FAIL_NO_REASON(this));
|
||||
}
|
||||
|
||||
*aPostData = autoStream.TakeOptionalValue();
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
@ -4110,6 +4131,12 @@ ContentParent::RecvKeygenProvideContent(nsString* aAttribute,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PFileDescriptorSetParent*
|
||||
ContentParent::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD)
|
||||
{
|
||||
return PContentParent::SendPFileDescriptorSetConstructor(aFD);
|
||||
}
|
||||
|
||||
PFileDescriptorSetParent*
|
||||
ContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD)
|
||||
{
|
||||
|
@ -5137,6 +5164,10 @@ ContentParent::RecvFileCreationRequest(const nsID& aID,
|
|||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
BlobParent* blobParent = BlobParent::GetOrCreate(this, blobImpl);
|
||||
if (NS_WARN_IF(!blobParent)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
if (!SendFileCreationResponse(aID,
|
||||
FileCreationSuccessResult(blobParent, nullptr))) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
|
|
|
@ -425,8 +425,19 @@ public:
|
|||
already_AddRefed<embedding::PrintingParent> GetPrintingParent();
|
||||
#endif
|
||||
|
||||
virtual PSendStreamParent* AllocPSendStreamParent() override;
|
||||
virtual bool DeallocPSendStreamParent(PSendStreamParent* aActor) override;
|
||||
virtual PChildToParentStreamParent* AllocPChildToParentStreamParent() override;
|
||||
virtual bool
|
||||
DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
|
||||
|
||||
virtual PParentToChildStreamParent*
|
||||
SendPParentToChildStreamConstructor(PParentToChildStreamParent*) override;
|
||||
|
||||
virtual PFileDescriptorSetParent*
|
||||
SendPFileDescriptorSetConstructor(const FileDescriptor&) override;
|
||||
|
||||
virtual PParentToChildStreamParent* AllocPParentToChildStreamParent() override;
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) override;
|
||||
|
||||
virtual PScreenManagerParent*
|
||||
AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBlob;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include IPCStream;
|
||||
include ProtocolTypes;
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ include protocol PGMPService;
|
|||
include protocol PPluginModule;
|
||||
include protocol PGMP;
|
||||
include protocol PPrinting;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include protocol POfflineCacheUpdate;
|
||||
include protocol PRenderFrame;
|
||||
include protocol PScreenManager;
|
||||
|
@ -286,7 +287,8 @@ nested(upto inside_cpow) sync protocol PContent
|
|||
manages PNecko;
|
||||
manages POfflineCacheUpdate;
|
||||
manages PPrinting;
|
||||
manages PSendStream;
|
||||
manages PChildToParentStream;
|
||||
manages PParentToChildStream;
|
||||
manages PScreenManager;
|
||||
manages PSpeechSynthesis;
|
||||
manages PStorage;
|
||||
|
@ -587,6 +589,8 @@ child:
|
|||
|
||||
async ParentActivated(PBrowser aTab, bool aActivated);
|
||||
|
||||
async PParentToChildStream();
|
||||
|
||||
parent:
|
||||
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
|
||||
|
||||
|
@ -701,7 +705,7 @@ parent:
|
|||
|
||||
async PPrinting();
|
||||
|
||||
async PSendStream();
|
||||
async PChildToParentStream();
|
||||
|
||||
nested(inside_sync) sync PScreenManager()
|
||||
returns (uint32_t numberOfScreens,
|
||||
|
|
|
@ -9,7 +9,8 @@ include protocol PBrowser;
|
|||
include protocol PContent;
|
||||
include protocol PJavaScript;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
|
||||
include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
|
@ -38,7 +39,11 @@ nested(upto inside_cpow) sync protocol PContentBridge
|
|||
manages PBrowser;
|
||||
manages PFileDescriptorSet;
|
||||
manages PJavaScript;
|
||||
manages PSendStream;
|
||||
manages PChildToParentStream;
|
||||
manages PParentToChildStream;
|
||||
|
||||
child:
|
||||
async PParentToChildStream();
|
||||
|
||||
parent:
|
||||
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
|
||||
|
@ -47,7 +52,7 @@ parent:
|
|||
|
||||
async PJavaScript();
|
||||
|
||||
async PSendStream();
|
||||
async PChildToParentStream();
|
||||
|
||||
both:
|
||||
// Both the parent and the child can construct the PBrowser.
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/SendStream.h"
|
||||
#include "mozilla/ipc/IPCStreamAlloc.h"
|
||||
#include "mozilla/ipc/IPCStreamDestination.h"
|
||||
#include "mozilla/ipc/IPCStreamSource.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamChild.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamChild.h"
|
||||
|
||||
#include "nsPrintfCString.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -135,14 +139,27 @@ nsIContentChild::GetOrCreateActorForBlobImpl(BlobImpl* aImpl)
|
|||
return actor;
|
||||
}
|
||||
|
||||
PSendStreamChild*
|
||||
nsIContentChild::AllocPSendStreamChild()
|
||||
PChildToParentStreamChild*
|
||||
nsIContentChild::AllocPChildToParentStreamChild()
|
||||
{
|
||||
MOZ_CRASH("PSendStreamChild actors should be manually constructed!");
|
||||
MOZ_CRASH("PChildToParentStreamChild actors should be manually constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContentChild::DeallocPSendStreamChild(PSendStreamChild* aActor)
|
||||
nsIContentChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PParentToChildStreamChild*
|
||||
nsIContentChild::AllocPParentToChildStreamChild()
|
||||
{
|
||||
return mozilla::ipc::AllocPParentToChildStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContentChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
|
|
|
@ -29,7 +29,8 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
class FileDescriptor;
|
||||
class PFileDescriptorSetChild;
|
||||
class PSendStreamChild;
|
||||
class PChildToParentStreamChild;
|
||||
class PParentToChildStreamChild;
|
||||
class Shmem;
|
||||
} // namespace ipc
|
||||
|
||||
|
@ -74,8 +75,8 @@ public:
|
|||
virtual mozilla::ipc::PFileDescriptorSetChild*
|
||||
SendPFileDescriptorSetConstructor(const mozilla::ipc::FileDescriptor&) = 0;
|
||||
|
||||
virtual mozilla::ipc::PSendStreamChild*
|
||||
SendPSendStreamConstructor(mozilla::ipc::PSendStreamChild*) = 0;
|
||||
virtual mozilla::ipc::PChildToParentStreamChild*
|
||||
SendPChildToParentStreamConstructor(mozilla::ipc::PChildToParentStreamChild*) = 0;
|
||||
|
||||
protected:
|
||||
virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
|
||||
|
@ -99,9 +100,15 @@ protected:
|
|||
|
||||
virtual bool DeallocPBlobChild(PBlobChild* aActor);
|
||||
|
||||
virtual mozilla::ipc::PSendStreamChild* AllocPSendStreamChild();
|
||||
virtual mozilla::ipc::PChildToParentStreamChild* AllocPChildToParentStreamChild();
|
||||
|
||||
virtual bool DeallocPSendStreamChild(mozilla::ipc::PSendStreamChild* aActor);
|
||||
virtual bool
|
||||
DeallocPChildToParentStreamChild(mozilla::ipc::PChildToParentStreamChild* aActor);
|
||||
|
||||
virtual mozilla::ipc::PParentToChildStreamChild* AllocPParentToChildStreamChild();
|
||||
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamChild(mozilla::ipc::PParentToChildStreamChild* aActor);
|
||||
|
||||
virtual mozilla::ipc::PFileDescriptorSetChild*
|
||||
AllocPFileDescriptorSetChild(const mozilla::ipc::FileDescriptor& aFD);
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/SendStreamAlloc.h"
|
||||
#include "mozilla/ipc/IPCStreamAlloc.h"
|
||||
#include "mozilla/ipc/IPCStreamDestination.h"
|
||||
#include "mozilla/ipc/IPCStreamSource.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsFrameMessageManager.h"
|
||||
|
@ -260,14 +262,27 @@ nsIContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aAct
|
|||
return true;
|
||||
}
|
||||
|
||||
PSendStreamParent*
|
||||
nsIContentParent::AllocPSendStreamParent()
|
||||
PChildToParentStreamParent*
|
||||
nsIContentParent::AllocPChildToParentStreamParent()
|
||||
{
|
||||
return mozilla::ipc::AllocPSendStreamParent();
|
||||
return mozilla::ipc::AllocPChildToParentStreamParent();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContentParent::DeallocPSendStreamParent(PSendStreamParent* aActor)
|
||||
nsIContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PParentToChildStreamParent*
|
||||
nsIContentParent::AllocPParentToChildStreamParent()
|
||||
{
|
||||
MOZ_CRASH("PParentToChildStreamChild actors should be manually constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamParent.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamParent.h"
|
||||
|
||||
#include "nsFrameMessageManager.h"
|
||||
#include "nsISupports.h"
|
||||
|
@ -32,7 +34,8 @@ class CpowEntry;
|
|||
|
||||
namespace ipc {
|
||||
class PFileDescriptorSetParent;
|
||||
class PSendStreamParent;
|
||||
class PChildToParentStreamParent;
|
||||
class PParentToChildStreamParent;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
@ -75,6 +78,9 @@ public:
|
|||
const ContentParentId& aCpId,
|
||||
const bool& aIsForBrowser) = 0;
|
||||
|
||||
virtual mozilla::ipc::PFileDescriptorSetParent*
|
||||
SendPFileDescriptorSetConstructor(const mozilla::ipc::FileDescriptor&) = 0;
|
||||
|
||||
virtual bool IsContentParent() const { return false; }
|
||||
|
||||
ContentParent* AsContentParent();
|
||||
|
@ -87,6 +93,9 @@ public:
|
|||
|
||||
virtual int32_t Pid() const = 0;
|
||||
|
||||
virtual mozilla::ipc::PParentToChildStreamParent*
|
||||
SendPParentToChildStreamConstructor(mozilla::ipc::PParentToChildStreamParent*) = 0;
|
||||
|
||||
protected: // methods
|
||||
bool CanOpenBrowser(const IPCTabContext& aContext);
|
||||
|
||||
|
@ -111,9 +120,15 @@ protected: // IPDL methods
|
|||
virtual bool
|
||||
DeallocPFileDescriptorSetParent(mozilla::ipc::PFileDescriptorSetParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::PSendStreamParent* AllocPSendStreamParent();
|
||||
virtual mozilla::ipc::PChildToParentStreamParent* AllocPChildToParentStreamParent();
|
||||
|
||||
virtual bool DeallocPSendStreamParent(mozilla::ipc::PSendStreamParent* aActor);
|
||||
virtual bool
|
||||
DeallocPChildToParentStreamParent(mozilla::ipc::PChildToParentStreamParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::PParentToChildStreamParent* AllocPParentToChildStreamParent();
|
||||
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamParent(mozilla::ipc::PParentToChildStreamParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
|
|
|
@ -699,7 +699,8 @@ D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
|||
mTextureClientAllocator = new D3D11RecycleAllocator(
|
||||
layers::ImageBridgeChild::GetSingleton().get(), mDevice);
|
||||
|
||||
if (ImageBridgeChild::GetSingleton() && gfxPrefs::PDMWMFUseSyncTexture()) {
|
||||
if (ImageBridgeChild::GetSingleton() && gfxPrefs::PDMWMFUseSyncTexture() &&
|
||||
mDevice != DeviceManagerDx::Get()->GetCompositorDevice()) {
|
||||
// We use a syncobject to avoid the cost of the mutex lock when compositing,
|
||||
// and because it allows color conversion ocurring directly from this texture
|
||||
// DXVA does not seem to accept IDXGIKeyedMutex textures as input.
|
||||
|
@ -902,7 +903,7 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
|||
if (mutex) {
|
||||
hr = mutex->AcquireSync(0, 2000);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
} else {
|
||||
} else if (mDevice != DeviceManagerDx::Get()->GetCompositorDevice()) {
|
||||
NS_ENSURE_TRUE(mSyncObject, E_FAIL);
|
||||
}
|
||||
|
||||
|
@ -939,10 +940,10 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
|||
hr = mTransform->Output(&sample);
|
||||
}
|
||||
|
||||
if (!mutex) {
|
||||
if (!mutex && mDevice != DeviceManagerDx::Get()->GetCompositorDevice()) {
|
||||
client->SyncWithObject(mSyncObject);
|
||||
mSyncObject->FinalizeFrame();
|
||||
} else {
|
||||
} else if (mutex) {
|
||||
mutex->ReleaseSync(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ include protocol PNecko;
|
|||
include protocol PBackground;
|
||||
include protocol PBlob; //FIXME: bug #792908
|
||||
include protocol PFileDescriptorSet; // FIXME: bug #792908
|
||||
include protocol PSendStream; //FIXME: bug #792908
|
||||
include protocol PChildToParentStream; //FIXME: bug #792908
|
||||
include protocol PParentToChildStream; //FIXME: bug #792908
|
||||
|
||||
include IPCStream;
|
||||
|
||||
|
|
|
@ -30,16 +30,29 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1224790
|
|||
SimpleTest.waitForFocus(gotFocus);
|
||||
}
|
||||
|
||||
var timer = null;
|
||||
function gotFocus() {
|
||||
var button = document.getElementById('button');
|
||||
synthesizeMouseAtCenter(button, { type: 'mousemove' }, window);
|
||||
// The bug is not reproducible with synthesizeMouseAtCenter.
|
||||
// Need to emulate native mouse event.
|
||||
synthesizeNativeOSXClick(button.boxObject.screenX + button.boxObject.width / 2,
|
||||
button.boxObject.screenY + button.boxObject.height / 2);
|
||||
function click() {
|
||||
// The bug is not reproducible with synthesizeMouseAtCenter.
|
||||
// Need to emulate native mouse event.
|
||||
synthesizeNativeOSXClick(button.boxObject.screenX + button.boxObject.width / 2,
|
||||
button.boxObject.screenY + button.boxObject.height / 2);
|
||||
}
|
||||
click();
|
||||
// On debug build, it's possible that the click event handler is not
|
||||
// triggered by the first click in case the click is dispatched too early
|
||||
// before Firefox gets ready for input.
|
||||
// Click the button again after 1 sec when we don't get click event.
|
||||
timer = setTimeout(click, 1000);
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
if (timer) {
|
||||
// Avoid clicking unrelated thing.
|
||||
clearTimeout(timer);
|
||||
}
|
||||
ok(true, "Click event should be fired");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -31,16 +31,29 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1224790
|
|||
SimpleTest.waitForFocus(gotFocus);
|
||||
}
|
||||
|
||||
var timer = null;
|
||||
function gotFocus() {
|
||||
var button = document.getElementById('button');
|
||||
synthesizeMouseAtCenter(button, { type: 'mousemove' }, window);
|
||||
// The bug is not reproducible with synthesizeMouseAtCenter.
|
||||
// Need to emulate native mouse event.
|
||||
synthesizeNativeOSXClick(button.boxObject.screenX + button.boxObject.width / 2,
|
||||
button.boxObject.screenY + button.boxObject.height / 2);
|
||||
function click() {
|
||||
// The bug is not reproducible with synthesizeMouseAtCenter.
|
||||
// Need to emulate native mouse event.
|
||||
synthesizeNativeOSXClick(button.boxObject.screenX + button.boxObject.width / 2,
|
||||
button.boxObject.screenY + button.boxObject.height / 2);
|
||||
}
|
||||
click();
|
||||
// On debug build, it's possible that the click event handler is not
|
||||
// triggered by the first click in case the click is dispatched too early
|
||||
// before Firefox gets ready for input.
|
||||
// Click the button again after 1 sec when we don't get click event.
|
||||
timer = setTimeout(click, 1000);
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
if (timer) {
|
||||
// Avoid clicking unrelated thing.
|
||||
clearTimeout(timer);
|
||||
}
|
||||
ok(true, "Click event should be fired");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ include protocol PContent;
|
|||
include protocol PWebBrowserPersistResources;
|
||||
include protocol PWebBrowserPersistSerialize;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream; //FIXME: bug #792908
|
||||
include protocol PParentToChildStream; //FIXME: bug #792908
|
||||
|
||||
include IPCStream;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/layers/TextureD3D11.h"
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "d3d11.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "DXVA2Manager.h"
|
||||
|
@ -19,6 +20,8 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize& aSize,
|
||||
const gfx::IntRect& aRect)
|
||||
: Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE),
|
||||
|
@ -193,7 +196,8 @@ D3D11RecycleAllocator::CreateOrRecycleClient(gfx::SurfaceFormat aFormat,
|
|||
const gfx::IntSize& aSize)
|
||||
{
|
||||
TextureAllocationFlags allocFlags = TextureAllocationFlags::ALLOC_DEFAULT;
|
||||
if (gfxPrefs::PDMWMFUseSyncTexture()) {
|
||||
if (gfxPrefs::PDMWMFUseSyncTexture() || mDevice == DeviceManagerDx::Get()->GetCompositorDevice()) {
|
||||
// If our device is the compositor device, we don't need any synchronization in practice.
|
||||
allocFlags = TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION;
|
||||
}
|
||||
RefPtr<TextureClient> textureClient =
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
#include "mozilla/dom/GamepadEventChannelChild.h"
|
||||
#include "mozilla/dom/GamepadTestChannelChild.h"
|
||||
#include "mozilla/dom/MessagePortChild.h"
|
||||
#include "mozilla/ipc/IPCStreamAlloc.h"
|
||||
#include "mozilla/ipc/PBackgroundTestChild.h"
|
||||
#include "mozilla/ipc/PSendStreamChild.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamChild.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamChild.h"
|
||||
#include "mozilla/layout/VsyncChild.h"
|
||||
#include "mozilla/net/PUDPSocketChild.h"
|
||||
#include "mozilla/dom/network/UDPSocketChild.h"
|
||||
|
@ -403,14 +405,27 @@ BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PSendStreamChild*
|
||||
BackgroundChildImpl::AllocPSendStreamChild()
|
||||
PChildToParentStreamChild*
|
||||
BackgroundChildImpl::AllocPChildToParentStreamChild()
|
||||
{
|
||||
MOZ_CRASH("PSendStreamChild actors should be manually constructed!");
|
||||
MOZ_CRASH("PChildToParentStreamChild actors should be manually constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::DeallocPSendStreamChild(PSendStreamChild* aActor)
|
||||
BackgroundChildImpl::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PParentToChildStreamChild*
|
||||
BackgroundChildImpl::AllocPParentToChildStreamChild()
|
||||
{
|
||||
return mozilla::ipc::AllocPParentToChildStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
|
|
|
@ -140,11 +140,17 @@ protected:
|
|||
virtual bool
|
||||
DeallocPMessagePortChild(PMessagePortChild* aActor) override;
|
||||
|
||||
virtual PSendStreamChild*
|
||||
AllocPSendStreamChild() override;
|
||||
virtual PChildToParentStreamChild*
|
||||
AllocPChildToParentStreamChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPSendStreamChild(PSendStreamChild* aActor) override;
|
||||
DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor) override;
|
||||
|
||||
virtual PParentToChildStreamChild*
|
||||
AllocPParentToChildStreamChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor) override;
|
||||
|
||||
virtual PAsmJSCacheEntryChild*
|
||||
AllocPAsmJSCacheEntryChild(const dom::asmjscache::OpenMode& aOpenMode,
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
#define CRASH_IN_CHILD_PROCESS(_msg) \
|
||||
do { \
|
||||
if (XRE_IsParentProcess()) { \
|
||||
if (XRE_IsParentProcess()) { \
|
||||
MOZ_ASSERT(false, _msg); \
|
||||
} else { \
|
||||
MOZ_CRASH(_msg); \
|
||||
|
|
|
@ -31,10 +31,11 @@
|
|||
#include "mozilla/dom/quota/ActorsParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/IPCStreamAlloc.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/ipc/PBackgroundTestParent.h"
|
||||
#include "mozilla/ipc/PSendStreamParent.h"
|
||||
#include "mozilla/ipc/SendStreamAlloc.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamParent.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamParent.h"
|
||||
#include "mozilla/layout/VsyncParent.h"
|
||||
#include "mozilla/dom/network/UDPSocketParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -302,14 +303,29 @@ BackgroundParentImpl::DeallocPFileDescriptorSetParent(
|
|||
return true;
|
||||
}
|
||||
|
||||
PSendStreamParent*
|
||||
BackgroundParentImpl::AllocPSendStreamParent()
|
||||
PChildToParentStreamParent*
|
||||
BackgroundParentImpl::AllocPChildToParentStreamParent()
|
||||
{
|
||||
return mozilla::ipc::AllocPSendStreamParent();
|
||||
return mozilla::ipc::AllocPChildToParentStreamParent();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::DeallocPSendStreamParent(PSendStreamParent* aActor)
|
||||
BackgroundParentImpl::DeallocPChildToParentStreamParent(
|
||||
PChildToParentStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PParentToChildStreamParent*
|
||||
BackgroundParentImpl::AllocPParentToChildStreamParent()
|
||||
{
|
||||
MOZ_CRASH("PParentToChildStreamParent actors should be manually constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::DeallocPParentToChildStreamParent(
|
||||
PParentToChildStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
|
|
|
@ -101,11 +101,17 @@ protected:
|
|||
virtual bool
|
||||
DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
|
||||
|
||||
virtual PSendStreamParent*
|
||||
AllocPSendStreamParent() override;
|
||||
virtual PChildToParentStreamParent*
|
||||
AllocPChildToParentStreamParent() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPSendStreamParent(PSendStreamParent* aActor) override;
|
||||
DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
|
||||
|
||||
virtual PParentToChildStreamParent*
|
||||
AllocPParentToChildStreamParent() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) override;
|
||||
|
||||
virtual PServiceWorkerManagerParent*
|
||||
AllocPServiceWorkerManagerParent() override;
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
* 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 protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include BlobTypes;
|
||||
include InputStreamParams;
|
||||
|
||||
|
@ -22,7 +23,8 @@ struct InputStreamParamsWithFds
|
|||
union IPCStream
|
||||
{
|
||||
InputStreamParamsWithFds;
|
||||
PSendStream;
|
||||
PChildToParentStream;
|
||||
PParentToChildStream;
|
||||
};
|
||||
|
||||
union OptionalIPCStream
|
||||
|
|
|
@ -4,18 +4,22 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ipc_SendStreamAlloc_h
|
||||
#define mozilla_ipc_SendStreamAlloc_h
|
||||
#ifndef mozilla_ipc_IPCStreamAlloc_h
|
||||
#define mozilla_ipc_IPCStreamAlloc_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class PSendStreamParent;
|
||||
class PChildToParentStreamParent;
|
||||
class PParentToChildStreamChild;
|
||||
|
||||
PSendStreamParent*
|
||||
AllocPSendStreamParent();
|
||||
PChildToParentStreamParent*
|
||||
AllocPChildToParentStreamParent();
|
||||
|
||||
PParentToChildStreamChild*
|
||||
AllocPParentToChildStreamChild();
|
||||
|
||||
} // ipc namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_ipc_SendStreamAlloc_h
|
||||
#endif // mozilla_ipc_IPCStreamAlloc_h
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- 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 "IPCStreamDestination.h"
|
||||
#include "IPCStreamSource.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamChild.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
// Child to Parent implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
class IPCStreamSourceChild final : public PChildToParentStreamChild
|
||||
, public IPCStreamSource
|
||||
{
|
||||
public:
|
||||
static IPCStreamSourceChild*
|
||||
Create(nsIAsyncInputStream* aInputStream)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
IPCStreamSourceChild* source = new IPCStreamSourceChild(aInputStream);
|
||||
if (!source->Initialize()) {
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// PChildToParentStreamChild methods
|
||||
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aReason) override
|
||||
{
|
||||
ActorDestroyed();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
RecvRequestClose(const nsresult& aRv) override
|
||||
{
|
||||
OnEnd(aRv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
Close(nsresult aRv) override
|
||||
{
|
||||
MOZ_ASSERT(IPCStreamSource::mState == IPCStreamSource::eClosed);
|
||||
Unused << SendClose(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
SendData(const nsCString& aBuffer) override
|
||||
{
|
||||
Unused << SendBuffer(aBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit IPCStreamSourceChild(nsIAsyncInputStream* aInputStream)
|
||||
:IPCStreamSource(aInputStream)
|
||||
{}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ PChildToParentStreamChild*
|
||||
IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
|
||||
dom::nsIContentChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// PContent can only be used on the main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
IPCStreamSourceChild* source = IPCStreamSourceChild::Create(aInputStream);
|
||||
if (!source) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aManager->SendPChildToParentStreamConstructor(source)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
source->ActorConstructed();
|
||||
return source;
|
||||
}
|
||||
|
||||
/* static */ PChildToParentStreamChild*
|
||||
IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
|
||||
PBackgroundChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
IPCStreamSourceChild* source = IPCStreamSourceChild::Create(aInputStream);
|
||||
if (!source) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aManager->SendPChildToParentStreamConstructor(source)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
source->ActorConstructed();
|
||||
return source;
|
||||
}
|
||||
|
||||
/* static */ IPCStreamSource*
|
||||
IPCStreamSource::Cast(PChildToParentStreamChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
return static_cast<IPCStreamSourceChild*>(aActor);
|
||||
}
|
||||
|
||||
// Parent to Child implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
class IPCStreamDestinationChild final : public PParentToChildStreamChild
|
||||
, public IPCStreamDestination
|
||||
{
|
||||
public:
|
||||
nsresult Initialize()
|
||||
{
|
||||
return IPCStreamDestination::Initialize();
|
||||
}
|
||||
|
||||
~IPCStreamDestinationChild()
|
||||
{}
|
||||
|
||||
private:
|
||||
// PParentToChildStreamChild methods
|
||||
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aReason) override
|
||||
{
|
||||
ActorDestroyed();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
RecvBuffer(const nsCString& aBuffer) override
|
||||
{
|
||||
BufferReceived(aBuffer);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
RecvClose(const nsresult& aRv) override
|
||||
{
|
||||
CloseReceived(aRv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// IPCStreamDestination methods
|
||||
|
||||
void
|
||||
RequestClose(nsresult aRv) override
|
||||
{
|
||||
Unused << SendRequestClose(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
TerminateDestination() override
|
||||
{
|
||||
Unused << Send__delete__(this);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
PParentToChildStreamChild*
|
||||
AllocPParentToChildStreamChild()
|
||||
{
|
||||
IPCStreamDestinationChild* actor = new IPCStreamDestinationChild();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(actor->Initialize()))) {
|
||||
delete actor;
|
||||
actor = nullptr;
|
||||
}
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
void
|
||||
DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
}
|
||||
|
||||
/* static */ IPCStreamDestination*
|
||||
IPCStreamDestination::Cast(PParentToChildStreamChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
return static_cast<IPCStreamDestinationChild*>(aActor);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- 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 "IPCStreamDestination.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsIPipe.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
IPCStreamDestination::IPCStreamDestination()
|
||||
{
|
||||
}
|
||||
|
||||
IPCStreamDestination::~IPCStreamDestination()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
IPCStreamDestination::Initialize()
|
||||
{
|
||||
MOZ_ASSERT(!mReader);
|
||||
MOZ_ASSERT(!mWriter);
|
||||
|
||||
// use async versions for both reader and writer even though we are
|
||||
// opening the writer as an infinite stream. We want to be able to
|
||||
// use CloseWithStatus() to communicate errors through the pipe.
|
||||
|
||||
// Use an "infinite" pipe because we cannot apply back-pressure through
|
||||
// the async IPC layer at the moment. Blocking the IPC worker thread
|
||||
// is not desirable, either.
|
||||
nsresult rv = NS_NewPipe2(getter_AddRefs(mReader),
|
||||
getter_AddRefs(mWriter),
|
||||
true, true, // non-blocking
|
||||
0, // segment size
|
||||
UINT32_MAX); // "infinite" pipe
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
IPCStreamDestination::TakeReader()
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
return mReader.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamDestination::ActorDestroyed()
|
||||
{
|
||||
MOZ_ASSERT(mWriter);
|
||||
|
||||
// If we were gracefully closed we should have gotten RecvClose(). In
|
||||
// that case, the writer will already be closed and this will have no
|
||||
// effect. This just aborts the writer in the case where the child process
|
||||
// crashes.
|
||||
mWriter->CloseWithStatus(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamDestination::BufferReceived(const nsCString& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(mWriter);
|
||||
|
||||
uint32_t numWritten = 0;
|
||||
|
||||
// This should only fail if we hit an OOM condition.
|
||||
nsresult rv = mWriter->Write(aBuffer.get(), aBuffer.Length(), &numWritten);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
RequestClose(rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamDestination::CloseReceived(nsresult aRv)
|
||||
{
|
||||
MOZ_ASSERT(mWriter);
|
||||
mWriter->CloseWithStatus(aRv);
|
||||
TerminateDestination();
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ipc_IPCStreamDestination_h
|
||||
#define mozilla_ipc_IPCStreamDestination_h
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIAsyncInputStream;
|
||||
class nsIAsyncOutputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class PChildToParentStreamParent;
|
||||
class PParentToChildStreamChild;
|
||||
|
||||
// On the destination side, you must simply call TakeReader() upon receiving a
|
||||
// reference to the IPCStream{Child,Parent} actor. You do not need to maintain
|
||||
// a reference to the actor itself.
|
||||
class IPCStreamDestination
|
||||
{
|
||||
public:
|
||||
static IPCStreamDestination*
|
||||
Cast(PChildToParentStreamParent* aActor);
|
||||
|
||||
static IPCStreamDestination*
|
||||
Cast(PParentToChildStreamChild* aActor);
|
||||
|
||||
virtual already_AddRefed<nsIInputStream>
|
||||
TakeReader();
|
||||
|
||||
protected:
|
||||
IPCStreamDestination();
|
||||
virtual ~IPCStreamDestination();
|
||||
|
||||
nsresult Initialize();
|
||||
|
||||
// The implementation of the actor should call these methods.
|
||||
|
||||
void
|
||||
ActorDestroyed();
|
||||
|
||||
void
|
||||
BufferReceived(const nsCString& aBuffer);
|
||||
|
||||
void
|
||||
CloseReceived(nsresult aRv);
|
||||
|
||||
// These methods will be implemented by the actor.
|
||||
|
||||
virtual void
|
||||
RequestClose(nsresult aRv) = 0;
|
||||
|
||||
virtual void
|
||||
TerminateDestination() = 0;
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mReader;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mWriter;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_IPCStreamDestination_h
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- 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 "IPCStreamDestination.h"
|
||||
#include "mozilla/dom/nsIContentParent.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamParent.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
// Child to Parent implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
class IPCStreamSourceParent final : public PParentToChildStreamParent
|
||||
, public IPCStreamSource
|
||||
{
|
||||
public:
|
||||
static IPCStreamSourceParent*
|
||||
Create(nsIAsyncInputStream* aInputStream)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
IPCStreamSourceParent* source = new IPCStreamSourceParent(aInputStream);
|
||||
if (!source->Initialize()) {
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// PParentToChildStreamParent methods
|
||||
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aReason) override
|
||||
{
|
||||
ActorDestroyed();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
RecvRequestClose(const nsresult& aRv) override
|
||||
{
|
||||
OnEnd(aRv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
Close(nsresult aRv) override
|
||||
{
|
||||
MOZ_ASSERT(IPCStreamSource::mState == IPCStreamSource::eClosed);
|
||||
Unused << SendClose(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
SendData(const nsCString& aBuffer) override
|
||||
{
|
||||
Unused << SendBuffer(aBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit IPCStreamSourceParent(nsIAsyncInputStream* aInputStream)
|
||||
:IPCStreamSource(aInputStream)
|
||||
{}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ PParentToChildStreamParent*
|
||||
IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
|
||||
dom::nsIContentParent* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// PContent can only be used on the main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
IPCStreamSourceParent* source = IPCStreamSourceParent::Create(aInputStream);
|
||||
if (!source) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aManager->SendPParentToChildStreamConstructor(source)) {
|
||||
// no delete here, the manager will delete the actor for us.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
source->ActorConstructed();
|
||||
return source;
|
||||
}
|
||||
|
||||
/* static */ PParentToChildStreamParent*
|
||||
IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
|
||||
PBackgroundParent* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
IPCStreamSourceParent* source = IPCStreamSourceParent::Create(aInputStream);
|
||||
if (!source) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aManager->SendPParentToChildStreamConstructor(source)) {
|
||||
// no delete here, the manager will delete the actor for us.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
source->ActorConstructed();
|
||||
return source;
|
||||
}
|
||||
|
||||
/* static */ IPCStreamSource*
|
||||
IPCStreamSource::Cast(PParentToChildStreamParent* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
return static_cast<IPCStreamSourceParent*>(aActor);
|
||||
}
|
||||
|
||||
// Child to Parent implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
class IPCStreamDestinationParent final : public PChildToParentStreamParent
|
||||
, public IPCStreamDestination
|
||||
{
|
||||
public:
|
||||
nsresult Initialize()
|
||||
{
|
||||
return IPCStreamDestination::Initialize();
|
||||
}
|
||||
|
||||
~IPCStreamDestinationParent()
|
||||
{}
|
||||
|
||||
private:
|
||||
// PChildToParentStreamParent methods
|
||||
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aReason) override
|
||||
{
|
||||
ActorDestroyed();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
RecvBuffer(const nsCString& aBuffer) override
|
||||
{
|
||||
BufferReceived(aBuffer);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
RecvClose(const nsresult& aRv) override
|
||||
{
|
||||
CloseReceived(aRv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// IPCStreamDestination methods
|
||||
|
||||
void
|
||||
RequestClose(nsresult aRv) override
|
||||
{
|
||||
Unused << SendRequestClose(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
TerminateDestination() override
|
||||
{
|
||||
Unused << Send__delete__(this);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
PChildToParentStreamParent*
|
||||
AllocPChildToParentStreamParent()
|
||||
{
|
||||
IPCStreamDestinationParent* actor = new IPCStreamDestinationParent();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(actor->Initialize()))) {
|
||||
delete actor;
|
||||
actor = nullptr;
|
||||
}
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
void
|
||||
DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
}
|
||||
|
||||
/* static */ IPCStreamDestination*
|
||||
IPCStreamDestination::Cast(PChildToParentStreamParent* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
return static_cast<IPCStreamDestinationParent*>(aActor);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,317 @@
|
|||
/* -*- 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 "IPCStreamSource.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsICancelableRunnable.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
using mozilla::dom::workers::Canceling;
|
||||
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
|
||||
using mozilla::dom::workers::Status;
|
||||
using mozilla::dom::workers::WorkerPrivate;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class IPCStreamSource::Callback final : public nsIInputStreamCallback
|
||||
, public nsIRunnable
|
||||
, public nsICancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Callback(IPCStreamSource* aSource)
|
||||
: mSource(aSource)
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(mSource);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnInputStreamReady(nsIAsyncInputStream* aStream) override
|
||||
{
|
||||
// any thread
|
||||
if (mOwningThread == NS_GetCurrentThread()) {
|
||||
return Run();
|
||||
}
|
||||
|
||||
// If this fails, then it means the owning thread is a Worker that has
|
||||
// been shutdown. Its ok to lose the event in this case because the
|
||||
// IPCStreamChild listens for this event through the WorkerHolder.
|
||||
nsresult rv = mOwningThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch stream readable event to owning thread");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
|
||||
if (mSource) {
|
||||
mSource->OnStreamReady(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Cancel() override
|
||||
{
|
||||
// Cancel() gets called when the Worker thread is being shutdown. We have
|
||||
// nothing to do here because IPCStreamChild handles this case via
|
||||
// the WorkerHolder.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ClearSource()
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(mSource);
|
||||
mSource = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
~Callback()
|
||||
{
|
||||
// called on any thread
|
||||
|
||||
// ClearSource() should be called before the Callback is destroyed
|
||||
MOZ_ASSERT(!mSource);
|
||||
}
|
||||
|
||||
// This is a raw pointer because the source keeps alive the callback and,
|
||||
// before beeing destroyed, it nullifies this pointer (this happens when
|
||||
// ActorDestroyed() is called).
|
||||
IPCStreamSource* mSource;
|
||||
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(IPCStreamSource::Callback, nsIInputStreamCallback,
|
||||
nsIRunnable,
|
||||
nsICancelableRunnable);
|
||||
|
||||
IPCStreamSource::IPCStreamSource(nsIAsyncInputStream* aInputStream)
|
||||
: mStream(aInputStream)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mState(ePending)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
}
|
||||
|
||||
IPCStreamSource::~IPCStreamSource()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
MOZ_ASSERT(mState == eClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
MOZ_ASSERT(!mWorkerPrivate);
|
||||
}
|
||||
|
||||
bool
|
||||
IPCStreamSource::Initialize()
|
||||
{
|
||||
bool nonBlocking = false;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mStream->IsNonBlocking(&nonBlocking)));
|
||||
// IPCStreamChild reads in the current thread, so it is only supported on
|
||||
// non-blocking, async channels
|
||||
if (!nonBlocking) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A source can be used on any thread, but we only support IPCStream on
|
||||
// main thread and Worker threads right now. This is due to the requirement
|
||||
// that the thread be guaranteed to live long enough to receive messages.
|
||||
// We can enforce this guarantee with a feature on worker threads, but not
|
||||
// other threads.
|
||||
WorkerPrivate* workerPrivate = nullptr;
|
||||
if (!NS_IsMainThread()) {
|
||||
workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_RELEASE_ASSERT(workerPrivate);
|
||||
|
||||
bool result = HoldWorker(workerPrivate, Canceling);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mWorkerPrivate = workerPrivate;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::ActorConstructed()
|
||||
{
|
||||
MOZ_ASSERT(mState == ePending);
|
||||
mState = eActorConstructed;
|
||||
}
|
||||
|
||||
bool
|
||||
IPCStreamSource::Notify(Status aStatus)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
|
||||
// Keep the worker thread alive until the stream is finished.
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::ActorDestroyed()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
|
||||
mState = eClosed;
|
||||
|
||||
if (mCallback) {
|
||||
mCallback->ClearSource();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
ReleaseWorker();
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::Start()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate);
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::StartDestroy()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
OnEnd(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::DoRead()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
MOZ_ASSERT(mState == eActorConstructed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
// The input stream (likely a pipe) probably uses a segment size of
|
||||
// 4kb. If there is data already buffered it would be nice to aggregate
|
||||
// multiple segments into a single IPC call. Conversely, don't send too
|
||||
// too large of a buffer in a single call to avoid spiking memory.
|
||||
static const uint64_t kMaxBytesPerMessage = 32 * 1024;
|
||||
static_assert(kMaxBytesPerMessage <= static_cast<uint64_t>(UINT32_MAX),
|
||||
"kMaxBytesPerMessage must cleanly cast to uint32_t");
|
||||
|
||||
while (true) {
|
||||
// It should not be possible to transition to closed state without
|
||||
// this loop terminating via a return.
|
||||
MOZ_ASSERT(mState == eActorConstructed);
|
||||
|
||||
// Use non-auto here as we're unlikely to hit stack storage with the
|
||||
// sizes we are sending. Also, it would be nice to avoid another copy
|
||||
// to the IPC layer which we avoid if we use COW strings. Unfortunately
|
||||
// IPC does not seem to support passing dependent storage types.
|
||||
nsCString buffer;
|
||||
|
||||
uint64_t available = 0;
|
||||
nsresult rv = mStream->Available(&available);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (available == 0) {
|
||||
Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t expectedBytes =
|
||||
static_cast<uint32_t>(std::min(available, kMaxBytesPerMessage));
|
||||
|
||||
buffer.SetLength(expectedBytes);
|
||||
|
||||
uint32_t bytesRead = 0;
|
||||
rv = mStream->Read(buffer.BeginWriting(), buffer.Length(), &bytesRead);
|
||||
MOZ_ASSERT_IF(NS_FAILED(rv), bytesRead == 0);
|
||||
buffer.SetLength(bytesRead);
|
||||
|
||||
// If we read any data from the stream, send it across.
|
||||
if (!buffer.IsEmpty()) {
|
||||
SendData(buffer);
|
||||
}
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
// Any other error or zero-byte read indicates end-of-stream
|
||||
if (NS_FAILED(rv) || buffer.IsEmpty()) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::Wait()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
MOZ_ASSERT(mState == eActorConstructed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
// Set mCallback immediately instead of waiting for success. Its possible
|
||||
// AsyncWait() will callback synchronously.
|
||||
mCallback = new Callback(this);
|
||||
nsresult rv = mStream->AsyncWait(mCallback, 0, 0, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::OnStreamReady(Callback* aCallback)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
MOZ_ASSERT(mCallback);
|
||||
MOZ_ASSERT(aCallback == mCallback);
|
||||
mCallback->ClearSource();
|
||||
mCallback = nullptr;
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamSource::OnEnd(nsresult aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
|
||||
MOZ_ASSERT(aRv != NS_BASE_STREAM_WOULD_BLOCK);
|
||||
|
||||
if (mState == eClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mState = eClosed;
|
||||
|
||||
mStream->CloseWithStatus(aRv);
|
||||
|
||||
if (aRv == NS_BASE_STREAM_CLOSED) {
|
||||
aRv = NS_OK;
|
||||
}
|
||||
|
||||
// This will trigger an ActorDestroy() from the other side
|
||||
Close(aRv);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,155 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ipc_IPCStreamSource_h
|
||||
#define mozilla_ipc_IPCStreamSource_h
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/workers/bindings/WorkerHolder.h"
|
||||
|
||||
class nsIAsyncInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class nsIContentChild;
|
||||
class nsIContentParent;
|
||||
} // dom namespace
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class PBackgroundChild;
|
||||
class PBackgroundParent;
|
||||
|
||||
// The IPCStream IPC actor is designed to push an nsIInputStream from child to
|
||||
// parent or parent to child incrementally. This is mainly needed for streams
|
||||
// such as nsPipe that may not yet have all their data available when the
|
||||
// stream must be sent across an IPC boundary. While many streams are handled
|
||||
// by SerializeInputStream(), these streams cannot be serialized and must be
|
||||
// sent using this actor.
|
||||
//
|
||||
// The IPCStream actor only support async, non-blocking streams because they
|
||||
// must be read inline on the main thread and Worker threads.
|
||||
//
|
||||
// In general, the creation and handling of the IPCStream actor cannot be
|
||||
// abstracted away behind SerializeInputStream() because the actor must be
|
||||
// carefully managed. Specifically:
|
||||
//
|
||||
// 1) The data flow must be explicitly initiated by calling
|
||||
// IPCStreamSource{Child,Parent}::Start() after the actor has been sent to
|
||||
// the other-side actor.
|
||||
// 2) If the actor is never sent to the other-side, then this code must
|
||||
// call IPCStreamSource{Child,Parent}::StartDestroy() to avoid memory leaks.
|
||||
// 3) The IPCStreamSource actor can only be used on threads that can be
|
||||
// guaranteed to stay alive as long as the actor is alive. Right now
|
||||
// this limits IPCStream to the main thread and Worker threads.
|
||||
//
|
||||
// In general you should probably use the AutoIPCStreamSource RAII class
|
||||
// defined in InputStreamUtils.h instead of using IPCStreamSource directly.
|
||||
class IPCStreamSource : public dom::workers::WorkerHolder
|
||||
{
|
||||
public:
|
||||
// Create a IPCStreamSource using a PContent IPC manager on the
|
||||
// main thread. This can return nullptr if the provided stream is
|
||||
// blocking.
|
||||
static PChildToParentStreamChild*
|
||||
Create(nsIAsyncInputStream* aInputStream, dom::nsIContentChild* aManager);
|
||||
|
||||
// Create a IPCStreamSource using a PBackground IPC manager on the
|
||||
// main thread or a Worker thread. This can return nullptr if the provided
|
||||
// stream is blocking or if the Worker thread is already shutting down.
|
||||
static PChildToParentStreamChild*
|
||||
Create(nsIAsyncInputStream* aInputStream, PBackgroundChild* aManager);
|
||||
|
||||
// Create a IPCStreamSource using a PContent IPC manager on the
|
||||
// main thread. This can return nullptr if the provided stream is
|
||||
// blocking.
|
||||
static PParentToChildStreamParent*
|
||||
Create(nsIAsyncInputStream* aInputStream, dom::nsIContentParent* aManager);
|
||||
|
||||
// Create a IPCStreamSource using a PBackground IPC manager on the
|
||||
// main thread or a Worker thread. This can return nullptr if the provided
|
||||
// stream is blocking or if the Worker thread is already shutting down.
|
||||
static PParentToChildStreamParent*
|
||||
Create(nsIAsyncInputStream* aInputStream, PBackgroundParent* aManager);
|
||||
|
||||
static IPCStreamSource*
|
||||
Cast(PChildToParentStreamChild* aActor);
|
||||
|
||||
static IPCStreamSource*
|
||||
Cast(PParentToChildStreamParent* aActor);
|
||||
|
||||
// Start reading data from the nsIAsyncInputStream used to create the actor.
|
||||
// This must be called after the actor is passed to the parent. If you
|
||||
// use AutoIPCStream this is handled automatically.
|
||||
void
|
||||
Start();
|
||||
|
||||
// Start cleaning up the actor. This must be called if the actor is never
|
||||
// sent to the other side. If you use AutoIPCStream this is handled
|
||||
// automatically.
|
||||
void
|
||||
StartDestroy();
|
||||
|
||||
protected:
|
||||
IPCStreamSource(nsIAsyncInputStream* aInputStream);
|
||||
virtual ~IPCStreamSource();
|
||||
|
||||
bool Initialize();
|
||||
|
||||
void ActorDestroyed();
|
||||
|
||||
void OnEnd(nsresult aRv);
|
||||
|
||||
virtual void
|
||||
Close(nsresult aRv) = 0;
|
||||
|
||||
virtual void
|
||||
SendData(const nsCString& aBuffer) = 0;
|
||||
|
||||
void
|
||||
ActorConstructed();
|
||||
|
||||
private:
|
||||
class Callback;
|
||||
|
||||
// WorkerHolder methods
|
||||
virtual bool
|
||||
Notify(dom::workers::Status aStatus) override;
|
||||
|
||||
void DoRead();
|
||||
|
||||
void Wait();
|
||||
|
||||
void OnStreamReady(Callback* aCallback);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mStream;
|
||||
RefPtr<Callback> mCallback;
|
||||
|
||||
// Raw pointer because this IPCStreamSource keeps the worker alive using a
|
||||
// WorkerHolder. The worker is kept alive when the actor is created and,
|
||||
// released when the actor is destroyed.
|
||||
dom::workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
#ifdef DEBUG
|
||||
protected:
|
||||
#endif
|
||||
|
||||
enum {
|
||||
ePending,
|
||||
eActorConstructed,
|
||||
eClosed
|
||||
} mState;
|
||||
|
||||
private:
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_IPCStreamSource_h
|
|
@ -15,9 +15,10 @@
|
|||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/IPCStreamDestination.h"
|
||||
#include "mozilla/ipc/IPCStreamSource.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/ipc/SendStream.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
|
@ -29,32 +30,43 @@ namespace ipc {
|
|||
|
||||
namespace {
|
||||
|
||||
void
|
||||
AssertValidValueToTake(const IPCStream& aVal)
|
||||
{
|
||||
MOZ_ASSERT(aVal.type() == IPCStream::TPChildToParentStreamChild ||
|
||||
aVal.type() == IPCStream::TPParentToChildStreamParent ||
|
||||
aVal.type() == IPCStream::TInputStreamParamsWithFds);
|
||||
}
|
||||
|
||||
void
|
||||
AssertValidValueToTake(const OptionalIPCStream& aVal)
|
||||
{
|
||||
MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
|
||||
aVal.type() == OptionalIPCStream::TIPCStream);
|
||||
if (aVal.type() == OptionalIPCStream::TIPCStream) {
|
||||
AssertValidValueToTake(aVal.get_IPCStream());
|
||||
}
|
||||
}
|
||||
|
||||
// These serialization and cleanup functions could be externally exposed. For
|
||||
// now, though, keep them private to encourage use of the safer RAII
|
||||
// AutoIPCStream class.
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStreamWithFdsChild(nsIInputStream* aStream,
|
||||
bool
|
||||
SerializeInputStreamWithFdsChild(nsIIPCSerializableInputStream* aStream,
|
||||
IPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_RELEASE_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// First attempt simple stream serialization
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
if (!serializable) {
|
||||
MOZ_CRASH("Input stream is not serializable!");
|
||||
}
|
||||
|
||||
aValue = InputStreamParamsWithFds();
|
||||
InputStreamParamsWithFds& streamWithFds =
|
||||
aValue.get_InputStreamParamsWithFds();
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
serializable->Serialize(streamWithFds.stream(), fds);
|
||||
aStream->Serialize(streamWithFds.stream(), fds);
|
||||
|
||||
if (streamWithFds.stream().type() == InputStreamParams::T__None) {
|
||||
MOZ_CRASH("Serialize failed!");
|
||||
|
@ -71,30 +83,25 @@ SerializeInputStreamWithFdsChild(nsIInputStream* aStream,
|
|||
|
||||
streamWithFds.optionalFds() = fdSet;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStreamWithFdsParent(nsIInputStream* aStream,
|
||||
bool
|
||||
SerializeInputStreamWithFdsParent(nsIIPCSerializableInputStream* aStream,
|
||||
IPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_RELEASE_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// First attempt simple stream serialization
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
if (!serializable) {
|
||||
MOZ_CRASH("Input stream is not serializable!");
|
||||
}
|
||||
|
||||
aValue = InputStreamParamsWithFds();
|
||||
InputStreamParamsWithFds& streamWithFds =
|
||||
aValue.get_InputStreamParamsWithFds();
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
serializable->Serialize(streamWithFds.stream(), fds);
|
||||
aStream->Serialize(streamWithFds.stream(), fds);
|
||||
|
||||
if (streamWithFds.stream().type() == InputStreamParams::T__None) {
|
||||
MOZ_CRASH("Serialize failed!");
|
||||
|
@ -116,84 +123,117 @@ SerializeInputStreamWithFdsParent(nsIInputStream* aStream,
|
|||
streamWithFds.optionalFds() = fdSet;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStreamWithFdsParent(nsIInputStream* aStream,
|
||||
OptionalIPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
if (!aStream) {
|
||||
aValue = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
aValue = IPCStream();
|
||||
SerializeInputStreamWithFdsParent(aStream, aValue.get_IPCStream(), aManager);
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
bool
|
||||
SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// As a fallback, attempt to stream the data across using a IPCStream
|
||||
// actor. For blocking streams, create a nonblocking pipe instead,
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
||||
if (!asyncStream) {
|
||||
const uint32_t kBufferSize = 32768; // matches IPCStream buffer size.
|
||||
nsCOMPtr<nsIAsyncOutputStream> sink;
|
||||
nsresult rv = NS_NewPipe2(getter_AddRefs(asyncStream),
|
||||
getter_AddRefs(sink),
|
||||
true,
|
||||
false,
|
||||
kBufferSize,
|
||||
UINT32_MAX);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
|
||||
rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
|
||||
kBufferSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(asyncStream);
|
||||
aValue = IPCStreamSource::Create(asyncStream, aManager);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
bool
|
||||
SerializeInputStreamChild(nsIInputStream* aStream, M* aManager,
|
||||
IPCStream* aValue,
|
||||
OptionalIPCStream* aOptionalValue)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(aValue || aOptionalValue);
|
||||
|
||||
// If a stream is known to be larger than 1MB, prefer sending it in chunks.
|
||||
const uint64_t kTooLargeStream = 1024 * 1024;
|
||||
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
|
||||
// ExpectedSerializedLength() returns the length of the stream if serialized.
|
||||
// This is useful to decide if we want to continue using the serialization
|
||||
// directly, or if it's better to use IPCStream.
|
||||
uint64_t expectedLength =
|
||||
serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
|
||||
if (serializable && expectedLength < kTooLargeStream) {
|
||||
if (aValue) {
|
||||
return SerializeInputStreamWithFdsChild(serializable, *aValue, aManager);
|
||||
}
|
||||
|
||||
return SerializeInputStreamWithFdsChild(serializable, *aOptionalValue,
|
||||
aManager);
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
return SerializeInputStream(aStream, *aValue, aManager);
|
||||
}
|
||||
|
||||
return SerializeInputStream(aStream, *aOptionalValue, aManager);
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
bool
|
||||
SerializeInputStreamParent(nsIInputStream* aStream, M* aManager,
|
||||
IPCStream* aValue,
|
||||
OptionalIPCStream* aOptionalValue)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(aValue || aOptionalValue);
|
||||
|
||||
// If a stream is known to be larger than 1MB, prefer sending it in chunks.
|
||||
const uint64_t kTooLargeStream = 1024 * 1024;
|
||||
|
||||
// First attempt simple stream serialization
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
uint64_t expectedLength =
|
||||
serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
|
||||
|
||||
if (serializable && expectedLength < kTooLargeStream) {
|
||||
SerializeInputStreamWithFdsChild(aStream, aValue, aManager);
|
||||
return;
|
||||
if (aValue) {
|
||||
return SerializeInputStreamWithFdsParent(serializable, *aValue, aManager);
|
||||
}
|
||||
|
||||
return SerializeInputStreamWithFdsParent(serializable, *aOptionalValue,
|
||||
aManager);
|
||||
}
|
||||
|
||||
// As a fallback, attempt to stream the data across using a SendStream
|
||||
// actor. For blocking streams, create a nonblocking pipe instead,
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
||||
if (!asyncStream) {
|
||||
const uint32_t kBufferSize = 32768; // matches SendStream buffer size.
|
||||
nsCOMPtr<nsIAsyncOutputStream> sink;
|
||||
DebugOnly<nsresult> rv = NS_NewPipe2(getter_AddRefs(asyncStream),
|
||||
getter_AddRefs(sink),
|
||||
true,
|
||||
false,
|
||||
kBufferSize,
|
||||
UINT32_MAX);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
|
||||
rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS, kBufferSize);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (aValue) {
|
||||
return SerializeInputStream(aStream, *aValue, aManager);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(asyncStream);
|
||||
aValue = SendStreamChild::Create(asyncStream, aManager);
|
||||
|
||||
if (!aValue.get_PSendStreamChild()) {
|
||||
MOZ_CRASH("SendStream creation failed!");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStream(nsIInputStream* aStream, OptionalIPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
if (!aStream) {
|
||||
aValue = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
aValue = IPCStream();
|
||||
SerializeInputStream(aStream, aValue.get_IPCStream(), aManager);
|
||||
return SerializeInputStream(aStream, *aOptionalValue, aManager);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -249,19 +289,24 @@ CleanupIPCStream(IPCStream& aValue, bool aConsumedByIPC)
|
|||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aValue.type() == IPCStream::TPSendStreamChild);
|
||||
IPCStreamSource* source = nullptr;
|
||||
if (aValue.type() == IPCStream::TPChildToParentStreamChild) {
|
||||
source = IPCStreamSource::Cast(aValue.get_PChildToParentStreamChild());
|
||||
} else {
|
||||
MOZ_ASSERT(aValue.type() == IPCStream::TPParentToChildStreamParent);
|
||||
source = IPCStreamSource::Cast(aValue.get_PParentToChildStreamParent());
|
||||
}
|
||||
|
||||
auto sendStream =
|
||||
static_cast<SendStreamChild*>(aValue.get_PSendStreamChild());
|
||||
MOZ_ASSERT(source);
|
||||
|
||||
if (!aConsumedByIPC) {
|
||||
sendStream->StartDestroy();
|
||||
source->StartDestroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the SendStream was taken to be sent to the parent, then we need to
|
||||
// start it before forgetting about it.
|
||||
sendStream->Start();
|
||||
// If the source stream was taken to be sent to the other side, then we need
|
||||
// to start it before forgetting about it.
|
||||
source->Start();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -274,19 +319,46 @@ CleanupIPCStream(OptionalIPCStream& aValue, bool aConsumedByIPC)
|
|||
CleanupIPCStream(aValue.get_IPCStream(), aConsumedByIPC);
|
||||
}
|
||||
|
||||
// Returns false if the serialization should not proceed. This means that the
|
||||
// inputStream is null.
|
||||
bool
|
||||
NormalizeOptionalValue(nsIInputStream* aStream,
|
||||
IPCStream* aValue,
|
||||
OptionalIPCStream* aOptionalValue)
|
||||
{
|
||||
if (aValue) {
|
||||
// if aStream is null, we will crash when serializing.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aStream) {
|
||||
*aOptionalValue = void_t();
|
||||
return false;
|
||||
}
|
||||
|
||||
*aOptionalValue = IPCStream();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeIPCStream(const IPCStream& aValue)
|
||||
{
|
||||
if (aValue.type() == IPCStream::TPSendStreamParent) {
|
||||
if (aValue.type() == IPCStream::TPChildToParentStreamParent) {
|
||||
auto sendStream =
|
||||
static_cast<SendStreamParent*>(aValue.get_PSendStreamParent());
|
||||
IPCStreamDestination::Cast(aValue.get_PChildToParentStreamParent());
|
||||
return sendStream->TakeReader();
|
||||
}
|
||||
|
||||
// Note, we explicitly do not support deserializing the PSendStream actor on
|
||||
// the child side. It can only be sent from child to parent.
|
||||
if (aValue.type() == IPCStream::TPParentToChildStreamChild) {
|
||||
auto sendStream =
|
||||
IPCStreamDestination::Cast(aValue.get_PParentToChildStreamChild());
|
||||
return sendStream->TakeReader();
|
||||
}
|
||||
|
||||
// Note, we explicitly do not support deserializing the PChildToParentStream actor on
|
||||
// the child side nor the PParentToChildStream actor on the parent side.
|
||||
MOZ_ASSERT(aValue.type() == IPCStream::TInputStreamParamsWithFds);
|
||||
|
||||
const InputStreamParamsWithFds& streamWithFds =
|
||||
|
@ -333,27 +405,6 @@ DeserializeIPCStream(const OptionalIPCStream& aValue)
|
|||
return DeserializeIPCStream(aValue.get_IPCStream());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
AssertValidValueToTake(const IPCStream& aVal)
|
||||
{
|
||||
MOZ_ASSERT(aVal.type() == IPCStream::TPSendStreamChild ||
|
||||
aVal.type() == IPCStream::TInputStreamParamsWithFds);
|
||||
}
|
||||
|
||||
void
|
||||
AssertValidValueToTake(const OptionalIPCStream& aVal)
|
||||
{
|
||||
MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
|
||||
aVal.type() == OptionalIPCStream::TIPCStream);
|
||||
if (aVal.type() == OptionalIPCStream::TIPCStream) {
|
||||
AssertValidValueToTake(aVal.get_IPCStream());
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
AutoIPCStream::AutoIPCStream()
|
||||
: mInlineValue(void_t())
|
||||
, mValue(nullptr)
|
||||
|
@ -389,7 +440,7 @@ AutoIPCStream::~AutoIPCStream()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, dom::nsIContentChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream || !mValue);
|
||||
|
@ -398,16 +449,25 @@ AutoIPCStream::Serialize(nsIInputStream* aStream, dom::nsIContentChild* aManager
|
|||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
// If NormalizeOptionalValue returns false, we don't have to proceed.
|
||||
if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue)) {
|
||||
MOZ_CRASH("IPCStream creation failed!");
|
||||
}
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStream(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStream(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream || !mValue);
|
||||
|
@ -416,17 +476,27 @@ AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundChild* aManager)
|
|||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
// If NormalizeOptionalValue returns false, we don't have to proceed.
|
||||
if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue)) {
|
||||
MOZ_CRASH("IPCStream creation failed!");
|
||||
}
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStream(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStream(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, dom::PContentParent* aManager)
|
||||
bool
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream,
|
||||
dom::nsIContentParent* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream || !mValue);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
@ -434,16 +504,25 @@ AutoIPCStream::Serialize(nsIInputStream* aStream, dom::PContentParent* aManager)
|
|||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
// If NormalizeOptionalValue returns false, we don't have to proceed.
|
||||
if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundParent* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream || !mValue);
|
||||
|
@ -452,13 +531,22 @@ AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundParent* aManager)
|
|||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
// If NormalizeOptionalValue returns false, we don't have to proceed.
|
||||
if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace mozilla {
|
|||
|
||||
namespace dom {
|
||||
class nsIContentChild;
|
||||
class PContentParent;
|
||||
class nsIContentParent;
|
||||
}
|
||||
|
||||
namespace ipc {
|
||||
|
@ -31,7 +31,7 @@ already_AddRefed<nsIInputStream>
|
|||
DeserializeIPCStream(const OptionalIPCStream& aValue);
|
||||
|
||||
// RAII helper class that serializes an nsIInputStream into an IPCStream struct.
|
||||
// Any file descriptor or PSendStream actors are automatically managed
|
||||
// Any file descriptor or PChildToParentStream actors are automatically managed
|
||||
// correctly.
|
||||
//
|
||||
// Here is a simple example:
|
||||
|
@ -60,7 +60,7 @@ DeserializeIPCStream(const OptionalIPCStream& aValue);
|
|||
// // Do something with stream...
|
||||
//
|
||||
// // You can also serialize streams from parent-to-child as long as
|
||||
// // they don't require PSendStream actor support.
|
||||
// // they don't require PChildToParentStream actor support.
|
||||
// AutoIPCStream anotherStream;
|
||||
// anotherStream.Serialize(mFileStream, Manager());
|
||||
// SendStuffDone(anotherStream.TakeValue());
|
||||
|
@ -101,14 +101,17 @@ DeserializeIPCStream(const OptionalIPCStream& aValue);
|
|||
// /* do something with the nsIInputStream */
|
||||
// }
|
||||
//
|
||||
// Note: This example is about child-to-parent inputStream, but AutoIPCStream
|
||||
// works also parent-to-child.
|
||||
//
|
||||
// The AutoIPCStream class also supports OptionalIPCStream values. As long as
|
||||
// you did not initialize the object with a non-optional IPCStream, you can call
|
||||
// TakeOptionalValue() instead.
|
||||
//
|
||||
// The AutoIPCStream class can also be used to serialize nsIInputStream objects
|
||||
// on the parent side to send to the child. Currently, however, this only
|
||||
// works for directly serializable stream types. The PSendStream actor mechanism
|
||||
// is not supported in this direction yet.
|
||||
// works for directly serializable stream types. The PChildToParentStream actor
|
||||
// mechanism is not supported in this direction yet.
|
||||
//
|
||||
// Like SerializeInputStream(), the AutoIPCStream will crash if
|
||||
// serialization cannot be completed.
|
||||
|
@ -146,35 +149,33 @@ public:
|
|||
// Serialize the input stream or create a SendStream actor using the PContent
|
||||
// manager. If neither of these succeed, then crash. This should only be
|
||||
// used on the main thread.
|
||||
void
|
||||
bool
|
||||
Serialize(nsIInputStream* aStream, dom::nsIContentChild* aManager);
|
||||
|
||||
// Serialize the input stream or create a SendStream actor using the
|
||||
// PBackground manager. If neither of these succeed, then crash. This can
|
||||
// be called on the main thread or Worker threads.
|
||||
void
|
||||
bool
|
||||
Serialize(nsIInputStream* aStream, PBackgroundChild* aManager);
|
||||
|
||||
// Serialize the input stream. A PSendStream cannot be used when going
|
||||
// from parent-to-child.
|
||||
void
|
||||
Serialize(nsIInputStream* aStream, dom::PContentParent* aManager);
|
||||
// Serialize the input stream.
|
||||
MOZ_MUST_USE bool
|
||||
Serialize(nsIInputStream* aStream, dom::nsIContentParent* aManager);
|
||||
|
||||
// Serialize the input stream. A PSendStream cannot be used when going
|
||||
// from parent-to-child.
|
||||
void
|
||||
// Serialize the input stream.
|
||||
MOZ_MUST_USE bool
|
||||
Serialize(nsIInputStream* aStream, PBackgroundParent* aManager);
|
||||
|
||||
// Get the IPCStream as a non-optional value. This will
|
||||
// assert if a stream has not been serialized or if it has already been taken.
|
||||
// This should only be called if the value is being, or has already been, sent
|
||||
// to the parent
|
||||
// to the other side.
|
||||
IPCStream&
|
||||
TakeValue();
|
||||
|
||||
// Get the OptionalIPCStream value. This will assert if
|
||||
// the value has already been taken. This should only be called if the value
|
||||
// is being, or has already been, sent to the parent
|
||||
// is being, or has already been, sent to the other side.
|
||||
OptionalIPCStream&
|
||||
TakeOptionalValue();
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
|
|
@ -18,7 +18,8 @@ include protocol PGamepadTestChannel;
|
|||
include protocol PMessagePort;
|
||||
include protocol PCameras;
|
||||
include protocol PQuota;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include protocol PServiceWorkerManager;
|
||||
include protocol PUDPSocket;
|
||||
include protocol PVsync;
|
||||
|
@ -61,7 +62,8 @@ sync protocol PBackground
|
|||
manages PMessagePort;
|
||||
manages PCameras;
|
||||
manages PQuota;
|
||||
manages PSendStream;
|
||||
manages PChildToParentStream;
|
||||
manages PParentToChildStream;
|
||||
manages PServiceWorkerManager;
|
||||
manages PUDPSocket;
|
||||
manages PVsync;
|
||||
|
@ -92,7 +94,7 @@ parent:
|
|||
|
||||
async PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
|
||||
|
||||
async PSendStream();
|
||||
async PChildToParentStream();
|
||||
|
||||
async MessagePortForceClose(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
|
||||
|
||||
|
@ -112,6 +114,8 @@ child:
|
|||
async PCache();
|
||||
async PCacheStreamControl();
|
||||
|
||||
async PParentToChildStream();
|
||||
|
||||
both:
|
||||
async PBlob(BlobConstructorParams params);
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ include protocol PContentBridge;
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
protocol PSendStream
|
||||
// This is protocol is the opposite of PParentToChildStream. Please keep these
|
||||
// protocols in sync.
|
||||
protocol PChildToParentStream
|
||||
{
|
||||
manager PBackground or PContent or PContentBridge;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
// This is protocol is the opposite of PChildToParentStream. Please keep these
|
||||
// protocols in sync.
|
||||
protocol PParentToChildStream
|
||||
{
|
||||
manager PBackground or PContent or PContentBridge;
|
||||
|
||||
child:
|
||||
async Buffer(nsCString aBuffer);
|
||||
async Close(nsresult aRv);
|
||||
|
||||
parent:
|
||||
// The parent side has hit an error condition and has requested the child
|
||||
// actor issue a Close() message. The close must be initiated by the child
|
||||
// to avoid racing with an in-flight Buffer() message.
|
||||
async RequestClose(nsresult aRv);
|
||||
|
||||
// Stream is always destroyed from the parent side. This occurs if the
|
||||
// parent encounters an error while writing to its pipe or if the child
|
||||
// signals the stream should close by SendClose().
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -1,101 +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/. */
|
||||
|
||||
#ifndef mozilla_ipc_SendStream_h
|
||||
#define mozilla_ipc_SendStream_h
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/ipc/PSendStreamChild.h"
|
||||
#include "mozilla/ipc/PSendStreamParent.h"
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIAsyncInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class nsIContentChild;
|
||||
} // dom namespace
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class PBackgroundChild;
|
||||
|
||||
// The SendStream IPC actor is designed to push an nsIInputStream from child to
|
||||
// parent incrementally. This is mainly needed for streams such as nsPipe that
|
||||
// may not yet have all their data available when the stream must be sent across
|
||||
// an IPC boundary. While many streams are handled by SerializeInputStream(),
|
||||
// these streams cannot be serialized and must be sent using this actor.
|
||||
//
|
||||
// The SendStream actor only supports sending data from child to parent.
|
||||
//
|
||||
// The SendStream actor only support async, non-blocking streams because they
|
||||
// must be read inline on the main thread and Worker threads.
|
||||
//
|
||||
// In general, the creation and handling of the SendStream actor cannot be
|
||||
// abstracted away behind SerializeInputStream() because the actor must be
|
||||
// carefully managed. Specifically:
|
||||
//
|
||||
// 1) The data flow must be explicitly initiated by calling
|
||||
// SendStreamChild::Start() after the actor has been sent to the parent.
|
||||
// 2) If the actor is never sent to the parent, then the child code must
|
||||
// call SendStreamChild::StartDestroy() to avoid memory leaks.
|
||||
// 3) The SendStreamChild actor can only be used on threads that can be
|
||||
// guaranteed to stay alive as long as the actor is alive. Right now
|
||||
// this limits SendStream to the main thread and Worker threads.
|
||||
//
|
||||
// In general you should probably use the AutoIPCStreamChild RAII class
|
||||
// defined in InputStreamUtils.h instead of using SendStreamChild directly.
|
||||
class SendStreamChild : public PSendStreamChild
|
||||
{
|
||||
public:
|
||||
// Create a SendStreamChild using a PContent IPC manager on the
|
||||
// main thread. This can return nullptr if the provided stream is
|
||||
// blocking.
|
||||
static SendStreamChild*
|
||||
Create(nsIAsyncInputStream* aInputStream, dom::nsIContentChild* aManager);
|
||||
|
||||
// Create a SendStreamChild using a PBackground IPC manager on the
|
||||
// main thread or a Worker thread. This can return nullptr if the provided
|
||||
// stream is blocking or if the Worker thread is already shutting down.
|
||||
static SendStreamChild*
|
||||
Create(nsIAsyncInputStream* aInputStream, PBackgroundChild* aManager);
|
||||
|
||||
// Start reading data from the nsIAsyncInputStream used to create the actor.
|
||||
// This must be called after the actor is passed to the parent. If you
|
||||
// use AutoIPCStream this is handled automatically.
|
||||
virtual void
|
||||
Start() = 0;
|
||||
|
||||
// Start cleaning up the actor. This must be called if the actor is never
|
||||
// sent to the parent. If you use AutoIPCStream this is handled
|
||||
// automatically.
|
||||
virtual void
|
||||
StartDestroy() = 0;
|
||||
|
||||
protected:
|
||||
virtual
|
||||
~SendStreamChild() = 0;
|
||||
};
|
||||
|
||||
// On the parent side, you must simply call TakeReader() upon receiving a
|
||||
// reference to the SendStreamParent actor. You do not need to maintain a
|
||||
// reference to the actor itself.
|
||||
class SendStreamParent : public PSendStreamParent
|
||||
{
|
||||
public:
|
||||
virtual already_AddRefed<nsIInputStream>
|
||||
TakeReader() = 0;
|
||||
|
||||
protected:
|
||||
virtual
|
||||
~SendStreamParent() = 0;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_SendStream_h
|
|
@ -1,429 +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 "mozilla/ipc/SendStream.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/workers/bindings/WorkerHolder.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsICancelableRunnable.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
using mozilla::dom::nsIContentChild;
|
||||
using mozilla::dom::workers::Canceling;
|
||||
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
|
||||
using mozilla::dom::workers::Status;
|
||||
using mozilla::dom::workers::WorkerHolder;
|
||||
using mozilla::dom::workers::WorkerPrivate;
|
||||
|
||||
namespace {
|
||||
|
||||
class SendStreamChildImpl final : public SendStreamChild
|
||||
, public WorkerHolder
|
||||
{
|
||||
public:
|
||||
explicit SendStreamChildImpl(nsIAsyncInputStream* aStream);
|
||||
~SendStreamChildImpl();
|
||||
|
||||
void Start() override;
|
||||
void StartDestroy() override;
|
||||
|
||||
bool
|
||||
AddAsWorkerHolder(dom::workers::WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
private:
|
||||
class Callback;
|
||||
|
||||
// PSendStreamChild methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestClose(const nsresult& aRv) override;
|
||||
|
||||
// WorkerHolder methods
|
||||
virtual bool
|
||||
Notify(Status aStatus) override;
|
||||
|
||||
void DoRead();
|
||||
|
||||
void Wait();
|
||||
|
||||
void OnStreamReady(Callback* aCallback);
|
||||
|
||||
void OnEnd(nsresult aRv);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mStream;
|
||||
RefPtr<Callback> mCallback;
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
bool mClosed;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
class SendStreamChildImpl::Callback final : public nsIInputStreamCallback
|
||||
, public nsIRunnable
|
||||
, public nsICancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Callback(SendStreamChildImpl* aActor)
|
||||
: mActor(aActor)
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnInputStreamReady(nsIAsyncInputStream* aStream) override
|
||||
{
|
||||
// any thread
|
||||
if (mOwningThread == NS_GetCurrentThread()) {
|
||||
return Run();
|
||||
}
|
||||
|
||||
// If this fails, then it means the owning thread is a Worker that has
|
||||
// been shutdown. Its ok to lose the event in this case because the
|
||||
// SendStreamChild listens for this event through the WorkerHolder.
|
||||
nsresult rv = mOwningThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch stream readable event to owning thread");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
|
||||
if (mActor) {
|
||||
mActor->OnStreamReady(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Cancel() override
|
||||
{
|
||||
// Cancel() gets called when the Worker thread is being shutdown. We have
|
||||
// nothing to do here because SendStreamChild handles this case via
|
||||
// the WorkerHolder.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ClearActor()
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(mActor);
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
~Callback()
|
||||
{
|
||||
// called on any thread
|
||||
|
||||
// ClearActor() should be called before the Callback is destroyed
|
||||
MOZ_ASSERT(!mActor);
|
||||
}
|
||||
|
||||
SendStreamChildImpl* mActor;
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SendStreamChildImpl::Callback, nsIInputStreamCallback,
|
||||
nsIRunnable,
|
||||
nsICancelableRunnable);
|
||||
|
||||
SendStreamChildImpl::SendStreamChildImpl(nsIAsyncInputStream* aStream)
|
||||
: mStream(aStream)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mClosed(false)
|
||||
{
|
||||
MOZ_ASSERT(mStream);
|
||||
}
|
||||
|
||||
SendStreamChildImpl::~SendStreamChildImpl()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT(mClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
MOZ_ASSERT(!mWorkerPrivate);
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::Start()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate);
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::StartDestroy()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
OnEnd(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
bool
|
||||
SendStreamChildImpl::AddAsWorkerHolder(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
bool result = HoldWorker(aWorkerPrivate, Canceling);
|
||||
if (result) {
|
||||
mWorkerPrivate = aWorkerPrivate;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
|
||||
// If the parent side runs into a problem it will ask the child to
|
||||
// close the connection via RequestClose(). Therefore OnEnd() should
|
||||
// always run before the actor is destroyed.
|
||||
MOZ_ASSERT(mClosed);
|
||||
|
||||
if (mCallback) {
|
||||
mCallback->ClearActor();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
ReleaseWorker();
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
SendStreamChildImpl::RecvRequestClose(const nsresult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
OnEnd(aRv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
SendStreamChildImpl::Notify(Status aStatus)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
|
||||
// Keep the worker thread alive until the stream is finished.
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::DoRead()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
// The input stream (likely a pipe) probably uses a segment size of
|
||||
// 4kb. If there is data already buffered it would be nice to aggregate
|
||||
// multiple segments into a single IPC call. Conversely, don't send too
|
||||
// too large of a buffer in a single call to avoid spiking memory.
|
||||
static const uint64_t kMaxBytesPerMessage = 32 * 1024;
|
||||
static_assert(kMaxBytesPerMessage <= static_cast<uint64_t>(UINT32_MAX),
|
||||
"kMaxBytesPerMessage must cleanly cast to uint32_t");
|
||||
|
||||
while (true) {
|
||||
// It should not be possible to transition to closed state without
|
||||
// this loop terminating via a return.
|
||||
MOZ_ASSERT(!mClosed);
|
||||
|
||||
// Use non-auto here as we're unlikely to hit stack storage with the
|
||||
// sizes we are sending. Also, it would be nice to avoid another copy
|
||||
// to the IPC layer which we avoid if we use COW strings. Unfortunately
|
||||
// IPC does not seem to support passing dependent storage types.
|
||||
nsCString buffer;
|
||||
|
||||
uint64_t available = 0;
|
||||
nsresult rv = mStream->Available(&available);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (available == 0) {
|
||||
Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t expectedBytes =
|
||||
static_cast<uint32_t>(std::min(available, kMaxBytesPerMessage));
|
||||
|
||||
buffer.SetLength(expectedBytes);
|
||||
|
||||
uint32_t bytesRead = 0;
|
||||
rv = mStream->Read(buffer.BeginWriting(), buffer.Length(), &bytesRead);
|
||||
MOZ_ASSERT_IF(NS_FAILED(rv), bytesRead == 0);
|
||||
buffer.SetLength(bytesRead);
|
||||
|
||||
// If we read any data from the stream, send it across.
|
||||
if (!buffer.IsEmpty()) {
|
||||
Unused << SendBuffer(buffer);
|
||||
}
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
// Any other error or zero-byte read indicates end-of-stream
|
||||
if (NS_FAILED(rv) || buffer.IsEmpty()) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::Wait()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
// Set mCallback immediately instead of waiting for success. Its possible
|
||||
// AsyncWait() will callback synchronously.
|
||||
mCallback = new Callback(this);
|
||||
nsresult rv = mStream->AsyncWait(mCallback, 0, 0, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::OnStreamReady(Callback* aCallback)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT(mCallback);
|
||||
MOZ_ASSERT(aCallback == mCallback);
|
||||
mCallback->ClearActor();
|
||||
mCallback = nullptr;
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamChildImpl::OnEnd(nsresult aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(SendStreamChild);
|
||||
MOZ_ASSERT(aRv != NS_BASE_STREAM_WOULD_BLOCK);
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
|
||||
mStream->CloseWithStatus(aRv);
|
||||
|
||||
if (aRv == NS_BASE_STREAM_CLOSED) {
|
||||
aRv = NS_OK;
|
||||
}
|
||||
|
||||
// This will trigger an ActorDestroy() from the parent side
|
||||
Unused << SendClose(aRv);
|
||||
}
|
||||
|
||||
bool
|
||||
IsBlocking(nsIAsyncInputStream* aInputStream)
|
||||
{
|
||||
bool nonBlocking = false;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aInputStream->IsNonBlocking(&nonBlocking)));
|
||||
return !nonBlocking;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
SendStreamChild*
|
||||
SendStreamChild::Create(nsIAsyncInputStream* aInputStream,
|
||||
nsIContentChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// PContent can only be used on the main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// SendStreamChild reads in the current thread, so it is only supported
|
||||
// on non-blocking, async channels
|
||||
if (NS_WARN_IF(IsBlocking(aInputStream))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SendStreamChild* actor = new SendStreamChildImpl(aInputStream);
|
||||
aManager->SendPSendStreamConstructor(actor);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
// static
|
||||
SendStreamChild*
|
||||
SendStreamChild::Create(nsIAsyncInputStream* aInputStream,
|
||||
PBackgroundChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// PBackground can be used on any thread, but we only support SendStream on
|
||||
// main thread and Worker threads right now. This is due to the requirement
|
||||
// that the thread be guaranteed to live long enough to receive messages
|
||||
// sent from parent to child. We can enforce this guarantee with a feature
|
||||
// on worker threads, but not other threads.
|
||||
WorkerPrivate* workerPrivate = nullptr;
|
||||
if (!NS_IsMainThread()) {
|
||||
workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
}
|
||||
|
||||
// SendStreamChild reads in the current thread, so it is only supported
|
||||
// on non-blocking, async channels
|
||||
if (NS_WARN_IF(IsBlocking(aInputStream))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SendStreamChildImpl* actor = new SendStreamChildImpl(aInputStream);
|
||||
|
||||
if (workerPrivate && !actor->AddAsWorkerHolder(workerPrivate)) {
|
||||
delete actor;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aManager->SendPSendStreamConstructor(actor);
|
||||
return actor;
|
||||
}
|
||||
|
||||
SendStreamChild::~SendStreamChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DeallocPSendStreamChild(PSendStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -1,136 +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 "mozilla/ipc/SendStream.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsIPipe.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
namespace {
|
||||
|
||||
class SendStreamParentImpl final : public SendStreamParent
|
||||
{
|
||||
public:
|
||||
SendStreamParentImpl(nsIAsyncInputStream* aReader,
|
||||
nsIAsyncOutputStream* aWriter);
|
||||
~SendStreamParentImpl();
|
||||
|
||||
private:
|
||||
// PSendStreamParentImpl methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
// SendStreamparent methods
|
||||
already_AddRefed<nsIInputStream>
|
||||
TakeReader() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvBuffer(const nsCString& aBuffer) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvClose(const nsresult& aRv) override;
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mReader;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mWriter;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
SendStreamParentImpl::~SendStreamParentImpl()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
SendStreamParentImpl::TakeReader()
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
return mReader.forget();
|
||||
}
|
||||
|
||||
void
|
||||
SendStreamParentImpl::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
// If we were gracefully closed we should have gotten RecvClose(). In
|
||||
// that case, the writer will already be closed and this will have no
|
||||
// effect. This just aborts the writer in the case where the child process
|
||||
// crashes.
|
||||
mWriter->CloseWithStatus(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
SendStreamParentImpl::RecvBuffer(const nsCString& aBuffer)
|
||||
{
|
||||
uint32_t numWritten = 0;
|
||||
|
||||
// This should only fail if we hit an OOM condition.
|
||||
nsresult rv = mWriter->Write(aBuffer.get(), aBuffer.Length(), &numWritten);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
Unused << SendRequestClose(rv);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
SendStreamParentImpl::RecvClose(const nsresult& aRv)
|
||||
{
|
||||
mWriter->CloseWithStatus(aRv);
|
||||
Unused << Send__delete__(this);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
SendStreamParentImpl::SendStreamParentImpl(nsIAsyncInputStream* aReader,
|
||||
nsIAsyncOutputStream* aWriter)
|
||||
: mReader(aReader)
|
||||
, mWriter(aWriter)
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
MOZ_ASSERT(mWriter);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SendStreamParent::~SendStreamParent()
|
||||
{
|
||||
}
|
||||
|
||||
PSendStreamParent*
|
||||
AllocPSendStreamParent()
|
||||
{
|
||||
// use async versions for both reader and writer even though we are
|
||||
// opening the writer as an infinite stream. We want to be able to
|
||||
// use CloseWithStatus() to communicate errors through the pipe.
|
||||
nsCOMPtr<nsIAsyncInputStream> reader;
|
||||
nsCOMPtr<nsIAsyncOutputStream> writer;
|
||||
|
||||
// Use an "infinite" pipe because we cannot apply back-pressure through
|
||||
// the async IPC layer at the moment. Blocking the IPC worker thread
|
||||
// is not desirable, either.
|
||||
nsresult rv = NS_NewPipe2(getter_AddRefs(reader),
|
||||
getter_AddRefs(writer),
|
||||
true, true, // non-blocking
|
||||
0, // segment size
|
||||
UINT32_MAX); // "infinite" pipe
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new SendStreamParentImpl(reader, writer);
|
||||
}
|
||||
|
||||
void
|
||||
DeallocPSendStreamParent(PSendStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -27,6 +27,9 @@ EXPORTS.mozilla.ipc += [
|
|||
'GeckoChildProcessHost.h',
|
||||
'InputStreamUtils.h',
|
||||
'IOThreadChild.h',
|
||||
'IPCStreamAlloc.h',
|
||||
'IPCStreamDestination.h',
|
||||
'IPCStreamSource.h',
|
||||
'IPCStreamUtils.h',
|
||||
'MessageChannel.h',
|
||||
'MessageLink.h',
|
||||
|
@ -34,8 +37,6 @@ EXPORTS.mozilla.ipc += [
|
|||
'ProcessChild.h',
|
||||
'ProtocolUtils.h',
|
||||
'ScopedXREEmbed.h',
|
||||
'SendStream.h',
|
||||
'SendStreamAlloc.h',
|
||||
'SharedMemory.h',
|
||||
'SharedMemoryBasic.h',
|
||||
'Shmem.h',
|
||||
|
@ -143,6 +144,10 @@ UNIFIED_SOURCES += [
|
|||
'FileDescriptorUtils.cpp',
|
||||
'InputStreamUtils.cpp',
|
||||
'IPCMessageUtils.cpp',
|
||||
'IPCStreamChild.cpp',
|
||||
'IPCStreamDestination.cpp',
|
||||
'IPCStreamParent.cpp',
|
||||
'IPCStreamSource.cpp',
|
||||
'IPCStreamUtils.cpp',
|
||||
'MessageChannel.cpp',
|
||||
'MessageLink.cpp',
|
||||
|
@ -150,8 +155,6 @@ UNIFIED_SOURCES += [
|
|||
'ProcessChild.cpp',
|
||||
'ProtocolUtils.cpp',
|
||||
'ScopedXREEmbed.cpp',
|
||||
'SendStreamChild.cpp',
|
||||
'SendStreamParent.cpp',
|
||||
'SharedMemory.cpp',
|
||||
'Shmem.cpp',
|
||||
'StringUtil.cpp',
|
||||
|
@ -189,9 +192,10 @@ IPDL_SOURCES = [
|
|||
'PBackground.ipdl',
|
||||
'PBackgroundSharedTypes.ipdlh',
|
||||
'PBackgroundTest.ipdl',
|
||||
'PChildToParentStream.ipdl',
|
||||
'PFileDescriptorSet.ipdl',
|
||||
'PParentToChildStream.ipdl',
|
||||
'ProtocolTypes.ipdlh',
|
||||
'PSendStream.ipdl',
|
||||
'URIParams.ipdlh',
|
||||
]
|
||||
|
||||
|
|
|
@ -1275,7 +1275,10 @@ NewExternalString(JSContext* cx, unsigned argc, Value* vp)
|
|||
RootedString str(cx, args[0].toString());
|
||||
size_t len = str->length();
|
||||
|
||||
UniqueTwoByteChars buf(js_pod_malloc<char16_t>(len));
|
||||
UniqueTwoByteChars buf(cx->pod_malloc<char16_t>(len));
|
||||
if (!buf)
|
||||
return false;
|
||||
|
||||
if (!JS_CopyStringChars(cx, mozilla::Range<char16_t>(buf.get(), len), str))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// |jit-test| allow-unhandlable-oom; allow-oom
|
||||
if (!('oomAfterAllocations' in this))
|
||||
quit();
|
||||
oomAfterAllocations(1);
|
||||
newExternalString("a");
|
|
@ -0,0 +1,7 @@
|
|||
for (var i=0; i<10; i++) {
|
||||
var o = {};
|
||||
if (i & 1)
|
||||
Object.preventExtensions(o);
|
||||
o[0] = i;
|
||||
assertEq(0 in o, !(i & 1));
|
||||
}
|
|
@ -767,7 +767,7 @@ BaselineCacheIRCompiler::emitStoreSlotShared(bool isFixed)
|
|||
masm.storeValue(val, slot);
|
||||
}
|
||||
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch1, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierSlot(obj, val, scratch1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -879,7 +879,7 @@ BaselineCacheIRCompiler::emitAddAndStoreSlotShared(CacheOp op)
|
|||
masm.storeValue(val, slot);
|
||||
}
|
||||
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch1, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierSlot(obj, val, scratch1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -935,7 +935,7 @@ BaselineCacheIRCompiler::emitStoreUnboxedProperty()
|
|||
/* failure = */ nullptr);
|
||||
|
||||
if (UnboxedTypeNeedsPostBarrier(fieldType))
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierSlot(obj, val, scratch);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -972,7 +972,7 @@ BaselineCacheIRCompiler::emitStoreTypedObjectReferenceProperty()
|
|||
emitStoreTypedObjectReferenceProp(val, type, dest, scratch2);
|
||||
|
||||
if (type != ReferenceTypeDescr::TYPE_STRING)
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch1, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierSlot(obj, val, scratch1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1075,7 +1075,7 @@ BaselineCacheIRCompiler::emitStoreDenseElement()
|
|||
EmitPreBarrier(masm, element, MIRType::Value);
|
||||
masm.storeValue(val, element);
|
||||
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1212,7 +1212,7 @@ BaselineCacheIRCompiler::emitStoreDenseElementHole()
|
|||
masm.bind(&doStore);
|
||||
masm.storeValue(val, element);
|
||||
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1310,7 +1310,7 @@ BaselineCacheIRCompiler::emitStoreUnboxedArrayElement()
|
|||
/* failure = */ nullptr);
|
||||
|
||||
if (UnboxedTypeNeedsPostBarrier(elementType))
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierSlot(obj, val, scratch);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1387,7 +1387,7 @@ BaselineCacheIRCompiler::emitStoreUnboxedArrayElementHole()
|
|||
/* failure = */ nullptr);
|
||||
|
||||
if (UnboxedTypeNeedsPostBarrier(elementType))
|
||||
BaselineEmitPostWriteBarrierSlot(masm, obj, val, scratch, LiveGeneralRegisterSet(), cx_);
|
||||
emitPostBarrierSlot(obj, val, scratch);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2469,9 +2469,12 @@ SetPropIRGenerator::tryAttachSetDenseElementHole(HandleObject obj, ObjOperandId
|
|||
return false;
|
||||
|
||||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
if (nobj->getElementsHeader()->isFrozen())
|
||||
if (!nobj->nonProxyIsExtensible())
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!nobj->getElementsHeader()->isFrozen(),
|
||||
"Extensible objects should not have frozen elements");
|
||||
|
||||
uint32_t initLength = nobj->getDenseInitializedLength();
|
||||
|
||||
// Optimize if we're adding an element at initLength or writing to a hole.
|
||||
|
|
|
@ -2113,6 +2113,54 @@ CacheIRCompiler::emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTy
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheIRCompiler::emitPostBarrierShared(Register obj, const ConstantOrRegister& val,
|
||||
Register scratch, Register maybeIndex)
|
||||
{
|
||||
if (!cx_->nursery().exists())
|
||||
return;
|
||||
|
||||
if (val.constant()) {
|
||||
MOZ_ASSERT_IF(val.value().isObject(), !IsInsideNursery(&val.value().toObject()));
|
||||
return;
|
||||
}
|
||||
|
||||
TypedOrValueRegister reg = val.reg();
|
||||
if (reg.hasTyped() && reg.type() != MIRType::Object)
|
||||
return;
|
||||
|
||||
Label skipBarrier;
|
||||
if (reg.hasValue()) {
|
||||
masm.branchValueIsNurseryObject(Assembler::NotEqual, reg.valueReg(), scratch,
|
||||
&skipBarrier);
|
||||
} else {
|
||||
masm.branchPtrInNurseryChunk(Assembler::NotEqual, reg.typedReg().gpr(), scratch,
|
||||
&skipBarrier);
|
||||
}
|
||||
masm.branchPtrInNurseryChunk(Assembler::Equal, obj, scratch, &skipBarrier);
|
||||
|
||||
// Call one of these, depending on maybeIndex:
|
||||
//
|
||||
// void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
|
||||
// void PostWriteElementBarrier(JSRuntime* rt, JSObject* obj,
|
||||
// int32_t index);
|
||||
LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
|
||||
masm.PushRegsInMask(save);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.movePtr(ImmPtr(cx_->runtime()), scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(obj);
|
||||
if (maybeIndex != InvalidReg) {
|
||||
masm.passABIArg(maybeIndex);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*,
|
||||
(PostWriteElementBarrier<IndexInBounds::Yes>)));
|
||||
} else {
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
|
||||
}
|
||||
masm.PopRegsInMask(save);
|
||||
|
||||
masm.bind(&skipBarrier);
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitWrapResult()
|
||||
|
|
|
@ -582,6 +582,27 @@ class MOZ_RAII CacheIRCompiler
|
|||
void emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTypeDescr::Type type,
|
||||
const Address& dest, Register scratch);
|
||||
|
||||
private:
|
||||
void emitPostBarrierShared(Register obj, const ConstantOrRegister& val, Register scratch,
|
||||
Register maybeIndex);
|
||||
|
||||
void emitPostBarrierShared(Register obj, ValueOperand val, Register scratch,
|
||||
Register maybeIndex) {
|
||||
emitPostBarrierShared(obj, ConstantOrRegister(val), scratch, maybeIndex);
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
void emitPostBarrierSlot(Register obj, const T& val, Register scratch) {
|
||||
emitPostBarrierShared(obj, val, scratch, InvalidReg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void emitPostBarrierElement(Register obj, const T& val, Register scratch, Register index) {
|
||||
MOZ_ASSERT(index != InvalidReg);
|
||||
emitPostBarrierShared(obj, val, scratch, index);
|
||||
}
|
||||
|
||||
#define DEFINE_SHARED_OP(op) MOZ_MUST_USE bool emit##op();
|
||||
CACHE_IR_SHARED_OPS(DEFINE_SHARED_OP)
|
||||
#undef DEFINE_SHARED_OP
|
||||
|
|
|
@ -3856,7 +3856,7 @@ CodeGenerator::visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteE
|
|||
masm.passABIArg(runtimereg);
|
||||
masm.passABIArg(objreg);
|
||||
masm.passABIArg(indexreg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteElementBarrier));
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (PostWriteElementBarrier<IndexInBounds::Maybe>)));
|
||||
|
||||
restoreLiveVolatile(ool->lir());
|
||||
|
||||
|
@ -10306,8 +10306,8 @@ CodeGenerator::addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
|
|||
Register temp, FloatRegister tempDouble,
|
||||
FloatRegister tempF32, const ConstantOrRegister& id,
|
||||
const ConstantOrRegister& value,
|
||||
bool strict, bool needsTypeBarrier, bool guardHoles,
|
||||
jsbytecode* profilerLeavePc)
|
||||
bool strict, bool needsPostBarrier, bool needsTypeBarrier,
|
||||
bool guardHoles, jsbytecode* profilerLeavePc)
|
||||
{
|
||||
CacheKind kind = CacheKind::SetElem;
|
||||
if (id.constant() && id.value().isString()) {
|
||||
|
@ -10317,7 +10317,7 @@ CodeGenerator::addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
|
|||
kind = CacheKind::SetProp;
|
||||
}
|
||||
IonSetPropertyIC cache(kind, liveRegs, objReg, temp, tempDouble, tempF32,
|
||||
id, value, strict, needsTypeBarrier, guardHoles);
|
||||
id, value, strict, needsPostBarrier, needsTypeBarrier, guardHoles);
|
||||
addIC(ins, allocateIC(cache));
|
||||
}
|
||||
|
||||
|
@ -10467,8 +10467,9 @@ CodeGenerator::visitSetPropertyCache(LSetPropertyCache* ins)
|
|||
toConstantOrRegister(ins, LSetPropertyCache::Value, ins->mir()->value()->type());
|
||||
|
||||
addSetPropertyCache(ins, liveRegs, objReg, temp, tempDouble, tempF32,
|
||||
id, value, ins->mir()->strict(), ins->mir()->needsTypeBarrier(),
|
||||
ins->mir()->guardHoles(), ins->mir()->profilerLeavePc());
|
||||
id, value, ins->mir()->strict(), ins->mir()->needsPostBarrier(),
|
||||
ins->mir()->needsTypeBarrier(), ins->mir()->guardHoles(),
|
||||
ins->mir()->profilerLeavePc());
|
||||
}
|
||||
|
||||
typedef bool (*ThrowFn)(JSContext*, HandleValue);
|
||||
|
|
|
@ -464,8 +464,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
Register temp, FloatRegister tempDouble,
|
||||
FloatRegister tempF32, const ConstantOrRegister& id,
|
||||
const ConstantOrRegister& value,
|
||||
bool strict, bool needsTypeBarrier, bool guardHoles,
|
||||
jsbytecode* profilerLeavePc);
|
||||
bool strict, bool needsPostBarrier, bool needsTypeBarrier,
|
||||
bool guardHoles, jsbytecode* profilerLeavePc);
|
||||
|
||||
MOZ_MUST_USE bool generateBranchV(const ValueOperand& value, Label* ifTrue, Label* ifFalse,
|
||||
FloatRegister fr);
|
||||
|
|
|
@ -7231,9 +7231,9 @@ IonBuilder::setStaticName(JSObject* staticObject, PropertyName* name)
|
|||
if (knownType != MIRType::Value)
|
||||
slotType = knownType;
|
||||
|
||||
bool needsBarrier = property.needsBarrier(constraints());
|
||||
bool needsPreBarrier = property.needsBarrier(constraints());
|
||||
return storeSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
|
||||
value, needsBarrier, slotType);
|
||||
value, needsPreBarrier, slotType);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -9022,17 +9022,11 @@ IonBuilder::initOrSetElemTryCache(bool* emitted, MDefinition* object,
|
|||
bool checkNative = !clasp || !clasp->isNative();
|
||||
object = addMaybeCopyElementsForWrite(object, checkNative);
|
||||
|
||||
if (NeedsPostBarrier(value)) {
|
||||
if (indexIsInt32)
|
||||
current->add(MPostWriteElementBarrier::New(alloc(), object, value, index));
|
||||
else
|
||||
current->add(MPostWriteBarrier::New(alloc(), object, value));
|
||||
}
|
||||
|
||||
// Emit SetPropertyCache.
|
||||
bool strict = JSOp(*pc) == JSOP_STRICTSETELEM;
|
||||
MSetPropertyCache* ins =
|
||||
MSetPropertyCache::New(alloc(), object, index, value, strict, barrier, guardHoles);
|
||||
MSetPropertyCache::New(alloc(), object, index, value, strict, NeedsPostBarrier(value),
|
||||
barrier, guardHoles);
|
||||
current->add(ins);
|
||||
|
||||
if (IsPropertyInitOp(JSOp(*pc)))
|
||||
|
@ -11285,11 +11279,6 @@ IonBuilder::jsop_setprop(PropertyName* name)
|
|||
return Ok();
|
||||
}
|
||||
|
||||
// Add post barrier if needed. The instructions above manage any post
|
||||
// barriers they need directly.
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
if (!forceInlineCaches()) {
|
||||
// Try to emit store from definite slots.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
|
||||
|
@ -11574,6 +11563,9 @@ IonBuilder::setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
|
|||
writeBarrier |= property.needsBarrier(constraints());
|
||||
}
|
||||
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
MInstruction* store;
|
||||
if (slot < nfixed) {
|
||||
store = MStoreFixedSlot::New(alloc(), obj, slot, value);
|
||||
|
@ -11723,8 +11715,11 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
|
|||
Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
|
||||
MOZ_ASSERT(shape);
|
||||
|
||||
bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
|
||||
MOZ_TRY(storeSlot(obj, shape, value, needsBarrier));
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
bool needsPreBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
|
||||
MOZ_TRY(storeSlot(obj, shape, value, needsPreBarrier));
|
||||
|
||||
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
|
||||
*emitted = true;
|
||||
|
@ -11746,8 +11741,11 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
|
|||
Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
|
||||
MOZ_ASSERT(shape);
|
||||
|
||||
bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
|
||||
MOZ_TRY(storeSlot(expando, shape, value, needsBarrier));
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
bool needsPreBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
|
||||
MOZ_TRY(storeSlot(expando, shape, value, needsPreBarrier));
|
||||
|
||||
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
|
||||
*emitted = true;
|
||||
|
@ -11763,6 +11761,9 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
|
|||
|
||||
obj = addGroupGuard(obj, group, Bailout_ShapeGuard);
|
||||
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name);
|
||||
storeUnboxedProperty(obj, property->offset, property->type, value);
|
||||
|
||||
|
@ -11781,14 +11782,20 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
|
|||
if (!obj)
|
||||
return abort(AbortReason::Alloc);
|
||||
|
||||
bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
|
||||
MOZ_TRY(storeSlot(obj, propShape, value, needsBarrier));
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
bool needsPreBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
|
||||
MOZ_TRY(storeSlot(obj, propShape, value, needsPreBarrier));
|
||||
|
||||
trackOptimizationOutcome(TrackedOutcome::Polymorphic);
|
||||
*emitted = true;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
if (NeedsPostBarrier(value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
MSetPropertyPolymorphic* ins = MSetPropertyPolymorphic::New(alloc(), obj, value, name);
|
||||
current->add(ins);
|
||||
current->push(value);
|
||||
|
@ -11823,7 +11830,8 @@ IonBuilder::setPropTryCache(bool* emitted, MDefinition* obj,
|
|||
bool strict = IsStrictSetPC(pc);
|
||||
|
||||
MConstant* id = constant(StringValue(name));
|
||||
MSetPropertyCache* ins = MSetPropertyCache::New(alloc(), obj, id, value, strict, barrier,
|
||||
MSetPropertyCache* ins = MSetPropertyCache::New(alloc(), obj, id, value, strict,
|
||||
NeedsPostBarrier(value), barrier,
|
||||
/* guardHoles = */ false);
|
||||
current->add(ins);
|
||||
current->push(value);
|
||||
|
|
|
@ -133,6 +133,10 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler
|
|||
|
||||
MOZ_MUST_USE bool emitAddAndStoreSlotShared(CacheOp op);
|
||||
|
||||
bool needsPostBarrier() const {
|
||||
return ic_->asSetPropertyIC()->needsPostBarrier();
|
||||
}
|
||||
|
||||
void pushStubCodePointer() {
|
||||
stubJitCodeOffset_.emplace(masm.PushWithPatch(ImmPtr((void*)-1)));
|
||||
}
|
||||
|
@ -1024,6 +1028,10 @@ IonCacheIRCompiler::emitStoreFixedSlot()
|
|||
int32_t offset = int32StubField(reader.stubOffset());
|
||||
ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
|
||||
|
||||
Maybe<AutoScratchRegister> scratch;
|
||||
if (needsPostBarrier())
|
||||
scratch.emplace(allocator, masm);
|
||||
|
||||
if (typeCheckInfo_->isSet()) {
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -1035,6 +1043,8 @@ IonCacheIRCompiler::emitStoreFixedSlot()
|
|||
Address slot(obj, offset);
|
||||
EmitPreBarrier(masm, slot, MIRType::Value);
|
||||
masm.storeConstantOrRegister(val, slot);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierSlot(obj, val, scratch.ref());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1058,6 +1068,8 @@ IonCacheIRCompiler::emitStoreDynamicSlot()
|
|||
Address slot(scratch, offset);
|
||||
EmitPreBarrier(masm, slot, MIRType::Value);
|
||||
masm.storeConstantOrRegister(val, slot);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierSlot(obj, val, scratch);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1146,6 +1158,9 @@ IonCacheIRCompiler::emitAddAndStoreSlotShared(CacheOp op)
|
|||
masm.storeConstantOrRegister(val, slot);
|
||||
}
|
||||
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierSlot(obj, val, scratch1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1175,6 +1190,10 @@ IonCacheIRCompiler::emitStoreUnboxedProperty()
|
|||
int32_t offset = int32StubField(reader.stubOffset());
|
||||
ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
|
||||
|
||||
Maybe<AutoScratchRegister> scratch;
|
||||
if (needsPostBarrier() && UnboxedTypeNeedsPostBarrier(fieldType))
|
||||
scratch.emplace(allocator, masm);
|
||||
|
||||
if (fieldType == JSVAL_TYPE_OBJECT && typeCheckInfo_->isSet()) {
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -1187,6 +1206,8 @@ IonCacheIRCompiler::emitStoreUnboxedProperty()
|
|||
Address fieldAddr(obj, offset);
|
||||
EmitICUnboxedPreBarrier(masm, fieldAddr, fieldType);
|
||||
masm.storeUnboxedProperty(fieldAddr, fieldType, val, /* failure = */ nullptr);
|
||||
if (needsPostBarrier() && UnboxedTypeNeedsPostBarrier(fieldType))
|
||||
emitPostBarrierSlot(obj, val, scratch.ref());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1218,6 +1239,9 @@ IonCacheIRCompiler::emitStoreTypedObjectReferenceProperty()
|
|||
Address dest(scratch1, offset);
|
||||
|
||||
emitStoreTypedObjectReferenceProp(val, type, dest, scratch2);
|
||||
|
||||
if (needsPostBarrier() && type != ReferenceTypeDescr::TYPE_STRING)
|
||||
emitPostBarrierSlot(obj, val, scratch1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1272,6 +1296,8 @@ IonCacheIRCompiler::emitStoreDenseElement()
|
|||
|
||||
EmitPreBarrier(masm, element, MIRType::Value);
|
||||
EmitIonStoreDenseElement(masm, val, scratch, element);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1356,6 +1382,8 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
|
||||
masm.bind(&doStore);
|
||||
EmitIonStoreDenseElement(masm, val, scratch, element);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -214,6 +214,7 @@ class IonSetPropertyIC : public IonIC
|
|||
ConstantOrRegister id_;
|
||||
ConstantOrRegister rhs_;
|
||||
bool strict_ : 1;
|
||||
bool needsPostBarrier_ : 1;
|
||||
bool needsTypeBarrier_ : 1;
|
||||
bool guardHoles_ : 1;
|
||||
|
||||
|
@ -221,7 +222,7 @@ class IonSetPropertyIC : public IonIC
|
|||
IonSetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, Register object, Register temp,
|
||||
FloatRegister maybeTempDouble, FloatRegister maybeTempFloat32,
|
||||
const ConstantOrRegister& id, const ConstantOrRegister& rhs, bool strict,
|
||||
bool needsTypeBarrier, bool guardHoles)
|
||||
bool needsPostBarrier, bool needsTypeBarrier, bool guardHoles)
|
||||
: IonIC(kind),
|
||||
liveRegs_(liveRegs),
|
||||
object_(object),
|
||||
|
@ -231,6 +232,7 @@ class IonSetPropertyIC : public IonIC
|
|||
id_(id),
|
||||
rhs_(rhs),
|
||||
strict_(strict),
|
||||
needsPostBarrier_(needsPostBarrier),
|
||||
needsTypeBarrier_(needsTypeBarrier),
|
||||
guardHoles_(guardHoles)
|
||||
{ }
|
||||
|
@ -245,6 +247,7 @@ class IonSetPropertyIC : public IonIC
|
|||
FloatRegister maybeTempFloat32() const { return maybeTempFloat32_; }
|
||||
|
||||
bool strict() const { return strict_; }
|
||||
bool needsPostBarrier() const { return needsPostBarrier_; }
|
||||
bool needsTypeBarrier() const { return needsTypeBarrier_; }
|
||||
bool guardHoles() const { return guardHoles_; }
|
||||
|
||||
|
|
|
@ -11835,13 +11835,15 @@ class MSetPropertyCache
|
|||
public Mix3Policy<SingleObjectPolicy, CacheIdPolicy<1>, NoFloatPolicy<2>>::Data
|
||||
{
|
||||
bool strict_ : 1;
|
||||
bool needsPostBarrier_ : 1;
|
||||
bool needsTypeBarrier_ : 1;
|
||||
bool guardHoles_ : 1;
|
||||
|
||||
MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, bool strict,
|
||||
bool typeBarrier, bool guardHoles)
|
||||
bool needsPostBarrier, bool typeBarrier, bool guardHoles)
|
||||
: MTernaryInstruction(obj, id, value),
|
||||
strict_(strict),
|
||||
needsPostBarrier_(needsPostBarrier),
|
||||
needsTypeBarrier_(typeBarrier),
|
||||
guardHoles_(guardHoles)
|
||||
{
|
||||
|
@ -11852,6 +11854,9 @@ class MSetPropertyCache
|
|||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object), (1, idval), (2, value))
|
||||
|
||||
bool needsPostBarrier() const {
|
||||
return needsPostBarrier_;
|
||||
}
|
||||
bool needsTypeBarrier() const {
|
||||
return needsTypeBarrier_;
|
||||
}
|
||||
|
|
|
@ -613,34 +613,6 @@ ICStubCompiler::PushStubPayload(MacroAssembler& masm, Register scratch)
|
|||
masm.adjustFrame(sizeof(intptr_t));
|
||||
}
|
||||
|
||||
void
|
||||
BaselineEmitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, ValueOperand val,
|
||||
Register scratch, LiveGeneralRegisterSet saveRegs,
|
||||
JSContext* cx)
|
||||
{
|
||||
if (!cx->nursery().exists())
|
||||
return;
|
||||
|
||||
Label skipBarrier;
|
||||
masm.branchPtrInNurseryChunk(Assembler::Equal, obj, scratch, &skipBarrier);
|
||||
masm.branchValueIsNurseryObject(Assembler::NotEqual, val, scratch, &skipBarrier);
|
||||
|
||||
// void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
saveRegs.add(ICTailCallReg);
|
||||
#endif
|
||||
saveRegs.set() = GeneralRegisterSet::Intersect(saveRegs.set(), GeneralRegisterSet::Volatile());
|
||||
masm.PushRegsInMask(saveRegs);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(obj);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
|
||||
masm.PopRegsInMask(saveRegs);
|
||||
|
||||
masm.bind(&skipBarrier);
|
||||
}
|
||||
|
||||
SharedStubInfo::SharedStubInfo(JSContext* cx, void* payload, ICEntry* icEntry)
|
||||
: maybeFrame_(nullptr),
|
||||
outerScript_(cx),
|
||||
|
|
|
@ -1140,10 +1140,6 @@ class ICStubCompiler
|
|||
}
|
||||
};
|
||||
|
||||
void BaselineEmitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, ValueOperand val,
|
||||
Register scratch, LiveGeneralRegisterSet saveRegs,
|
||||
JSContext* cx);
|
||||
|
||||
class SharedStubInfo
|
||||
{
|
||||
BaselineFrame* maybeFrame_;
|
||||
|
|
|
@ -660,32 +660,55 @@ GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
|
|||
void
|
||||
PostWriteBarrier(JSRuntime* rt, JSObject* obj)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(!IsInsideNursery(obj));
|
||||
obj->zone()->group()->storeBuffer().putWholeCell(obj);
|
||||
rt->gc.storeBuffer().putWholeCell(obj);
|
||||
}
|
||||
|
||||
static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
|
||||
|
||||
template <IndexInBounds InBounds>
|
||||
void
|
||||
PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
|
||||
MOZ_ASSERT(!IsInsideNursery(obj));
|
||||
if (obj->is<NativeObject>() &&
|
||||
!obj->as<NativeObject>().isInWholeCellBuffer() &&
|
||||
uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength() &&
|
||||
(obj->as<NativeObject>().getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE
|
||||
|
||||
if (InBounds == IndexInBounds::Yes) {
|
||||
MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength());
|
||||
} else {
|
||||
if (MOZ_UNLIKELY(!obj->is<NativeObject>()) ||
|
||||
uint32_t(index) >= obj->as<NativeObject>().getDenseInitializedLength())
|
||||
{
|
||||
rt->gc.storeBuffer().putWholeCell(obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
if (nobj->isInWholeCellBuffer())
|
||||
return;
|
||||
|
||||
if (nobj->getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE
|
||||
#ifdef JS_GC_ZEAL
|
||||
|| rt->hasZealMode(gc::ZealMode::ElementsBarrier)
|
||||
#endif
|
||||
))
|
||||
)
|
||||
{
|
||||
obj->zone()->group()->storeBuffer().putSlot(&obj->as<NativeObject>(), HeapSlot::Element, index, 1);
|
||||
rt->gc.storeBuffer().putSlot(nobj, HeapSlot::Element, index, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
obj->zone()->group()->storeBuffer().putWholeCell(obj);
|
||||
rt->gc.storeBuffer().putWholeCell(obj);
|
||||
}
|
||||
|
||||
template void
|
||||
PostWriteElementBarrier<IndexInBounds::Yes>(JSRuntime* rt, JSObject* obj, int32_t index);
|
||||
|
||||
template void
|
||||
PostWriteElementBarrier<IndexInBounds::Maybe>(JSRuntime* rt, JSObject* obj, int32_t index);
|
||||
|
||||
void
|
||||
PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj)
|
||||
{
|
||||
|
|
|
@ -674,9 +674,13 @@ CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHa
|
|||
void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
|
||||
|
||||
void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
|
||||
void PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index);
|
||||
void PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj);
|
||||
|
||||
enum class IndexInBounds { Yes, Maybe };
|
||||
|
||||
template <IndexInBounds InBounds>
|
||||
void PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index);
|
||||
|
||||
// If |str| is an index in the range [0, INT32_MAX], return it. If the string
|
||||
// is not an index in this range, return -1.
|
||||
int32_t GetIndexFromString(JSString* str);
|
||||
|
|
|
@ -50,6 +50,9 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
'xul.dll',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'Android':
|
||||
LDFLAGS += ['-pie']
|
||||
|
||||
CFLAGS += CONFIG['TK_CFLAGS']
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
OS_LIBS += CONFIG['TK_LIBS']
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<html class="reftest-wait"><head><title> Bug 489647 - New 1.9.0.9 topcrash [@nsTextFrame::ClearTextRun()]</title></head>
|
||||
<body>
|
||||
<div id="a" style="white-space: pre;">
|
||||
m</div>
|
||||
<script>
|
||||
function doe() {
|
||||
document.getElementById('a').childNodes[0].splitText(1);
|
||||
document.documentElement.className = "";
|
||||
}
|
||||
setTimeout(doe, 100);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<html>
|
||||
<body>
|
||||
<blockquote>
|
||||
<ul style="float: right;-moz-column-count: 7723">
|
||||
<li>
|
||||
<table></table>
|
||||
<button><table></table></button>
|
||||
<form style="float: left">
|
||||
<button>
|
||||
<ol><li></ol>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<div></div>
|
||||
<meter style="float: right;">
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<body>
|
||||
<ul style="width: 600px; -moz-column-count: 13">
|
||||
<li>
|
||||
<table></table>
|
||||
<button></button>
|
||||
<form style="float: left">
|
||||
<button>
|
||||
<ol><li></li></ol>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<div></div>
|
||||
<img style="float: left">
|
|
@ -351,6 +351,7 @@ load 481921.html
|
|||
load 489462-1.html
|
||||
load 489477.html
|
||||
asserts-if(stylo,7) load 489480-1.xhtml # bug 1330260
|
||||
load 489647-1.html
|
||||
load 493111-1.html
|
||||
load 493118-1.html
|
||||
load 493649.html
|
||||
|
@ -546,6 +547,8 @@ load 866547-1.html
|
|||
needs-focus pref(accessibility.browsewithcaret,true) load 868906.html
|
||||
asserts(0-5) load 876074-1.html # bug 876749
|
||||
load 876155.html
|
||||
load 883514-1.html
|
||||
load 883514-2.html
|
||||
load 885009-1.html
|
||||
load 893496-1.html
|
||||
load 893523.html
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>#980223 testcase</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="position:relative;">Test table cell</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
document.body.offsetHeight;
|
||||
document.querySelector('tbody').innerHTML = '';
|
||||
document.body.offsetHeight;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -151,6 +151,7 @@ load 711864-1.html
|
|||
asserts-if(gtkWidget&&browserIsRemote,5) load 759249-1.html # Bug 1195474
|
||||
load 759249-2.html
|
||||
load 814713.html
|
||||
load 980223.html
|
||||
load 1027611-1.html
|
||||
load 1031934.html
|
||||
load 1183896.html
|
||||
|
|
|
@ -103,8 +103,8 @@ class AndroidEmulatorCommands(MachCommandBase):
|
|||
@Command('android-emulator', category='devenv',
|
||||
conditions=[],
|
||||
description='Run the Android emulator with an AVD from test automation.')
|
||||
@CommandArgument('--version', metavar='VERSION', choices=['4.3', '6.0', 'x86'],
|
||||
help='Specify Android version to run in emulator. One of "4.3", "6.0", or "x86".',
|
||||
@CommandArgument('--version', metavar='VERSION', choices=['4.3', '6.0', 'x86', 'x86-6.0'],
|
||||
help='Specify Android version to run in emulator. One of "4.3", "6.0", "x86", or "x86-6.0".',
|
||||
default='4.3')
|
||||
@CommandArgument('--wait', action='store_true',
|
||||
help='Wait for emulator to be closed.')
|
||||
|
|
|
@ -643,9 +643,10 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
|||
mFailedProxyTimeout);
|
||||
|
||||
if (!pref || !strcmp(pref, PROXY_PREF("no_proxies_on"))) {
|
||||
nsCString no_proxies;
|
||||
proxy_GetStringPref(prefBranch, PROXY_PREF("no_proxies_on"), no_proxies);
|
||||
LoadHostFilters(no_proxies.get());
|
||||
rv = prefBranch->GetCharPref(PROXY_PREF("no_proxies_on"),
|
||||
getter_Copies(tempString));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
LoadHostFilters(tempString.get());
|
||||
}
|
||||
|
||||
// We're done if not using something that could give us a PAC URL
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
include protocol PHttpChannel;
|
||||
include protocol PFTPChannel;
|
||||
include protocol PRtspChannel;
|
||||
include protocol PSendStream;
|
||||
include protocol PChildToParentStream;
|
||||
include BlobTypes;
|
||||
include URIParams;
|
||||
include IPCStream;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче