Merge inbound to central, a=merge

MozReview-Commit-ID: KWDF34vWlBx
This commit is contained in:
Wes Kocher 2017-03-14 17:18:59 -07:00
Родитель 6315d21293 f500c10597
Коммит a7c590aa9c
106 изменённых файлов: 2341 добавлений и 1314 удалений

Просмотреть файл

@ -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);
}
}

2
dom/cache/AutoUtils.cpp поставляемый
Просмотреть файл

@ -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

4
dom/cache/CacheOpParent.cpp поставляемый
Просмотреть файл

@ -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());
}

5
dom/cache/CacheStreamControlParent.cpp поставляемый
Просмотреть файл

@ -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));
}

2
dom/cache/CacheTypes.ipdlh поставляемый
Просмотреть файл

@ -4,7 +4,7 @@
include protocol PCache;
include protocol PCacheStreamControl;
include protocol PSendStream;
include protocol PChildToParentStream;
include IPCStream;
include ChannelInfo;
include PBackgroundSharedTypes;

3
dom/cache/PCache.ipdl поставляемый
Просмотреть файл

@ -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;

3
dom/cache/PCacheOp.ipdl поставляемый
Просмотреть файл

@ -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;

3
dom/cache/PCacheStorage.ipdl поставляемый
Просмотреть файл

@ -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;

1
dom/cache/TypeUtils.cpp поставляемый
Просмотреть файл

@ -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"

1
dom/cache/TypeUtils.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

212
ipc/glue/IPCStreamChild.cpp Normal file
Просмотреть файл

@ -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

155
ipc/glue/IPCStreamSource.h Normal file
Просмотреть файл

@ -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;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше