Merge inbound to mozilla-central. a=merge

This commit is contained in:
Csoregi Natalia 2018-04-18 00:52:25 +03:00
commit 12a8bddd95
252 changed files with 3606 additions and 6853 deletions

View File

@ -44,11 +44,10 @@ XULMAP_TYPE(tooltip, XULTooltipAccessible)
XULMAP(
colorpicker,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (aContent->IsElement() &&
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
[](Element* aElement, Accessible* aContext) -> Accessible* {
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::button, eIgnoreCase)) {
return new XULColorPickerAccessible(aContent, aContext->Document());
return new XULColorPickerAccessible(aElement, aContext->Document());
}
return nullptr;
}
@ -56,52 +55,47 @@ XULMAP(
XULMAP(
label,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (aContent->IsElement() &&
aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("text-link"))) {
return new XULLinkAccessible(aContent, aContext->Document());
[](Element* aElement, Accessible* aContext) -> Accessible* {
if (aElement->ClassList()->Contains(NS_LITERAL_STRING("text-link"))) {
return new XULLinkAccessible(aElement, aContext->Document());
}
return new XULLabelAccessible(aContent, aContext->Document());
return new XULLabelAccessible(aElement, aContext->Document());
}
)
XULMAP(
image,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (!aContent->IsElement()) {
return nullptr;
[](Element* aElement, Accessible* aContext) -> Accessible* {
if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) {
return new XULToolbarButtonAccessible(aElement, aContext->Document());
}
if (aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) {
return new XULToolbarButtonAccessible(aContent, aContext->Document());
}
if (aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("colorpickertile"))) {
return new XULColorPickerTileAccessible(aContent, aContext->Document());
if (aElement->ClassList()->Contains(NS_LITERAL_STRING("colorpickertile"))) {
return new XULColorPickerTileAccessible(aElement, aContext->Document());
}
// Don't include nameless images in accessible tree.
if (!aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext)) {
if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext)) {
return nullptr;
}
return new ImageAccessibleWrap(aContent, aContext->Document());
return new ImageAccessibleWrap(aElement, aContext->Document());
}
)
XULMAP(
listcell,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
[](Element* aElement, Accessible* aContext) -> Accessible* {
// Only create cells if there's more than one per row.
nsIContent* listItem = aContent->GetParent();
nsIContent* listItem = aElement->GetParent();
if (!listItem) {
return nullptr;
}
for (nsIContent* child = listItem->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->IsXULElement(nsGkAtoms::listcell) && child != aContent) {
return new XULListCellAccessibleWrap(aContent, aContext->Document());
if (child->IsXULElement(nsGkAtoms::listcell) && child != aElement) {
return new XULListCellAccessibleWrap(aElement, aContext->Document());
}
}
@ -111,59 +105,55 @@ XULMAP(
XULMAP(
menupopup,
[](nsIContent* aContent, Accessible* aContext) {
return CreateMenupopupAccessible(aContent, aContext);
[](Element* aElement, Accessible* aContext) {
return CreateMenupopupAccessible(aElement, aContext);
}
)
XULMAP(
panel,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
[](Element* aElement, Accessible* aContext) -> Accessible* {
static const Element::AttrValuesArray sIgnoreTypeVals[] =
{ &nsGkAtoms::autocomplete_richlistbox, &nsGkAtoms::autocomplete, nullptr };
if (!aContent->IsElement() ||
aContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
if (aElement->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
sIgnoreTypeVals, eIgnoreCase) >= 0) {
return nullptr;
}
if (aContent->AsElement()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::noautofocus,
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus,
nsGkAtoms::_true, eCaseMatters)) {
return new XULAlertAccessible(aContent, aContext->Document());
return new XULAlertAccessible(aElement, aContext->Document());
}
return new EnumRoleAccessible<roles::PANE>(aContent, aContext->Document());
return new EnumRoleAccessible<roles::PANE>(aElement, aContext->Document());
}
)
XULMAP(
popup,
[](nsIContent* aContent, Accessible* aContext) {
return CreateMenupopupAccessible(aContent, aContext);
[](Element* aElement, Accessible* aContext) {
return CreateMenupopupAccessible(aElement, aContext);
}
)
XULMAP(
textbox,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (aContent->IsElement() &&
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
[](Element* aElement, Accessible* aContext) -> Accessible* {
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::autocomplete, eIgnoreCase)) {
return new XULComboboxAccessible(aContent, aContext->Document());
return new XULComboboxAccessible(aElement, aContext->Document());
}
return new EnumRoleAccessible<roles::SECTION>(aContent, aContext->Document());
return new EnumRoleAccessible<roles::SECTION>(aElement, aContext->Document());
}
)
XULMAP(
thumb,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (aContent->IsElement() &&
aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("scale-thumb"))) {
return new XULThumbAccessible(aContent, aContext->Document());
[](Element* aElement, Accessible* aContext) -> Accessible* {
if (aElement->ClassList()->Contains(NS_LITERAL_STRING("scale-thumb"))) {
return new XULThumbAccessible(aElement, aContext->Document());
}
return nullptr;
}
@ -171,8 +161,8 @@ XULMAP(
XULMAP(
tree,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
nsIContent* child = nsTreeUtils::GetDescendantChild(aContent,
[](Element* aElement, Accessible* aContext) -> Accessible* {
nsIContent* child = nsTreeUtils::GetDescendantChild(aElement,
nsGkAtoms::treechildren);
if (!child)
return nullptr;
@ -187,10 +177,10 @@ XULMAP(
// Outline of list accessible.
if (count == 1) {
return new XULTreeAccessible(aContent, aContext->Document(), treeFrame);
return new XULTreeAccessible(aElement, aContext->Document(), treeFrame);
}
// Table or tree table accessible.
return new XULTreeGridAccessibleWrap(aContent, aContext->Document(), treeFrame);
return new XULTreeGridAccessibleWrap(aElement, aContext->Document(), treeFrame);
}
)

View File

@ -149,7 +149,7 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
*/
#ifdef MOZ_XUL
Accessible*
CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
CreateMenupopupAccessible(Element* aElement, Accessible* aContext)
{
#ifdef MOZ_ACCESSIBILITY_ATK
// ATK considers this node to be redundant when within menubars, and it makes menu
@ -157,12 +157,12 @@ CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
// XXX In the future we will should this for consistency across the nsIAccessible
// implementations on each platform for a consistent scripting environment, but
// then strip out redundant accessibles in the AccessibleWrap class for each platform.
nsIContent *parent = aContent->GetParent();
nsIContent *parent = aElement->GetParent();
if (parent && parent->IsXULElement(nsGkAtoms::menu))
return nullptr;
#endif
return new XULMenupopupAccessible(aContent, aContext->Document());
return new XULMenupopupAccessible(aElement, aContext->Document());
}
#endif
@ -170,128 +170,122 @@ CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
// Accessible constructors
static Accessible*
New_HTMLLink(nsIContent* aContent, Accessible* aContext)
New_HTMLLink(Element* aElement, Accessible* aContext)
{
// Only some roles truly enjoy life as HTMLLinkAccessibles, for details
// see closed bug 494807.
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent->AsElement());
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement);
if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
roleMapEntry->role != roles::LINK) {
return new HyperTextAccessibleWrap(aContent, aContext->Document());
return new HyperTextAccessibleWrap(aElement, aContext->Document());
}
return new HTMLLinkAccessible(aContent, aContext->Document());
return new HTMLLinkAccessible(aElement, aContext->Document());
}
static Accessible* New_HyperText(nsIContent* aContent, Accessible* aContext)
{ return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
static Accessible* New_HyperText(Element* aElement, Accessible* aContext)
{ return new HyperTextAccessibleWrap(aElement, aContext->Document()); }
static Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
{ return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLFigcaption(Element* aElement, Accessible* aContext)
{ return new HTMLFigcaptionAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
{ return new HTMLFigureAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLFigure(Element* aElement, Accessible* aContext)
{ return new HTMLFigureAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLHeaderOrFooter(nsIContent* aContent, Accessible* aContext)
{ return new HTMLHeaderOrFooterAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLHeaderOrFooter(Element* aElement, Accessible* aContext)
{ return new HTMLHeaderOrFooterAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
{ return new HTMLLegendAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLLegend(Element* aElement, Accessible* aContext)
{ return new HTMLLegendAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
{ return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLOption(Element* aElement, Accessible* aContext)
{ return new HTMLSelectOptionAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
{ return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLOptgroup(Element* aElement, Accessible* aContext)
{ return new HTMLSelectOptGroupAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLList(nsIContent* aContent, Accessible* aContext)
{ return new HTMLListAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLList(Element* aElement, Accessible* aContext)
{ return new HTMLListAccessible(aElement, aContext->Document()); }
static Accessible*
New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
New_HTMLListitem(Element* aElement, Accessible* aContext)
{
// If list item is a child of accessible list then create an accessible for
// it unconditionally by tag name. nsBlockFrame creates the list item
// accessible for other elements styled as list items.
if (aContext->IsList() && aContext->GetContent() == aContent->GetParent())
return new HTMLLIAccessible(aContent, aContext->Document());
if (aContext->IsList() && aContext->GetContent() == aElement->GetParent())
return new HTMLLIAccessible(aElement, aContext->Document());
return nullptr;
}
static Accessible*
New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
New_HTMLDefinition(Element* aElement, Accessible* aContext)
{
if (aContext->IsList())
return new HyperTextAccessibleWrap(aContent, aContext->Document());
return new HyperTextAccessibleWrap(aElement, aContext->Document());
return nullptr;
}
static Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext)
{ return new HTMLLabelAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLLabel(Element* aElement, Accessible* aContext)
{ return new HTMLLabelAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLInput(nsIContent* aContent, Accessible* aContext)
static Accessible* New_HTMLInput(Element* aElement, Accessible* aContext)
{
if (!aContent->IsElement()) {
return nullptr;
}
Element* element = aContent->AsElement();
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::checkbox, eIgnoreCase)) {
return new HTMLCheckboxAccessible(aContent, aContext->Document());
return new HTMLCheckboxAccessible(aElement, aContext->Document());
}
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::radio, eIgnoreCase)) {
return new HTMLRadioButtonAccessible(aContent, aContext->Document());
return new HTMLRadioButtonAccessible(aElement, aContext->Document());
}
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::time, eIgnoreCase)) {
return new EnumRoleAccessible<roles::GROUPING>(aContent, aContext->Document());
return new EnumRoleAccessible<roles::GROUPING>(aElement, aContext->Document());
}
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::date, eIgnoreCase)) {
return new EnumRoleAccessible<roles::DATE_EDITOR>(aContent, aContext->Document());
return new EnumRoleAccessible<roles::DATE_EDITOR>(aElement, aContext->Document());
}
return nullptr;
}
static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
{ return new HTMLOutputAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLOutput(Element* aElement, Accessible* aContext)
{ return new HTMLOutputAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
{ return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLProgress(Element* aElement, Accessible* aContext)
{ return new HTMLProgressMeterAccessible(aElement, aContext->Document()); }
static Accessible* New_HTMLSummary(nsIContent* aContent, Accessible* aContext)
{ return new HTMLSummaryAccessible(aContent, aContext->Document()); }
static Accessible* New_HTMLSummary(Element* aElement, Accessible* aContext)
{ return new HTMLSummaryAccessible(aElement, aContext->Document()); }
static Accessible*
New_HTMLTableAccessible(nsIContent* aContent, Accessible* aContext)
{ return new HTMLTableAccessible(aContent, aContext->Document()); }
New_HTMLTableAccessible(Element* aElement, Accessible* aContext)
{ return new HTMLTableAccessible(aElement, aContext->Document()); }
static Accessible*
New_HTMLTableRowAccessible(nsIContent* aContent, Accessible* aContext)
{ return new HTMLTableRowAccessible(aContent, aContext->Document()); }
New_HTMLTableRowAccessible(Element* aElement, Accessible* aContext)
{ return new HTMLTableRowAccessible(aElement, aContext->Document()); }
static Accessible*
New_HTMLTableCellAccessible(nsIContent* aContent, Accessible* aContext)
{ return new HTMLTableCellAccessible(aContent, aContext->Document()); }
New_HTMLTableCellAccessible(Element* aElement, Accessible* aContext)
{ return new HTMLTableCellAccessible(aElement, aContext->Document()); }
static Accessible*
New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
New_HTMLTableHeaderCell(Element* aElement, Accessible* aContext)
{
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent())
return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent())
return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
return nullptr;
}
static Accessible*
New_HTMLTableHeaderCellIfScope(nsIContent* aContent, Accessible* aContext)
New_HTMLTableHeaderCellIfScope(Element* aElement, Accessible* aContext)
{
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent() &&
aContent->IsElement() &&
aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent() &&
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
return nullptr;
}
@ -328,8 +322,8 @@ static const HTMLMarkupMapInfo sHTMLMarkupMapList[] = {
#define XULMAP_TYPE(atom, new_type) \
XULMAP( \
atom, \
[](nsIContent* aContent, Accessible* aContext) -> Accessible* { \
return new new_type(aContent, aContext->Document()); \
[](Element* aElement, Accessible* aContext) -> Accessible* { \
return new new_type(aElement, aContext->Document()); \
} \
)
@ -1177,7 +1171,7 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
const HTMLMarkupMapInfo* markupMap =
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
if (markupMap && markupMap->new_func)
newAcc = markupMap->new_func(content, aContext);
newAcc = markupMap->new_func(content->AsElement(), aContext);
if (!newAcc) // try by frame accessible type.
newAcc = CreateAccessibleByFrameType(frame, content, aContext);
@ -1240,7 +1234,7 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
const XULMarkupMapInfo* xulMap =
mXULMarkupMap.Get(content->NodeInfo()->NameAtom());
if (xulMap && xulMap->new_func) {
newAcc = xulMap->new_func(content, aContext);
newAcc = xulMap->new_func(content->AsElement(), aContext);
}
#endif
@ -1272,7 +1266,7 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
const HTMLMarkupMapInfo* markupMap =
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
if (markupMap && markupMap->new_func)
newAcc = markupMap->new_func(content, aContext);
newAcc = markupMap->new_func(content->AsElement(), aContext);
// Fall back to text when encountering Content MathML.
if (!newAcc && !content->IsAnyOfMathMLElements(nsGkAtoms::annotation_,

View File

@ -51,7 +51,7 @@ SelectionManager* SelectionMgr();
ApplicationAccessible* ApplicationAcc();
xpcAccessibleApplication* XPCApplicationAcc();
typedef Accessible* (New_Accessible)(nsIContent* aContent, Accessible* aContext);
typedef Accessible* (New_Accessible)(Element* aElement, Accessible* aContext);
struct MarkupAttrInfo {
nsStaticAtom** name;

View File

@ -339,6 +339,7 @@ add_task(async function checkAllTheCSS() {
iframe.contentWindow.location = testFile;
await iframeLoaded;
let doc = iframe.contentWindow.document;
doc.docShell.cssErrorReportingEnabled = true;
// Parse and remove all manifests from the list.
// NOTE that this must be done before filtering out devtools paths

View File

@ -40,6 +40,7 @@ function AccessibilityPanel(iframeWindow, toolbox) {
this.onAccessibilityInspectorUpdated.bind(this);
this.updateA11YServiceDurationTimer = this.updateA11YServiceDurationTimer.bind(this);
this.updatePickerButton = this.updatePickerButton.bind(this);
this.updateToolboxButtons = this.updateToolboxButtons.bind(this);
EventEmitter.decorate(this);
}
@ -130,11 +131,11 @@ AccessibilityPanel.prototype = {
this.cancelPicker();
if (this.isVisible) {
this._front.on("init", this.updatePickerButton);
this._front.on("shutdown", this.updatePickerButton);
this._front.on("init", this.updateToolboxButtons);
this._front.on("shutdown", this.updateToolboxButtons);
} else {
this._front.off("init", this.updatePickerButton);
this._front.off("shutdown", this.updatePickerButton);
this._front.off("init", this.updateToolboxButtons);
this._front.off("shutdown", this.updateToolboxButtons);
// Do not refresh if the panel isn't visible.
return;
}
@ -183,6 +184,10 @@ AccessibilityPanel.prototype = {
this.panelWin.dispatchEvent(event);
},
updateToolboxButtons() {
this._toolbox.updatePickerButton();
},
updatePickerButton() {
this.picker && this.picker.updateButton();
},

View File

@ -145,6 +145,7 @@ support-files =
[browser_dbg-asm.js]
[browser_dbg-async-stepping.js]
[browser_dbg-babel-breakpoint-console.js]
skip-if = (os == "win" && ccov) # Bug 1453549
[browser_dbg-babel-scopes.js]
skip-if = ccov # Bug 1441545
[browser_dbg-babel-stepping.js]

View File

@ -155,7 +155,7 @@ function Toolbox(target, selectedTool, hostType, contentWindow, frameId) {
this._onPickerStopped = this._onPickerStopped.bind(this);
this._onInspectObject = this._onInspectObject.bind(this);
this._onNewSelectedNodeFront = this._onNewSelectedNodeFront.bind(this);
this._updatePickerButton = this._updatePickerButton.bind(this);
this.updatePickerButton = this.updatePickerButton.bind(this);
this.selectTool = this.selectTool.bind(this);
this.toggleSplitConsole = this.toggleSplitConsole.bind(this);
@ -180,7 +180,7 @@ function Toolbox(target, selectedTool, hostType, contentWindow, frameId) {
this.on("host-changed", this._refreshHostTitle);
this.on("select", this._refreshHostTitle);
this.on("select", this._updatePickerButton);
this.on("select", this.updatePickerButton);
this.on("ready", this._showDevEditionPromo);
@ -1365,7 +1365,7 @@ Toolbox.prototype = {
* update the visual state of the picker button such as disabled state,
* additional CSS classes (className), and tooltip (description).
*/
_updatePickerButton() {
updatePickerButton() {
const button = this.pickerButton;
let currentPanel = this.getCurrentPanel();
@ -2670,7 +2670,7 @@ Toolbox.prototype = {
this._target.off("navigate", this._refreshHostTitle);
this._target.off("frame-update", this._updateFrames);
this.off("select", this._refreshHostTitle);
this.off("select", this._updatePickerButton);
this.off("select", this.updatePickerButton);
this.off("host-changed", this._refreshHostTitle);
this.off("ready", this._showDevEditionPromo);

View File

@ -7,11 +7,6 @@
// Tests that the contextual menu items shown when clicking on linked attributes
// for <script> and <link> tags actually open the right tools.
// The following rejection should not be left uncaught. This test has been
// whitelisted until the issue is fixed.
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
PromiseTestUtils.expectUncaughtRejection(/NS_ERROR_NOT_INITIALIZED/);
const TEST_URL = URL_ROOT + "doc_markup_links.html";
add_task(async function() {

View File

@ -22,6 +22,8 @@ const {
REMOVED_ACTORS_CLEAR,
NETWORK_MESSAGE_UPDATE,
PREFS,
INITIALIZE,
FILTER_TOGGLE,
} = require("devtools/client/webconsole/constants");
const { reducers } = require("./reducers/index");
const {
@ -77,6 +79,7 @@ function configureStore(hud, options = {}) {
enableBatching(),
enableNetProvider(hud),
enableMessagesCacheClearing(hud),
ensureCSSErrorReportingEnabled(hud),
)
);
}
@ -165,6 +168,34 @@ function enableActorReleaser(hud) {
};
}
/**
* This is responsible for ensuring that error reporting is enabled if the CSS
* filter is toggled on.
*/
function ensureCSSErrorReportingEnabled(hud) {
return next => (reducer, initialState, enhancer) => {
function ensureErrorReportingEnhancer(state, action) {
let proxy = hud ? hud.proxy : null;
if (!proxy) {
return reducer(state, action);
}
state = reducer(state, action);
if (!state.filters.css) {
return state;
}
let cssFilterToggled =
action.type == FILTER_TOGGLE && action.filter == "css";
if (cssFilterToggled || action.type == INITIALIZE) {
proxy.target.activeTab.ensureCSSErrorReportingEnabled();
}
return state;
}
return next(ensureErrorReportingEnhancer, initialState, enhancer);
};
}
/**
* This enhancer is responsible for fetching HTTP details data
* collected by the backend. The fetch happens on-demand

View File

@ -370,6 +370,7 @@ async function generateCssMessageStubs() {
gBrowser.selectedBrowser,
[key, code],
function([subKey, subCode]) {
content.document.docShell.cssErrorReportingEnabled = true;
let style = content.document.createElement("style");
// eslint-disable-next-line no-unsanitized/property
style.innerHTML = subCode;

View File

@ -9,19 +9,14 @@
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>hello world" +
"<button onclick='foobar.explode()' " +
"style='test-color: green-please'>click!</button>";
"<button onclick='foobar.explode()'>click!</button>";
add_task(async function() {
await addTab(TEST_URI);
let hud = await HUDService.toggleBrowserConsole();
ok(hud, "browser console opened");
// Enable CSS warnings and errors.
await setFilterState(hud, {
css: true
});
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
@ -36,9 +31,6 @@ add_task(async function() {
await waitForMessageAndViewSource(hud,
"ReferenceError: foobar is not defined");
await waitForMessageAndViewSource(hud,
"Unknown property \u2018test-color\u2019.");
await resetFilters(hud);
});
async function waitForMessageAndViewSource(hud, message) {

View File

@ -25,17 +25,18 @@ add_task(async function() {
info("Open the console");
let hud = await openConsole();
testMessagesVisibility(hud);
await testMessagesVisibility(hud, true);
info("Close the toolbox");
await closeToolbox();
info("Open the console again");
hud = await openConsole();
testMessagesVisibility(hud);
await testMessagesVisibility(hud, false);
});
function testMessagesVisibility(hud) {
async function testMessagesVisibility(hud, waitForCSSMessage) {
let message = findMessage(hud, "log Bazzle", ".message.log");
ok(message, "console.log message is visible");
@ -45,6 +46,11 @@ function testMessagesVisibility(hud) {
message = findMessage(hud, "bazBug611032", ".message.error");
ok(message, "exception message is visible");
// The CSS message arrives lazily, so spin a bit for it unless it should be
// cached.
if (waitForCSSMessage) {
await waitForMessage(hud, "cssColorBug611032");
}
message = findMessage(hud, "cssColorBug611032", ".message.warn.css");
ok(message, "css warning message is visible");
}

View File

@ -125,6 +125,137 @@ var MediaRuleActor = protocol.ActorClassWithSpec(mediaRuleSpec, {
}
});
function getSheetText(sheet, consoleActor) {
let cssText = modifiedStyleSheets.get(sheet);
if (cssText !== undefined) {
return Promise.resolve(cssText);
}
if (!sheet.href) {
// this is an inline <style> sheet
let content = sheet.ownerNode.textContent;
return Promise.resolve(content);
}
return fetchStylesheet(sheet, consoleActor).then(({ content }) => content);
}
exports.getSheetText = getSheetText;
/**
* Try to fetch the stylesheet text from the network monitor. If it was enabled during
* the load, it should have a copy of the text saved.
*
* @param string href
* The URL of the sheet to fetch.
*/
function fetchStylesheetFromNetworkMonitor(href, consoleActor) {
if (!consoleActor) {
return null;
}
let request = consoleActor.getNetworkEventActorForURL(href);
if (!request) {
return null;
}
let content = request._response.content;
if (request._discardResponseBody || request._truncated || !content) {
return null;
}
if (content.text.type != "longString") {
// For short strings, the text is available directly.
return {
content: content.text,
contentType: content.mimeType,
};
}
// For long strings, look up the actor that holds the full text.
let longStringActor = consoleActor.conn._getOrCreateActor(content.text.actor);
if (!longStringActor) {
return null;
}
return {
content: longStringActor.rawValue(),
contentType: content.mimeType,
};
}
/**
* Get the charset of the stylesheet.
*/
function getCSSCharset(sheet) {
if (sheet) {
// charset attribute of <link> or <style> element, if it exists
if (sheet.ownerNode && sheet.ownerNode.getAttribute) {
let linkCharset = sheet.ownerNode.getAttribute("charset");
if (linkCharset != null) {
return linkCharset;
}
}
// charset of referring document.
if (sheet.ownerNode && sheet.ownerNode.ownerDocument.characterSet) {
return sheet.ownerNode.ownerDocument.characterSet;
}
}
return "UTF-8";
}
/**
* Fetch a stylesheet at the provided URL. Returns a promise that will resolve the
* result of the fetch command.
*
* @return {Promise} a promise that resolves with an object with the following members
* on success:
* - content: the document at that URL, as a string,
* - contentType: the content type of the document
* If an error occurs, the promise is rejected with that error.
*/
async function fetchStylesheet(sheet, consoleActor) {
let href = sheet.href;
let result = fetchStylesheetFromNetworkMonitor(href, consoleActor);
if (result) {
return result;
}
let options = {
loadFromCache: true,
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
charset: getCSSCharset(sheet)
};
// Bug 1282660 - We use the system principal to load the default internal
// stylesheets instead of the content principal since such stylesheets
// require system principal to load. At meanwhile, we strip the loadGroup
// for preventing the assertion of the userContextId mismatching.
// chrome|file|resource|moz-extension protocols rely on the system principal.
let excludedProtocolsRe = /^(chrome|file|resource|moz-extension):\/\//;
if (!excludedProtocolsRe.test(href)) {
// Stylesheets using other protocols should use the content principal.
if (sheet.ownerNode) {
// eslint-disable-next-line mozilla/use-ownerGlobal
options.window = sheet.ownerNode.ownerDocument.defaultView;
options.principal = sheet.ownerNode.ownerDocument.nodePrincipal;
}
}
try {
result = await fetch(href, options);
} catch (e) {
// The list of excluded protocols can be missing some protocols, try to use the
// system principal if the first fetch failed.
console.error(`stylesheets actor: fetch failed for ${href},` +
` using system principal instead.`);
options.window = undefined;
options.principal = undefined;
result = await fetch(href, options);
}
return result;
}
/**
* A StyleSheetActor represents a stylesheet on the server.
*/
@ -372,80 +503,16 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
return Promise.resolve(this.text);
}
let cssText = modifiedStyleSheets.get(this.rawSheet);
if (cssText !== undefined) {
this.text = cssText;
return Promise.resolve(cssText);
}
if (!this.href) {
// this is an inline <style> sheet
let content = this.ownerNode.textContent;
this.text = content;
return Promise.resolve(content);
}
return this.fetchStylesheet(this.href).then(({ content }) => {
this.text = content;
return content;
return getSheetText(this.rawSheet, this._consoleActor).then(text => {
this.text = text;
return text;
});
},
/**
* Fetch a stylesheet at the provided URL. Returns a promise that will resolve the
* result of the fetch command.
*
* @param {String} href
* The href of the stylesheet to retrieve.
* @return {Promise} a promise that resolves with an object with the following members
* on success:
* - content: the document at that URL, as a string,
* - contentType: the content type of the document
* If an error occurs, the promise is rejected with that error.
*/
async fetchStylesheet(href) {
// Check if network monitor observed this load, and if so, use that.
let result = this.fetchStylesheetFromNetworkMonitor(href);
if (result) {
return result;
}
let options = {
loadFromCache: true,
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
charset: this._getCSSCharset()
};
// Bug 1282660 - We use the system principal to load the default internal
// stylesheets instead of the content principal since such stylesheets
// require system principal to load. At meanwhile, we strip the loadGroup
// for preventing the assertion of the userContextId mismatching.
// chrome|file|resource|moz-extension protocols rely on the system principal.
let excludedProtocolsRe = /^(chrome|file|resource|moz-extension):\/\//;
if (!excludedProtocolsRe.test(this.href)) {
// Stylesheets using other protocols should use the content principal.
options.window = this.ownerWindow;
options.principal = this.ownerDocument.nodePrincipal;
}
try {
result = await fetch(this.href, options);
} catch (e) {
// The list of excluded protocols can be missing some protocols, try to use the
// system principal if the first fetch failed.
console.error(`stylesheets actor: fetch failed for ${this.href},` +
` using system principal instead.`);
options.window = undefined;
options.principal = undefined;
result = await fetch(this.href, options);
}
return result;
},
/**
* Try to locate the console actor if it exists via our parent actor (the tab).
*
* Keep this in sync with the TabActor version.
*/
get _consoleActor() {
if (this.parentActor.exited) {
@ -455,44 +522,6 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
return this.conn._getOrCreateActor(form.consoleActor);
},
/**
* Try to fetch the stylesheet text from the network monitor. If it was enabled during
* the load, it should have a copy of the text saved.
*
* @param string href
* The URL of the sheet to fetch.
*/
fetchStylesheetFromNetworkMonitor(href) {
let consoleActor = this._consoleActor;
if (!consoleActor) {
return null;
}
let request = consoleActor.getNetworkEventActorForURL(href);
if (!request) {
return null;
}
let content = request._response.content;
if (request._discardResponseBody || request._truncated || !content) {
return null;
}
if (content.text.type != "longString") {
// For short strings, the text is available directly.
return {
content: content.text,
contentType: content.mimeType,
};
}
// For long strings, look up the actor that holds the full text.
let longStringActor = this.conn._getOrCreateActor(content.text.actor);
if (!longStringActor) {
return null;
}
return {
content: longStringActor.rawValue(),
contentType: content.mimeType,
};
},
/**
* Protocol method to get the media rules for the stylesheet.
*/
@ -523,49 +552,6 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
});
},
/**
* Get the charset of the stylesheet according to the character set rules
* defined in <http://www.w3.org/TR/CSS2/syndata.html#charset>.
* Note that some of the algorithm is implemented in DevToolsUtils.fetch.
*/
_getCSSCharset: function() {
let sheet = this.rawSheet;
if (sheet) {
// Do we have a @charset rule in the stylesheet?
// step 2 of syndata.html (without the BOM check).
if (sheet.cssRules) {
let rules = sheet.cssRules;
if (rules.length
&& rules.item(0).type == CSSRule.CHARSET_RULE) {
return rules.item(0).encoding;
}
}
// step 3: charset attribute of <link> or <style> element, if it exists
if (sheet.ownerNode && sheet.ownerNode.getAttribute) {
let linkCharset = sheet.ownerNode.getAttribute("charset");
if (linkCharset != null) {
return linkCharset;
}
}
// step 4 (1 of 2): charset of referring stylesheet.
let parentSheet = sheet.parentStyleSheet;
if (parentSheet && parentSheet.cssRules &&
parentSheet.cssRules[0].type == CSSRule.CHARSET_RULE) {
return parentSheet.cssRules[0].encoding;
}
// step 4 (2 of 2): charset of referring document.
if (sheet.ownerNode && sheet.ownerNode.ownerDocument.characterSet) {
return sheet.ownerNode.ownerDocument.characterSet;
}
}
// step 5: default to utf-8.
return "UTF-8";
},
/**
* Update the style sheet in place with new text.
*

View File

@ -24,6 +24,7 @@ var { assert } = DevToolsUtils;
var { TabSources } = require("./utils/TabSources");
var makeDebugger = require("./utils/make-debugger");
const EventEmitter = require("devtools/shared/event-emitter");
const InspectorUtils = require("InspectorUtils");
const EXTENSION_CONTENT_JSM = "resource://gre/modules/ExtensionContent.jsm";
@ -33,6 +34,7 @@ loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker
loader.lazyImporter(this, "ExtensionContent", EXTENSION_CONTENT_JSM);
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
loader.lazyRequireGetter(this, "getSheetText", "devtools/server/actors/stylesheets", true);
function getWindowID(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
@ -258,6 +260,17 @@ TabActor.prototype = {
return !!this._attached;
},
/**
* Try to locate the console actor if it exists.
*/
get _consoleActor() {
if (this.exited) {
return null;
}
let form = this.form();
return this.conn._getOrCreateActor(form.consoleActor);
},
_tabPool: null,
get tabActorPool() {
return this._tabPool;
@ -1007,6 +1020,33 @@ TabActor.prototype = {
return {};
},
/**
* Ensure that CSS error reporting is enabled.
*/
ensureCSSErrorReportingEnabled(request) {
for (let docShell of this.docShells) {
if (docShell.cssErrorReportingEnabled) {
continue;
}
try {
docShell.cssErrorReportingEnabled = true;
} catch (e) {
continue;
}
// We don't really want to reparse UA sheets and such, but want to do
// Shadow DOM / XBL.
let sheets =
InspectorUtils.getAllStyleSheets(docShell.document, /* documentOnly = */ true);
for (let sheet of sheets) {
getSheetText(sheet, this._consoleActor).then(text => {
InspectorUtils.parseStyleSheet(sheet, text, /* aUpdate = */ false);
});
}
}
return {};
},
/**
* Handle logic to enable/disable JS/cache/Service Worker testing.
*/
@ -1430,6 +1470,7 @@ TabActor.prototype.requestTypes = {
"reload": TabActor.prototype.onReload,
"navigateTo": TabActor.prototype.onNavigateTo,
"reconfigure": TabActor.prototype.onReconfigure,
"ensureCSSErrorReportingEnabled": TabActor.prototype.ensureCSSErrorReportingEnabled,
"switchToFrame": TabActor.prototype.onSwitchToFrame,
"listFrames": TabActor.prototype.onListFrames,
"listWorkers": TabActor.prototype.onListWorkers,

View File

@ -102,6 +102,13 @@ TabClient.prototype = {
type: "focus"
}, {}),
/**
* Ensure relevant pages have error reporting enabled.
*/
ensureCSSErrorReportingEnabled: DebuggerClient.requester({
type: "ensureCSSErrorReportingEnabled",
}, {}),
/**
* Reload the page in this tab.
*

View File

@ -12,6 +12,7 @@
<p>Test for cached messages</p>
<script class="testbody" type="application/javascript">
document.docShell.cssErrorReportingEnabled = true;
var ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"]
.getService(Ci.nsIConsoleAPIStorage);
let expectedConsoleCalls = [];

View File

@ -362,6 +362,7 @@ nsDocShell::nsDocShell()
, mAllowContentRetargetingOnChildren(true)
, mUseErrorPages(false)
, mObserveErrorPages(true)
, mCSSErrorReportingEnabled(false)
, mAllowAuth(true)
, mAllowKeywordFixup(false)
, mIsOffScreenBrowser(false)
@ -1686,6 +1687,21 @@ nsDocShell::GetAllowJavascript(bool* aAllowJavascript)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled)
{
MOZ_ASSERT(aEnabled);
*aEnabled = mCSSErrorReportingEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetCssErrorReportingEnabled(bool aEnabled)
{
mCSSErrorReportingEnabled = aEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetAllowJavascript(bool aAllowJavascript)
{

View File

@ -890,6 +890,11 @@ private: // member functions
return (mObserveErrorPages ? sUseErrorPages : mUseErrorPages);
}
bool CSSErrorReportingEnabled() const
{
return mCSSErrorReportingEnabled;
}
private: // data members
static nsIURIFixup* sURIFixup;
@ -1108,6 +1113,7 @@ private: // data members
bool mAllowContentRetargetingOnChildren : 1;
bool mUseErrorPages : 1;
bool mObserveErrorPages : 1;
bool mCSSErrorReportingEnabled : 1;
bool mAllowAuth : 1;
bool mAllowKeywordFixup : 1;
bool mIsOffScreenBrowser : 1;

View File

@ -293,6 +293,11 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
attribute DOMString customUserAgent;
/**
* Whether CSS error reporting is enabled.
*/
attribute boolean cssErrorReportingEnabled;
/**
* Whether to allow plugin execution
*/

View File

@ -7,6 +7,7 @@
#include "TimelineConsumers.h"
#include "mozilla/ClearOnShutdown.h"
#include "jsapi.h"
#include "nsAppRunner.h" // for XRE_IsContentProcess, XRE_IsParentProcess
#include "nsDocShell.h"
@ -126,6 +127,9 @@ TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
MOZ_ASSERT(!observed);
if (mActiveConsumers == 0) {
JS::SetProfileTimelineRecordingEnabled(true);
}
mActiveConsumers++;
ObservedDocShell* obsDocShell = new ObservedDocShell(aDocShell);
@ -145,6 +149,9 @@ TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
MOZ_ASSERT(observed);
mActiveConsumers--;
if (mActiveConsumers == 0) {
JS::SetProfileTimelineRecordingEnabled(false);
}
// Clear all markers from the `mTimelineMarkers` store.
observed.get()->ClearMarkers();

View File

@ -17,7 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=513194
// The use of document.write is deliberate. We are testing for the
// HTML parser to call the CSS parser once and only once when it
// encounters a new <style> element.
SpecialPowers.wrap(document).docShell.cssErrorReportingEnabled = true;
SimpleTest.runTestExpectingConsoleMessages(
function () { document.write("<style>qux { foo : bar; }<\/style>") },
[{ errorMessage: /Unknown property/ }]

View File

@ -125,48 +125,6 @@ private:
ErrorResult& mRv;
};
class BCPostMessageRunnable final : public nsIRunnable,
public nsICancelableRunnable
{
public:
NS_DECL_ISUPPORTS
BCPostMessageRunnable(BroadcastChannelChild* aActor,
BroadcastChannelMessage* aData)
: mActor(aActor)
, mData(aData)
{
MOZ_ASSERT(mActor);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(mActor);
if (mActor->IsActorDestroyed()) {
return NS_OK;
}
ClonedMessageData message;
mData->BuildClonedMessageDataForBackgroundChild(mActor->Manager(), message);
mActor->SendPostMessage(message);
return NS_OK;
}
nsresult Cancel() override
{
mActor = nullptr;
return NS_OK;
}
private:
~BCPostMessageRunnable() {}
RefPtr<BroadcastChannelChild> mActor;
RefPtr<BroadcastChannelMessage> mData;
};
NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable)
class CloseRunnable final : public nsIRunnable,
public nsICancelableRunnable
{
@ -398,14 +356,6 @@ BroadcastChannel::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
return;
}
PostMessageInternal(aCx, aMessage, aRv);
}
void
BroadcastChannel::PostMessageInternal(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
ErrorResult& aRv)
{
RefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
data->Write(aCx, aMessage, aRv);
@ -413,20 +363,11 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx,
return;
}
PostMessageData(data);
}
void
BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData)
{
RemoveDocFromBFCache();
RefPtr<BCPostMessageRunnable> runnable =
new BCPostMessageRunnable(mActor, aData);
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch to the current thread!");
}
ClonedMessageData message;
data->BuildClonedMessageDataForBackgroundChild(mActor->Manager(), message);
mActor->SendPostMessage(message);
}
void

View File

@ -1,8 +1,7 @@
(new BroadcastChannel('foobar')).postMessage('READY');
(new BroadcastChannel('foobar')).addEventListener('message', function(event) {
if (event.data != 'READY') {
event.target.postMessage(event.data);
}
});
(new BroadcastChannel('foobar')).postMessage('READY');

View File

@ -23,10 +23,10 @@ async function useBroadcastChannel(contentWindow) {
count += 1;
const name = `test_event_listener_leaks-${count}`;
let bc = new contentWindow.BroadcastChannel(name);
let outer = new BroadcastChannel(name);
outer.postMessage('foo');
let bc = new contentWindow.BroadcastChannel(name);
await new Promise(resolve => {
bc.onmessage = e => {
contentWindow.messageCount += 1;

View File

@ -11,7 +11,8 @@
*/
[ChromeOnly]
namespace InspectorUtils {
sequence<StyleSheet> getAllStyleSheets(Document document);
// documentOnly tells whether user and UA sheets should get included.
sequence<StyleSheet> getAllStyleSheets(Document document, optional boolean documentOnly = false);
sequence<CSSRule> getCSSStyleRules(
Element element,
[TreatNullAs=EmptyString] optional DOMString pseudo = "");

View File

@ -289,7 +289,7 @@ GMPChild::RecvPreloadLibs(const nsCString& aLibs)
u"msmpeg2vdec.dll", // H.264 decoder
u"psapi.dll", // For GetMappedFileNameW, see bug 1383611
};
constexpr static bool (*IsASCII)(const char16_t*) = NS_ConstExprIsAscii;
constexpr static bool (*IsASCII)(const char16_t*) = NS_IsAscii;
static_assert(AllOf(std::begin(whitelist), std::end(whitelist), IsASCII),
"Items in the whitelist must not contain non-ASCII "
"characters!");

View File

@ -33,7 +33,8 @@ struct ScrollbarData {
CSSCoord aThumbLength,
bool aThumbIsAsyncDraggable,
CSSCoord aScrollTrackStart,
CSSCoord aScrollTrackLength)
CSSCoord aScrollTrackLength,
uint64_t aTargetViewId)
: mDirection(Some(aDirection))
, mScrollbarLayerType(aScrollbarLayerType)
, mThumbRatio(aThumbRatio)
@ -42,6 +43,7 @@ struct ScrollbarData {
, mThumbIsAsyncDraggable(aThumbIsAsyncDraggable)
, mScrollTrackStart(aScrollTrackStart)
, mScrollTrackLength(aScrollTrackLength)
, mTargetViewId(aTargetViewId)
{}
/**
@ -158,20 +160,6 @@ public:
return true;
}
bool SetScrollbarContainer(FrameMetrics::ViewID aTargetViewId,
ScrollDirection aDirection) {
if (mScrollbarData.mScrollbarLayerType == ScrollbarLayerType::Container &&
mScrollbarData.mDirection &&
*mScrollbarData.mDirection == aDirection &&
mScrollbarData.mTargetViewId == aTargetViewId) {
return false;
}
mScrollbarData.mDirection = Some(aDirection);
mScrollbarData.mTargetViewId = aTargetViewId;
mScrollbarData.mScrollbarLayerType = ScrollbarLayerType::Container;
return true;
}
bool SetMixBlendMode(gfx::CompositionOp aMixBlendMode) {
if (mMixBlendMode == aMixBlendMode) {
return false;

View File

@ -1259,9 +1259,9 @@ public:
/**
* CONSTRUCTION PHASE ONLY
* If a layer is a scroll thumb container layer, set the scroll identifier
* of the scroll frame scrolled by the thumb, and other data related to the
* thumb.
* If a layer is a scroll thumb container layer or a scrollbar container
* layer, set the scroll identifier of the scroll frame scrolled by
* the scrollbar, and other data related to the scrollbar.
*/
void SetScrollbarData(const ScrollbarData& aThumbData)
{
@ -1271,17 +1271,6 @@ public:
}
}
// Set during construction for the container layer of scrollbar components.
// |aScrollId| holds the scroll identifier of the scrollable content that
// the scrollbar is for.
void SetScrollbarContainer(FrameMetrics::ViewID aScrollId,
ScrollDirection aDirection)
{
if (mSimpleAttrs.SetScrollbarContainer(aScrollId, aDirection)) {
MutatedSimple();
}
}
// Used when forwarding transactions. Do not use at any other time.
void SetSimpleAttributes(const SimpleLayerAttributes& aAttrs) {
mSimpleAttrs = aAttrs;

View File

@ -485,7 +485,7 @@ IProtocol::AllocShmem(size_t aSize,
return false;
}
*aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
*aOutMem = Shmem(Shmem::PrivateIPDLCaller(), rawmem, id);
return true;
}
@ -500,7 +500,7 @@ IProtocol::AllocUnsafeShmem(size_t aSize,
return false;
}
*aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
*aOutMem = Shmem(Shmem::PrivateIPDLCaller(), rawmem, id);
return true;
}
@ -518,7 +518,7 @@ IProtocol::DeallocShmem(Shmem& aMem)
return false;
}
#endif // DEBUG
aMem.forget(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
aMem.forget(Shmem::PrivateIPDLCaller());
return ok;
}
@ -747,13 +747,13 @@ IToplevelProtocol::CreateSharedMemory(size_t aSize,
Shmem::id_t* aId)
{
RefPtr<Shmem::SharedMemory> segment(
Shmem::Alloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aSize, aType, aUnsafe));
Shmem::Alloc(Shmem::PrivateIPDLCaller(), aSize, aType, aUnsafe));
if (!segment) {
return nullptr;
}
int32_t id = GetSide() == ParentSide ? ++mLastShmemId : --mLastShmemId;
Shmem shmem(
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(),
Shmem::PrivateIPDLCaller(),
segment.get(),
id);
@ -768,13 +768,13 @@ IToplevelProtocol::CreateSharedMemory(size_t aSize,
#endif
Message* descriptor = shmem.ShareTo(
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), pid, MSG_ROUTING_CONTROL);
Shmem::PrivateIPDLCaller(), pid, MSG_ROUTING_CONTROL);
if (!descriptor) {
return nullptr;
}
Unused << GetIPCChannel()->Send(descriptor);
*aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
*aId = shmem.Id(Shmem::PrivateIPDLCaller());
Shmem::SharedMemory* rawSegment = segment.get();
mShmemMap.AddWithID(segment.forget().take(), *aId);
return rawSegment;
@ -795,17 +795,17 @@ IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* segment)
bool
IToplevelProtocol::DestroySharedMemory(Shmem& shmem)
{
Shmem::id_t aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
Shmem::id_t aId = shmem.Id(Shmem::PrivateIPDLCaller());
Shmem::SharedMemory* segment = LookupSharedMemory(aId);
if (!segment) {
return false;
}
Message* descriptor = shmem.UnshareFrom(
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), MSG_ROUTING_CONTROL);
Shmem::PrivateIPDLCaller(), MSG_ROUTING_CONTROL);
mShmemMap.Remove(aId);
Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), segment);
Shmem::Dealloc(Shmem::PrivateIPDLCaller(), segment);
if (!GetIPCChannel()->CanSend()) {
delete descriptor;
@ -819,7 +819,7 @@ void
IToplevelProtocol::DeallocShmems()
{
for (IDMap<SharedMemory*>::const_iterator cit = mShmemMap.begin(); cit != mShmemMap.end(); ++cit) {
Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), cit->second);
Shmem::Dealloc(Shmem::PrivateIPDLCaller(), cit->second);
}
mShmemMap.Clear();
}
@ -828,7 +828,7 @@ bool
IToplevelProtocol::ShmemCreated(const Message& aMsg)
{
Shmem::id_t id;
RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aMsg, &id, true));
RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::PrivateIPDLCaller(), aMsg, &id, true));
if (!rawmem) {
return false;
}
@ -849,7 +849,7 @@ IToplevelProtocol::ShmemDestroyed(const Message& aMsg)
Shmem::SharedMemory* rawmem = LookupSharedMemory(id);
if (rawmem) {
mShmemMap.Remove(id);
Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem);
Shmem::Dealloc(Shmem::PrivateIPDLCaller(), rawmem);
}
return true;
}

View File

@ -247,7 +247,7 @@ Unprotect(SharedMemory* aSegment)
// to touch the segment, it dies with SIGSEGV.
//
Shmem::Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::Shmem(PrivateIPDLCaller,
SharedMemory* aSegment, id_t aId) :
mSegment(aSegment),
mData(nullptr),
@ -300,7 +300,7 @@ Shmem::AssertInvariants() const
}
void
Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
Shmem::RevokeRights(PrivateIPDLCaller)
{
AssertInvariants();
@ -319,7 +319,7 @@ Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
// static
already_AddRefed<Shmem::SharedMemory>
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::Alloc(PrivateIPDLCaller,
size_t aNBytes,
SharedMemoryType aType,
bool aUnsafe,
@ -360,7 +360,7 @@ Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
// static
already_AddRefed<Shmem::SharedMemory>
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::OpenExisting(PrivateIPDLCaller,
const IPC::Message& aDescriptor,
id_t* aId,
bool aProtect)
@ -396,7 +396,7 @@ Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
// static
void
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::Dealloc(PrivateIPDLCaller,
SharedMemory* aSegment)
{
if (!aSegment)
@ -422,7 +422,7 @@ Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
// static
already_AddRefed<Shmem::SharedMemory>
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::Alloc(PrivateIPDLCaller,
size_t aNBytes,
SharedMemoryType aType,
bool /*unused*/,
@ -440,7 +440,7 @@ Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
// static
already_AddRefed<Shmem::SharedMemory>
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::OpenExisting(PrivateIPDLCaller,
const IPC::Message& aDescriptor,
id_t* aId,
bool /*unused*/)
@ -461,7 +461,7 @@ Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
// static
void
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::Dealloc(PrivateIPDLCaller,
SharedMemory* aSegment)
{
DestroySegment(aSegment);
@ -470,7 +470,7 @@ Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
#endif // if defined(DEBUG)
IPC::Message*
Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::ShareTo(PrivateIPDLCaller,
base::ProcessId aTargetPid,
int32_t routingId)
{
@ -486,7 +486,7 @@ Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
}
IPC::Message*
Shmem::UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem::UnshareFrom(PrivateIPDLCaller,
int32_t routingId)
{
AssertInvariants();
@ -500,9 +500,9 @@ IPDLParamTraits<Shmem>::Write(IPC::Message* aMsg, IProtocol* aActor,
WriteIPDLParam(aMsg, aActor, aParam.mId);
aParam.RevokeRights(
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
Shmem::PrivateIPDLCaller());
aParam.forget(
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
Shmem::PrivateIPDLCaller());
}
bool
@ -517,7 +517,7 @@ IPDLParamTraits<Shmem>::Read(const IPC::Message* aMsg, PickleIterator* aIter,
Shmem::SharedMemory* rawmem = aActor->LookupSharedMemory(id);
if (rawmem) {
*aResult = Shmem(
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(),
Shmem::PrivateIPDLCaller(),
rawmem, id);
return true;
}

View File

@ -73,7 +73,11 @@ public:
// Low-level wrapper around platform shmem primitives.
typedef mozilla::ipc::SharedMemory SharedMemory;
typedef SharedMemory::SharedMemoryType SharedMemoryType;
struct IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead {};
// Shmem objects should only be constructed directly from SharedMemory
// objects by the Shmem implementation itself, or by a select few functions
// in ProtocolUtils.{h,cpp}. You should not need to add new instances of
// this token.
struct PrivateIPDLCaller {};
Shmem() :
mSegment(nullptr),
@ -92,7 +96,7 @@ public:
}
#if !defined(DEBUG)
Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem(PrivateIPDLCaller,
SharedMemory* aSegment, id_t aId) :
mSegment(aSegment),
mData(aSegment->memory()),
@ -102,7 +106,7 @@ public:
mSize = static_cast<size_t>(*PtrToSize(mSegment));
}
#else
Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Shmem(PrivateIPDLCaller,
SharedMemory* aSegment, id_t aId);
#endif
@ -110,7 +114,7 @@ public:
{
// Shmem only holds a "weak ref" to the actual segment, which is
// owned by IPDL. So there's nothing interesting to be done here
forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
forget(PrivateIPDLCaller());
}
Shmem& operator=(const Shmem& aRhs)
@ -169,23 +173,23 @@ public:
}
// These shouldn't be used directly, use the IPDL interface instead.
id_t Id(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const {
id_t Id(PrivateIPDLCaller) const {
return mId;
}
SharedMemory* Segment(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const {
SharedMemory* Segment(PrivateIPDLCaller) const {
return mSegment;
}
#ifndef DEBUG
void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
void RevokeRights(PrivateIPDLCaller)
{
}
#else
void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead);
void RevokeRights(PrivateIPDLCaller);
#endif
void forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
void forget(PrivateIPDLCaller)
{
mSegment = nullptr;
mData = nullptr;
@ -194,7 +198,7 @@ public:
}
static already_AddRefed<Shmem::SharedMemory>
Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Alloc(PrivateIPDLCaller,
size_t aNBytes,
SharedMemoryType aType,
bool aUnsafe,
@ -205,7 +209,7 @@ public:
// this segment in OpenExisting() below. Return a new message if
// successful (owned by the caller), nullptr if not.
IPC::Message*
ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
ShareTo(PrivateIPDLCaller,
base::ProcessId aTargetPid,
int32_t routingId);
@ -214,7 +218,7 @@ public:
// segment. Return a new message if successful (owned by the
// caller), nullptr if not.
IPC::Message*
UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
UnshareFrom(PrivateIPDLCaller,
int32_t routingId);
// Return a SharedMemory instance in this process using the
@ -222,13 +226,13 @@ public:
// underlying OS shmem resource. The contents of the descriptor
// depend on the type of SharedMemory that was passed to us.
static already_AddRefed<SharedMemory>
OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
OpenExisting(PrivateIPDLCaller,
const IPC::Message& aDescriptor,
id_t* aId,
bool aProtect=false);
static void
Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
Dealloc(PrivateIPDLCaller,
SharedMemory* aSegment);
private:

View File

@ -189,7 +189,7 @@ impl Runtime {
});
if use_internal_job_queue {
assert!(js::UseInternalJobQueues(js_context, false));
assert!(js::UseInternalJobQueues(js_context));
}
JS::InitSelfHostedCode(js_context);

View File

@ -139,7 +139,7 @@ public:
static mozilla::Atomic<js::Mutex*> lock_;
// A flag that controls whether waiting is allowed.
ThreadLocalData<bool> canWait_;
ThreadData<bool> canWait_;
};
JSObject*

View File

@ -2344,8 +2344,8 @@ js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value)
/**
* ES2016, 25.4.4.4, Promise.reject.
*/
bool
js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
static bool
Promise_reject(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue thisVal(cx, args.thisv());
@ -2373,8 +2373,8 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
/**
* ES2016, 25.4.4.5, Promise.resolve.
*/
bool
js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
static bool
Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue thisVal(cx, args.thisv());
@ -2461,7 +2461,7 @@ IsPromiseSpecies(JSContext* cx, JSFunction* species)
MOZ_MUST_USE bool
js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
HandleValue onFulfilled, HandleValue onRejected,
MutableHandleObject dependent, bool createDependent)
MutableHandleObject dependent, CreateDependentPromise createDependent)
{
RootedObject promiseObj(cx, promise);
if (promise->compartment() != cx->compartment()) {
@ -2473,16 +2473,20 @@ js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
RootedObject resolve(cx);
RootedObject reject(cx);
if (createDependent) {
if (createDependent != CreateDependentPromise::Never) {
// Step 3.
RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
if (!C)
return false;
if (createDependent == CreateDependentPromise::Always ||
!IsNativeFunction(C, PromiseConstructor))
{
// Step 4.
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
return false;
}
}
// Step 5.
if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, resolve, reject))
@ -3024,18 +3028,79 @@ js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
return true;
}
// ES2016, 25.4.5.3.
bool
js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
static bool Promise_then(JSContext* cx, unsigned argc, Value* vp);
static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
HandleValue onRejected, MutableHandleValue rval, bool rvalUsed);
static bool
Promise_catch_impl(JSContext* cx, unsigned argc, Value* vp, bool rvalUsed)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedValue promiseVal(cx, args.thisv());
RootedValue thenVal(cx);
if (!GetProperty(cx, args.thisv(), cx->names().then, &thenVal))
return false;
RootedValue onFulfilled(cx, args.get(0));
RootedValue onRejected(cx, args.get(1));
if (IsNativeFunction(thenVal, &Promise_then)) {
return Promise_then_impl(cx, args.thisv(), UndefinedHandleValue, args.get(0),
args.rval(), rvalUsed);
}
FixedInvokeArgs<2> iargs(cx);
iargs[0].setUndefined();
iargs[1].set(args.get(0));
return Call(cx, thenVal, args.thisv(), iargs, args.rval());
}
static MOZ_ALWAYS_INLINE bool
IsPromiseThenOrCatchRetValImplicitlyUsed(JSContext* cx)
{
// The returned promise of Promise#then and Promise#catch contains
// stack info if async stack is enabled. Even if their return value is not
// used explicitly in the script, the stack info is observable in devtools
// and profilers. We shouldn't apply the optimization not to allocate the
// returned Promise object if the it's implicitly used by them.
//
// FIXME: Once bug 1280819 gets fixed, we can use ShouldCaptureDebugInfo.
if (!cx->options().asyncStack())
return false;
// If devtools is opened, the current compartment will become debuggee.
if (cx->compartment()->isDebuggee())
return true;
// There are 2 profilers, and they can be independently enabled.
if (cx->runtime()->geckoProfiler().enabled())
return true;
if (JS::IsProfileTimelineRecordingEnabled())
return true;
// The stack is also observable from Error#stack, but we don't care since
// it's nonstandard feature.
return false;
}
// ES2016, 25.4.5.3.
static bool
Promise_catch_noRetVal(JSContext* cx, unsigned argc, Value* vp)
{
return Promise_catch_impl(cx, argc, vp, IsPromiseThenOrCatchRetValImplicitlyUsed(cx));
}
// ES2016, 25.4.5.3.
static bool
Promise_catch(JSContext* cx, unsigned argc, Value* vp)
{
return Promise_catch_impl(cx, argc, vp, true);
}
static bool
Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
HandleValue onRejected, MutableHandleValue rval, bool rvalUsed)
{
// Step 1 (implicit).
// Step 2.
if (!promiseVal.isObject()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
@ -3063,14 +3128,40 @@ js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
}
// Steps 3-5.
CreateDependentPromise createDependent = rvalUsed
? CreateDependentPromise::Always
: CreateDependentPromise::SkipIfCtorUnobservable;
RootedObject resultPromise(cx);
if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, &resultPromise, true))
if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, &resultPromise,
createDependent))
{
return false;
}
args.rval().setObject(*resultPromise);
if (rvalUsed)
rval.setObject(*resultPromise);
else
rval.setUndefined();
return true;
}
// ES2016, 25.4.5.3.
bool
Promise_then_noRetVal(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(),
IsPromiseThenOrCatchRetValImplicitlyUsed(cx));
}
// ES2016, 25.4.5.3.
static bool
Promise_then(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(), true);
}
// ES2016, 25.4.5.3.1.
static MOZ_MUST_USE bool
PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
@ -3737,9 +3828,27 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key)
return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_);
}
const JSJitInfo promise_then_info = {
{ (JSJitGetterOp)Promise_then_noRetVal },
{ 0 }, /* unused */
{ 0 }, /* unused */
JSJitInfo::IgnoresReturnValueNative,
JSJitInfo::AliasEverything,
JSVAL_TYPE_UNDEFINED,
};
const JSJitInfo promise_catch_info = {
{ (JSJitGetterOp)Promise_catch_noRetVal },
{ 0 }, /* unused */
{ 0 }, /* unused */
JSJitInfo::IgnoresReturnValueNative,
JSJitInfo::AliasEverything,
JSVAL_TYPE_UNDEFINED,
};
static const JSFunctionSpec promise_methods[] = {
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
JS_FN("then", Promise_then, 2, 0),
JS_FNINFO("then", Promise_then, &promise_then_info, 2, 0),
JS_FNINFO("catch", Promise_catch, &promise_catch_info, 1, 0),
JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0),
JS_FS_END
};

View File

@ -103,6 +103,12 @@ class PromiseObject : public NativeObject
MOZ_MUST_USE JSObject*
GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
enum class CreateDependentPromise {
Always,
SkipIfCtorUnobservable,
Never
};
/**
* Enqueues resolve/reject reactions in the given Promise's reactions lists
* as though calling the original value of Promise.prototype.then.
@ -116,7 +122,7 @@ GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
MOZ_MUST_USE bool
OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
HandleValue onFulfilled, HandleValue onRejected,
MutableHandleObject dependent, bool createDependent);
MutableHandleObject dependent, CreateDependentPromise createDependent);
/**
* PromiseResolve ( C, x )
@ -253,13 +259,6 @@ class OffThreadPromiseRuntimeState
void shutdown(JSContext* cx);
};
bool
Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp);
bool
Promise_reject(JSContext* cx, unsigned argc, Value* vp);
bool
Promise_then(JSContext* cx, unsigned argc, Value* vp);
} // namespace js
#endif /* builtin_Promise_h */

View File

@ -3632,7 +3632,7 @@ ReadableStreamBYOBRequest::constructor(JSContext* cx, unsigned argc, Value* vp)
return false;
}
RootedArrayBufferObject view(cx, &viewVal.toObject().as<ArrayBufferObject>());
Rooted<ArrayBufferViewObject*> view(cx, &viewVal.toObject().as<ArrayBufferViewObject>());
RootedObject request(cx, CreateReadableStreamBYOBRequest(cx, controller, view));
if (!request)

View File

@ -636,7 +636,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
options.setMutedErrors(lazy->mutedErrors())
.setFileAndLine(lazy->filename(), lazy->lineno())
.setColumn(lazy->column())
.setScriptSourceOffset(lazy->begin())
.setScriptSourceOffset(lazy->sourceStart())
.setNoScriptRval(false)
.setSelfHostingMode(false);
@ -678,7 +678,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
MOZ_ASSERT(sourceObject);
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
lazy->begin(), lazy->end(),
lazy->sourceStart(), lazy->sourceEnd(),
lazy->toStringStart(), lazy->toStringEnd()));
if (!script)
return false;

View File

@ -3256,7 +3256,7 @@ Parser<FullParseHandler, CharT>::skipLazyInnerFunction(ParseNode* funcNode, uint
PropagateTransitiveParseFlags(lazy, pc->sc());
if (!tokenStream.advance(fun->lazyScript()->end()))
if (!tokenStream.advance(fun->lazyScript()->sourceEnd()))
return false;
// Append possible Annex B function box only upon successfully parsing.

View File

@ -252,7 +252,7 @@ impl GlobalRules {
let mut rules = self.per_node.get(name)
.cloned()
.unwrap_or_default();
if let Some(ref parent) = rule.inherits {
if let Some(ref parent) = rules.inherits {
let NodeRules {
inherits: _,
type_ok,

View File

@ -251,7 +251,7 @@ class ArenaLists
const BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) const { return backgroundFinalizeState_.ref()[i]; }
/* For each arena kind, a list of arenas remaining to be swept. */
ActiveThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
MainThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
Arena*& arenaListsToSweep(AllocKind i) { return arenaListsToSweep_.ref()[i]; }
Arena* arenaListsToSweep(AllocKind i) const { return arenaListsToSweep_.ref()[i]; }

View File

@ -192,6 +192,7 @@
#include "mozilla/MacroForEach.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/Range.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TypeTraits.h"
@ -1024,25 +1025,44 @@ const char* gc::ZealModeHelpText =
" 2: (Alloc) Collect when every N allocations (default: 100)\n"
" 4: (VerifierPre) Verify pre write barriers between instructions\n"
" 7: (GenerationalGC) Collect the nursery every N nursery allocations\n"
" 8: (IncrementalRootsThenFinish) Incremental GC in two slices: 1) mark roots 2) finish collection\n"
" 9: (IncrementalMarkAllThenFinish) Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
" 10: (IncrementalMultipleSlices) Incremental GC in multiple slices\n"
" 8: (YieldBeforeMarking) Incremental GC in two slices that yields between\n"
" the root marking and marking phases\n"
" 9: (YieldBeforeSweeping) Incremental GC in two slices that yields between\n"
" the marking and sweeping phases\n"
" 10: (IncrementalMultipleSlices) Incremental GC in many slices\n"
" 11: (IncrementalMarkingValidator) Verify incremental marking\n"
" 12: (ElementsBarrier) Always use the individual element post-write barrier, regardless of elements size\n"
" 12: (ElementsBarrier) Use the individual element post-write barrier\n"
" regardless of elements size\n"
" 13: (CheckHashTablesOnMinorGC) Check internal hashtables on minor GC\n"
" 14: (Compact) Perform a shrinking collection every N allocations\n"
" 15: (CheckHeapAfterGC) Walk the heap to check its integrity after every GC\n"
" 16: (CheckNursery) Check nursery integrity on minor GC\n"
" 17: (IncrementalSweepThenFinish) Incremental GC in two slices: 1) start sweeping 2) finish collection\n"
" 18: (CheckGrayMarking) Check gray marking invariants after every GC\n";
" 17: (YieldBeforeSweepingAtoms) Incremental GC in two slices that yields\n"
" before sweeping the atoms table\n"
" 18: (CheckGrayMarking) Check gray marking invariants after every GC\n"
" 19: (YieldBeforeSweepingCaches) Incremental GC in two slices that yields\n"
" before sweeping weak caches\n"
" 20: (YieldBeforeSweepingTypes) Incremental GC in two slices that yields\n"
" before sweeping type information\n"
" 21: (YieldBeforeSweepingObjects) Incremental GC in two slices that yields\n"
" before sweeping foreground finalized objects\n"
" 22: (YieldBeforeSweepingNonObjects) Incremental GC in two slices that yields\n"
" before sweeping non-object GC things\n"
" 23: (YieldBeforeSweepingShapeTrees) Incremental GC in two slices that yields\n"
" before sweeping shape trees\n";
// The set of zeal modes that control incremental slices. These modes are
// mutually exclusive.
static const mozilla::EnumSet<ZealMode> IncrementalSliceZealModes = {
ZealMode::IncrementalRootsThenFinish,
ZealMode::IncrementalMarkAllThenFinish,
ZealMode::YieldBeforeMarking,
ZealMode::YieldBeforeSweeping,
ZealMode::IncrementalMultipleSlices,
ZealMode::IncrementalSweepThenFinish
ZealMode::YieldBeforeSweepingAtoms,
ZealMode::YieldBeforeSweepingCaches,
ZealMode::YieldBeforeSweepingTypes,
ZealMode::YieldBeforeSweepingObjects,
ZealMode::YieldBeforeSweepingNonObjects,
ZealMode::YieldBeforeSweepingShapeTrees
};
void
@ -1089,66 +1109,108 @@ GCRuntime::setNextScheduled(uint32_t count)
nextScheduled = count;
}
bool
GCRuntime::parseAndSetZeal(const char* str)
{
int frequency = -1;
bool foundFrequency = false;
mozilla::Vector<int, 0, SystemAllocPolicy> zeals;
using CharRange = mozilla::Range<const char>;
using CharRangeVector = Vector<CharRange, 0, SystemAllocPolicy>;
static const struct {
const char* const zealMode;
static bool
ParseZealModeName(CharRange text, uint32_t* modeOut)
{
struct ModeInfo
{
const char* name;
size_t length;
uint32_t zeal;
} zealModes[] = {
#define ZEAL_MODE(name, value) {#name, sizeof(#name) - 1, value},
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
#undef ZEAL_MODE
{"None", 4, 0}
uint32_t value;
};
do {
int zeal = -1;
static const ModeInfo zealModes[] = {
{"None", 0},
#define ZEAL_MODE(name, value) {#name, strlen(#name), value},
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
#undef ZEAL_MODE
};
const char* p = nullptr;
if (isdigit(str[0])) {
zeal = atoi(str);
size_t offset = strspn(str, "0123456789");
p = str + offset;
} else {
for (auto z : zealModes) {
if (!strncmp(str, z.zealMode, z.length)) {
zeal = z.zeal;
p = str + z.length;
break;
}
}
}
if (p) {
if (!*p || *p == ';') {
frequency = JS_DEFAULT_ZEAL_FREQ;
} else if (*p == ',') {
frequency = atoi(p + 1);
foundFrequency = true;
for (auto mode : zealModes) {
if (text.length() == mode.length &&
memcmp(text.begin().get(), mode.name, mode.length) == 0)
{
*modeOut = mode.value;
return true;
}
}
if (zeal < 0 || zeal > int(ZealMode::Limit) || frequency <= 0) {
return false;
}
static bool
ParseZealModeNumericParam(CharRange text, uint32_t* paramOut)
{
if (text.length() == 0)
return false;
for (auto c : text) {
if (!isdigit(c))
return false;
}
*paramOut = atoi(text.begin().get());
return true;
}
static bool
SplitStringBy(CharRange text, char delimiter, CharRangeVector* result)
{
auto start = text.begin();
for (auto ptr = start; ptr != text.end(); ptr++) {
if (*ptr == delimiter) {
if (!result->emplaceBack(start, ptr))
return false;
start = ptr + 1;
}
}
return result->emplaceBack(start, text.end());
}
static bool
PrintZealHelpAndFail()
{
fprintf(stderr, "Format: JS_GC_ZEAL=level(;level)*[,N]\n");
fputs(ZealModeHelpText, stderr);
return false;
}
}
if (!zeals.emplaceBack(zeal)) {
bool
GCRuntime::parseAndSetZeal(const char* str)
{
// Set the zeal mode from a string consisting of one or more mode specifiers
// separated by ';', optionally followed by a ',' and the trigger frequency.
// The mode specifiers can by a mode name or its number.
auto text = CharRange(str, strlen(str));
CharRangeVector parts;
if (!SplitStringBy(text, ',', &parts))
return false;
}
} while (!foundFrequency &&
(str = strchr(str, ';')) != nullptr &&
str++);
for (auto z : zeals)
setZeal(z, frequency);
if (parts.length() == 0 || parts.length() > 2)
return PrintZealHelpAndFail();
uint32_t frequency = JS_DEFAULT_ZEAL_FREQ;
if (parts.length() == 2 && !ParseZealModeNumericParam(parts[1], &frequency))
return PrintZealHelpAndFail();
CharRangeVector modes;
if (!SplitStringBy(parts[0], ';', &modes))
return false;
for (const auto& descr : modes) {
uint32_t mode;
if (!ParseZealModeName(descr, &mode) && !ParseZealModeNumericParam(descr, &mode))
return PrintZealHelpAndFail();
setZeal(mode, frequency);
}
return true;
}
@ -4944,12 +5006,10 @@ GCRuntime::groupZonesForSweeping(JS::gcreason::Reason reason)
finder.useOneComponent();
#ifdef JS_GC_ZEAL
// Use one component for IncrementalSweepThenFinish zeal mode.
if (isIncremental && reason == JS::gcreason::DEBUG_GC &&
hasZealMode(ZealMode::IncrementalSweepThenFinish))
{
// Use one component for two-slice zeal modes.
MOZ_ASSERT_IF(useZeal, isIncremental);
if (useZeal && hasIncrementalTwoSliceZealMode())
finder.useOneComponent();
}
#endif
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
@ -5688,6 +5748,14 @@ GCRuntime::beginSweepingSweepGroup(FreeOp* fop, SliceBudget& budget)
}
#ifdef JS_GC_ZEAL
bool
GCRuntime::shouldYieldForZeal(ZealMode mode)
{
MOZ_ASSERT_IF(useZeal, isIncremental);
return useZeal && hasZealMode(mode);
}
IncrementalProgress
GCRuntime::maybeYieldForSweepingZeal(FreeOp* fop, SliceBudget& budget)
{
@ -5696,15 +5764,12 @@ GCRuntime::maybeYieldForSweepingZeal(FreeOp* fop, SliceBudget& budget)
* in incremental multi-slice zeal mode so RunDebugGC can reset the slice
* budget.
*/
if (isIncremental && useZeal && initialState != State::Sweep &&
(hasZealMode(ZealMode::IncrementalMultipleSlices) ||
hasZealMode(ZealMode::IncrementalSweepThenFinish)))
{
if (initialState != State::Sweep && shouldYieldForZeal(ZealMode::IncrementalMultipleSlices))
return NotFinished;
}
return Finished;
}
#endif
IncrementalProgress
@ -6235,6 +6300,38 @@ class SweepActionCall final : public SweepAction<GCRuntime*, Args...>
void assertFinished() const override { }
};
#ifdef JS_GC_ZEAL
// Implementation of the SweepAction interface that yields in a specified zeal
// mode and then calls another action.
template <typename... Args>
class SweepActionMaybeYield final : public SweepAction<GCRuntime*, Args...>
{
using Action = SweepAction<GCRuntime*, Args...>;
ZealMode mode;
UniquePtr<Action> action;
bool triggered;
public:
SweepActionMaybeYield(UniquePtr<Action> action, ZealMode mode)
: mode(mode), action(Move(action)), triggered(false) {}
IncrementalProgress run(GCRuntime* gc, Args... args) override {
if (!triggered && gc->shouldYieldForZeal(mode)) {
triggered = true;
return NotFinished;
}
triggered = false;
return action->run(gc, args...);
}
void assertFinished() const override {
MOZ_ASSERT(!triggered);
}
};
#endif
// Implementation of the SweepAction interface that calls a list of actions in
// sequence.
template <typename... Args>
@ -6374,6 +6471,16 @@ Call(IncrementalProgress (GCRuntime::*method)(Args...)) {
return MakeUnique<SweepActionCall<Args...>>(method);
}
template <typename... Args>
static UniquePtr<SweepAction<GCRuntime*, Args...>>
MaybeYield(ZealMode zealMode, UniquePtr<SweepAction<GCRuntime*, Args...>> action) {
#ifdef JS_GC_ZEAL
return js::MakeUnique<SweepActionMaybeYield<Args...>>(Move(action), zealMode);
#else
return action;
#endif
}
template <typename... Args, typename... Rest>
static UniquePtr<SweepAction<Args...>>
Sequence(UniquePtr<SweepAction<Args...>> first, Rest... rest)
@ -6437,16 +6544,22 @@ GCRuntime::initSweepActions()
#ifdef JS_GC_ZEAL
Call(&GCRuntime::maybeYieldForSweepingZeal),
#endif
Call(&GCRuntime::sweepAtomsTable),
Call(&GCRuntime::sweepWeakCaches),
MaybeYield(ZealMode::YieldBeforeSweepingAtoms,
Call(&GCRuntime::sweepAtomsTable)),
MaybeYield(ZealMode::YieldBeforeSweepingCaches,
Call(&GCRuntime::sweepWeakCaches)),
ForEachZoneInSweepGroup(rt,
Sequence(
Call(&GCRuntime::sweepTypeInformation),
MaybeYield(ZealMode::YieldBeforeSweepingTypes,
Call(&GCRuntime::sweepTypeInformation)),
MaybeYield(ZealMode::YieldBeforeSweepingObjects,
ForEachAllocKind(ForegroundObjectFinalizePhase.kinds,
Call(&GCRuntime::finalizeAllocKind)),
Call(&GCRuntime::finalizeAllocKind))),
MaybeYield(ZealMode::YieldBeforeSweepingNonObjects,
ForEachAllocKind(ForegroundNonObjectFinalizePhase.kinds,
Call(&GCRuntime::finalizeAllocKind)),
Call(&GCRuntime::sweepShapeTree),
Call(&GCRuntime::finalizeAllocKind))),
MaybeYield(ZealMode::YieldBeforeSweepingShapeTrees,
Call(&GCRuntime::sweepShapeTree)),
Call(&GCRuntime::releaseSweptEmptyArenas))),
Call(&GCRuntime::endSweepingSweepGroup)));
@ -6944,10 +7057,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
isIncremental = !budget.isUnlimited();
if (useZeal && (hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
hasZealMode(ZealMode::IncrementalSweepThenFinish)))
{
if (useZeal && hasIncrementalTwoSliceZealMode()) {
/*
* Yields between slices occurs at predetermined points in these modes;
* the budget is not used.
@ -6978,7 +7088,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
incrementalState = State::Mark;
if (isIncremental && useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish))
if (isIncremental && useZeal && hasZealMode(ZealMode::YieldBeforeMarking))
break;
MOZ_FALLTHROUGH;
@ -7004,16 +7114,16 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
* the next slice, since the first slice of sweeping can be expensive.
*
* This is modified by the various zeal modes. We don't yield in
* IncrementalRootsThenFinish mode and we always yield in
* IncrementalMarkAllThenFinish mode.
* YieldBeforeMarking mode and we always yield in YieldBeforeSweeping
* mode.
*
* We will need to mark anything new on the stack when we resume, so
* we stay in Mark state.
*/
if (!lastMarkSlice && isIncremental &&
((initialState == State::Mark &&
!(useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish))) ||
(useZeal && hasZealMode(ZealMode::IncrementalMarkAllThenFinish))))
!(useZeal && hasZealMode(ZealMode::YieldBeforeMarking))) ||
(useZeal && hasZealMode(ZealMode::YieldBeforeSweeping))))
{
lastMarkSlice = true;
break;
@ -8024,12 +8134,6 @@ GCRuntime::runDebugGC()
PrepareForDebugGC(rt);
auto budget = SliceBudget::unlimited();
if (hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
hasZealMode(ZealMode::IncrementalMultipleSlices) ||
hasZealMode(ZealMode::IncrementalSweepThenFinish))
{
js::gc::State initialState = incrementalState;
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
/*
* Start with a small slice limit and double it every slice. This
@ -8041,26 +8145,26 @@ GCRuntime::runDebugGC()
else
incrementalLimit *= 2;
budget = SliceBudget(WorkBudget(incrementalLimit));
} else {
// This triggers incremental GC but is actually ignored by IncrementalMarkSlice.
budget = SliceBudget(WorkBudget(1));
}
js::gc::State initialState = incrementalState;
if (!isIncrementalGCInProgress())
invocationKind = GC_SHRINK;
collect(false, budget, JS::gcreason::DEBUG_GC);
/*
* For multi-slice zeal, reset the slice size when we get to the sweep
* or compact phases.
*/
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
/* Reset the slice size when we get to the sweep or compact phases. */
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
(initialState == State::Sweep && incrementalState == State::Compact))
{
incrementalLimit = zealFrequency / 2;
}
}
} else if (hasIncrementalTwoSliceZealMode()) {
// These modes trigger incremental GC that happens in two slices and the
// supplied budget is ignored by incrementalCollectSlice.
budget = SliceBudget(WorkBudget(1));
if (!isIncrementalGCInProgress())
invocationKind = GC_NORMAL;
collect(false, budget, JS::gcreason::DEBUG_GC);
} else if (hasZealMode(ZealMode::Compact)) {
gc(GC_SHRINK, JS::gcreason::DEBUG_GC);
} else {

View File

@ -164,10 +164,11 @@ MaybeVerifyBarriers(JSContext* cx, bool always = false) {}
#endif
/*
* Instances of this class set the |JSRuntime::suppressGC| flag for the duration
* that they are live. Use of this class is highly discouraged. Please carefully
* read the comment in vm/Runtime.h above |suppressGC| and take all appropriate
* precautions before instantiating this class.
* Instances of this class prevent GC while they are live by updating the
* |JSContext::suppressGC| counter. Use of this class is highly
* discouraged. Please carefully read the comment in vm/JSContext.h above
* |suppressGC| and take all appropriate precautions before instantiating this
* class.
*/
class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC
{

View File

@ -62,8 +62,8 @@ enum class AbortReason {
D(Alloc, 2) \
D(VerifierPre, 4) \
D(GenerationalGC, 7) \
D(IncrementalRootsThenFinish, 8) \
D(IncrementalMarkAllThenFinish, 9) \
D(YieldBeforeMarking, 8) \
D(YieldBeforeSweeping, 9) \
D(IncrementalMultipleSlices, 10) \
D(IncrementalMarkingValidator, 11) \
D(ElementsBarrier, 12) \
@ -71,14 +71,20 @@ enum class AbortReason {
D(Compact, 14) \
D(CheckHeapAfterGC, 15) \
D(CheckNursery, 16) \
D(IncrementalSweepThenFinish, 17) \
D(CheckGrayMarking, 18)
D(YieldBeforeSweepingAtoms, 17) \
D(CheckGrayMarking, 18) \
D(YieldBeforeSweepingCaches, 19) \
D(YieldBeforeSweepingTypes, 20) \
D(YieldBeforeSweepingObjects, 21) \
D(YieldBeforeSweepingNonObjects, 22) \
D(YieldBeforeSweepingShapeTrees, 23)
enum class ZealMode {
#define ZEAL_MODE(name, value) name = value,
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
#undef ZEAL_MODE
Limit = 18
Count,
Limit = Count - 1
};
} /* namespace gc */

View File

@ -42,7 +42,7 @@ class GCHelperState
ConditionVariable done;
// Activity for the helper to do, protected by the GC lock.
ActiveThreadOrGCTaskData<State> state_;
MainThreadOrGCTaskData<State> state_;
// Whether work is being performed on some thread.
GCLockData<bool> hasThread;

View File

@ -174,13 +174,13 @@ class MarkStack
const TaggedPtr& peekPtr() const;
MOZ_MUST_USE bool pushTaggedPtr(Tag tag, Cell* ptr);
ActiveThreadData<TaggedPtr*> stack_;
ActiveThreadData<TaggedPtr*> tos_;
ActiveThreadData<TaggedPtr*> end_;
MainThreadData<TaggedPtr*> stack_;
MainThreadData<TaggedPtr*> tos_;
MainThreadData<TaggedPtr*> end_;
// The capacity we start with and reset() to.
ActiveThreadData<size_t> baseCapacity_;
ActiveThreadData<size_t> maxCapacity_;
MainThreadData<size_t> baseCapacity_;
MainThreadData<size_t> maxCapacity_;
#ifdef DEBUG
mutable size_t iteratorCount_;
@ -349,29 +349,29 @@ class GCMarker : public JSTracer
gc::MarkStack stack;
/* The color is only applied to objects and functions. */
ActiveThreadData<gc::MarkColor> color;
MainThreadData<gc::MarkColor> color;
/* Pointer to the top of the stack of arenas we are delaying marking on. */
ActiveThreadData<js::gc::Arena*> unmarkedArenaStackTop;
MainThreadData<js::gc::Arena*> unmarkedArenaStackTop;
/*
* If the weakKeys table OOMs, disable the linear algorithm and fall back
* to iterating until the next GC.
*/
ActiveThreadData<bool> linearWeakMarkingDisabled_;
MainThreadData<bool> linearWeakMarkingDisabled_;
#ifdef DEBUG
/* Count of arenas that are currently in the stack. */
ActiveThreadData<size_t> markLaterArenas;
MainThreadData<size_t> markLaterArenas;
/* Assert that start and stop are called with correct ordering. */
ActiveThreadData<bool> started;
MainThreadData<bool> started;
/*
* If this is true, all marked objects must belong to a compartment being
* GCed. This is used to look for compartment bugs.
*/
ActiveThreadData<bool> strictCompartmentChecking;
MainThreadData<bool> strictCompartmentChecking;
#endif // DEBUG
};

View File

@ -28,7 +28,7 @@ class GCParallelTask
UnprotectedData<TaskState> state;
// Amount of time this task took to execute.
ActiveThreadOrGCTaskData<mozilla::TimeDuration> duration_;
MainThreadOrGCTaskData<mozilla::TimeDuration> duration_;
explicit GCParallelTask(const GCParallelTask&) = delete;

View File

@ -134,13 +134,13 @@ class BackgroundDecommitTask : public GCParallelTask
void run() override;
private:
ActiveThreadOrGCTaskData<ChunkVector> toDecommit;
MainThreadOrGCTaskData<ChunkVector> toDecommit;
};
template<typename F>
struct Callback {
ActiveThreadOrGCTaskData<F> op;
ActiveThreadOrGCTaskData<void*> data;
MainThreadOrGCTaskData<F> op;
MainThreadOrGCTaskData<void*> data;
Callback()
: op(nullptr), data(nullptr)
@ -151,7 +151,7 @@ struct Callback {
};
template<typename F>
using CallbackVector = ActiveThreadData<Vector<Callback<F>, 4, SystemAllocPolicy>>;
using CallbackVector = MainThreadData<Vector<Callback<F>, 4, SystemAllocPolicy>>;
template <typename T, typename Iter0, typename Iter1>
class ChainedIter
@ -230,6 +230,7 @@ class GCRuntime
inline void clearZealMode(ZealMode mode);
inline bool upcomingZealousGC();
inline bool needZealousGC();
inline bool hasIncrementalTwoSliceZealMode();
MOZ_MUST_USE bool addRoot(Value* vp, const char* name);
void removeRoot(Value* vp);
@ -446,6 +447,7 @@ class GCRuntime
void endVerifyPreBarriers();
void finishVerifier();
bool isVerifyPreBarriersEnabled() const { return !!verifyPreData; }
bool shouldYieldForZeal(ZealMode mode);
#else
bool isVerifyPreBarriersEnabled() const { return false; }
#endif
@ -643,7 +645,7 @@ class GCRuntime
// All zones in the runtime, except the atoms zone.
private:
ActiveThreadOrGCTaskData<ZoneVector> zones_;
MainThreadOrGCTaskData<ZoneVector> zones_;
public:
ZoneVector& zones() { return zones_.ref(); }
@ -690,7 +692,7 @@ class GCRuntime
// so as to reduce the cost of operations on the available lists.
GCLockData<ChunkPool> fullChunks_;
ActiveThreadData<RootedValueMap> rootsHash;
MainThreadData<RootedValueMap> rootsHash;
// An incrementing id used to assign unique ids to cells that require one.
mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> nextCellUniqueId_;
@ -699,23 +701,23 @@ class GCRuntime
* Number of the committed arenas in all GC chunks including empty chunks.
*/
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
ActiveThreadData<VerifyPreTracer*> verifyPreData;
MainThreadData<VerifyPreTracer*> verifyPreData;
private:
UnprotectedData<bool> chunkAllocationSinceLastGC;
ActiveThreadData<int64_t> lastGCTime;
MainThreadData<int64_t> lastGCTime;
/*
* JSGC_MODE
* prefs: javascript.options.mem.gc_per_zone and
* javascript.options.mem.gc_incremental.
*/
ActiveThreadData<JSGCMode> mode;
MainThreadData<JSGCMode> mode;
mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
/* During shutdown, the GC needs to clean up every possible object. */
ActiveThreadData<bool> cleanUpEverything;
MainThreadData<bool> cleanUpEverything;
// Gray marking must be done after all black marking is complete. However,
// we do not have write barriers on XPConnect roots. Therefore, XPConnect
@ -728,7 +730,7 @@ class GCRuntime
Okay,
Failed
};
ActiveThreadOrGCTaskData<GrayBufferState> grayBufferState;
MainThreadOrGCTaskData<GrayBufferState> grayBufferState;
bool hasValidGrayRootsBuffer() const { return grayBufferState == GrayBufferState::Okay; }
// Clear each zone's gray buffers, but do not change the current state.
@ -750,85 +752,85 @@ class GCRuntime
private:
/* Perform full GC if rt->keepAtoms() becomes false. */
ActiveThreadData<bool> fullGCForAtomsRequested_;
MainThreadData<bool> fullGCForAtomsRequested_;
/* Incremented at the start of every minor GC. */
ActiveThreadData<uint64_t> minorGCNumber;
MainThreadData<uint64_t> minorGCNumber;
/* Incremented at the start of every major GC. */
ActiveThreadData<uint64_t> majorGCNumber;
MainThreadData<uint64_t> majorGCNumber;
/* The major GC number at which to release observed type information. */
ActiveThreadData<uint64_t> jitReleaseNumber;
MainThreadData<uint64_t> jitReleaseNumber;
/* Incremented on every GC slice. */
ActiveThreadData<uint64_t> number;
MainThreadData<uint64_t> number;
/* Whether the currently running GC can finish in multiple slices. */
ActiveThreadData<bool> isIncremental;
MainThreadData<bool> isIncremental;
/* Whether all zones are being collected in first GC slice. */
ActiveThreadData<bool> isFull;
MainThreadData<bool> isFull;
/* Whether the heap will be compacted at the end of GC. */
ActiveThreadData<bool> isCompacting;
MainThreadData<bool> isCompacting;
/* The invocation kind of the current GC, taken from the first slice. */
ActiveThreadData<JSGCInvocationKind> invocationKind;
MainThreadData<JSGCInvocationKind> invocationKind;
/* The initial GC reason, taken from the first slice. */
ActiveThreadData<JS::gcreason::Reason> initialReason;
MainThreadData<JS::gcreason::Reason> initialReason;
/*
* The current incremental GC phase. This is also used internally in
* non-incremental GC.
*/
ActiveThreadOrGCTaskData<State> incrementalState;
MainThreadOrGCTaskData<State> incrementalState;
/* The incremental state at the start of this slice. */
ActiveThreadData<State> initialState;
MainThreadData<State> initialState;
#ifdef JS_GC_ZEAL
/* Whether to pay attention the zeal settings in this incremental slice. */
ActiveThreadData<bool> useZeal;
MainThreadData<bool> useZeal;
#endif
/* Indicates that the last incremental slice exhausted the mark stack. */
ActiveThreadData<bool> lastMarkSlice;
MainThreadData<bool> lastMarkSlice;
/* Whether it's currently safe to yield to the mutator in an incremental GC. */
ActiveThreadData<bool> safeToYield;
MainThreadData<bool> safeToYield;
/* Whether any sweeping will take place in the separate GC helper thread. */
ActiveThreadData<bool> sweepOnBackgroundThread;
MainThreadData<bool> sweepOnBackgroundThread;
/* Whether observed type information is being released in the current GC. */
ActiveThreadData<bool> releaseObservedTypes;
MainThreadData<bool> releaseObservedTypes;
/* Singly linked list of zones to be swept in the background. */
ActiveThreadOrGCTaskData<ZoneList> backgroundSweepZones;
MainThreadOrGCTaskData<ZoneList> backgroundSweepZones;
/*
* Free LIFO blocks are transferred to this allocator before being freed on
* the background GC thread after sweeping.
*/
ActiveThreadOrGCTaskData<LifoAlloc> blocksToFreeAfterSweeping;
MainThreadOrGCTaskData<LifoAlloc> blocksToFreeAfterSweeping;
private:
/* Index of current sweep group (for stats). */
ActiveThreadData<unsigned> sweepGroupIndex;
MainThreadData<unsigned> sweepGroupIndex;
/*
* Incremental sweep state.
*/
ActiveThreadData<JS::Zone*> sweepGroups;
ActiveThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
ActiveThreadData<UniquePtr<SweepAction<GCRuntime*, FreeOp*, SliceBudget&>>> sweepActions;
ActiveThreadOrGCTaskData<JS::Zone*> sweepZone;
ActiveThreadData<mozilla::Maybe<AtomSet::Enum>> maybeAtomsToSweep;
ActiveThreadOrGCTaskData<JS::detail::WeakCacheBase*> sweepCache;
ActiveThreadData<bool> abortSweepAfterCurrentGroup;
MainThreadData<JS::Zone*> sweepGroups;
MainThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
MainThreadData<UniquePtr<SweepAction<GCRuntime*, FreeOp*, SliceBudget&>>> sweepActions;
MainThreadOrGCTaskData<JS::Zone*> sweepZone;
MainThreadData<mozilla::Maybe<AtomSet::Enum>> maybeAtomsToSweep;
MainThreadOrGCTaskData<JS::detail::WeakCacheBase*> sweepCache;
MainThreadData<bool> abortSweepAfterCurrentGroup;
friend class SweepGroupsIter;
friend class WeakCacheSweepIterator;
@ -836,12 +838,12 @@ class GCRuntime
/*
* Incremental compacting state.
*/
ActiveThreadData<bool> startedCompacting;
ActiveThreadData<ZoneList> zonesToMaybeCompact;
ActiveThreadData<Arena*> relocatedArenasToRelease;
MainThreadData<bool> startedCompacting;
MainThreadData<ZoneList> zonesToMaybeCompact;
MainThreadData<Arena*> relocatedArenasToRelease;
#ifdef JS_GC_ZEAL
ActiveThreadData<MarkingValidator*> markingValidator;
MainThreadData<MarkingValidator*> markingValidator;
#endif
/*
@ -850,13 +852,13 @@ class GCRuntime
* JSGC_SLICE_TIME_BUDGET
* pref: javascript.options.mem.gc_incremental_slice_ms,
*/
ActiveThreadData<int64_t> defaultTimeBudget_;
MainThreadData<int64_t> defaultTimeBudget_;
/*
* We disable incremental GC if we encounter a Class with a trace hook
* that does not implement write barriers.
*/
ActiveThreadData<bool> incrementalAllowed;
MainThreadData<bool> incrementalAllowed;
/*
* Whether compacting GC can is enabled globally.
@ -864,9 +866,9 @@ class GCRuntime
* JSGC_COMPACTING_ENABLED
* pref: javascript.options.mem.gc_compacting
*/
ActiveThreadData<bool> compactingEnabled;
MainThreadData<bool> compactingEnabled;
ActiveThreadData<bool> rootsRemoved;
MainThreadData<bool> rootsRemoved;
/*
* These options control the zealousness of the GC. At every allocation,
@ -894,18 +896,20 @@ class GCRuntime
* zeal_ value 14 performs periodic shrinking collections.
*/
#ifdef JS_GC_ZEAL
ActiveThreadData<uint32_t> zealModeBits;
ActiveThreadData<int> zealFrequency;
ActiveThreadData<int> nextScheduled;
ActiveThreadData<bool> deterministicOnly;
ActiveThreadData<int> incrementalLimit;
static_assert(size_t(ZealMode::Count) <= 32,
"Too many zeal modes to store in a uint32_t");
MainThreadData<uint32_t> zealModeBits;
MainThreadData<int> zealFrequency;
MainThreadData<int> nextScheduled;
MainThreadData<bool> deterministicOnly;
MainThreadData<int> incrementalLimit;
ActiveThreadData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
MainThreadData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
#endif
ActiveThreadData<bool> fullCompartmentChecks;
MainThreadData<bool> fullCompartmentChecks;
ActiveThreadData<uint32_t> gcCallbackDepth;
MainThreadData<uint32_t> gcCallbackDepth;
Callback<JSGCCallback> gcCallback;
Callback<JS::DoCycleCollectionCallback> gcDoCycleCollectionCallback;
@ -926,10 +930,10 @@ class GCRuntime
Callback<JSTraceDataOp> grayRootTracer;
/* Always preserve JIT code during GCs, for testing. */
ActiveThreadData<bool> alwaysPreserveCode;
MainThreadData<bool> alwaysPreserveCode;
#ifdef DEBUG
ActiveThreadData<bool> arenasEmptyAtShutdown;
MainThreadData<bool> arenasEmptyAtShutdown;
#endif
/* Synchronize GC heap access among GC helper threads and active threads. */
@ -946,18 +950,18 @@ class GCRuntime
* During incremental sweeping, this field temporarily holds the arenas of
* the current AllocKind being swept in order of increasing free space.
*/
ActiveThreadData<SortedArenaList> incrementalSweepList;
MainThreadData<SortedArenaList> incrementalSweepList;
private:
ActiveThreadData<Nursery> nursery_;
ActiveThreadData<gc::StoreBuffer> storeBuffer_;
MainThreadData<Nursery> nursery_;
MainThreadData<gc::StoreBuffer> storeBuffer_;
public:
Nursery& nursery() { return nursery_.ref(); }
gc::StoreBuffer& storeBuffer() { return storeBuffer_.ref(); }
// Free LIFO blocks are transferred to this allocator before being freed
// after minor GC.
ActiveThreadData<LifoAlloc> blocksToFreeAfterMinorGC;
MainThreadData<LifoAlloc> blocksToFreeAfterMinorGC;
const void* addressOfNurseryPosition() {
return nursery_.refNoCheck().addressOfPosition();
@ -1024,11 +1028,9 @@ GCRuntime::needZealousGC() {
if (nextScheduled > 0 && --nextScheduled == 0) {
if (hasZealMode(ZealMode::Alloc) ||
hasZealMode(ZealMode::GenerationalGC) ||
hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
hasZealMode(ZealMode::IncrementalMultipleSlices) ||
hasZealMode(ZealMode::Compact) ||
hasZealMode(ZealMode::IncrementalSweepThenFinish))
hasIncrementalTwoSliceZealMode())
{
nextScheduled = zealFrequency;
}
@ -1036,11 +1038,25 @@ GCRuntime::needZealousGC() {
}
return false;
}
inline bool
GCRuntime::hasIncrementalTwoSliceZealMode() {
return hasZealMode(ZealMode::YieldBeforeMarking) ||
hasZealMode(ZealMode::YieldBeforeSweeping) ||
hasZealMode(ZealMode::YieldBeforeSweepingAtoms) ||
hasZealMode(ZealMode::YieldBeforeSweepingCaches) ||
hasZealMode(ZealMode::YieldBeforeSweepingTypes) ||
hasZealMode(ZealMode::YieldBeforeSweepingObjects) ||
hasZealMode(ZealMode::YieldBeforeSweepingNonObjects) ||
hasZealMode(ZealMode::YieldBeforeSweepingShapeTrees);
}
#else
inline bool GCRuntime::hasZealMode(ZealMode mode) { return false; }
inline void GCRuntime::clearZealMode(ZealMode mode) { }
inline bool GCRuntime::upcomingZealousGC() { return false; }
inline bool GCRuntime::needZealousGC() { return false; }
inline bool GCRuntime::hasIncrementalTwoSliceZealMode() { return false; }
#endif
} /* namespace gc */

View File

@ -342,7 +342,7 @@ class GCSchedulingTunables
*
* Maximum nursery size for each runtime.
*/
ActiveThreadData<size_t> gcMaxNurseryBytes_;
MainThreadData<size_t> gcMaxNurseryBytes_;
/*
* JSGC_ALLOCATION_THRESHOLD
@ -351,7 +351,7 @@ class GCSchedulingTunables
* usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
* zone may be scheduled for a GC, depending on the exact circumstances.
*/
ActiveThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
MainThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
/*
* JSGC_ALLOCATION_THRESHOLD_FACTOR
@ -381,7 +381,7 @@ class GCSchedulingTunables
* Totally disables |highFrequencyGC|, the HeapGrowthFactor, and other
* tunables that make GC non-deterministic.
*/
ActiveThreadData<bool> dynamicHeapGrowthEnabled_;
MainThreadData<bool> dynamicHeapGrowthEnabled_;
/*
* JSGC_HIGH_FREQUENCY_TIME_LIMIT
@ -389,7 +389,7 @@ class GCSchedulingTunables
* We enter high-frequency mode if we GC a twice within this many
* microseconds. This value is stored directly in microseconds.
*/
ActiveThreadData<uint64_t> highFrequencyThresholdUsec_;
MainThreadData<uint64_t> highFrequencyThresholdUsec_;
/*
* JSGC_HIGH_FREQUENCY_LOW_LIMIT
@ -400,10 +400,10 @@ class GCSchedulingTunables
* When in the |highFrequencyGC| mode, these parameterize the per-zone
* "HeapGrowthFactor" computation.
*/
ActiveThreadData<uint64_t> highFrequencyLowLimitBytes_;
ActiveThreadData<uint64_t> highFrequencyHighLimitBytes_;
ActiveThreadData<double> highFrequencyHeapGrowthMax_;
ActiveThreadData<double> highFrequencyHeapGrowthMin_;
MainThreadData<uint64_t> highFrequencyLowLimitBytes_;
MainThreadData<uint64_t> highFrequencyHighLimitBytes_;
MainThreadData<double> highFrequencyHeapGrowthMax_;
MainThreadData<double> highFrequencyHeapGrowthMin_;
/*
* JSGC_LOW_FREQUENCY_HEAP_GROWTH
@ -411,14 +411,14 @@ class GCSchedulingTunables
* When not in |highFrequencyGC| mode, this is the global (stored per-zone)
* "HeapGrowthFactor".
*/
ActiveThreadData<double> lowFrequencyHeapGrowth_;
MainThreadData<double> lowFrequencyHeapGrowth_;
/*
* JSGC_DYNAMIC_MARK_SLICE
*
* Doubles the length of IGC slices when in the |highFrequencyGC| mode.
*/
ActiveThreadData<bool> dynamicMarkSliceEnabled_;
MainThreadData<bool> dynamicMarkSliceEnabled_;
/*
* JSGC_MIN_EMPTY_CHUNK_COUNT
@ -473,7 +473,7 @@ class GCSchedulingState
* growth factor is a measure of how large (as a percentage of the last GC)
* the heap is allowed to grow before we try to schedule another GC.
*/
ActiveThreadData<bool> inHighFrequencyGCMode_;
MainThreadData<bool> inHighFrequencyGCMode_;
public:
GCSchedulingState()
@ -500,7 +500,7 @@ class MemoryCounter
size_t maxBytes_;
// The counter value at the start of a GC.
ActiveThreadData<size_t> bytesAtStartOfGC_;
MainThreadData<size_t> bytesAtStartOfGC_;
// Which kind of GC has been triggered if any.
mozilla::Atomic<TriggerKind, mozilla::ReleaseAcquire> triggered_;

View File

@ -307,7 +307,7 @@ struct Zone : public JS::shadow::Zone,
private:
// The set of compartments in this zone.
js::ActiveThreadOrGCTaskData<CompartmentVector> compartments_;
js::MainThreadOrGCTaskData<CompartmentVector> compartments_;
public:
CompartmentVector& compartments() { return compartments_.ref(); }
@ -349,7 +349,7 @@ struct Zone : public JS::shadow::Zone,
//
// This is used during GC while calculating sweep groups to record edges
// that can't be determined by examining this zone by itself.
js::ActiveThreadData<ZoneSet> gcSweepGroupEdges_;
js::MainThreadData<ZoneSet> gcSweepGroupEdges_;
public:
ZoneSet& gcSweepGroupEdges() { return gcSweepGroupEdges_.ref(); }
@ -705,15 +705,15 @@ struct Zone : public JS::shadow::Zone,
private:
js::ZoneData<js::jit::JitZone*> jitZone_;
js::ActiveThreadData<bool> gcScheduled_;
js::ActiveThreadData<bool> gcScheduledSaved_;
js::MainThreadData<bool> gcScheduled_;
js::MainThreadData<bool> gcScheduledSaved_;
js::ZoneData<bool> gcPreserveCode_;
js::ZoneData<bool> keepShapeTables_;
// Allow zones to be linked into a list
friend class js::gc::ZoneList;
static Zone * const NotOnList;
js::ActiveThreadOrGCTaskData<Zone*> listNext_;
js::MainThreadOrGCTaskData<Zone*> listNext_;
bool isOnList() const;
Zone* nextZone() const;

View File

@ -6,7 +6,7 @@
load(libdir + "../../tests/non262/shell.js");
if (typeof assertWarning === 'undefined') {
var assertWarning = function assertWarning(f, errorClass, msg) {
var assertWarning = function assertWarning(f, pattern) {
var hadWerror = options().split(",").indexOf("werror") !== -1;
// Ensure the "werror" option is disabled.
@ -19,10 +19,6 @@ if (typeof assertWarning === 'undefined') {
if (hadWerror)
options("werror");
// print() rather than throw a different exception value, in case
// the caller wants exc.stack.
if (msg)
print("assertWarning: " + msg);
print("assertWarning: Unexpected exception calling " + f +
" with warnings-as-errors disabled");
throw exc;
@ -32,20 +28,21 @@ if (typeof assertWarning === 'undefined') {
options("werror");
try {
assertThrowsInstanceOf(f, errorClass, msg);
f();
} catch (exc) {
if (msg)
print("assertWarning: " + msg);
throw exc;
if (!String(exc).match(pattern))
throw new Error(`assertWarning failed: "${exc}" does not match "${pattern}"`);
return;
} finally {
if (!hadWerror)
options("werror");
}
throw new Error("assertWarning failed: no warning");
};
}
if (typeof assertNoWarning === 'undefined') {
var assertNoWarning = function assertWarning(f, msg) {
var assertNoWarning = function assertNoWarning(f, msg) {
// Ensure the "werror" option is enabled.
var hadWerror = options().split(",").indexOf("werror") !== -1;
if (!hadWerror)

View File

@ -56,11 +56,23 @@ while (gcstate() == "Finalize") { gcslice(1); }
while (gcstate() == "Decommit") { gcslice(1); }
assertEq(gcstate(), "NotActive");
// Zeal mode 17: Incremental GC in two slices:
// 1) mark everything and start sweeping
// 2) finish sweeping
gczeal(17, 0);
gcslice(1);
assertEq(gcstate(), "Sweep");
gcslice(1);
assertEq(gcstate(), "NotActive");
// Two-slice zeal modes that yield once during sweeping.
for (let mode of [ 17, 19 ]) {
print(mode);
gczeal(mode, 0);
gcslice(1);
assertEq(gcstate(), "Sweep");
gcslice(1);
assertEq(gcstate(), "NotActive");
}
// Two-slice zeal modes that yield per-zone during sweeping.
const sweepingZealModes = [ 20, 21, 22, 23 ];
for (let mode of sweepingZealModes) {
print(mode);
gczeal(mode, 0);
gcslice(1);
while (gcstate() === "Sweep")
gcslice(1);
assertEq(gcstate(), "NotActive");
}

View File

@ -232,20 +232,19 @@ function elemSection(elemArrays) {
return { name: elemId, body };
}
function nameSection(moduleName, funcNames) {
function moduleNameSubsection(moduleName) {
var body = [];
body.push(...string(nameName));
if (moduleName) {
body.push(...varU32(nameTypeModule));
var subsection = encodedString(moduleName);
body.push(...varU32(subsection.length));
body.push(...subsection);
}
if (funcNames) {
return body;
}
function funcNameSubsection(funcNames) {
var body = [];
body.push(...varU32(nameTypeFunction));
var subsection = varU32(funcNames.length);
@ -259,7 +258,15 @@ function nameSection(moduleName, funcNames) {
body.push(...varU32(subsection.length));
body.push(...subsection);
}
return body;
}
function nameSection(subsections) {
var body = [];
body.push(...string(nameName));
for (let ss of subsections)
body.push(...ss);
return { name: userDefinedId, body };
}
@ -395,7 +402,7 @@ wasmEval(moduleWithSections([tooBigNameSection]));
var customDefSec = customSection("wee", 42, 13);
var declSec = declSection([0]);
var bodySec = bodySection([v2vBody]);
var nameSec = nameSection(null, [{name:'hi'}]);
var nameSec = nameSection([funcNameSubsection([{name:'hi'}])]);
wasmEval(moduleWithSections([customDefSec, v2vSigSection, declSec, bodySec]));
wasmEval(moduleWithSections([v2vSigSection, customDefSec, declSec, bodySec]));
wasmEval(moduleWithSections([v2vSigSection, declSec, customDefSec, bodySec]));
@ -432,6 +439,26 @@ var arr = Module.customSections(m, "name");
assertEq(arr.length, 1);
assertEq(arr[0].byteLength, nameSec.body.length - 5 /* 4name */);
// Test name/custom section warnings:
const nameWarning = /validated with warning.*'name' custom section/;
const okNameSec = nameSection([]);
assertNoWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, okNameSec])));
const badNameSec1 = nameSection([]);
badNameSec1.body.push(1);
assertWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, badNameSec1])), nameWarning);
const badNameSec2 = nameSection([funcNameSubsection([{name:'blah'}])]);
badNameSec2.body.push(100, 20, 42, 83);
assertWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, badNameSec2])), nameWarning);
const badNameSec3 = nameSection([funcNameSubsection([{name:'blah'}])]);
badNameSec3.body.pop();
assertWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, badNameSec3])), nameWarning);
assertNoWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi')])])));
assertWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), moduleNameSubsection('boo')])])), nameWarning);
// Unknown name subsection
assertNoWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), [4, 0]])])));
assertWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), [4, 1]])])), nameWarning);
assertNoWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), [4, 1, 42]])])));
// Diagnose nonstandard block signature types.
for (var bad of [0xff, 0, 1, 0x3f])
assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[BlockCode, bad, EndCode]})])])), CompileError, /invalid inline block type/);
@ -499,8 +526,14 @@ function runStackTraceTest(moduleName, funcNames, expectedName) {
customSection("whoa"),
customSection("wee", 42),
];
if (moduleName || funcNames)
sections.push(nameSection(moduleName, funcNames));
if (moduleName || funcNames) {
var subsections = [];
if (moduleName)
subsections.push(moduleNameSubsection(moduleName));
if (funcNames)
subsections.push(funcNameSubsection(funcNames));
sections.push(nameSection(subsections));
}
sections.push(customSection("yay", 13));
var result = "";

View File

@ -62,9 +62,9 @@ class JitRuntime
friend class JitCompartment;
// Executable allocator for all code except wasm code.
ActiveThreadData<ExecutableAllocator> execAlloc_;
MainThreadData<ExecutableAllocator> execAlloc_;
ActiveThreadData<uint64_t> nextCompilationId_;
MainThreadData<uint64_t> nextCompilationId_;
// Shared exception-handler tail.
ExclusiveAccessLockWriteOnceData<uint32_t> exceptionTailOffset_;
@ -138,7 +138,7 @@ class JitRuntime
#ifdef DEBUG
// The number of possible bailing places encounters before forcefully bailing
// in that place. Zero means inactive.
ActiveThreadData<uint32_t> ionBailAfter_;
MainThreadData<uint32_t> ionBailAfter_;
#endif
// Number of Ion compilations which were finished off thread and are
@ -148,8 +148,8 @@ class JitRuntime
// List of Ion compilation waiting to get linked.
using IonBuilderList = mozilla::LinkedList<js::jit::IonBuilder>;
ActiveThreadData<IonBuilderList> ionLazyLinkList_;
ActiveThreadData<size_t> ionLazyLinkListSize_;
MainThreadData<IonBuilderList> ionLazyLinkList_;
MainThreadData<size_t> ionLazyLinkListSize_;
private:
void generateLazyLinkStub(MacroAssembler& masm);

View File

@ -357,6 +357,7 @@ MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 1, JSEXN_TYPEERR, "asm.js link error: {0}
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})")
// wasm
MSG_DEF(JSMSG_WASM_COMPILE_WARNING, 1, JSEXN_WARN, "WebAssembly module validated with warning: {0}")
MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}")
MSG_DEF(JSMSG_WASM_NO_SHMEM_COMPILE, 0, JSEXN_WASMCOMPILEERROR, "shared memory is disabled")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}")

View File

@ -111,7 +111,7 @@ BEGIN_TEST(testGCFinalizeCallback)
while (cx->runtime()->gc.isIncrementalGCInProgress())
cx->runtime()->gc.debugGCSlice(budget);
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
CHECK(checkMultipleGroups());
CHECK(checkSingleGroup());
CHECK(checkFinalizeStatus());
JS_SetGCZeal(cx, 0, 0);

View File

@ -1339,6 +1339,20 @@ JS::detail::ComputeThis(JSContext* cx, Value* vp, MutableHandleObject thisObject
return true;
}
static bool gProfileTimelineRecordingEnabled = false;
JS_PUBLIC_API(void)
JS::SetProfileTimelineRecordingEnabled(bool enabled)
{
gProfileTimelineRecordingEnabled = enabled;
}
JS_PUBLIC_API(bool)
JS::IsProfileTimelineRecordingEnabled()
{
return gProfileTimelineRecordingEnabled;
}
JS_PUBLIC_API(void*)
JS_malloc(JSContext* cx, size_t nbytes)
{
@ -1640,7 +1654,7 @@ JS_SetNativeStackQuota(JSContext* cx, size_t systemCodeStackSize, size_t trusted
SetNativeStackQuotaAndLimit(cx, JS::StackForTrustedScript, trustedScriptStackSize);
SetNativeStackQuotaAndLimit(cx, JS::StackForUntrustedScript, untrustedScriptStackSize);
if (cx->isCooperativelyScheduled())
if (cx->isMainThreadContext())
cx->initJitStackLimit();
}
@ -5205,7 +5219,8 @@ JS::RejectPromise(JSContext* cx, JS::HandleObject promiseObj, JS::HandleValue re
static bool
CallOriginalPromiseThenImpl(JSContext* cx, JS::HandleObject promiseObj,
JS::HandleObject onResolvedObj_, JS::HandleObject onRejectedObj_,
JS::MutableHandleObject resultObj, bool createDependent)
JS::MutableHandleObject resultObj,
CreateDependentPromise createDependent)
{
AssertHeapIsIdle();
CHECK_REQUEST(cx);
@ -5254,8 +5269,11 @@ JS::CallOriginalPromiseThen(JSContext* cx, JS::HandleObject promiseObj,
JS::HandleObject onResolvedObj, JS::HandleObject onRejectedObj)
{
RootedObject resultPromise(cx);
if (!CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise, true))
if (!CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise,
CreateDependentPromise::Always))
{
return nullptr;
}
return resultPromise;
}
@ -5264,7 +5282,8 @@ JS::AddPromiseReactions(JSContext* cx, JS::HandleObject promiseObj,
JS::HandleObject onResolvedObj, JS::HandleObject onRejectedObj)
{
RootedObject resultPromise(cx);
bool result = CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise, false);
bool result = CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj,
&resultPromise, CreateDependentPromise::Never);
MOZ_ASSERT(!resultPromise);
return result;
}

View File

@ -1502,6 +1502,22 @@ JS_DefineProfilingFunctions(JSContext* cx, JS::HandleObject obj);
extern JS_PUBLIC_API(bool)
JS_DefineDebuggerObject(JSContext* cx, JS::HandleObject obj);
namespace JS {
/**
* Tell JS engine whether Profile Timeline Recording is enabled or not.
* If Profile Timeline Recording is enabled, data shown there like stack won't
* be optimized out.
* This is global state and not associated with specific runtime or context.
*/
extern JS_PUBLIC_API(void)
SetProfileTimelineRecordingEnabled(bool enabled);
extern JS_PUBLIC_API(bool)
IsProfileTimelineRecordingEnabled();
} // namespace JS
#ifdef JS_HAS_CTYPES
/**
* Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes'

View File

@ -431,7 +431,7 @@ ForgetSourceHook(JSContext* cx);
* right time(s), such as after evaluation of a script has run to completion.
*/
extern JS_FRIEND_API(bool)
UseInternalJobQueues(JSContext* cx, bool cooperative = false);
UseInternalJobQueues(JSContext* cx);
/**
* Enqueue |job| on the internal job queue.

View File

@ -402,7 +402,6 @@ UNIFIED_SOURCES += [
'vm/Xdr.cpp',
'wasm/AsmJS.cpp',
'wasm/WasmBaselineCompile.cpp',
'wasm/WasmBinaryIterator.cpp',
'wasm/WasmBinaryToAST.cpp',
'wasm/WasmBinaryToText.cpp',
'wasm/WasmBuiltins.cpp',
@ -416,6 +415,7 @@ UNIFIED_SOURCES += [
'wasm/WasmIonCompile.cpp',
'wasm/WasmJS.cpp',
'wasm/WasmModule.cpp',
'wasm/WasmOpIter.cpp',
'wasm/WasmProcess.cpp',
'wasm/WasmSignalHandlers.cpp',
'wasm/WasmStubs.cpp',

View File

@ -3548,14 +3548,11 @@ WorkerMain(void* arg)
js_delete(input);
});
if (input->parentRuntime)
sc->isWorker = true;
JS_SetContextPrivate(cx, sc);
SetWorkerContextOptions(cx);
JS::SetBuildIdOp(cx, ShellBuildId);
Maybe<EnvironmentPreparer> environmentPreparer;
if (input->parentRuntime) {
JS_SetFutexCanWait(cx);
JS::SetWarningReporter(cx, WarningReporter);
js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
@ -3566,16 +3563,7 @@ WorkerMain(void* arg)
if (!JS::InitSelfHostedCode(cx))
return;
environmentPreparer.emplace(cx);
} else {
JS_AddInterruptCallback(cx, ShellInterruptCallback);
js::UseInternalJobQueues(cx, /* cooperative = */true);
// The Gecko Profiler requires that all cooperating contexts have
// profiling stacks installed.
MOZ_ALWAYS_TRUE(EnsureGeckoProfilingStackInstalled(cx, sc));
}
EnvironmentPreparer environmentPreparer(cx);
do {
JSAutoRequest ar(cx);
@ -8627,11 +8615,10 @@ SetWorkerContextOptions(JSContext* cx)
#ifdef JS_GC_ZEAL
if (gZealBits && gZealFrequency) {
#define ZEAL_MODE(_, value) \
if (gZealBits & (1 << value)) \
cx->runtime()->gc.setZeal(value, gZealFrequency);
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
#undef ZEAL_MODE
for (size_t i = 0; i < size_t(gc::ZealMode::Count); i++) {
if (gZealBits & (1 << i))
cx->runtime()->gc.setZeal(i, gZealFrequency);
}
}
#endif
@ -8863,6 +8850,8 @@ main(int argc, char** argv, char** envp)
"instantiation on completion of tier2")
#ifdef ENABLE_WASM_GC
|| !op.addBoolOption('\0', "wasm-gc", "Enable wasm GC features")
#else
|| !op.addBoolOption('\0', "wasm-gc", "No-op")
#endif
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|| !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")

View File

@ -38,19 +38,14 @@ CheckThreadLocal::check() const
{
JSContext* cx = TlsContext.get();
MOZ_ASSERT(cx);
// As for CheckZone, in a cooperatively scheduled runtime the active
// thread is permitted access to thread local state for other suspended
// threads in the same runtime.
if (cx->isCooperativelyScheduled())
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
else
MOZ_ASSERT_IF(cx->isMainThreadContext(),
CurrentThreadCanAccessRuntime(cx->runtime()));
MOZ_ASSERT(id == ThisThread::GetId());
}
template <AllowedHelperThread Helper>
void
CheckActiveThread<Helper>::check() const
CheckMainThread<Helper>::check() const
{
if (OnHelperThread<Helper>())
return;
@ -59,9 +54,9 @@ CheckActiveThread<Helper>::check() const
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
}
template class CheckActiveThread<AllowedHelperThread::None>;
template class CheckActiveThread<AllowedHelperThread::GCTask>;
template class CheckActiveThread<AllowedHelperThread::IonCompile>;
template class CheckMainThread<AllowedHelperThread::None>;
template class CheckMainThread<AllowedHelperThread::GCTask>;
template class CheckMainThread<AllowedHelperThread::IonCompile>;
template <AllowedHelperThread Helper>
void

View File

@ -189,7 +189,7 @@ class CheckThreadLocal
// Data which may only be accessed by the thread on which it is created.
template <typename T>
using ThreadLocalData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;
using ThreadData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;
// Enum describing which helper threads (GC tasks or Ion compilations) may
// access data even though they do not have exclusive access to any zone.
@ -202,26 +202,25 @@ enum class AllowedHelperThread
};
template <AllowedHelperThread Helper>
class CheckActiveThread
class CheckMainThread
{
public:
void check() const;
};
// Data which may only be accessed by the runtime's cooperatively scheduled
// active thread.
// Data which may only be accessed by the runtime's main thread.
template <typename T>
using ActiveThreadData =
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::None>, T>;
using MainThreadData =
ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::None>, T>;
// Data which may only be accessed by the runtime's cooperatively scheduled
// active thread, or by various helper thread tasks.
// Data which may only be accessed by the runtime's main thread or by various
// helper thread tasks.
template <typename T>
using ActiveThreadOrGCTaskData =
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::GCTask>, T>;
using MainThreadOrGCTaskData =
ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::GCTask>, T>;
template <typename T>
using ActiveThreadOrIonCompileData =
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::IonCompile>, T>;
using MainThreadOrIonCompileData =
ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::IonCompile>, T>;
template <AllowedHelperThread Helper>
class CheckZone

View File

@ -2224,7 +2224,7 @@ HelperThread::threadLoop()
JSContext cx(nullptr, JS::ContextOptions());
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!cx.init(ContextKind::Background))
if (!cx.init(ContextKind::HelperThread))
oomUnsafe.crash("HelperThread cx.init()");
}
cx.setHelperThread(this);

View File

@ -100,7 +100,7 @@ bool
JSContext::init(ContextKind kind)
{
// Skip most of the initialization if this thread will not be running JS.
if (kind == ContextKind::Cooperative) {
if (kind == ContextKind::MainThread) {
if (!regexpStack.ref().init())
return false;
@ -153,7 +153,7 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
return nullptr;
}
if (!cx->init(ContextKind::Cooperative)) {
if (!cx->init(ContextKind::MainThread)) {
runtime->destroyRuntime();
js_delete(cx);
js_delete(runtime);
@ -1071,11 +1071,11 @@ class MOZ_STACK_CLASS ReportExceptionClosure : public ScriptEnvironmentPreparer:
} // anonymous namespace
JS_FRIEND_API(bool)
js::UseInternalJobQueues(JSContext* cx, bool cooperative)
js::UseInternalJobQueues(JSContext* cx)
{
// Internal job queue handling must be set up very early. Self-hosting
// initialization is as good a marker for that as any.
MOZ_RELEASE_ASSERT(cooperative || !cx->runtime()->hasInitializedSelfHosting(),
MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
"js::UseInternalJobQueues must be called early during runtime startup.");
MOZ_ASSERT(!cx->jobQueue);
auto* queue = js_new<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
@ -1084,7 +1084,6 @@ js::UseInternalJobQueues(JSContext* cx, bool cooperative)
cx->jobQueue = queue;
if (!cooperative)
cx->runtime()->offThreadPromiseState.ref().initInternalDispatchQueue();
MOZ_ASSERT(cx->runtime()->offThreadPromiseState.ref().initialized());
@ -1218,7 +1217,7 @@ JSContext::alreadyReportedError()
JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
: runtime_(runtime),
kind_(ContextKind::Background),
kind_(ContextKind::HelperThread),
helperThread_(nullptr),
options_(options),
arenas_(nullptr),
@ -1316,7 +1315,7 @@ JSContext::~JSContext()
{
// Clear the ContextKind first, so that ProtectedData checks will allow us to
// destroy this context even if the runtime is already gone.
kind_ = ContextKind::Background;
kind_ = ContextKind::HelperThread;
/* Free the stuff hanging off of cx. */
MOZ_ASSERT(!resolvingList);

View File

@ -80,8 +80,11 @@ extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
enum class ContextKind
{
Cooperative,
Background
// Context for the main thread of a JSRuntime.
MainThread,
// Context for a helper thread.
HelperThread
};
#ifdef DEBUG
@ -108,21 +111,21 @@ struct JSContext : public JS::RootingContext,
js::WriteOnceData<js::ContextKind> kind_;
// The thread on which this context is running if this is not the main thread.
js::ThreadLocalData<js::HelperThread*> helperThread_;
js::ThreadData<js::HelperThread*> helperThread_;
friend class js::gc::AutoSuppressNurseryCellAlloc;
js::ThreadLocalData<size_t> nurserySuppressions_;
js::ThreadData<size_t> nurserySuppressions_;
js::ThreadLocalData<JS::ContextOptions> options_;
js::ThreadData<JS::ContextOptions> options_;
js::ThreadLocalData<js::gc::ArenaLists*> arenas_;
js::ThreadData<js::gc::ArenaLists*> arenas_;
public:
// This is used by helper threads to change the runtime their context is
// currently operating on.
void setRuntime(JSRuntime* rt);
bool isCooperativelyScheduled() const { return kind_ == js::ContextKind::Cooperative; }
bool isMainThreadContext() const { return kind_ == js::ContextKind::MainThread; }
inline js::gc::ArenaLists* arenas() const { return arenas_; }
@ -192,7 +195,7 @@ struct JSContext : public JS::RootingContext,
* manually calling cx->enterCompartment/leaveCompartment.
*/
protected:
js::ThreadLocalData<unsigned> enterCompartmentDepth_;
js::ThreadData<unsigned> enterCompartmentDepth_;
inline void setCompartment(JSCompartment* comp,
const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
@ -332,16 +335,16 @@ struct JSContext : public JS::RootingContext,
* Points to the most recent JitActivation pushed on the thread.
* See JitActivation constructor in vm/Stack.cpp
*/
js::ThreadLocalData<js::jit::JitActivation*> jitActivation;
js::ThreadData<js::jit::JitActivation*> jitActivation;
// Information about the heap allocated backtrack stack used by RegExp JIT code.
js::ThreadLocalData<js::irregexp::RegExpStack> regexpStack;
js::ThreadData<js::irregexp::RegExpStack> regexpStack;
/*
* Points to the most recent activation running on the thread.
* See Activation comment in vm/Stack.h.
*/
js::ThreadLocalData<js::Activation*> activation_;
js::ThreadData<js::Activation*> activation_;
/*
* Points to the most recent profiling activation running on the
@ -376,7 +379,7 @@ struct JSContext : public JS::RootingContext,
private:
/* Space for interpreter frames. */
js::ThreadLocalData<js::InterpreterStack> interpreterStack_;
js::ThreadData<js::InterpreterStack> interpreterStack_;
public:
js::InterpreterStack& interpreterStack() {
@ -387,11 +390,11 @@ struct JSContext : public JS::RootingContext,
const uintptr_t nativeStackBase;
/* The native stack size limit that runtime should not exceed. */
js::ThreadLocalData<size_t> nativeStackQuota[JS::StackKindCount];
js::ThreadData<size_t> nativeStackQuota[JS::StackKindCount];
public:
/* If non-null, report JavaScript entry points to this monitor. */
js::ThreadLocalData<JS::dbg::AutoEntryMonitor*> entryMonitor;
js::ThreadData<JS::dbg::AutoEntryMonitor*> entryMonitor;
/*
* Stack of debuggers that currently disallow debuggee execution.
@ -400,46 +403,46 @@ struct JSContext : public JS::RootingContext,
* stack of Debuggers that have prevented execution need to be tracked to
* enter the correct Debugger compartment to report the error.
*/
js::ThreadLocalData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
js::ThreadData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
js::ThreadLocalData<js::ActivityCallback> activityCallback;
js::ThreadLocalData<void*> activityCallbackArg;
js::ThreadData<js::ActivityCallback> activityCallback;
js::ThreadData<void*> activityCallbackArg;
void triggerActivityCallback(bool active);
/* The request depth for this thread. */
js::ThreadLocalData<unsigned> requestDepth;
js::ThreadData<unsigned> requestDepth;
#ifdef DEBUG
js::ThreadLocalData<unsigned> checkRequestDepth;
js::ThreadLocalData<uint32_t> inUnsafeCallWithABI;
js::ThreadLocalData<bool> hasAutoUnsafeCallWithABI;
js::ThreadData<unsigned> checkRequestDepth;
js::ThreadData<uint32_t> inUnsafeCallWithABI;
js::ThreadData<bool> hasAutoUnsafeCallWithABI;
#endif
#ifdef JS_SIMULATOR
private:
js::ThreadLocalData<js::jit::Simulator*> simulator_;
js::ThreadData<js::jit::Simulator*> simulator_;
public:
js::jit::Simulator* simulator() const;
uintptr_t* addressOfSimulatorStackLimit();
#endif
#ifdef JS_TRACE_LOGGING
js::ThreadLocalData<js::TraceLoggerThread*> traceLogger;
js::ThreadData<js::TraceLoggerThread*> traceLogger;
#endif
private:
/* Pointer to the current AutoFlushICache. */
js::ThreadLocalData<js::jit::AutoFlushICache*> autoFlushICache_;
js::ThreadData<js::jit::AutoFlushICache*> autoFlushICache_;
public:
js::jit::AutoFlushICache* autoFlushICache() const;
void setAutoFlushICache(js::jit::AutoFlushICache* afc);
// State used by util/DoubleToString.cpp.
js::ThreadLocalData<DtoaState*> dtoaState;
js::ThreadData<DtoaState*> dtoaState;
// Any GC activity occurring on this thread.
js::ThreadLocalData<JS::HeapState> heapState;
js::ThreadData<JS::HeapState> heapState;
/*
* When this flag is non-zero, any attempt to GC will be skipped. It is used
@ -449,37 +452,37 @@ struct JSContext : public JS::RootingContext,
* extremely dangerous and should only be used when in an OOM situation or
* in non-exposed debugging facilities.
*/
js::ThreadLocalData<int32_t> suppressGC;
js::ThreadData<int32_t> suppressGC;
#ifdef DEBUG
// Whether this thread is actively Ion compiling.
js::ThreadLocalData<bool> ionCompiling;
js::ThreadData<bool> ionCompiling;
// Whether this thread is actively Ion compiling in a context where a minor
// GC could happen simultaneously. If this is true, this thread cannot use
// any pointers into the nursery.
js::ThreadLocalData<bool> ionCompilingSafeForMinorGC;
js::ThreadData<bool> ionCompilingSafeForMinorGC;
// Whether this thread is currently performing GC. This thread could be the
// active thread or a helper thread while the active thread is running the
// collector.
js::ThreadLocalData<bool> performingGC;
js::ThreadData<bool> performingGC;
// Whether this thread is currently sweeping GC things. This thread could
// be the active thread or a helper thread while the active thread is running
// the mutator. This is used to assert that destruction of GCPtr only
// happens when we are sweeping.
js::ThreadLocalData<bool> gcSweeping;
js::ThreadData<bool> gcSweeping;
// Whether this thread is performing work in the background for a runtime's
// GCHelperState.
js::ThreadLocalData<bool> gcHelperStateThread;
js::ThreadData<bool> gcHelperStateThread;
// Whether this thread is currently manipulating possibly-gray GC things.
js::ThreadLocalData<size_t> isTouchingGrayThings;
js::ThreadData<size_t> isTouchingGrayThings;
js::ThreadLocalData<size_t> noGCOrAllocationCheck;
js::ThreadLocalData<size_t> noNurseryAllocationCheck;
js::ThreadData<size_t> noGCOrAllocationCheck;
js::ThreadData<size_t> noNurseryAllocationCheck;
/*
* If this is 0, all cross-compartment proxies must be registered in the
@ -487,7 +490,7 @@ struct JSContext : public JS::RootingContext,
* new wrappers. When non-zero, this records the recursion depth of wrapper
* creation.
*/
js::ThreadLocalData<uintptr_t> disableStrictProxyCheckingCount;
js::ThreadData<uintptr_t> disableStrictProxyCheckingCount;
bool isAllocAllowed() { return noGCOrAllocationCheck == 0; }
void disallowAlloc() { ++noGCOrAllocationCheck; }
@ -513,13 +516,13 @@ struct JSContext : public JS::RootingContext,
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
// We are currently running a simulated OOM test.
js::ThreadLocalData<bool> runningOOMTest;
js::ThreadData<bool> runningOOMTest;
#endif
// True if we should assert that
// !comp->validAccessPtr || *comp->validAccessPtr
// is true for every |comp| that we run JS code in.
js::ThreadLocalData<unsigned> enableAccessValidation;
js::ThreadData<unsigned> enableAccessValidation;
/*
* Some regions of code are hard for the static rooting hazard analysis to
@ -527,14 +530,14 @@ struct JSContext : public JS::RootingContext,
* analysis. When this is non-zero, we should assert if we trigger, or
* might trigger, a GC.
*/
js::ThreadLocalData<int> inUnsafeRegion;
js::ThreadData<int> inUnsafeRegion;
// Count of AutoDisableGenerationalGC instances on the thread's stack.
js::ThreadLocalData<unsigned> generationalDisabled;
js::ThreadData<unsigned> generationalDisabled;
// Some code cannot tolerate compacting GC so it can be disabled temporarily
// with AutoDisableCompactingGC which uses this counter.
js::ThreadLocalData<unsigned> compactingDisabledCount;
js::ThreadData<unsigned> compactingDisabledCount;
// Count of AutoKeepAtoms instances on the current thread's stack. When any
// instances exist, atoms in the runtime will not be collected. Threads
@ -545,7 +548,7 @@ struct JSContext : public JS::RootingContext,
// their exclusive compartment (which is not collected) or to the atoms
// compartment. Therefore, we avoid collecting the atoms compartment when
// exclusive threads are running.
js::ThreadLocalData<unsigned> keepAtoms;
js::ThreadData<unsigned> keepAtoms;
bool canCollectAtoms() const {
return !keepAtoms && !runtime()->hasHelperThreadZones();
@ -555,7 +558,7 @@ struct JSContext : public JS::RootingContext,
// Pools used for recycling name maps and vectors when parsing and
// emitting bytecode. Purged on GC when there are no active script
// compilations.
js::ThreadLocalData<js::frontend::NameCollectionPool> frontendCollectionPool_;
js::ThreadData<js::frontend::NameCollectionPool> frontendCollectionPool_;
public:
js::frontend::NameCollectionPool& frontendCollectionPool() {
@ -589,20 +592,20 @@ struct JSContext : public JS::RootingContext,
/* Temporary arena pool used while compiling and decompiling. */
static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
private:
js::ThreadLocalData<js::LifoAlloc> tempLifoAlloc_;
js::ThreadData<js::LifoAlloc> tempLifoAlloc_;
public:
js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
js::ThreadLocalData<uint32_t> debuggerMutations;
js::ThreadData<uint32_t> debuggerMutations;
// Cache for jit::GetPcScript().
js::ThreadLocalData<js::jit::PcScriptCache*> ionPcScriptCache;
js::ThreadData<js::jit::PcScriptCache*> ionPcScriptCache;
private:
/* Exception state -- the exception member is a GC root by definition. */
js::ThreadLocalData<bool> throwing; /* is there a pending exception? */
js::ThreadLocalData<JS::PersistentRooted<JS::Value>> unwrappedException_; /* most-recently-thrown exception */
js::ThreadData<bool> throwing; /* is there a pending exception? */
js::ThreadData<JS::PersistentRooted<JS::Value>> unwrappedException_; /* most-recently-thrown exception */
JS::Value& unwrappedException() {
if (!unwrappedException_.ref().initialized())
@ -612,32 +615,32 @@ struct JSContext : public JS::RootingContext,
// True if the exception currently being thrown is by result of
// ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
js::ThreadLocalData<bool> overRecursed_;
js::ThreadData<bool> overRecursed_;
// True if propagating a forced return from an interrupt handler during
// debug mode.
js::ThreadLocalData<bool> propagatingForcedReturn_;
js::ThreadData<bool> propagatingForcedReturn_;
// A stack of live iterators that need to be updated in case of debug mode
// OSR.
js::ThreadLocalData<js::jit::DebugModeOSRVolatileJitFrameIter*>
js::ThreadData<js::jit::DebugModeOSRVolatileJitFrameIter*>
liveVolatileJitFrameIter_;
public:
js::ThreadLocalData<int32_t> reportGranularity; /* see vm/Probes.h */
js::ThreadData<int32_t> reportGranularity; /* see vm/Probes.h */
js::ThreadLocalData<js::AutoResolving*> resolvingList;
js::ThreadData<js::AutoResolving*> resolvingList;
#ifdef DEBUG
js::ThreadLocalData<js::AutoEnterPolicy*> enteredPolicy;
js::ThreadData<js::AutoEnterPolicy*> enteredPolicy;
#endif
/* True if generating an error, to prevent runaway recursion. */
js::ThreadLocalData<bool> generatingError;
js::ThreadData<bool> generatingError;
private:
/* State for object and array toSource conversion. */
js::ThreadLocalData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
js::ThreadData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
public:
js::AutoCycleDetector::Vector& cycleDetectorVector() {
@ -663,9 +666,9 @@ struct JSContext : public JS::RootingContext,
}
// Number of JS_BeginRequest calls without the corresponding JS_EndRequest.
js::ThreadLocalData<unsigned> outstandingRequests;
js::ThreadData<unsigned> outstandingRequests;
js::ThreadLocalData<bool> jitIsBroken;
js::ThreadData<bool> jitIsBroken;
void updateJITEnabled();
@ -679,7 +682,7 @@ struct JSContext : public JS::RootingContext,
* New activations will reset this to nullptr on construction after getting
* the current value, and will restore the previous value on destruction.
*/
js::ThreadLocalData<JS::PersistentRooted<js::SavedFrame*>> asyncStackForNewActivations_;
js::ThreadData<JS::PersistentRooted<js::SavedFrame*>> asyncStackForNewActivations_;
public:
js::SavedFrame*& asyncStackForNewActivations() {
@ -691,13 +694,13 @@ struct JSContext : public JS::RootingContext,
/*
* Value of asyncCause to be attached to asyncStackForNewActivations.
*/
js::ThreadLocalData<const char*> asyncCauseForNewActivations;
js::ThreadData<const char*> asyncCauseForNewActivations;
/*
* True if the async call was explicitly requested, e.g. via
* callFunctionWithAsyncStack.
*/
js::ThreadLocalData<bool> asyncCallIsExplicit;
js::ThreadData<bool> asyncCallIsExplicit;
bool currentlyRunningInInterpreter() const {
return activation()->isInterpreter();
@ -778,11 +781,11 @@ struct JSContext : public JS::RootingContext,
using InterruptCallbackVector = js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
private:
js::ThreadLocalData<InterruptCallbackVector> interruptCallbacks_;
js::ThreadData<InterruptCallbackVector> interruptCallbacks_;
public:
InterruptCallbackVector& interruptCallbacks() { return interruptCallbacks_.ref(); }
js::ThreadLocalData<bool> interruptCallbackDisabled;
js::ThreadData<bool> interruptCallbackDisabled;
mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptRegExpJit_;
@ -838,7 +841,7 @@ struct JSContext : public JS::RootingContext,
// Buffer for OSR from baseline to Ion. To avoid holding on to this for
// too long, it's also freed in EnterBaseline (after returning from JIT code).
js::ThreadLocalData<uint8_t*> osrTempData_;
js::ThreadData<uint8_t*> osrTempData_;
uint8_t* allocateOsrTempData(size_t size);
void freeOsrTempData();
@ -855,7 +858,7 @@ struct JSContext : public JS::RootingContext,
// value that will be temporarily corrupt. This special override value is set
// only in callVM() targets that are about to return *and* have invalidated
// their callee.
js::ThreadLocalData<js::Value> ionReturnOverride_;
js::ThreadData<js::Value> ionReturnOverride_;
bool hasIonReturnOverride() const {
return !ionReturnOverride_.ref().isMagic(JS_ARG_POISON);
@ -874,22 +877,22 @@ struct JSContext : public JS::RootingContext,
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
// Like jitStackLimit, but not reset to trigger interrupts.
js::ThreadLocalData<uintptr_t> jitStackLimitNoInterrupt;
js::ThreadData<uintptr_t> jitStackLimitNoInterrupt;
// Promise callbacks.
js::ThreadLocalData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
js::ThreadLocalData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
js::ThreadLocalData<void*> enqueuePromiseJobCallbackData;
js::ThreadData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
js::ThreadData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
js::ThreadData<void*> enqueuePromiseJobCallbackData;
// Queue of pending jobs as described in ES2016 section 8.4.
// Only used if internal job queue handling was activated using
// `js::UseInternalJobQueues`.
js::ThreadLocalData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
js::ThreadLocalData<bool> drainingJobQueue;
js::ThreadLocalData<bool> stopDrainingJobQueue;
js::ThreadData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
js::ThreadData<bool> drainingJobQueue;
js::ThreadData<bool> stopDrainingJobQueue;
js::ThreadLocalData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
js::ThreadLocalData<void*> promiseRejectionTrackerCallbackData;
js::ThreadData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
js::ThreadData<void*> promiseRejectionTrackerCallbackData;
JSObject* getIncumbentGlobal(JSContext* cx);
bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise,

View File

@ -1616,10 +1616,10 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
// Parse and compile the script from source.
size_t lazyLength = lazy->end() - lazy->begin();
size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
UncompressedSourceCache::AutoHoldEntry holder;
ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
lazy->begin(), lazyLength);
lazy->sourceStart(), lazyLength);
if (!chars.get())
return false;

View File

@ -530,6 +530,11 @@ IsNativeFunction(const js::Value& v, JSNative native)
return IsFunctionObject(v, &fun) && fun->maybeNative() == native;
}
static MOZ_ALWAYS_INLINE bool
IsNativeFunction(const JSObject* obj, JSNative native)
{
return obj->is<JSFunction>() && obj->as<JSFunction>().maybeNative() == native;
}
// Return whether looking up a method on 'obj' definitely resolves to the
// original specified native function. The method may conservatively return

View File

@ -244,8 +244,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
uint64_t packedFields;
{
uint32_t begin = script->sourceStart();
uint32_t end = script->sourceEnd();
uint32_t sourceStart = script->sourceStart();
uint32_t sourceEnd = script->sourceEnd();
uint32_t toStringStart = script->toStringStart();
uint32_t toStringEnd = script->toStringEnd();
uint32_t lineno = script->lineno();
@ -253,8 +253,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
if (mode == XDR_ENCODE) {
packedFields = lazy->packedFields();
MOZ_ASSERT(begin == lazy->begin());
MOZ_ASSERT(end == lazy->end());
MOZ_ASSERT(sourceStart == lazy->sourceStart());
MOZ_ASSERT(sourceEnd == lazy->sourceEnd());
MOZ_ASSERT(toStringStart == lazy->toStringStart());
MOZ_ASSERT(toStringEnd == lazy->toStringEnd());
MOZ_ASSERT(lineno == lazy->lineno());
@ -270,7 +270,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
if (mode == XDR_DECODE) {
RootedScriptSource sourceObject(cx, &script->scriptSourceUnwrap());
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
packedFields, begin, end, toStringStart, lineno, column));
packedFields, sourceStart, sourceEnd, toStringStart,
lineno, column));
if (!lazy)
return xdr->fail(JS::TranscodeResult_Throw);
@ -911,8 +912,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
JSContext* cx = xdr->cx();
{
uint32_t begin;
uint32_t end;
uint32_t sourceStart;
uint32_t sourceEnd;
uint32_t toStringStart;
uint32_t toStringEnd;
uint32_t lineno;
@ -926,8 +927,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
MOZ_ASSERT(fun == lazy->functionNonDelazifying());
begin = lazy->begin();
end = lazy->end();
sourceStart = lazy->sourceStart();
sourceEnd = lazy->sourceEnd();
toStringStart = lazy->toStringStart();
toStringEnd = lazy->toStringEnd();
lineno = lazy->lineno();
@ -935,8 +936,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
packedFields = lazy->packedFields();
}
MOZ_TRY(xdr->codeUint32(&begin));
MOZ_TRY(xdr->codeUint32(&end));
MOZ_TRY(xdr->codeUint32(&sourceStart));
MOZ_TRY(xdr->codeUint32(&sourceEnd));
MOZ_TRY(xdr->codeUint32(&toStringStart));
MOZ_TRY(xdr->codeUint32(&toStringEnd));
MOZ_TRY(xdr->codeUint32(&lineno));
@ -945,7 +946,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
if (mode == XDR_DECODE) {
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
packedFields, begin, end, toStringStart, lineno, column));
packedFields, sourceStart, sourceEnd, toStringStart,
lineno, column));
if (!lazy)
return xdr->fail(JS::TranscodeResult_Throw);
lazy->setToStringEnd(toStringEnd);
@ -4173,7 +4175,7 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
}
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
uint32_t begin, uint32_t end,
uint32_t sourceStart, uint32_t sourceEnd,
uint32_t toStringStart, uint32_t lineno, uint32_t column)
: script_(nullptr),
function_(fun),
@ -4181,15 +4183,15 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
sourceObject_(nullptr),
table_(table),
packedFields_(packedFields),
begin_(begin),
end_(end),
sourceStart_(sourceStart),
sourceEnd_(sourceEnd),
toStringStart_(toStringStart),
toStringEnd_(end),
toStringEnd_(sourceEnd),
lineno_(lineno),
column_(column)
{
MOZ_ASSERT(begin <= end);
MOZ_ASSERT(toStringStart <= begin);
MOZ_ASSERT(sourceStart <= sourceEnd);
MOZ_ASSERT(toStringStart <= sourceStart);
}
void
@ -4235,7 +4237,7 @@ LazyScript::maybeForwardedScriptSource() const
/* static */ LazyScript*
LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
uint64_t packedFields, uint32_t begin, uint32_t end,
uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
uint32_t toStringStart, uint32_t lineno, uint32_t column)
{
union {
@ -4264,7 +4266,7 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
cx->compartment()->scheduleDelazificationForDebugger();
return new (res) LazyScript(fun, table.forget(), packed, begin, end,
return new (res) LazyScript(fun, table.forget(), packed, sourceStart, sourceEnd,
toStringStart, lineno, column);
}
@ -4272,7 +4274,7 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
LazyScript::Create(JSContext* cx, HandleFunction fun,
const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions,
uint32_t begin, uint32_t end,
uint32_t sourceStart, uint32_t sourceEnd,
uint32_t toStringStart, uint32_t lineno, uint32_t column)
{
union {
@ -4295,8 +4297,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
p.isDerivedClassConstructor = false;
p.needsHomeObject = false;
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
lineno, column);
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, sourceStart, sourceEnd,
toStringStart, lineno, column);
if (!res)
return nullptr;
@ -4315,7 +4317,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
LazyScript::Create(JSContext* cx, HandleFunction fun,
HandleScript script, HandleScope enclosingScope,
HandleScriptSource sourceObject,
uint64_t packedFields, uint32_t begin, uint32_t end,
uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
uint32_t toStringStart, uint32_t lineno, uint32_t column)
{
// Dummy atom which is not a valid property name.
@ -4325,8 +4327,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
// holding this lazy script.
HandleFunction dummyFun = fun;
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
lineno, column);
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, sourceStart, sourceEnd,
toStringStart, lineno, column);
if (!res)
return nullptr;

View File

@ -2145,8 +2145,8 @@ class LazyScript : public gc::TenuredCell
// Source location for the script.
// See the comment in JSScript for the details
uint32_t begin_;
uint32_t end_;
uint32_t sourceStart_;
uint32_t sourceEnd_;
uint32_t toStringStart_;
uint32_t toStringEnd_;
// Line and column of |begin_| position, that is the position where we
@ -2352,11 +2352,11 @@ class LazyScript : public gc::TenuredCell
const char* filename() const {
return scriptSource()->filename();
}
uint32_t begin() const {
return begin_;
uint32_t sourceStart() const {
return sourceStart_;
}
uint32_t end() const {
return end_;
uint32_t sourceEnd() const {
return sourceEnd_;
}
uint32_t toStringStart() const {
return toStringStart_;
@ -2373,7 +2373,7 @@ class LazyScript : public gc::TenuredCell
void setToStringEnd(uint32_t toStringEnd) {
MOZ_ASSERT(toStringStart_ <= toStringEnd);
MOZ_ASSERT(toStringEnd_ >= end_);
MOZ_ASSERT(toStringEnd_ >= sourceEnd_);
toStringEnd_ = toStringEnd;
}

View File

@ -18,7 +18,6 @@
_(TestMutex, 100) \
_(ShellContextWatchdog, 100) \
_(ShellWorkerThreads, 100) \
_(ShellThreadCooperation, 100) \
_(ShellArrayBufferMailbox, 100) \
\
_(RuntimeExclusiveAccess, 200) \

View File

@ -160,8 +160,8 @@ ObjectGroup::useSingletonForClone(JSFunction* fun)
} else {
if (!fun->lazyScript()->isLikelyConstructorWrapper())
return false;
begin = fun->lazyScript()->begin();
end = fun->lazyScript()->end();
begin = fun->lazyScript()->sourceStart();
end = fun->lazyScript()->sourceEnd();
}
return end - begin <= 100;

View File

@ -301,10 +301,10 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
}
/* Call this to accumulate telemetry data. */
js::ActiveThreadData<JSAccumulateTelemetryDataCallback> telemetryCallback;
js::MainThreadData<JSAccumulateTelemetryDataCallback> telemetryCallback;
/* Call this to accumulate use counter data. */
js::ActiveThreadData<JSSetUseCounterCallback> useCounterCallback;
js::MainThreadData<JSSetUseCounterCallback> useCounterCallback;
public:
// Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
@ -345,35 +345,35 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
* Allow relazifying functions in compartments that are active. This is
* only used by the relazifyFunctions() testing function.
*/
js::ActiveThreadData<bool> allowRelazificationForTesting;
js::MainThreadData<bool> allowRelazificationForTesting;
/* Compartment destroy callback. */
js::ActiveThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
js::MainThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
/* Compartment memory reporting callback. */
js::ActiveThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
js::MainThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
/* Call this to get the name of a compartment. */
js::ActiveThreadData<JSCompartmentNameCallback> compartmentNameCallback;
js::MainThreadData<JSCompartmentNameCallback> compartmentNameCallback;
/* Realm destroy callback. */
js::ActiveThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
js::MainThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
/* Call this to get the name of a realm. */
js::ActiveThreadData<JS::RealmNameCallback> realmNameCallback;
js::MainThreadData<JS::RealmNameCallback> realmNameCallback;
/* Callback for doing memory reporting on external strings. */
js::ActiveThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
js::MainThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
js::ActiveThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
js::MainThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
js::ActiveThreadData<const JSSecurityCallbacks*> securityCallbacks;
js::ActiveThreadData<const js::DOMCallbacks*> DOMcallbacks;
js::ActiveThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
js::ActiveThreadData<JSReadPrincipalsOp> readPrincipals;
js::MainThreadData<const JSSecurityCallbacks*> securityCallbacks;
js::MainThreadData<const js::DOMCallbacks*> DOMcallbacks;
js::MainThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
js::MainThreadData<JSReadPrincipalsOp> readPrincipals;
/* Optional warning reporter. */
js::ActiveThreadData<JS::WarningReporter> warningReporter;
js::MainThreadData<JS::WarningReporter> warningReporter;
private:
/* Gecko profiling metadata */
@ -382,7 +382,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
js::GeckoProfilerRuntime& geckoProfiler() { return geckoProfiler_.ref(); }
// Heap GC roots for PersistentRooted pointers.
js::ActiveThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
js::MainThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
mozilla::LinkedList<JS::PersistentRooted<void*>>>> heapRoots;
void tracePersistentRoots(JSTracer* trc);
@ -402,12 +402,12 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
js::ActiveThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
js::ActiveThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
js::MainThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
js::MainThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
js::ActiveThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
js::MainThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
js::ActiveThreadData<js::CTypesActivityCallback> ctypesActivityCallback;
js::MainThreadData<js::CTypesActivityCallback> ctypesActivityCallback;
private:
js::WriteOnceData<const js::Class*> windowProxyClass_;
@ -422,7 +422,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
private:
// List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup.
js::ActiveThreadData<mozilla::LinkedList<JS::detail::WeakCacheBase>> weakCaches_;
js::MainThreadData<mozilla::LinkedList<JS::detail::WeakCacheBase>> weakCaches_;
public:
mozilla::LinkedList<JS::detail::WeakCacheBase>& weakCaches() { return weakCaches_.ref(); }
void registerWeakCache(JS::detail::WeakCacheBase* cachep) {
@ -444,14 +444,14 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
* List of all enabled Debuggers that have onNewGlobalObject handler
* methods established.
*/
js::ActiveThreadData<WatchersList> onNewGlobalObjectWatchers_;
js::MainThreadData<WatchersList> onNewGlobalObjectWatchers_;
public:
WatchersList& onNewGlobalObjectWatchers() { return onNewGlobalObjectWatchers_.ref(); }
private:
/* Linked list of all Debugger objects in the runtime. */
js::ActiveThreadData<mozilla::LinkedList<js::Debugger>> debuggerList_;
js::MainThreadData<mozilla::LinkedList<js::Debugger>> debuggerList_;
public:
mozilla::LinkedList<js::Debugger>& debuggerList() { return debuggerList_.ref(); }
@ -480,10 +480,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
bool activeThreadHasScriptDataAccess;
#endif
/*
* Number of zones which may be operated on by non-cooperating helper
* threads.
*/
// Number of zones which may be operated on by helper threads.
mozilla::Atomic<size_t> numActiveHelperThreadZones;
friend class js::AutoLockForExclusiveAccess;
@ -516,19 +513,19 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
// How many compartments there are across all zones. This number includes
// off thread context compartments, so it isn't necessarily equal to the
// number of compartments visited by CompartmentsIter.
js::ActiveThreadData<size_t> numCompartments;
js::MainThreadData<size_t> numCompartments;
/* Locale-specific callbacks for string conversion. */
js::ActiveThreadData<const JSLocaleCallbacks*> localeCallbacks;
js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
/* Default locale for Internationalization API */
js::ActiveThreadData<char*> defaultLocale;
js::MainThreadData<char*> defaultLocale;
/* If true, new scripts must be created with PC counter information. */
js::ActiveThreadOrIonCompileData<bool> profilingScripts;
js::MainThreadOrIonCompileData<bool> profilingScripts;
/* Strong references on scripts held for PCCount profiling API. */
js::ActiveThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
js::MainThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
private:
/* Code coverage output. */
@ -789,7 +786,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
js::WriteOnceData<js::WellKnownSymbols*> wellKnownSymbols;
/* Shared Intl data for this runtime. */
js::ActiveThreadData<js::intl::SharedIntlData> sharedIntlData;
js::MainThreadData<js::intl::SharedIntlData> sharedIntlData;
void traceSharedIntlData(JSTracer* trc);
@ -862,7 +859,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
mozilla::Atomic<bool> parallelParsingEnabled_;
js::ActiveThreadData<bool> autoWritableJitCodeActive_;
js::MainThreadData<bool> autoWritableJitCodeActive_;
public:
@ -887,20 +884,20 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
}
/* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
js::ActiveThreadData<JS::OutOfMemoryCallback> oomCallback;
js::ActiveThreadData<void*> oomCallbackData;
js::MainThreadData<JS::OutOfMemoryCallback> oomCallback;
js::MainThreadData<void*> oomCallbackData;
/*
* Debugger.Memory functions like takeCensus use this embedding-provided
* function to assess the size of malloc'd blocks of memory.
*/
js::ActiveThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
js::MainThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
/* Last time at which an animation was played for this runtime. */
mozilla::Atomic<int64_t> lastAnimationTime;
private:
js::ActiveThreadData<js::PerformanceMonitoring> performanceMonitoring_;
js::MainThreadData<js::PerformanceMonitoring> performanceMonitoring_;
public:
js::PerformanceMonitoring& performanceMonitoring() { return performanceMonitoring_.ref(); }
@ -930,7 +927,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
friend class JS::AutoEnterCycleCollection;
private:
js::ActiveThreadData<js::RuntimeCaches> caches_;
js::MainThreadData<js::RuntimeCaches> caches_;
public:
js::RuntimeCaches& caches() { return caches_.ref(); }

View File

@ -869,7 +869,7 @@ TraceLoggerThreadState::init()
"\n"
"usage: TLOPTIONS=option,option,option,... where options can be:\n"
"\n"
" EnableActiveThread Start logging cooperating threads immediately.\n"
" EnableMainThread Start logging main threads immediately.\n"
" EnableOffThread Start logging helper threads immediately.\n"
" EnableGraph Enable spewing the tracelogging graph to a file.\n"
" Errors Report errors during tracing to stderr.\n"
@ -879,8 +879,8 @@ TraceLoggerThreadState::init()
/*NOTREACHED*/
}
if (strstr(options, "EnableActiveThread"))
cooperatingThreadEnabled = true;
if (strstr(options, "EnableMainThread"))
mainThreadEnabled = true;
if (strstr(options, "EnableOffThread"))
helperThreadEnabled = true;
if (strstr(options, "EnableGraph"))
@ -985,7 +985,7 @@ TraceLoggerThreadState::forCurrentThread(JSContext* maybecx)
if (graphSpewingEnabled)
logger->initGraph();
if (CurrentHelperThread() ? helperThreadEnabled : cooperatingThreadEnabled)
if (CurrentHelperThread() ? helperThreadEnabled : mainThreadEnabled)
logger->enable();
}

View File

@ -378,7 +378,7 @@ class TraceLoggerThreadState
#endif
bool enabledTextIds[TraceLogger_Last];
bool cooperatingThreadEnabled;
bool mainThreadEnabled;
bool helperThreadEnabled;
bool graphSpewingEnabled;
bool spewErrors;
@ -405,7 +405,7 @@ class TraceLoggerThreadState
#ifdef DEBUG
initialized(false),
#endif
cooperatingThreadEnabled(false),
mainThreadEnabled(false),
helperThreadEnabled(false),
graphSpewingEnabled(false),
spewErrors(false),

View File

@ -230,10 +230,10 @@ AutoXDRTree::Key
XDRIncrementalEncoder::getTreeKey(JSFunction* fun) const
{
if (fun->isInterpretedLazy()) {
static_assert(sizeof(fun->lazyScript()->begin()) == 4 ||
sizeof(fun->lazyScript()->end()) == 4,
static_assert(sizeof(fun->lazyScript()->sourceStart()) == 4 ||
sizeof(fun->lazyScript()->sourceEnd()) == 4,
"AutoXDRTree key requires LazyScripts positions to be uint32");
return uint64_t(fun->lazyScript()->begin()) << 32 | fun->lazyScript()->end();
return uint64_t(fun->lazyScript()->sourceStart()) << 32 | fun->lazyScript()->sourceEnd();
}
if (fun->isInterpreted()) {

View File

@ -135,8 +135,8 @@
# include "jit/mips64/Assembler-mips64.h"
#endif
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmGenerator.h"
#include "wasm/WasmOpIter.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmValidate.h"

View File

@ -23,7 +23,7 @@
#include "vm/JSCompartment.h"
#include "vm/JSContext.h"
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmOpIter.h"
#include "wasm/WasmValidate.h"
using namespace js;
@ -2277,7 +2277,7 @@ wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAllo
return false;
UniqueChars error;
Decoder d(bytes, bytes + length, 0, &error, /* resilient */ true);
Decoder d(bytes, bytes + length, 0, &error, nullptr, /* resilient */ true);
AstDecodeContext c(cx, lifo, d, *result, true);
if (!AstDecodeEnvironment(c) ||

View File

@ -24,9 +24,9 @@
#include "jit/ProcessExecutableMemory.h"
#include "util/Text.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmGenerator.h"
#include "wasm/WasmIonCompile.h"
#include "wasm/WasmOpIter.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmValidate.h"
@ -420,11 +420,12 @@ InitialCompileFlags(const CompileArgs& args, Decoder& d, CompileMode* mode, Tier
}
SharedModule
wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error)
wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error,
UniqueCharsVector* warnings)
{
MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
Decoder d(bytecode.bytes, 0, error);
Decoder d(bytecode.bytes, 0, error, warnings);
CompileMode mode;
Tier tier;
@ -486,8 +487,8 @@ class StreamingDecoder
public:
StreamingDecoder(const ModuleEnvironment& env, const Bytes& begin,
const ExclusiveStreamEnd& streamEnd, const Atomic<bool>& cancelled,
UniqueChars* error)
: d_(begin, env.codeSection->start, error),
UniqueChars* error, UniqueCharsVector* warnings)
: d_(begin, env.codeSection->start, error, warnings),
streamEnd_(streamEnd),
cancelled_(cancelled)
{}
@ -567,14 +568,15 @@ wasm::CompileStreaming(const CompileArgs& args,
const ExclusiveStreamEnd& codeStreamEnd,
const ExclusiveTailBytesPtr& tailBytesPtr,
const Atomic<bool>& cancelled,
UniqueChars* error)
UniqueChars* error,
UniqueCharsVector* warnings)
{
MOZ_ASSERT(wasm::HaveSignalHandlers());
Maybe<ModuleEnvironment> env;
{
Decoder d(envBytes, 0, error);
Decoder d(envBytes, 0, error, warnings);
CompileMode mode;
Tier tier;
@ -595,7 +597,7 @@ wasm::CompileStreaming(const CompileArgs& args,
{
MOZ_ASSERT(env->codeSection->size == codeBytes.length());
StreamingDecoder d(*env, codeBytes, codeStreamEnd, cancelled, error);
StreamingDecoder d(*env, codeBytes, codeStreamEnd, cancelled, error, warnings);
if (!DecodeCodeSection(*env, d, mg))
return nullptr;
@ -615,7 +617,7 @@ wasm::CompileStreaming(const CompileArgs& args,
const Bytes& tailBytes = *tailBytesPtr.lock();
{
Decoder d(tailBytes, env->codeSection->end(), error);
Decoder d(tailBytes, env->codeSection->end(), error, warnings);
if (!DecodeModuleTail(d, env.ptr()))
return nullptr;

View File

@ -86,7 +86,10 @@ EstimateCompiledCodeSize(Tier tier, size_t bytecodeSize);
// - *error is null and the caller should report out-of-memory.
SharedModule
CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error);
CompileBuffer(const CompileArgs& args,
const ShareableBytes& bytecode,
UniqueChars* error,
UniqueCharsVector* warnings);
// Attempt to compile the second tier of the given wasm::Module, returning whether
// tier-2 compilation succeeded and Module::finishTier2 was called.
@ -121,7 +124,8 @@ CompileStreaming(const CompileArgs& args,
const ExclusiveStreamEnd& codeStreamEnd,
const ExclusiveTailBytesPtr& tailBytesPtr,
const Atomic<bool>& cancelled,
UniqueChars* error);
UniqueChars* error,
UniqueCharsVector* warnings);
} // namespace wasm
} // namespace js

View File

@ -23,8 +23,8 @@
#include "jit/CodeGenerator.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmGenerator.h"
#include "wasm/WasmOpIter.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmValidate.h"

View File

@ -337,7 +337,8 @@ wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj
return false;
UniqueChars error;
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error);
UniqueCharsVector warnings;
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
if (!module) {
if (error) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
@ -871,6 +872,27 @@ InitCompileArgs(JSContext* cx)
return compileArgs;
}
static bool
ReportCompileWarnings(JSContext* cx, const UniqueCharsVector& warnings)
{
// Avoid spamming the console.
size_t numWarnings = Min<size_t>(warnings.length(), 3);
for (size_t i = 0; i < numWarnings; i++) {
if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
JSMSG_WASM_COMPILE_WARNING, warnings[i].get()))
return false;
}
if (warnings.length() > numWarnings) {
if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
JSMSG_WASM_COMPILE_WARNING, "other warnings suppressed"))
return false;
}
return true;
}
/* static */ bool
WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
{
@ -896,7 +918,8 @@ WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
return false;
UniqueChars error;
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error);
UniqueCharsVector warnings;
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
if (!module) {
if (error) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
@ -907,6 +930,9 @@ WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
return false;
}
if (!ReportCompileWarnings(cx, warnings))
return false;
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
RootedObject moduleObj(cx, WasmModuleObject::create(cx, *module, proto));
if (!moduleObj)
@ -2334,7 +2360,8 @@ RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
}
static bool
Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<PromiseObject*> promise)
Reject(JSContext* cx, const CompileArgs& args, Handle<PromiseObject*> promise,
const UniqueChars& error)
{
if (!error) {
ReportOutOfMemory(cx);
@ -2371,8 +2398,11 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<Promise
static bool
Resolve(JSContext* cx, Module& module, Handle<PromiseObject*> promise, bool instantiate,
HandleObject importObj)
HandleObject importObj, const UniqueCharsVector& warnings)
{
if (!ReportCompileWarnings(cx, warnings))
return false;
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
if (!moduleObj)
@ -2413,6 +2443,7 @@ struct CompileBufferTask : PromiseHelperTask
MutableBytes bytecode;
SharedCompileArgs compileArgs;
UniqueChars error;
UniqueCharsVector warnings;
SharedModule module;
bool instantiate;
PersistentRootedObject importObj;
@ -2436,13 +2467,13 @@ struct CompileBufferTask : PromiseHelperTask
}
void execute() override {
module = CompileBuffer(*compileArgs, *bytecode, &error);
module = CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
}
bool resolve(JSContext* cx, Handle<PromiseObject*> promise) override {
return module
? Resolve(cx, *module, promise, instantiate, importObj)
: Reject(cx, *compileArgs, Move(error), promise);
? Resolve(cx, *module, promise, instantiate, importObj, warnings)
: Reject(cx, *compileArgs, promise, error);
}
};
@ -2640,6 +2671,7 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
// Mutated on helper thread (execute()):
SharedModule module_;
UniqueChars compileError_;
UniqueCharsVector warnings_;
// Called on some thread before consumeChunk() or streamClosed():
@ -2773,7 +2805,7 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
rejectAndDestroyBeforeHelperThreadStarted(JSMSG_OUT_OF_MEMORY);
return;
}
module_ = CompileBuffer(*compileArgs_, *bytecode, &compileError_);
module_ = CompileBuffer(*compileArgs_, *bytecode, &compileError_, &warnings_);
setClosedAndDestroyBeforeHelperThreadStarted();
return;
}
@ -2810,8 +2842,14 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
// Called on a helper thread:
void execute() override {
module_ = CompileStreaming(*compileArgs_, envBytes_, codeBytes_, exclusiveCodeStreamEnd_,
exclusiveTailBytes_, streamFailed_, &compileError_);
module_ = CompileStreaming(*compileArgs_,
envBytes_,
codeBytes_,
exclusiveCodeStreamEnd_,
exclusiveTailBytes_,
streamFailed_,
&compileError_,
&warnings_);
// When execute() returns, the CompileStreamTask will be dispatched
// back to its JS thread to call resolve() and then be destroyed. We
@ -2828,10 +2866,10 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
MOZ_ASSERT(streamState_.lock() == Closed);
MOZ_ASSERT_IF(module_, !streamFailed_ && !streamError_ && !compileError_);
return module_
? Resolve(cx, *module_, promise, instantiate_, importObj_)
? Resolve(cx, *module_, promise, instantiate_, importObj_, warnings_)
: streamError_
? RejectWithErrorNumber(cx, *streamError_, promise)
: Reject(cx, *compileArgs_, Move(compileError_), promise);
: Reject(cx, *compileArgs_, promise, compileError_);
}
public:

View File

@ -603,7 +603,8 @@ wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
args->sharedMemoryEnabled = true;
UniqueChars error;
return CompileBuffer(*args, *bytecode, &error);
UniqueCharsVector warnings;
return CompileBuffer(*args, *bytecode, &error, &warnings);
}
/* virtual */ void

View File

@ -16,7 +16,7 @@
* limitations under the License.
*/
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmOpIter.h"
using namespace js;
using namespace js::jit;

View File

@ -16,8 +16,8 @@
* limitations under the License.
*/
#ifndef wasm_binary_iterator_h
#define wasm_binary_iterator_h
#ifndef wasm_op_iter_h
#define wasm_op_iter_h
#include "mozilla/Poison.h"
@ -2244,4 +2244,4 @@ template<> struct IsPod<js::wasm::ControlStackEntry<Nothing>> : TrueType {};
} // namespace mozilla
#endif // wasm_iterator_h
#endif // wasm_op_iter_h

View File

@ -328,7 +328,7 @@ SuppressGC(MacroAssembler& masm, int32_t increment, Register scratch)
masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), scratch);
masm.add32(Imm32(increment),
Address(scratch, offsetof(JSContext, suppressGC) +
js::ThreadLocalData<int32_t>::offsetOfValue()));
js::ThreadData<int32_t>::offsetOfValue()));
}
#endif

View File

@ -108,6 +108,7 @@ typedef UniquePtr<Bytes> UniqueBytes;
typedef UniquePtr<const Bytes> UniqueConstBytes;
typedef Vector<char, 0, SystemAllocPolicy> UTF8Bytes;
typedef Vector<Instance*, 0, SystemAllocPolicy> InstanceVector;
typedef Vector<UniqueChars, 0, SystemAllocPolicy> UniqueCharsVector;
// To call Vector::podResizeToFit, a type must specialize mozilla::IsPod
// which is pretty verbose to do within js::wasm, so factor that process out

View File

@ -19,18 +19,20 @@
#include "wasm/WasmValidate.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Unused.h"
#include "jit/JitOptions.h"
#include "js/Printf.h"
#include "vm/JSCompartment.h"
#include "vm/JSContext.h"
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmOpIter.h"
using namespace js;
using namespace js::jit;
using namespace js::wasm;
using mozilla::CheckedInt;
using mozilla::Unused;
// Decoder implementation.
@ -47,6 +49,22 @@ Decoder::failf(const char* msg, ...)
return fail(str.get());
}
void
Decoder::warnf(const char* msg, ...)
{
if (!warnings_)
return;
va_list ap;
va_start(ap, msg);
UniqueChars str(JS_vsmprintf(msg, ap));
va_end(ap);
if (!str)
return;
Unused << warnings_->append(Move(str));
}
bool
Decoder::fail(size_t errorOffset, const char* msg)
{
@ -192,7 +210,7 @@ Decoder::startCustomSection(const char* expected, size_t expectedLength, ModuleE
}
// Otherwise, blindly skip the custom section and keep looking.
finishCustomSection(**range);
skipAndFinishCustomSection(**range);
range->reset();
}
MOZ_CRASH("unreachable");
@ -207,7 +225,35 @@ Decoder::startCustomSection(const char* expected, size_t expectedLength, ModuleE
}
void
Decoder::finishCustomSection(const SectionRange& range)
Decoder::finishCustomSection(const char* name, const SectionRange& range)
{
MOZ_ASSERT(cur_ >= beg_);
MOZ_ASSERT(cur_ <= end_);
if (error_ && *error_) {
warnf("in the '%s' custom section: %s", name, error_->get());
skipAndFinishCustomSection(range);
return;
}
uint32_t actualSize = currentOffset() - range.start;
if (range.size != actualSize) {
if (actualSize < range.size) {
warnf("in the '%s' custom section: %" PRIu32 " unconsumed bytes",
name, uint32_t(range.size - actualSize));
} else {
warnf("in the '%s' custom section: %" PRIu32 " bytes consumed past the end",
name, uint32_t(actualSize - range.size));
}
skipAndFinishCustomSection(range);
return;
}
// Nothing to do! (c.f. skipAndFinishCustomSection())
}
void
Decoder::skipAndFinishCustomSection(const SectionRange& range)
{
MOZ_ASSERT(cur_ >= beg_);
MOZ_ASSERT(cur_ <= end_);
@ -225,7 +271,7 @@ Decoder::skipCustomSection(ModuleEnvironment* env)
if (!range)
return fail("expected custom section");
finishCustomSection(*range);
skipAndFinishCustomSection(*range);
return true;
}
@ -234,29 +280,59 @@ Decoder::startNameSubsection(NameType nameType, Maybe<uint32_t>* endOffset)
{
MOZ_ASSERT(!*endOffset);
const uint8_t* initialPosition = cur_;
const uint8_t* const initialPosition = cur_;
uint8_t nameTypeValue;
if (!readFixedU8(&nameTypeValue))
return false;
goto rewind;
if (nameTypeValue != uint8_t(nameType)) {
cur_ = initialPosition;
return true;
}
if (nameTypeValue != uint8_t(nameType))
goto rewind;
uint32_t payloadLength;
if (!readVarU32(&payloadLength) || payloadLength > bytesRemain())
return false;
return fail("bad name subsection payload length");
*endOffset = Some(currentOffset() + payloadLength);
return true;
rewind:
cur_ = initialPosition;
return true;
}
bool
Decoder::finishNameSubsection(uint32_t endOffset)
Decoder::finishNameSubsection(uint32_t expected)
{
return endOffset == uint32_t(currentOffset());
uint32_t actual = currentOffset();
if (expected != actual) {
return failf("bad name subsection length (expected: %" PRIu32 ", actual: %" PRIu32 ")",
expected, actual);
}
return true;
}
bool
Decoder::skipNameSubsection()
{
uint8_t nameTypeValue;
if (!readFixedU8(&nameTypeValue))
return fail("unable to read name subsection id");
switch (nameTypeValue) {
case uint8_t(NameType::Module):
case uint8_t(NameType::Function):
return fail("out of order name subsections");
default:
break;
}
uint32_t payloadLength;
if (!readVarU32(&payloadLength) || !readBytes(payloadLength))
return fail("bad name subsection payload length");
return true;
}
// Misc helpers.
@ -1885,11 +1961,11 @@ DecodeModuleNameSubsection(Decoder& d)
uint32_t nameLength;
if (!d.readVarU32(&nameLength))
return false;
return d.fail("failed to read module name length");
const uint8_t* bytes;
if (!d.readBytes(nameLength, &bytes))
return false;
return d.fail("failed to read module name bytes");
// Do nothing with module name for now; a future patch will incorporate the
// module name into the callstack format.
@ -1908,22 +1984,22 @@ DecodeFunctionNameSubsection(Decoder& d, ModuleEnvironment* env)
uint32_t nameCount = 0;
if (!d.readVarU32(&nameCount) || nameCount > MaxFuncs)
return false;
return d.fail("bad function name count");
NameInBytecodeVector funcNames;
for (uint32_t i = 0; i < nameCount; ++i) {
uint32_t funcIndex = 0;
if (!d.readVarU32(&funcIndex))
return false;
return d.fail("unable to read function index");
// Names must refer to real functions and be given in ascending order.
if (funcIndex >= env->numFuncs() || funcIndex < funcNames.length())
return false;
return d.fail("invalid function index");
uint32_t nameLength = 0;
if (!d.readVarU32(&nameLength) || nameLength > MaxStringLength)
return false;
return d.fail("unable to read function name length");
if (!nameLength)
continue;
@ -1934,7 +2010,7 @@ DecodeFunctionNameSubsection(Decoder& d, ModuleEnvironment* env)
funcNames[funcIndex] = NameInBytecode(d.currentOffset(), nameLength);
if (!d.readBytes(nameLength))
return false;
return d.fail("unable to read function name bytes");
}
if (!d.finishNameSubsection(*endOffset))
@ -1963,12 +2039,13 @@ DecodeNameSection(Decoder& d, ModuleEnvironment* env)
if (!DecodeFunctionNameSubsection(d, env))
goto finish;
// The names we care about have already been extracted into 'env' so don't
// bother decoding the rest of the name section. finishCustomSection() will
// skip to the end of the name section (as it would for any other error).
while (d.currentOffset() < range->end()) {
if (!d.skipNameSubsection())
goto finish;
}
finish:
d.finishCustomSection(*range);
d.finishCustomSection(NameSectionName, *range);
return true;
}

View File

@ -354,6 +354,7 @@ class Decoder
const uint8_t* cur_;
const size_t offsetInModule_;
UniqueChars* error_;
UniqueCharsVector* warnings_;
bool resilientMode_;
template <class T>
@ -439,28 +440,32 @@ class Decoder
public:
Decoder(const uint8_t* begin, const uint8_t* end, size_t offsetInModule, UniqueChars* error,
bool resilientMode = false)
UniqueCharsVector* warnings = nullptr, bool resilientMode = false)
: beg_(begin),
end_(end),
cur_(begin),
offsetInModule_(offsetInModule),
error_(error),
warnings_(warnings),
resilientMode_(resilientMode)
{
MOZ_ASSERT(begin <= end);
}
explicit Decoder(const Bytes& bytes, size_t offsetInModule = 0, UniqueChars* error = nullptr)
explicit Decoder(const Bytes& bytes, size_t offsetInModule = 0, UniqueChars* error = nullptr,
UniqueCharsVector* warnings = nullptr)
: beg_(bytes.begin()),
end_(bytes.end()),
cur_(bytes.begin()),
offsetInModule_(offsetInModule),
error_(error),
warnings_(warnings),
resilientMode_(false)
{}
// These convenience functions use currentOffset() as the errorOffset.
bool fail(const char* msg) { return fail(currentOffset(), msg); }
bool failf(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3);
void warnf(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3);
// Report an error at the given offset (relative to the whole module).
bool fail(size_t errorOffset, const char* msg);
@ -594,6 +599,7 @@ class Decoder
size_t expectedLength,
ModuleEnvironment* env,
MaybeSectionRange* range);
template <size_t NameSizeWith0>
MOZ_MUST_USE bool startCustomSection(const char (&name)[NameSizeWith0],
ModuleEnvironment* env,
@ -602,13 +608,17 @@ class Decoder
MOZ_ASSERT(name[NameSizeWith0 - 1] == '\0');
return startCustomSection(name, NameSizeWith0 - 1, env, range);
}
void finishCustomSection(const SectionRange& range);
void finishCustomSection(const char* name, const SectionRange& range);
void skipAndFinishCustomSection(const SectionRange& range);
MOZ_MUST_USE bool skipCustomSection(ModuleEnvironment* env);
// The Name section has its own optional subsections.
MOZ_MUST_USE bool startNameSubsection(NameType nameType, Maybe<uint32_t>* endOffset);
MOZ_MUST_USE bool finishNameSubsection(uint32_t endOffset);
MOZ_MUST_USE bool skipNameSubsection();
// The infallible "unchecked" decoding functions can be used when we are
// sure that the bytes are well-formed (by construction or due to previous

View File

@ -189,8 +189,6 @@ public:
typedef ServoElementSnapshotTable SnapshotTable;
typedef mozilla::dom::Element Element;
NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
// Get an integer that increments every time we process pending restyles.
// The value is never 0.
uint64_t GetRestyleGeneration() const { return mRestyleGeneration; }
@ -204,6 +202,13 @@ public:
void Disconnect() { mPresContext = nullptr; }
~RestyleManager()
{
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
"leaving dangling pointers from AnimationsWithDestroyedFrame");
MOZ_ASSERT(!mReentrantChanges);
}
static nsCString RestyleHintToString(nsRestyleHint aHint);
#ifdef DEBUG
@ -449,13 +454,6 @@ protected:
ServoStyleSet* StyleSet() const { return PresContext()->StyleSet(); }
~RestyleManager()
{
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
"leaving dangling pointers from AnimationsWithDestroyedFrame");
MOZ_ASSERT(!mReentrantChanges);
}
void RestyleForEmptyChange(Element* aContainer);
void MaybeRestyleForEdgeChildChange(Element* aContainer, nsIContent* aChangedChild);

View File

@ -102,9 +102,6 @@ void
nsFrameManager::RemoveFrame(ChildListID aListID,
nsIFrame* aOldFrame)
{
bool wasDestroyingFrames = mIsDestroyingFrames;
mIsDestroyingFrames = true;
// In case the reflow doesn't invalidate anything since it just leaves
// a gap where the old frame was, we invalidate it here. (This is
// reasonably likely to happen when removing a last child in a way
@ -128,8 +125,6 @@ nsFrameManager::RemoveFrame(ChildListID aListID,
} else {
parentFrame->RemoveFrame(aListID, aOldFrame);
}
mIsDestroyingFrames = wasDestroyingFrames;
}
//----------------------------------------------------------------------

View File

@ -37,14 +37,11 @@ public:
explicit nsFrameManager(nsIPresShell* aPresShell)
: mPresShell(aPresShell)
, mRootFrame(nullptr)
, mIsDestroyingFrames(false)
{
MOZ_ASSERT(mPresShell, "need a pres shell");
}
~nsFrameManager();
bool IsDestroyingFrames() const { return mIsDestroyingFrames; }
/*
* Gets and sets the root frame (typically the viewport). The lifetime of the
* root frame is controlled by the frame manager. When the frame manager is
@ -104,7 +101,6 @@ protected:
// weak link, because the pres shell owns us
nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
nsIFrame* mRootFrame;
bool mIsDestroyingFrames; // The frame manager is destroying some frame(s).
};
#endif

View File

@ -843,8 +843,8 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
mAnimationEventDispatcher = new mozilla::AnimationEventDispatcher(this);
mEffectCompositor = new mozilla::EffectCompositor(this);
mTransitionManager = new nsTransitionManager(this);
mAnimationManager = new nsAnimationManager(this);
mTransitionManager = MakeUnique<nsTransitionManager>(this);
mAnimationManager = MakeUnique<nsAnimationManager>(this);
if (mDocument->GetDisplayDocument()) {
NS_ASSERTION(mDocument->GetDisplayDocument()->GetPresContext(),
@ -956,7 +956,7 @@ nsPresContext::AttachShell(nsIPresShell* aShell)
MOZ_ASSERT(!mShell);
mShell = aShell;
mRestyleManager = new mozilla::RestyleManager(this);
mRestyleManager = MakeUnique<mozilla::RestyleManager>(this);
// Since CounterStyleManager is also the name of a method of
// nsPresContext, it is necessary to prefix the class with the mozilla

View File

@ -239,15 +239,15 @@ public:
}
mozilla::EffectCompositor* EffectCompositor() { return mEffectCompositor; }
nsTransitionManager* TransitionManager() { return mTransitionManager; }
nsAnimationManager* AnimationManager() { return mAnimationManager; }
const nsAnimationManager* AnimationManager() const { return mAnimationManager; }
nsTransitionManager* TransitionManager() { return mTransitionManager.get(); }
nsAnimationManager* AnimationManager() { return mAnimationManager.get(); }
const nsAnimationManager* AnimationManager() const { return mAnimationManager.get(); }
nsRefreshDriver* RefreshDriver() { return mRefreshDriver; }
mozilla::RestyleManager* RestyleManager() {
MOZ_ASSERT(mRestyleManager);
return mRestyleManager;
return mRestyleManager.get();
}
mozilla::CounterStyleManager* CounterStyleManager() const {
@ -1298,9 +1298,9 @@ protected:
RefPtr<nsRefreshDriver> mRefreshDriver;
RefPtr<mozilla::AnimationEventDispatcher> mAnimationEventDispatcher;
RefPtr<mozilla::EffectCompositor> mEffectCompositor;
RefPtr<nsTransitionManager> mTransitionManager;
RefPtr<nsAnimationManager> mAnimationManager;
RefPtr<mozilla::RestyleManager> mRestyleManager;
mozilla::UniquePtr<nsTransitionManager> mTransitionManager;
mozilla::UniquePtr<nsAnimationManager> mAnimationManager;
mozilla::UniquePtr<mozilla::RestyleManager> mRestyleManager;
RefPtr<mozilla::CounterStyleManager> mCounterStyleManager;
nsAtom* MOZ_UNSAFE_REF("always a static atom") mMedium; // initialized by subclass ctors
RefPtr<nsAtom> mMediaEmulated;

View File

@ -3382,7 +3382,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, &resultList,
aBuilder->CurrentActiveScrolledRoot(),
nsDisplayOwnLayerFlags::eNone,
mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
ScrollbarData{}, /* aForceActive = */ false));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;

View File

@ -3042,21 +3042,21 @@ AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
nsDisplayWrapList* newItem;
const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
if (aFlags & APPEND_OWN_LAYER) {
FrameMetrics::ViewID scrollTarget = FrameMetrics::NULL_SCROLL_ID;
nsDisplayOwnLayerFlags flags = aBuilder->GetCurrentScrollbarFlags();
// The flags here should be at most one scrollbar direction and nothing else
MOZ_ASSERT(flags == nsDisplayOwnLayerFlags::eNone ||
flags == nsDisplayOwnLayerFlags::eVerticalScrollbar ||
flags == nsDisplayOwnLayerFlags::eHorizontalScrollbar);
ScrollbarData scrollbarData;
if (aFlags & APPEND_SCROLLBAR_CONTAINER) {
scrollTarget = aBuilder->GetCurrentScrollbarTarget();
scrollbarData.mTargetViewId = aBuilder->GetCurrentScrollbarTarget();
// The flags here should be exactly one scrollbar direction
MOZ_ASSERT(flags != nsDisplayOwnLayerFlags::eNone);
flags |= nsDisplayOwnLayerFlags::eScrollbarContainer;
}
newItem = MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, aSourceFrame, aSource, asr, flags, scrollTarget);
newItem = MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, aSourceFrame, aSource, asr, flags, scrollbarData);
} else {
newItem = MakeDisplayItem<nsDisplayWrapList>(aBuilder, aSourceFrame, aSource, asr);
}

View File

@ -61,6 +61,7 @@ namespace dom {
/* static */ void
InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
nsIDocument& aDocument,
bool aDocumentOnly,
nsTArray<RefPtr<StyleSheet>>& aResult)
{
// Get the agent, then user and finally xbl sheets in the style set.
@ -68,6 +69,8 @@ InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
if (presShell) {
ServoStyleSet* styleSet = presShell->StyleSet();
if (!aDocumentOnly) {
SheetType sheetType = SheetType::Agent;
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
@ -76,11 +79,14 @@ InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
}
}
AutoTArray<StyleSheet*, 32> xblSheetArray;
styleSet->AppendAllXBLStyleSheets(xblSheetArray);
styleSet->AppendAllNonDocumentAuthorSheets(xblSheetArray);
// The XBL stylesheet array will quite often be full of duplicates. Cope:
//
// FIXME(emilio, bug 1454467): I think this is not true since bug 1452525.
nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet;
for (StyleSheet* sheet : xblSheetArray) {
if (!sheetSet.Contains(sheet)) {
@ -1048,16 +1054,8 @@ InspectorUtils::ParseStyleSheet(GlobalObject& aGlobalObject,
ErrorResult& aRv)
{
RefPtr<ServoStyleSheet> servoSheet = do_QueryObject(&aSheet);
if (servoSheet) {
nsresult rv = servoSheet->ReparseSheet(aInput);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
return;
}
aRv.Throw(NS_ERROR_INVALID_POINTER);
RefPtr<ServoStyleSheet> servoSheet = aSheet.AsServo();
aRv = servoSheet->ReparseSheet(aInput);
}
void

View File

@ -37,6 +37,7 @@ class InspectorUtils
public:
static void GetAllStyleSheets(GlobalObject& aGlobal,
nsIDocument& aDocument,
bool aDocumentOnly,
nsTArray<RefPtr<StyleSheet>>& aResult);
static void GetCSSStyleRules(GlobalObject& aGlobal,
Element& aElement,

View File

@ -6922,14 +6922,13 @@ nsDisplayTableBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder*
nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot,
nsDisplayOwnLayerFlags aFlags, ViewID aScrollTarget,
const ScrollbarData& aThumbData,
nsDisplayOwnLayerFlags aFlags,
const ScrollbarData& aScrollbarData,
bool aForceActive,
bool aClearClipChain)
: nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, aClearClipChain)
, mFlags(aFlags)
, mScrollTarget(aScrollTarget)
, mThumbData(aThumbData)
, mScrollbarData(aScrollbarData)
, mForceActive(aForceActive)
, mWrAnimationId(0)
{
@ -6965,7 +6964,7 @@ nsDisplayOwnLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
bool
nsDisplayOwnLayer::IsScrollThumbLayer() const
{
return mThumbData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb;
return mScrollbarData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb;
}
bool
@ -6986,15 +6985,16 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
aContainerParameters, nullptr,
FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
if (IsScrollThumbLayer()) {
mThumbData.mTargetViewId = mScrollTarget;
layer->SetScrollbarData(mThumbData);
}
if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
ScrollDirection dir = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
? ScrollDirection::eVertical
: ScrollDirection::eHorizontal;
layer->SetScrollbarContainer(mScrollTarget, dir);
layer->SetScrollbarData(mScrollbarData);
} else if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
mScrollbarData.mScrollbarLayerType = ScrollbarLayerType::Container;
mScrollbarData.mDirection = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
? Some(ScrollDirection::eVertical)
: Some(ScrollDirection::eHorizontal);
layer->SetScrollbarData(mScrollbarData);
}
if (mFlags & nsDisplayOwnLayerFlags::eGenerateSubdocInvalidations) {
@ -7044,9 +7044,9 @@ nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
if (IsScrollThumbLayer()) {
ret = true;
if (aLayerData) {
aLayerData->SetScrollbarData(mThumbData);
aLayerData->SetScrollbarData(mScrollbarData);
aLayerData->SetScrollbarAnimationId(mWrAnimationId);
aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
aLayerData->SetScrollbarTargetContainerId(mScrollbarData.mTargetViewId);
}
}
if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
@ -7056,7 +7056,7 @@ nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
? ScrollDirection::eVertical
: ScrollDirection::eHorizontal;
aLayerData->SetScrollbarContainerDirection(dir);
aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
aLayerData->SetScrollbarTargetContainerId(mScrollbarData.mTargetViewId);
}
}
return ret;
@ -7065,7 +7065,7 @@ nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
void
nsDisplayOwnLayer::WriteDebugInfo(std::stringstream& aStream)
{
aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")", (int)mFlags, mScrollTarget).get();
aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")", (int)mFlags, mScrollbarData.mTargetViewId).get();
}
nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,

View File

@ -5606,18 +5606,18 @@ public:
nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot,
nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::eNone,
ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
const ScrollbarData& aThumbData = ScrollbarData{},
const ScrollbarData& aScrollbarData = ScrollbarData{},
bool aForceActive = true,
bool aClearClipChain = false);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayOwnLayer();
#endif
nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, const nsDisplayOwnLayer& aOther)
: nsDisplayWrapList(aBuilder, aOther)
, mFlags(aOther.mFlags)
, mScrollTarget(aOther.mScrollTarget)
, mThumbData(aOther.mThumbData)
, mScrollbarData(aOther.mScrollbarData)
, mForceActive(aOther.mForceActive)
, mWrAnimationId(aOther.mWrAnimationId)
{
@ -5657,12 +5657,15 @@ public:
NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
protected:
nsDisplayOwnLayerFlags mFlags;
ViewID mScrollTarget;
// If this nsDisplayOwnLayer represents a scroll thumb layer, mThumbData
// stores information about the scroll thumb. Otherwise, mThumbData will be
// default-constructed (in particular with mDirection == Nothing())
// and can be ignored.
ScrollbarData mThumbData;
/**
* If this nsDisplayOwnLayer represents a scroll thumb layer or a
* scrollbar container layer, mScrollbarData stores information
* about the scrollbar. Otherwise, mScrollbarData will be
* default-constructed (in particular with mDirection == Nothing())
* and can be ignored.
*/
ScrollbarData mScrollbarData;
bool mForceActive;
uint64_t mWrAnimationId;
};

View File

@ -10,7 +10,7 @@ default-preferences pref(gfx.font_loader.delay,0)
# (First attempt is random-if(windows 7), due to intermittent failure with a
# single missing character - see bug 1451723 & more generally bug 1392106.)
pref(font.default.zh-CN,"serif") pref(font.default.zh-TW,"serif") pref(font.default.ja,"serif") pref(font.default.ko,"serif") random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1394311.htm 1394311-ref.htm
pref(font.default.zh-CN,"sans-serif") pref(font.default.zh-TW,"sans-serif") pref(font.default.ja,"sans-serif") pref(font.default.ko,"sans-serif") == 1394311.htm 1394311-ref.htm
pref(font.default.zh-CN,"sans-serif") pref(font.default.zh-TW,"sans-serif") pref(font.default.ja,"sans-serif") pref(font.default.ko,"sans-serif") skip-if(winWidget&&/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1394311.htm 1394311-ref.htm
# tests for bug 1367860 (correct default generic font based on language)
== 1367860-1.htm 1367860-ref.htm

Some files were not shown because too many files have changed in this diff Show More