Merge mozilla-inbound to mozilla-central. a=merge

This commit is contained in:
Dorel Luca 2018-03-02 00:09:29 +02:00
Родитель 109ad47bbf 8bbbdc6337
Коммит 3ccafa2b66
169 изменённых файлов: 5290 добавлений и 1286 удалений

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

@ -1047,11 +1047,7 @@ pref("dom.ipc.plugins.sandbox-level.flash", 0);
// On windows these levels are: // On windows these levels are:
// See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
// SetSecurityLevelForContentProcess() for what the different settings mean. // SetSecurityLevelForContentProcess() for what the different settings mean.
#if defined(NIGHTLY_BUILD)
pref("security.sandbox.content.level", 5); pref("security.sandbox.content.level", 5);
#else
pref("security.sandbox.content.level", 4);
#endif
// This controls the depth of stack trace that is logged when Windows sandbox // This controls the depth of stack trace that is logged when Windows sandbox
// logging is turned on. This is only currently available for the content // logging is turned on. This is only currently available for the content

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

@ -6,13 +6,11 @@
"use strict"; "use strict";
const { gDevTools } = require("devtools/client/framework/devtools");
const { getColor } = require("devtools/client/shared/theme"); const { getColor } = require("devtools/client/shared/theme");
const { createFactory, createElement } = require("devtools/client/shared/vendor/react"); const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux"); const { Provider } = require("devtools/client/shared/vendor/react-redux");
const { gDevTools } = require("devtools/client/framework/devtools");
const FontsApp = createFactory(require("./components/FontsApp")); const FontsApp = createFactory(require("./components/FontsApp"));
const { LocalizationHelper } = require("devtools/shared/l10n"); const { LocalizationHelper } = require("devtools/shared/l10n");
@ -193,6 +191,11 @@ class FontInspector {
previewFillStyle: getColor("body-color") previewFillStyle: getColor("body-color")
}; };
// Add the includeVariations argument into the option to get font variation data.
if (this.pageStyle.supportsFontVariations) {
options.includeVariations = true;
}
fonts = await this.getFontsForNode(node, options); fonts = await this.getFontsForNode(node, options);
otherFonts = await this.getFontsNotInNode(fonts, options); otherFonts = await this.getFontsNotInNode(fonts, options);

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

@ -6,6 +6,45 @@
const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
/**
* A font variation axis.
*/
const fontVariationAxis = exports.fontVariationAxis = {
// The OpenType tag name of the variation axis
tag: PropTypes.string,
// The axis name of the variation axis
name: PropTypes.string,
// The minimum value of the variation axis
minValue: PropTypes.number,
// The maximum value of the variation axis
maxValue: PropTypes.number,
// The default value of the variation axis
defaultValue: PropTypes.number,
};
const fontVariationInstanceValue = exports.fontVariationInstanceValue = {
// The axis name of the variation axis
axis: PropTypes.string,
// The value of the variation axis
value: PropTypes.number,
};
/**
* A font variation instance.
*/
const fontVariationInstance = exports.fontVariationInstance = {
// The variation instance name of the font
axis: PropTypes.string,
// The font variation values for the variation instance of the font
values: PropTypes.arrayOf(PropTypes.shape(fontVariationInstanceValue)),
};
/** /**
* A single font. * A single font.
*/ */
@ -27,6 +66,12 @@ const font = exports.font = {
// The URI of the font file // The URI of the font file
URI: PropTypes.string, URI: PropTypes.string,
// The variation axes of the font
variationAxes: PropTypes.arrayOf(PropTypes.shape(fontVariationAxis)),
// The variation instances of the font
variationInstances: PropTypes.arrayOf(PropTypes.shape(fontVariationInstance))
}; };
exports.fontOptions = { exports.fontOptions = {
@ -35,7 +80,7 @@ exports.fontOptions = {
}; };
/** /**
* Font data * Font data.
*/ */
exports.fontData = { exports.fontData = {
// The fonts used in the current element. // The fonts used in the current element.

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

@ -91,7 +91,7 @@ class SnapshotListItem extends Component {
className: "save", className: "save",
}, L10N.getStr("snapshot.io.save")); }, L10N.getStr("snapshot.io.save"));
let deleteButton = !snapshot.path ? void 0 : dom.div({ let deleteButton = !snapshot.path ? void 0 : dom.button({
onClick: () => onDelete(snapshot), onClick: () => onDelete(snapshot),
className: "delete", className: "delete",
title: L10N.getStr("snapshot.io.delete") title: L10N.getStr("snapshot.io.delete")

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

@ -811,7 +811,7 @@ class TreeNodeClass extends Component {
id: this.props.id, id: this.props.id,
className: classList.join(" "), className: classList.join(" "),
role: "treeitem", role: "treeitem",
"aria-level": this.props.depth, "aria-level": this.props.depth + 1,
onClick: this.props.onClick, onClick: this.props.onClick,
"aria-expanded": ariaExpanded, "aria-expanded": ariaExpanded,
"data-expanded": this.props.expanded ? "" : undefined, "data-expanded": this.props.expanded ? "" : undefined,

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

@ -96,7 +96,9 @@ function isAccessibleTree(tree, options = {}) {
for (let node of treeNodes) { for (let node of treeNodes) {
ok(node.id, "TreeNode has an id"); ok(node.id, "TreeNode has an id");
is(node.getAttribute("role"), "treeitem", "Tree item semantics is present"); is(node.getAttribute("role"), "treeitem", "Tree item semantics is present");
ok(node.hasAttribute("aria-level"), "Aria level attribute is set"); is(parseInt(node.getAttribute("aria-level"), 10),
parseInt(node.getAttribute("data-depth"), 10) + 1,
"Aria level attribute is set correctly");
} }
} }

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

@ -209,9 +209,13 @@ html, body, #app, #memory-tool {
.snapshot-list-item .delete { .snapshot-list-item .delete {
cursor: pointer; cursor: pointer;
background-color: transparent;
border: 0;
padding: 0;
position: relative; position: relative;
min-height: 1em; min-height: 1em;
min-width: 1.3em; min-width: 1.3em;
color: currentColor;
} }
.snapshot-list-item .delete::before { .snapshot-list-item .delete::before {

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

@ -0,0 +1,232 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Cc, Ci } = require("chrome");
const Services = require("Services");
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
/**
* A helper class that does all the work related to accessibility service
* lifecycle (initialization, shutdown, consumer changes, etc) in parent
* parent process. It is not guaranteed that the AccessibilityActor starts in
* parent process and thus triggering these lifecycle functions directly is
* extremely unreliable.
*/
class AccessibilityParent {
constructor(mm, prefix) {
this._msgName = `debug:${prefix}accessibility`;
this.onAccessibilityMessage = this.onAccessibilityMessage.bind(this);
this.setMessageManager(mm);
this.userPref = Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
Services.obs.addObserver(this, "a11y-consumers-changed");
Services.prefs.addObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
if (this.enabled && !this.accService) {
// Set a local reference to an accessibility service if accessibility was
// started elsewhere to ensure that parent process a11y service does not
// get GC'ed away.
this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
}
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
topic: "initialized",
data: {
canBeDisabled: this.canBeDisabled,
canBeEnabled: this.canBeEnabled
}
});
}
/**
* Set up message manager listener to listen for messages coming from the
* AccessibilityActor when it is instantiated in the child process.
*
* @param {Object} mm
* Message manager that corresponds to the current content tab.
*/
setMessageManager(mm) {
if (this.messageManager === mm) {
return;
}
if (this.messageManager) {
// If the browser was swapped we need to reset the message manager.
let oldMM = this.messageManager;
oldMM.removeMessageListener(this._msgName, this.onAccessibilityMessage);
}
this.messageManager = mm;
if (mm) {
mm.addMessageListener(this._msgName, this.onAccessibilityMessage);
}
}
/**
* Content AccessibilityActor message listener.
*
* @param {String} msg
* Name of the action to perform.
*/
onAccessibilityMessage(msg) {
let { action } = msg.json;
switch (action) {
case "enable":
this.enable();
break;
case "disable":
this.disable();
break;
case "disconnect":
this.destroy();
break;
default:
break;
}
}
observe(subject, topic, data) {
if (topic === "a11y-consumers-changed") {
// This event is fired when accessibility service consumers change. Since
// this observer lives in parent process there are 2 possible consumers of
// a11y service: XPCOM and PlatformAPI (e.g. screen readers). We only care
// about PlatformAPI consumer changes because when set, we can no longer
// disable accessibility service.
let { PlatformAPI } = JSON.parse(data);
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
topic: "can-be-disabled-change",
data: !PlatformAPI
});
} else if (!this.disabling && topic === "nsPref:changed" &&
data === PREF_ACCESSIBILITY_FORCE_DISABLED) {
// PREF_ACCESSIBILITY_FORCE_DISABLED preference change event. When set to
// >=1, it means that the user wants to disable accessibility service and
// prevent it from starting in the future. Note: we also check
// this.disabling state when handling this pref change because this is how
// we disable the accessibility inspector itself.
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
topic: "can-be-enabled-change",
data: Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1
});
}
}
/**
* A getter that indicates if accessibility service is enabled.
*
* @return {Boolean}
* True if accessibility service is on.
*/
get enabled() {
return Services.appinfo.accessibilityEnabled;
}
/**
* A getter that indicates if the accessibility service can be disabled.
*
* @return {Boolean}
* True if accessibility service can be disabled.
*/
get canBeDisabled() {
if (this.enabled) {
let a11yService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
let { PlatformAPI } = JSON.parse(a11yService.getConsumers());
return !PlatformAPI;
}
return true;
}
/**
* A getter that indicates if the accessibility service can be enabled.
*
* @return {Boolean}
* True if accessibility service can be enabled.
*/
get canBeEnabled() {
return Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1;
}
/**
* Enable accessibility service (via XPCOM service).
*/
enable() {
if (this.enabled || !this.canBeEnabled) {
return;
}
this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
}
/**
* Force disable accessibility service. This method removes the reference to
* the XPCOM a11y service object and flips the
* PREF_ACCESSIBILITY_FORCE_DISABLED preference on and off to shutdown a11y
* service.
*/
disable() {
if (!this.enabled || !this.canBeDisabled) {
return;
}
this.disabling = true;
this.accService = null;
// Set PREF_ACCESSIBILITY_FORCE_DISABLED to 1 to force disable
// accessibility service. This is the only way to guarantee an immediate
// accessibility service shutdown in all processes. This also prevents
// accessibility service from starting up in the future.
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
// Set PREF_ACCESSIBILITY_FORCE_DISABLED back to previous default or user
// set value. This will not start accessibility service until the user
// activates it again. It simply ensures that accessibility service can
// start again (when value is below 1).
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, this.userPref);
delete this.disabling;
}
/**
* Destroy thie helper class, remove all listeners and if possible disable
* accessibility service in the parent process.
*/
destroy() {
Services.obs.removeObserver(this, "a11y-consumers-changed");
Services.prefs.removeObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
this.setMessageManager(null);
this.accService = null;
}
}
/**
* Setup function that runs in parent process and setups AccessibleActor bits
* that must always run in parent process.
*
* @param {Object} options.mm
* Message manager that corresponds to the current content tab.
* @param {String} options.prefix
* Unique prefix for message manager messages.
* @return {Object}
* Defines event listeners for when client disconnects or browser gets
* swapped.
*/
function setupParentProcess({ mm, prefix }) {
let accessibility = new AccessibilityParent(mm, prefix);
return {
onBrowserSwap: newMM => accessibility.setMessageManager(newMM),
onDisconnected: () => {
accessibility.destroy();
accessibility = null;
}
};
}
exports.setupParentProcess = setupParentProcess;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -13,6 +13,7 @@ DIRS += [
] ]
DevToolsModules( DevToolsModules(
'accessibility-parent.js',
'accessibility.js', 'accessibility.js',
'actor-registry.js', 'actor-registry.js',
'addon.js', 'addon.js',

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

@ -5,6 +5,7 @@
"use strict"; "use strict";
const {Ci} = require("chrome"); const {Ci} = require("chrome");
const Services = require("Services");
const protocol = require("devtools/shared/protocol"); const protocol = require("devtools/shared/protocol");
const {LongStringActor} = require("devtools/server/actors/string"); const {LongStringActor} = require("devtools/server/actors/string");
const InspectorUtils = require("InspectorUtils"); const InspectorUtils = require("InspectorUtils");
@ -29,6 +30,9 @@ loader.lazyRequireGetter(this, "UPDATE_GENERAL",
loader.lazyGetter(this, "PSEUDO_ELEMENTS", () => { loader.lazyGetter(this, "PSEUDO_ELEMENTS", () => {
return InspectorUtils.getCSSPseudoElementNames(); return InspectorUtils.getCSSPseudoElementNames();
}); });
loader.lazyGetter(this, "FONT_VARIATIONS_ENABLED", () => {
return Services.prefs.getBoolPref("layout.css.font-variations.enabled");
});
const XHTML_NS = "http://www.w3.org/1999/xhtml"; const XHTML_NS = "http://www.w3.org/1999/xhtml";
const FONT_PREVIEW_TEXT = "Abc"; const FONT_PREVIEW_TEXT = "Abc";
@ -115,7 +119,10 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
// been fixed must make sure cssLogic.highlight(node) was called before. // been fixed must make sure cssLogic.highlight(node) was called before.
getAppliedCreatesStyleCache: true, getAppliedCreatesStyleCache: true,
// Whether addNewRule accepts the editAuthored argument. // Whether addNewRule accepts the editAuthored argument.
authoredStyles: true authoredStyles: true,
// Whether getAllUsedFontFaces/getUsedFontFaces accepts the includeVariations
// argument.
fontVariations: FONT_VARIATIONS_ENABLED,
} }
}; };
}, },
@ -320,6 +327,12 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
size: size size: size
}; };
} }
if (options.includeVariations && FONT_VARIATIONS_ENABLED) {
fontFace.variationAxes = font.getVariationAxes();
fontFace.variationInstances = font.getVariationInstances();
}
fontsArray.push(fontFace); fontsArray.push(fontFace);
} }

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

@ -27,8 +27,8 @@ support-files =
!/devtools/server/tests/mochitest/hello-actor.js !/devtools/server/tests/mochitest/hello-actor.js
!/devtools/client/framework/test/shared-head.js !/devtools/client/framework/test/shared-head.js
[browser_accessibility_node_events.js]
[browser_accessibility_node.js] [browser_accessibility_node.js]
[browser_accessibility_node_events.js]
[browser_accessibility_simple.js] [browser_accessibility_simple.js]
[browser_accessibility_walker.js] [browser_accessibility_walker.js]
[browser_animation_emitMutations.js] [browser_animation_emitMutations.js]

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

@ -10,7 +10,8 @@ add_task(async function () {
let {client, walker, accessibility} = let {client, walker, accessibility} =
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html"); await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
let a11yWalker = await accessibility.getWalker(walker); let a11yWalker = await accessibility.getWalker();
await accessibility.enable();
let buttonNode = await walker.querySelector(walker.rootNode, "#button"); let buttonNode = await walker.querySelector(walker.rootNode, "#button");
let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode); let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
@ -22,38 +23,23 @@ add_task(async function () {
help: "", help: "",
keyboardShortcut: "", keyboardShortcut: "",
childCount: 1, childCount: 1,
domNodeType: 1 domNodeType: 1,
indexInParent: 1,
states: ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
actions: [ "Press" ],
attributes: {
"margin-top": "0px",
display: "inline-block",
"text-align": "center",
"text-indent": "0px",
"margin-left": "0px",
tag: "button",
"margin-right": "0px",
id: "button",
"margin-bottom": "0px"
}
}); });
info("Actions");
let actions = await accessibleFront.getActions();
is(actions.length, 1, "Accessible Front has correct number of actions");
is(actions[0], "Press", "Accessible Front default action is correct");
info("Index in parent");
let index = await accessibleFront.getIndexInParent();
is(index, 1, "Accessible Front has correct index in parent");
info("State");
let state = await accessibleFront.getState();
SimpleTest.isDeeply(state,
["focusable", "selectable text", "opaque", "enabled", "sensitive"],
"Accessible Front has correct states");
info("Attributes");
let attributes = await accessibleFront.getAttributes();
SimpleTest.isDeeply(attributes, {
"margin-top": "0px",
display: "inline-block",
"text-align": "center",
"text-indent": "0px",
"margin-left": "0px",
tag: "button",
"margin-right": "0px",
id: "button",
"margin-bottom": "0px"
}, "Accessible Front has correct attributes");
info("Children"); info("Children");
let children = await accessibleFront.children(); let children = await accessibleFront.children();
is(children.length, 1, "Accessible Front has correct number of children"); is(children.length, 1, "Accessible Front has correct number of children");
@ -62,13 +48,8 @@ add_task(async function () {
role: "text leaf" role: "text leaf"
}); });
info("DOM Node"); await accessibility.disable();
let node = await accessibleFront.getDOMNode(walker); await waitForA11yShutdown();
is(node, buttonNode, "Accessible Front has correct DOM node");
let a11yShutdown = waitForA11yShutdown();
await client.close(); await client.close();
forceCollections();
await a11yShutdown;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
}); });

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

@ -10,8 +10,10 @@ add_task(async function () {
let {client, walker, accessibility} = let {client, walker, accessibility} =
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html"); await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
let a11yWalker = await accessibility.getWalker(walker); let a11yWalker = await accessibility.getWalker();
let a11yDoc = await a11yWalker.getDocument(); await accessibility.enable();
let rootNode = await walker.getRootNode();
let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
let buttonNode = await walker.querySelector(walker.rootNode, "#button"); let buttonNode = await walker.querySelector(walker.rootNode, "#button");
let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode); let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
let sliderNode = await walker.querySelector(walker.rootNode, "#slider"); let sliderNode = await walker.querySelector(walker.rootNode, "#slider");
@ -26,7 +28,21 @@ add_task(async function () {
help: "", help: "",
keyboardShortcut: "", keyboardShortcut: "",
childCount: 1, childCount: 1,
domNodeType: 1 domNodeType: 1,
indexInParent: 1,
states: ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
actions: [ "Press" ],
attributes: {
"margin-top": "0px",
display: "inline-block",
"text-align": "center",
"text-indent": "0px",
"margin-left": "0px",
tag: "button",
"margin-right": "0px",
id: "button",
"margin-bottom": "0px"
}
}); });
info("Name change event"); info("Name change event");
@ -45,27 +61,35 @@ add_task(async function () {
content.document.getElementById("button").removeAttribute("aria-describedby"))); content.document.getElementById("button").removeAttribute("aria-describedby")));
info("State change event"); info("State change event");
let states = await accessibleFront.getState();
let expectedStates = ["unavailable", "selectable text", "opaque"]; let expectedStates = ["unavailable", "selectable text", "opaque"];
SimpleTest.isDeeply(states, ["focusable", "selectable text", "opaque", await emitA11yEvent(accessibleFront, "states-change",
"enabled", "sensitive"], "States are correct"); newStates => {
await emitA11yEvent(accessibleFront, "state-change", checkA11yFront(accessibleFront, { states: expectedStates });
newStates => SimpleTest.isDeeply(newStates, expectedStates, SimpleTest.isDeeply(newStates, expectedStates, "States are updated");
"States are updated"), }, () => ContentTask.spawn(browser, null, () =>
() => ContentTask.spawn(browser, null, () =>
content.document.getElementById("button").setAttribute("disabled", true))); content.document.getElementById("button").setAttribute("disabled", true)));
states = await accessibleFront.getState();
SimpleTest.isDeeply(states, expectedStates, "States are updated");
info("Attributes change event"); info("Attributes change event");
let attrs = await accessibleFront.getAttributes();
ok(!attrs.live, "Attribute is not present");
await emitA11yEvent(accessibleFront, "attributes-change", await emitA11yEvent(accessibleFront, "attributes-change",
newAttrs => is(newAttrs.live, "polite", "Attributes are updated"), newAttrs => {
() => ContentTask.spawn(browser, null, () => checkA11yFront(accessibleFront, { attributes: {
"container-live": "polite",
display: "inline-block",
"event-from-input": "false",
"explicit-name": "true",
id: "button",
live: "polite",
"margin-bottom": "0px",
"margin-left": "0px",
"margin-right": "0px",
"margin-top": "0px",
tag: "button",
"text-align": "center",
"text-indent": "0px"
}});
is(newAttrs.live, "polite", "Attributes are updated");
}, () => ContentTask.spawn(browser, null, () =>
content.document.getElementById("button").setAttribute("aria-live", "polite"))); content.document.getElementById("button").setAttribute("aria-live", "polite")));
attrs = await accessibleFront.getAttributes();
is(attrs.live, "polite", "Attributes are updated");
info("Value change event"); info("Value change event");
checkA11yFront(accessibleSliderFront, { value: "5" }); checkA11yFront(accessibleSliderFront, { value: "5" });
@ -76,18 +100,29 @@ add_task(async function () {
info("Reorder event"); info("Reorder event");
is(accessibleSliderFront.childCount, 1, "Slider has only 1 child"); is(accessibleSliderFront.childCount, 1, "Slider has only 1 child");
let [firstChild, ] = await accessibleSliderFront.children();
is(firstChild.indexInParent, 0, "Slider's first child has correct index in parent");
await emitA11yEvent(accessibleSliderFront, "reorder", await emitA11yEvent(accessibleSliderFront, "reorder",
childCount => is(childCount, 2, "Child count is updated"), childCount => {
() => ContentTask.spawn(browser, null, () => { is(childCount, 2, "Child count is updated");
let button = content.document.createElement("button"); is(accessibleSliderFront.childCount, 2, "Child count is updated");
is(firstChild.indexInParent, 1,
"Slider's first child has an updated index in parent");
}, () => ContentTask.spawn(browser, null, () => {
let doc = content.document;
let slider = doc.getElementById("slider");
let button = doc.createElement("button");
button.innerText = "Slider button"; button.innerText = "Slider button";
content.document.getElementById("slider").appendChild(button); content.document.getElementById("slider").insertBefore(button, slider.firstChild);
})); }));
is(accessibleSliderFront.childCount, 2, "Child count is updated");
let a11yShutdown = waitForA11yShutdown(); await emitA11yEvent(firstChild, "index-in-parent-change", indexInParent =>
is(indexInParent, 0, "Slider's first child has an updated index in parent"), () =>
ContentTask.spawn(browser, null, () =>
content.document.getElementById("slider").firstChild.remove()));
await accessibility.disable();
await waitForA11yShutdown();
await client.close(); await client.close();
forceCollections();
await a11yShutdown;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
}); });

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

@ -4,10 +4,19 @@
"use strict"; "use strict";
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
function checkAccessibilityState(accessibility, expected) {
let { enabled, canBeDisabled, canBeEnabled } = accessibility;
is(enabled, expected.enabled, "Enabled state is correct.");
is(canBeDisabled, expected.canBeDisabled, "canBeDisabled state is correct.");
is(canBeEnabled, expected.canBeEnabled, "canBeEnabled state is correct.");
}
// Simple checks for the AccessibilityActor and AccessibleWalkerActor // Simple checks for the AccessibilityActor and AccessibleWalkerActor
add_task(async function () { add_task(async function () {
let {client, accessibility} = await initAccessibilityFrontForUrl( let { walker: domWalker, client, accessibility} = await initAccessibilityFrontForUrl(
"data:text/html;charset=utf-8,<title>test</title><div></div>"); "data:text/html;charset=utf-8,<title>test</title><div></div>");
ok(accessibility, "The AccessibilityFront was created"); ok(accessibility, "The AccessibilityFront was created");
@ -16,6 +25,44 @@ add_task(async function () {
let a11yWalker = await accessibility.getWalker(); let a11yWalker = await accessibility.getWalker();
ok(a11yWalker, "The AccessibleWalkerFront was returned"); ok(a11yWalker, "The AccessibleWalkerFront was returned");
checkAccessibilityState(accessibility,
{ enabled: false, canBeDisabled: true, canBeEnabled: true });
info("Force disable accessibility service: updates canBeEnabled flag");
let onEvent = accessibility.once("can-be-enabled-change");
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
await onEvent;
checkAccessibilityState(accessibility,
{ enabled: false, canBeDisabled: true, canBeEnabled: false });
info("Clear force disable accessibility service: updates canBeEnabled flag");
onEvent = accessibility.once("can-be-enabled-change");
Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
await onEvent;
checkAccessibilityState(accessibility,
{ enabled: false, canBeDisabled: true, canBeEnabled: true });
info("Initialize accessibility service");
let initEvent = accessibility.once("init");
await accessibility.enable();
await waitForA11yInit();
await initEvent;
checkAccessibilityState(accessibility,
{ enabled: true, canBeDisabled: true, canBeEnabled: true });
a11yWalker = await accessibility.getWalker();
let rootNode = await domWalker.getRootNode();
let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
ok(a11yDoc, "Accessible document actor is created");
info("Shutdown accessibility service");
let shutdownEvent = accessibility.once("shutdown");
await accessibility.disable();
await waitForA11yShutdown();
await shutdownEvent;
checkAccessibilityState(accessibility,
{ enabled: false, canBeDisabled: true, canBeEnabled: true });
await client.close(); await client.close();
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
}); });

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

@ -10,10 +10,12 @@ add_task(async function () {
let {client, walker, accessibility} = let {client, walker, accessibility} =
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html"); await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
let a11yWalker = await accessibility.getWalker(walker); let a11yWalker = await accessibility.getWalker();
ok(a11yWalker, "The AccessibleWalkerFront was returned"); ok(a11yWalker, "The AccessibleWalkerFront was returned");
let a11yDoc = await a11yWalker.getDocument(); await accessibility.enable();
let rootNode = await walker.getRootNode();
let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
ok(a11yDoc, "The AccessibleFront for root doc is created"); ok(a11yDoc, "The AccessibleFront for root doc is created");
let children = await a11yWalker.children(); let children = await a11yWalker.children();
@ -30,6 +32,15 @@ add_task(async function () {
role: "pushbutton" role: "pushbutton"
}); });
let ancestry = await a11yWalker.getAncestry(accessibleFront);
is(ancestry.length, 1, "Button is a direct child of a root document.");
is(ancestry[0].accessible, a11yDoc,
"Button's only ancestor is a root document");
is(ancestry[0].children.length, 3,
"Root doc should have correct number of children");
ok(ancestry[0].children.includes(accessibleFront),
"Button accessible front is in root doc's children");
let browser = gBrowser.selectedBrowser; let browser = gBrowser.selectedBrowser;
// Ensure name-change event is emitted by walker when cached accessible's name // Ensure name-change event is emitted by walker when cached accessible's name
@ -67,9 +78,55 @@ add_task(async function () {
() => ContentTask.spawn(browser, null, () => () => ContentTask.spawn(browser, null, () =>
content.document.getElementById("button").remove())); content.document.getElementById("button").remove()));
let a11yShutdown = waitForA11yShutdown(); let shown = await a11yWalker.highlightAccessible(docChildren[0]);
ok(shown, "AccessibleHighlighter highlighted the node");
shown = await a11yWalker.highlightAccessible(a11yDoc);
ok(!shown, "AccessibleHighlighter does not highlight an accessible with no bounds");
await a11yWalker.unhighlight();
info("Checking AccessibleWalker picker functionality");
ok(a11yWalker.pick, "AccessibleWalker pick method exists");
ok(a11yWalker.pickAndFocus, "AccessibleWalker pickAndFocus method exists");
ok(a11yWalker.cancelPick, "AccessibleWalker cancelPick method exists");
let onPickerEvent = a11yWalker.once("picker-accessible-hovered");
await a11yWalker.pick();
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { type: "mousemove" }, browser);
let acc = await onPickerEvent;
checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
onPickerEvent = a11yWalker.once("picker-accessible-previewed");
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { shiftKey: true }, browser);
acc = await onPickerEvent;
checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
onPickerEvent = a11yWalker.once("picker-accessible-canceled");
await BrowserTestUtils.synthesizeKey("VK_ESCAPE", { type: "keydown" }, browser);
await onPickerEvent;
onPickerEvent = a11yWalker.once("picker-accessible-hovered");
await a11yWalker.pick();
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { type: "mousemove" }, browser);
await onPickerEvent;
onPickerEvent = a11yWalker.once("picker-accessible-picked");
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { }, browser);
acc = await onPickerEvent;
checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
await a11yWalker.cancelPick();
info("Checking document-ready event fired by walker when top level accessible " +
"document is recreated.");
let reloaded = BrowserTestUtils.browserLoaded(browser);
let documentReady = a11yWalker.once("document-ready");
browser.reload();
await reloaded;
await documentReady;
await accessibility.disable();
await waitForA11yShutdown();
await client.close(); await client.close();
forceCollections();
await a11yShutdown;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
}); });

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

@ -89,6 +89,8 @@ async function initAccessibilityFrontForUrl(url) {
let walker = await inspector.getWalker(); let walker = await inspector.getWalker();
let accessibility = AccessibilityFront(client, form); let accessibility = AccessibilityFront(client, form);
await accessibility.bootstrap();
return {inspector, walker, accessibility, client}; return {inspector, walker, accessibility, client};
} }
@ -308,24 +310,47 @@ function checkA11yFront(front, expected, expectedFront) {
} }
for (let key in expected) { for (let key in expected) {
is(front[key], expected[key], `accessibility front has correct ${key}`); if (["actions", "states", "attributes"].includes(key)) {
SimpleTest.isDeeply(front[key], expected[key],
`Accessible Front has correct ${key}`);
} else {
is(front[key], expected[key], `accessibility front has correct ${key}`);
}
} }
} }
function getA11yInitOrShutdownPromise() {
return new Promise(resolve => {
let observe = (subject, topic, data) => {
Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
resolve(data);
};
Services.obs.addObserver(observe, "a11y-init-or-shutdown");
});
}
/** /**
* Wait for accessibility service to shut down. We consider it shut down when * Wait for accessibility service to shut down. We consider it shut down when
* an "a11y-init-or-shutdown" event is received with a value of "0". * an "a11y-init-or-shutdown" event is received with a value of "0".
*/ */
async function waitForA11yShutdown() { async function waitForA11yShutdown() {
await ContentTask.spawn(gBrowser.selectedBrowser, {}, () => if (!Services.appinfo.accessibilityEnabled) {
new Promise(resolve => { return;
let observe = (subject, topic, data) => { }
Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
if (data === "0") { await getA11yInitOrShutdownPromise().then(data =>
resolve(); data === "0" ? Promise.resolve() : Promise.reject());
} }
};
Services.obs.addObserver(observe, "a11y-init-or-shutdown"); /**
})); * Wait for accessibility service to initialize. We consider it initialized when
* an "a11y-init-or-shutdown" event is received with a value of "1".
*/
async function waitForA11yInit() {
if (Services.appinfo.accessibilityEnabled) {
return;
}
await getA11yInitOrShutdownPromise().then(data =>
data === "1" ? Promise.resolve() : Promise.reject());
} }

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

@ -3,50 +3,74 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const { const {
custom,
Front, Front,
FrontClassWithSpec, FrontClassWithSpec,
preEvent, preEvent
types
} = require("devtools/shared/protocol.js"); } = require("devtools/shared/protocol.js");
const { const {
accessibleSpec, accessibleSpec,
accessibleWalkerSpec, accessibleWalkerSpec,
accessibilitySpec accessibilitySpec
} = require("devtools/shared/specs/accessibility"); } = require("devtools/shared/specs/accessibility");
const events = require("devtools/shared/event-emitter"); const events = require("devtools/shared/event-emitter");
const ACCESSIBLE_PROPERTIES = [
"role",
"name",
"value",
"description",
"help",
"keyboardShortcut",
"childCount",
"domNodeType"
];
const AccessibleFront = FrontClassWithSpec(accessibleSpec, { const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
initialize(client, form) { initialize(client, form) {
Front.prototype.initialize.call(this, client, form); Front.prototype.initialize.call(this, client, form);
// Define getters for accesible properties that are received from the actor.
// Note: we would like accessible properties to be iterable for a11y
// clients.
for (let key of ACCESSIBLE_PROPERTIES) {
Object.defineProperty(this, key, {
get() {
return this._form[key];
},
enumerable: true
});
}
}, },
marshallPool() { marshallPool() {
return this.walker; return this.parent();
},
get role() {
return this._form.role;
},
get name() {
return this._form.name;
},
get value() {
return this._form.value;
},
get description() {
return this._form.description;
},
get help() {
return this._form.help;
},
get keyboardShortcut() {
return this._form.keyboardShortcut;
},
get childCount() {
return this._form.childCount;
},
get domNodeType() {
return this._form.domNodeType;
},
get indexInParent() {
return this._form.indexInParent;
},
get states() {
return this._form.states;
},
get actions() {
return this._form.actions;
},
get attributes() {
return this._form.attributes;
}, },
form(form, detail) { form(form, detail) {
@ -57,25 +81,14 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
this.actorID = form.actor; this.actorID = form.actor;
this._form = form; this._form = form;
DevToolsUtils.defineLazyGetter(this, "walker", () =>
types.getType("accessiblewalker").read(this._form.walker, this));
}, },
/** nameChange: preEvent("name-change", function (name, parent, walker) {
* Get a dom node front from accessible actor's raw accessible object's
* DONNode property.
*/
getDOMNode(domWalker) {
return domWalker.getNodeFromActor(this.actorID,
["rawAccessible", "DOMNode"]);
},
nameChange: preEvent("name-change", function (name, parent) {
this._form.name = name; this._form.name = name;
// Name change event affects the tree rendering, we fire this event on // Name change event affects the tree rendering, we fire this event on
// accessibility walker as the point of interaction for UI. // accessibility walker as the point of interaction for UI.
if (this.walker) { if (walker) {
events.emit(this.walker, "name-change", this, parent); events.emit(walker, "name-change", this, parent);
} }
}), }),
@ -95,21 +108,37 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
this._form.keyboardShortcut = keyboardShortcut; this._form.keyboardShortcut = keyboardShortcut;
}), }),
reorder: preEvent("reorder", function (childCount) { reorder: preEvent("reorder", function (childCount, walker) {
this._form.childCount = childCount; this._form.childCount = childCount;
// Reorder event affects the tree rendering, we fire this event on // Reorder event affects the tree rendering, we fire this event on
// accessibility walker as the point of interaction for UI. // accessibility walker as the point of interaction for UI.
if (this.walker) { if (walker) {
events.emit(this.walker, "reorder", this); events.emit(walker, "reorder", this);
} }
}), }),
textChange: preEvent("text-change", function () { textChange: preEvent("text-change", function (walker) {
// Text event affects the tree rendering, we fire this event on // Text event affects the tree rendering, we fire this event on
// accessibility walker as the point of interaction for UI. // accessibility walker as the point of interaction for UI.
if (this.walker) { if (walker) {
events.emit(this.walker, "text-change", this); events.emit(walker, "text-change", this);
} }
}),
indexInParentChange: preEvent("index-in-parent-change", function (indexInParent) {
this._form.indexInParent = indexInParent;
}),
statesChange: preEvent("states-change", function (states) {
this._form.states = states;
}),
actionsChange: preEvent("actions-change", function (actions) {
this._form.actions = actions;
}),
attributesChange: preEvent("attributes-change", function (attributes) {
this._form.attributes = attributes;
}) })
}); });
@ -120,7 +149,17 @@ const AccessibleWalkerFront = FrontClassWithSpec(accessibleWalkerSpec, {
form(json) { form(json) {
this.actorID = json.actor; this.actorID = json.actor;
} },
pick: custom(function (doFocus) {
if (doFocus) {
return this.pickAndFocus();
}
return this._pick();
}, {
impl: "_pick"
})
}); });
const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, { const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, {
@ -128,7 +167,33 @@ const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, {
Front.prototype.initialize.call(this, client, form); Front.prototype.initialize.call(this, client, form);
this.actorID = form.accessibilityActor; this.actorID = form.accessibilityActor;
this.manage(this); this.manage(this);
} },
bootstrap: custom(function () {
return this._bootstrap().then(state => {
this.enabled = state.enabled;
this.canBeEnabled = state.canBeEnabled;
this.canBeDisabled = state.canBeDisabled;
});
}, {
impl: "_bootstrap"
}),
init: preEvent("init", function () {
this.enabled = true;
}),
shutdown: preEvent("shutdown", function () {
this.enabled = false;
}),
canBeEnabled: preEvent("can-be-enabled-change", function (canBeEnabled) {
this.canBeEnabled = canBeEnabled;
}),
canBeDisabled: preEvent("can-be-disabled-change", function (canBeDisabled) {
this.canBeDisabled = canBeDisabled;
})
}); });
exports.AccessibleFront = AccessibleFront; exports.AccessibleFront = AccessibleFront;

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

@ -47,6 +47,10 @@ const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
return this._form.traits && this._form.traits.authoredStyles; return this._form.traits && this._form.traits.authoredStyles;
}, },
get supportsFontVariations() {
return this._form.traits && this._form.traits.fontVariations;
},
getMatchedSelectors: custom(function (node, property, options) { getMatchedSelectors: custom(function (node, property, options) {
return this._getMatchedSelectors(node, property, options).then(ret => { return this._getMatchedSelectors(node, property, options).then(ret => {
return ret.matched; return ret.matched;

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

@ -9,6 +9,17 @@ const { Arg, generateActorSpec, RetVal, types } = protocol;
types.addActorType("accessible"); types.addActorType("accessible");
/**
* Accessible with children listed in the ancestry structure calculated by the
* walker.
*/
types.addDictType("accessibleWithChildren", {
// Accessible
accessible: "accessible",
// Accessible's children
children: "array:accessible"
});
const accessibleSpec = generateActorSpec({ const accessibleSpec = generateActorSpec({
typeName: "accessible", typeName: "accessible",
@ -20,7 +31,8 @@ const accessibleSpec = generateActorSpec({
"name-change": { "name-change": {
type: "nameChange", type: "nameChange",
name: Arg(0, "string"), name: Arg(0, "string"),
parent: Arg(1, "nullable:accessible") parent: Arg(1, "nullable:accessible"),
walker: Arg(2, "nullable:accessiblewalker")
}, },
"value-change": { "value-change": {
type: "valueChange", type: "valueChange",
@ -30,13 +42,13 @@ const accessibleSpec = generateActorSpec({
type: "descriptionChange", type: "descriptionChange",
description: Arg(0, "string") description: Arg(0, "string")
}, },
"state-change": { "states-change": {
type: "stateChange", type: "statesChange",
states: Arg(0, "array:string") states: Arg(0, "array:string")
}, },
"attributes-change": { "attributes-change": {
type: "attributesChange", type: "attributesChange",
states: Arg(0, "json") attributes: Arg(0, "json")
}, },
"help-change": { "help-change": {
type: "helpChange", type: "helpChange",
@ -48,38 +60,20 @@ const accessibleSpec = generateActorSpec({
}, },
"reorder": { "reorder": {
type: "reorder", type: "reorder",
childCount: Arg(0, "number") childCount: Arg(0, "number"),
walker: Arg(1, "nullable:accessiblewalker")
}, },
"text-change": { "text-change": {
type: "textChange" type: "textChange",
walker: Arg(0, "nullable:accessiblewalker")
},
"index-in-parent-change": {
type: "indexInParentChange",
indexInParent: Arg(0, "number")
} }
}, },
methods: { methods: {
getActions: {
request: {},
response: {
actions: RetVal("array:string")
}
},
getIndexInParent: {
request: {},
response: {
indexInParent: RetVal("number")
}
},
getState: {
request: {},
response: {
states: RetVal("array:string")
}
},
getAttributes: {
request: {},
response: {
attributes: RetVal("json")
}
},
children: { children: {
request: {}, request: {},
response: { response: {
@ -96,6 +90,24 @@ const accessibleWalkerSpec = generateActorSpec({
"accessible-destroy": { "accessible-destroy": {
type: "accessibleDestroy", type: "accessibleDestroy",
accessible: Arg(0, "accessible") accessible: Arg(0, "accessible")
},
"document-ready": {
type: "documentReady",
},
"picker-accessible-picked": {
type: "pickerAccessiblePicked",
accessible: Arg(0, "nullable:accessible")
},
"picker-accessible-previewed": {
type: "pickerAccessiblePreviewed",
accessible: Arg(0, "nullable:accessible")
},
"picker-accessible-hovered": {
type: "pickerAccessibleHovered",
accessible: Arg(0, "nullable:accessible")
},
"picker-accessible-canceled": {
type: "pickerAccessibleCanceled"
} }
}, },
@ -106,30 +118,76 @@ const accessibleWalkerSpec = generateActorSpec({
children: RetVal("array:accessible") children: RetVal("array:accessible")
} }
}, },
getDocument: {
request: {},
response: {
document: RetVal("accessible")
}
},
getAccessibleFor: { getAccessibleFor: {
request: { node: Arg(0, "domnode") }, request: { node: Arg(0, "domnode") },
response: { response: {
accessible: RetVal("accessible") accessible: RetVal("accessible")
} }
} },
getAncestry: {
request: { accessible: Arg(0, "accessible") },
response: {
ancestry: RetVal("array:accessibleWithChildren")
}
},
highlightAccessible: {
request: {
accessible: Arg(0, "accessible"),
options: Arg(1, "nullable:json")
},
response: {
value: RetVal("nullable:boolean")
}
},
unhighlight: {
request: {}
},
pick: {},
pickAndFocus: {},
cancelPick: {}
} }
}); });
const accessibilitySpec = generateActorSpec({ const accessibilitySpec = generateActorSpec({
typeName: "accessibility", typeName: "accessibility",
events: {
"init": {
type: "init"
},
"shutdown": {
type: "shutdown"
},
"can-be-disabled-change": {
type: "canBeDisabledChange",
canBeDisabled: Arg(0, "boolean")
},
"can-be-enabled-change": {
type: "canBeEnabledChange",
canBeEnabled: Arg(0, "boolean")
}
},
methods: { methods: {
bootstrap: {
request: {},
response: {
state: RetVal("json")
}
},
getWalker: { getWalker: {
request: {}, request: {},
response: { response: {
walker: RetVal("accessiblewalker") walker: RetVal("accessiblewalker")
} }
},
enable: {
request: {},
response: {}
},
disable: {
request: {},
response: {}
} }
} }
}); });

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

@ -58,6 +58,24 @@ types.addDictType("fontpreview", {
size: "json" size: "json"
}); });
types.addDictType("fontvariationaxis", {
tag: "string",
name: "string",
minValue: "number",
maxValue: "number",
defaultValue: "number"
});
types.addDictType("fontvariationinstancevalue", {
axis: "string",
value: "number"
});
types.addDictType("fontvariationinstance", {
name: "string",
values: "array:fontvariationinstancevalue"
});
types.addDictType("fontface", { types.addDictType("fontface", {
name: "string", name: "string",
CSSFamilyName: "string", CSSFamilyName: "string",
@ -67,7 +85,9 @@ types.addDictType("fontface", {
format: "string", format: "string",
preview: "nullable:fontpreview", preview: "nullable:fontpreview",
localName: "string", localName: "string",
metadata: "string" metadata: "string",
variationAxes: "array:fontvariationaxis",
variationInstances: "array:fontvariationinstance"
}); });
const pageStyleSpec = generateActorSpec({ const pageStyleSpec = generateActorSpec({
@ -95,6 +115,7 @@ const pageStyleSpec = generateActorSpec({
getAllUsedFontFaces: { getAllUsedFontFaces: {
request: { request: {
includePreviews: Option(0, "boolean"), includePreviews: Option(0, "boolean"),
includeVariations: Option(1, "boolean"),
previewText: Option(0, "string"), previewText: Option(0, "string"),
previewFontSize: Option(0, "string"), previewFontSize: Option(0, "string"),
previewFillStyle: Option(0, "string") previewFillStyle: Option(0, "string")
@ -107,6 +128,7 @@ const pageStyleSpec = generateActorSpec({
request: { request: {
node: Arg(0, "domnode"), node: Arg(0, "domnode"),
includePreviews: Option(1, "boolean"), includePreviews: Option(1, "boolean"),
includeVariations: Option(1, "boolean"),
previewText: Option(1, "string"), previewText: Option(1, "string"),
previewFontSize: Option(1, "string"), previewFontSize: Option(1, "string"),
previewFillStyle: Option(1, "string") previewFillStyle: Option(1, "string")

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

@ -423,6 +423,11 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) { definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) {
return; return;
} }
if (!definition->mCallbacks) {
// definition has been unlinked. Don't try to mess with it.
return;
}
} }
auto callback = auto callback =

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

@ -1102,7 +1102,12 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
nsContentUtils::Retarget(relatedTargetAsNode, this); nsContentUtils::Retarget(relatedTargetAsNode, this);
nsCOMPtr<nsINode> targetInKnownToBeHandledScope = nsCOMPtr<nsINode> targetInKnownToBeHandledScope =
FindChromeAccessOnlySubtreeOwner(aVisitor.mTargetInKnownToBeHandledScope); FindChromeAccessOnlySubtreeOwner(aVisitor.mTargetInKnownToBeHandledScope);
if (nsContentUtils::ContentIsShadowIncludingDescendantOf( // If aVisitor.mTargetInKnownToBeHandledScope wasn't nsINode,
// targetInKnownToBeHandledScope will be null. This may happen when
// dispatching event to Window object in a content page and
// propagating the event to a chrome Element.
if (targetInKnownToBeHandledScope &&
nsContentUtils::ContentIsShadowIncludingDescendantOf(
this, targetInKnownToBeHandledScope->SubtreeRoot())) { this, targetInKnownToBeHandledScope->SubtreeRoot())) {
// Part of step 11.4. // Part of step 11.4.
// "If target's root is a shadow-including inclusive ancestor of // "If target's root is a shadow-including inclusive ancestor of

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

@ -1445,8 +1445,8 @@ nsIDocument::nsIDocument()
mHasHadScriptHandlingObject(false), mHasHadScriptHandlingObject(false),
mIsBeingUsedAsImage(false), mIsBeingUsedAsImage(false),
mIsSyntheticDocument(false), mIsSyntheticDocument(false),
mHasLinksToUpdate(false),
mHasLinksToUpdateRunnable(false), mHasLinksToUpdateRunnable(false),
mFlushingPendingLinkUpdates(false),
mMayHaveDOMMutationObservers(false), mMayHaveDOMMutationObservers(false),
mMayHaveAnimationObservers(false), mMayHaveAnimationObservers(false),
mHasMixedActiveContentLoaded(false), mHasMixedActiveContentLoaded(false),
@ -1491,7 +1491,6 @@ nsIDocument::nsIDocument()
mType(eUnknown), mType(eUnknown),
mDefaultElementType(0), mDefaultElementType(0),
mAllowXULXBL(eTriUnset), mAllowXULXBL(eTriUnset),
mIsLinkUpdateRegistrationsForbidden(false),
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS), mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
mSandboxFlags(0), mSandboxFlags(0),
mPartID(0), mPartID(0),
@ -9612,15 +9611,13 @@ nsIDocument::EnumerateActivityObservers(ActivityObserverEnumerator aEnumerator,
void void
nsIDocument::RegisterPendingLinkUpdate(Link* aLink) nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
{ {
MOZ_RELEASE_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
if (aLink->HasPendingLinkUpdate()) { if (aLink->HasPendingLinkUpdate()) {
return; return;
} }
aLink->SetHasPendingLinkUpdate(); aLink->SetHasPendingLinkUpdate();
if (!mHasLinksToUpdateRunnable) { if (!mHasLinksToUpdateRunnable && !mFlushingPendingLinkUpdates) {
nsCOMPtr<nsIRunnable> event = nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("nsIDocument::FlushPendingLinkUpdatesFromRunnable", NewRunnableMethod("nsIDocument::FlushPendingLinkUpdatesFromRunnable",
this, this,
@ -9637,7 +9634,6 @@ nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
} }
mLinksToUpdate.InfallibleAppend(aLink); mLinksToUpdate.InfallibleAppend(aLink);
mHasLinksToUpdate = true;
} }
void void
@ -9651,24 +9647,26 @@ nsIDocument::FlushPendingLinkUpdatesFromRunnable()
void void
nsIDocument::FlushPendingLinkUpdates() nsIDocument::FlushPendingLinkUpdates()
{ {
MOZ_RELEASE_ASSERT(!mIsLinkUpdateRegistrationsForbidden); if (mFlushingPendingLinkUpdates) {
if (!mHasLinksToUpdate)
return; return;
}
AutoRestore<bool> saved(mIsLinkUpdateRegistrationsForbidden); auto restore = MakeScopeExit([&] { mFlushingPendingLinkUpdates = false; });
mIsLinkUpdateRegistrationsForbidden = true; mFlushingPendingLinkUpdates = true;
for (auto iter = mLinksToUpdate.Iter(); !iter.Done(); iter.Next()) {
Link* link = iter.Get(); while (!mLinksToUpdate.IsEmpty()) {
Element* element = link->GetElement(); LinksToUpdateList links(Move(mLinksToUpdate));
if (element->OwnerDoc() == this) { for (auto iter = links.Iter(); !iter.Done(); iter.Next()) {
link->ClearHasPendingLinkUpdate(); Link* link = iter.Get();
if (element->IsInComposedDoc()) { Element* element = link->GetElement();
element->UpdateLinkState(link->LinkState()); if (element->OwnerDoc() == this) {
link->ClearHasPendingLinkUpdate();
if (element->IsInComposedDoc()) {
element->UpdateLinkState(link->LinkState());
}
} }
} }
} }
mLinksToUpdate.Clear();
mHasLinksToUpdate = false;
} }
already_AddRefed<nsIDocument> already_AddRefed<nsIDocument>

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

@ -3344,10 +3344,13 @@ protected:
// The array of all links that need their status resolved. Links must add themselves // The array of all links that need their status resolved. Links must add themselves
// to this set by calling RegisterPendingLinkUpdate when added to a document. // to this set by calling RegisterPendingLinkUpdate when added to a document.
static const size_t kSegmentSize = 128; static const size_t kSegmentSize = 128;
mozilla::SegmentedVector<nsCOMPtr<mozilla::dom::Link>,
kSegmentSize, typedef mozilla::SegmentedVector<nsCOMPtr<mozilla::dom::Link>,
InfallibleAllocPolicy> kSegmentSize,
mLinksToUpdate; InfallibleAllocPolicy>
LinksToUpdateList;
LinksToUpdateList mLinksToUpdate;
// SMIL Animation Controller, lazily-initialized in GetAnimationController // SMIL Animation Controller, lazily-initialized in GetAnimationController
RefPtr<nsSMILAnimationController> mAnimationController; RefPtr<nsSMILAnimationController> mAnimationController;
@ -3441,12 +3444,12 @@ protected:
// file, etc. // file, etc.
bool mIsSyntheticDocument : 1; bool mIsSyntheticDocument : 1;
// True if this document has links whose state needs updating
bool mHasLinksToUpdate : 1;
// True is there is a pending runnable which will call FlushPendingLinkUpdates(). // True is there is a pending runnable which will call FlushPendingLinkUpdates().
bool mHasLinksToUpdateRunnable : 1; bool mHasLinksToUpdateRunnable : 1;
// True if we're flushing pending link updates.
bool mFlushingPendingLinkUpdates : 1;
// True if a DOMMutationObserver is perhaps attached to a node in the document. // True if a DOMMutationObserver is perhaps attached to a node in the document.
bool mMayHaveDOMMutationObservers : 1; bool mMayHaveDOMMutationObservers : 1;
@ -3595,12 +3598,6 @@ protected:
Tri mAllowXULXBL; Tri mAllowXULXBL;
/**
* This is true while FlushPendingLinkUpdates executes. Calls to
* [Un]RegisterPendingLinkUpdate will assert when this is true.
*/
bool mIsLinkUpdateRegistrationsForbidden;
// The document's script global object, the object from which the // The document's script global object, the object from which the
// document can get its script context and scope. This is the // document can get its script context and scope. This is the
// *inner* window object. // *inner* window object.

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

@ -23,10 +23,6 @@ class nsICycleCollectorListener;
class nsScriptNameSpaceManager; class nsScriptNameSpaceManager;
class nsIDocShell; class nsIDocShell;
namespace JS {
class AutoValueVector;
} // namespace JS
namespace mozilla { namespace mozilla {
template <class> class Maybe; template <class> class Maybe;
struct CycleCollectorResults; struct CycleCollectorResults;

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

@ -208,7 +208,9 @@ ClientSource::WorkerExecutionReady(WorkerPrivate* aWorkerPrivate)
// execution ready. We can't reliably determine what our storage policy // execution ready. We can't reliably determine what our storage policy
// is before execution ready, unfortunately. // is before execution ready, unfortunately.
if (mController.isSome()) { if (mController.isSome()) {
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->IsStorageAllowed()); MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->IsStorageAllowed() ||
StringBeginsWith(aWorkerPrivate->ScriptURL(),
NS_LITERAL_STRING("blob:")));
} }
// Its safe to store the WorkerPrivate* here because the ClientSource // Its safe to store the WorkerPrivate* here because the ClientSource
@ -236,34 +238,36 @@ ClientSource::WindowExecutionReady(nsPIDOMWindowInner* aInnerWindow)
} }
nsIDocument* doc = aInnerWindow->GetExtantDoc(); nsIDocument* doc = aInnerWindow->GetExtantDoc();
if (NS_WARN_IF(!doc)) { NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
return NS_ERROR_UNEXPECTED;
} nsIURI* uri = doc->GetOriginalURI();
NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
// Don't use nsAutoCString here since IPC requires a full nsCString anyway.
nsCString spec;
nsresult rv = uri->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
// A client without access to storage should never be controlled by // A client without access to storage should never be controlled by
// a service worker. Check this here in case we were controlled before // a service worker. Check this here in case we were controlled before
// execution ready. We can't reliably determine what our storage policy // execution ready. We can't reliably determine what our storage policy
// is before execution ready, unfortunately. // is before execution ready, unfortunately.
//
// Note, explicitly avoid checking storage policy for windows that inherit
// service workers from their parent. If a user opens a controlled window
// and then blocks storage, that window will continue to be controlled by
// the SW until the window is closed. Any about:blank or blob URL should
// continue to inherit the SW as well. We need to avoid triggering the
// assertion in this corner case.
if (mController.isSome()) { if (mController.isSome()) {
MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::StorageAllowedForWindow(aInnerWindow) == MOZ_DIAGNOSTIC_ASSERT(spec.LowerCaseEqualsLiteral("about:blank") ||
StringBeginsWith(spec, NS_LITERAL_CSTRING("blob:")) ||
nsContentUtils::StorageAllowedForWindow(aInnerWindow) ==
nsContentUtils::StorageAccess::eAllow); nsContentUtils::StorageAccess::eAllow);
} }
// Don't use nsAutoCString here since IPC requires a full nsCString anyway.
nsCString spec;
nsIURI* uri = doc->GetOriginalURI();
if (uri) {
nsresult rv = uri->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
nsPIDOMWindowOuter* outer = aInnerWindow->GetOuterWindow(); nsPIDOMWindowOuter* outer = aInnerWindow->GetOuterWindow();
if (NS_WARN_IF(!outer)) { NS_ENSURE_TRUE(outer, NS_ERROR_UNEXPECTED);
return NS_ERROR_UNEXPECTED;
}
FrameType frameType = FrameType::Top_level; FrameType frameType = FrameType::Top_level;
if (!outer->IsTopLevelWindow()) { if (!outer->IsTopLevelWindow()) {
@ -386,11 +390,19 @@ ClientSource::SetController(const ServiceWorkerDescriptor& aServiceWorker)
// A client without access to storage should never be controlled a // A client without access to storage should never be controlled a
// a service worker. If we are already execution ready with a real // a service worker. If we are already execution ready with a real
// window or worker, then verify assert the storage policy is correct. // window or worker, then verify assert the storage policy is correct.
//
// Note, explicitly avoid checking storage policy for clients that inherit
// service workers from their parent. This basically means blob: URLs
// and about:blank windows.
if (GetInnerWindow()) { if (GetInnerWindow()) {
MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) == MOZ_DIAGNOSTIC_ASSERT(Info().URL().LowerCaseEqualsLiteral("about:blank") ||
StringBeginsWith(Info().URL(), NS_LITERAL_CSTRING("blob:")) ||
nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
nsContentUtils::StorageAccess::eAllow); nsContentUtils::StorageAccess::eAllow);
} else if (GetWorkerPrivate()) { } else if (GetWorkerPrivate()) {
MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->IsStorageAllowed()); MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->IsStorageAllowed() ||
StringBeginsWith(GetWorkerPrivate()->ScriptURL(),
NS_LITERAL_STRING("blob:")));
} }
if (mController.isSome() && mController.ref() == aServiceWorker) { if (mController.isSome() && mController.ref() == aServiceWorker) {

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

@ -2074,7 +2074,9 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
aOptions->setMutedErrors(!subsumes); aOptions->setMutedErrors(!subsumes);
} }
if (!aRequest->IsModuleRequest()) { if (aRequest->IsModuleRequest()) {
aOptions->hideScriptFromDebugger = true;
} else {
JSContext* cx = jsapi.cx(); JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> elementVal(cx); JS::Rooted<JS::Value> elementVal(cx);
MOZ_ASSERT(aRequest->mElement); MOZ_ASSERT(aRequest->mElement);
@ -2245,6 +2247,10 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->mElement); rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->mElement);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
moduleScript->SetSourceElementAssociated(); moduleScript->SetSourceElementAssociated();
// The script is now ready to be exposed to the debugger.
JS::Rooted<JSScript*> script(cx, JS::GetModuleScript(module));
JS::ExposeScriptToDebugger(cx, script);
} }
rv = nsJSUtils::ModuleEvaluate(cx, module); rv = nsJSUtils::ModuleEvaluate(cx, module);

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

@ -43,13 +43,17 @@ NS_IMPL_ISUPPORTS(CSPService, nsIContentPolicy, nsIChannelEventSink)
// Helper function to identify protocols and content types not subject to CSP. // Helper function to identify protocols and content types not subject to CSP.
bool bool
subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) { subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
nsContentPolicyType contentType =
nsContentUtils::InternalContentPolicyTypeToExternal(aContentType);
// These content types are not subject to CSP content policy checks: // These content types are not subject to CSP content policy checks:
// TYPE_CSP_REPORT -- csp can't block csp reports // TYPE_CSP_REPORT -- csp can't block csp reports
// TYPE_REFRESH -- never passed to ShouldLoad (see nsIContentPolicy.idl) // TYPE_REFRESH -- never passed to ShouldLoad (see nsIContentPolicy.idl)
// TYPE_DOCUMENT -- used for frame-ancestors // TYPE_DOCUMENT -- used for frame-ancestors
if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT || if (contentType == nsIContentPolicy::TYPE_CSP_REPORT ||
aContentType == nsIContentPolicy::TYPE_REFRESH || contentType == nsIContentPolicy::TYPE_REFRESH ||
aContentType == nsIContentPolicy::TYPE_DOCUMENT) { contentType == nsIContentPolicy::TYPE_DOCUMENT) {
return false; return false;
} }
@ -90,12 +94,16 @@ subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
// hence we use protocol flags to accomplish that, but we also // hence we use protocol flags to accomplish that, but we also
// want resource:, chrome: and moz-icon to be subject to CSP // want resource:, chrome: and moz-icon to be subject to CSP
// (which also use URI_IS_LOCAL_RESOURCE). // (which also use URI_IS_LOCAL_RESOURCE).
// Exception to the rule are images and styles using a scheme
// of resource: or chrome:
bool isImgOrStyle = contentType == nsIContentPolicy::TYPE_IMAGE ||
contentType == nsIContentPolicy::TYPE_STYLESHEET;
rv = aURI->SchemeIs("resource", &match); rv = aURI->SchemeIs("resource", &match);
if (NS_SUCCEEDED(rv) && match) { if (NS_SUCCEEDED(rv) && match && !isImgOrStyle) {
return true; return true;
} }
rv = aURI->SchemeIs("chrome", &match); rv = aURI->SchemeIs("chrome", &match);
if (NS_SUCCEEDED(rv) && match) { if (NS_SUCCEEDED(rv) && match && !isImgOrStyle) {
return true; return true;
} }
rv = aURI->SchemeIs("moz-icon", &match); rv = aURI->SchemeIs("moz-icon", &match);

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

@ -95,6 +95,148 @@ add_task(async function test_session_permission() {
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie"); Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
}); });
// Test to verify an about:blank iframe successfully inherits the
// parent's controller when storage is blocked between opening the
// parent page and creating the iframe.
add_task(async function test_block_storage_before_blank_iframe() {
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
let controller = await ContentTask.spawn(browser, null, async function() {
return content.navigator.serviceWorker.controller;
});
ok(!!controller, "page should be controlled with storage allowed");
let controller2 = await ContentTask.spawn(browser, null, async function() {
let f = content.document.createElement("iframe");
content.document.body.appendChild(f);
await new Promise(resolve => f.onload = resolve);
return !!f.contentWindow.navigator.serviceWorker.controller;
});
ok(!!controller2, "page should be controlled with storage allowed");
await SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT],
]});
let controller3 = await ContentTask.spawn(browser, null, async function() {
let f = content.document.createElement("iframe");
content.document.body.appendChild(f);
await new Promise(resolve => f.onload = resolve);
return !!f.contentWindow.navigator.serviceWorker.controller;
});
ok(!!controller3, "page should be controlled with storage allowed");
await SpecialPowers.popPrefEnv();
await BrowserTestUtils.removeTab(tab);
});
// Test to verify a blob URL iframe successfully inherits the
// parent's controller when storage is blocked between opening the
// parent page and creating the iframe.
add_task(async function test_block_storage_before_blob_iframe() {
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
let controller = await ContentTask.spawn(browser, null, async function() {
return content.navigator.serviceWorker.controller;
});
ok(!!controller, "page should be controlled with storage allowed");
let controller2 = await ContentTask.spawn(browser, null, async function() {
let b = new content.Blob(["<!DOCTYPE html><html></html>"], { type: "text/html" });
let f = content.document.createElement("iframe");
// No need to call revokeObjectURL() since the window will be closed shortly.
f.src = content.URL.createObjectURL(b);
content.document.body.appendChild(f);
await new Promise(resolve => f.onload = resolve);
return !!f.contentWindow.navigator.serviceWorker.controller;
});
ok(!!controller2, "page should be controlled with storage allowed");
await SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT],
]});
let controller3 = await ContentTask.spawn(browser, null, async function() {
let b = new content.Blob(["<!DOCTYPE html><html></html>"], { type: "text/html" });
let f = content.document.createElement("iframe");
// No need to call revokeObjectURL() since the window will be closed shortly.
f.src = content.URL.createObjectURL(b);
content.document.body.appendChild(f);
await new Promise(resolve => f.onload = resolve);
return !!f.contentWindow.navigator.serviceWorker.controller;
});
ok(!!controller3, "page should be controlled with storage allowed");
await SpecialPowers.popPrefEnv();
await BrowserTestUtils.removeTab(tab);
});
// Test to verify a blob worker script does not hit our service
// worker storage assertions when storage is blocked between opening
// the parent page and creating the worker. Note, we cannot
// explicitly check if the worker is controlled since we don't expose
// WorkerNavigator.serviceWorkers.controller yet.
add_task(async function test_block_storage_before_blob_worker() {
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
let controller = await ContentTask.spawn(browser, null, async function() {
return content.navigator.serviceWorker.controller;
});
ok(!!controller, "page should be controlled with storage allowed");
let scriptURL = await ContentTask.spawn(browser, null, async function() {
let b = new content.Blob(["self.postMessage(self.location.href);self.close()"],
{ type: "application/javascript" });
// No need to call revokeObjectURL() since the window will be closed shortly.
let u = content.URL.createObjectURL(b);
let w = new content.Worker(u);
return await new Promise(resolve => {
w.onmessage = e => resolve(e.data);
});
});
ok(scriptURL.startsWith("blob:"), "blob URL worker should run");
await SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT],
]});
let scriptURL2 = await ContentTask.spawn(browser, null, async function() {
let b = new content.Blob(["self.postMessage(self.location.href);self.close()"],
{ type: "application/javascript" });
// No need to call revokeObjectURL() since the window will be closed shortly.
let u = content.URL.createObjectURL(b);
let w = new content.Worker(u);
return await new Promise(resolve => {
w.onmessage = e => resolve(e.data);
});
});
ok(scriptURL2.startsWith("blob:"), "blob URL worker should run");
await SpecialPowers.popPrefEnv();
await BrowserTestUtils.removeTab(tab);
});
add_task(async function cleanup() { add_task(async function cleanup() {
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie"); Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");

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

@ -20,6 +20,22 @@
// ]; // ];
// //
// See createInterfaceMap() below for a complete list of properties. // See createInterfaceMap() below for a complete list of properties.
//
// The values of the properties need to be either literal true/false
// (e.g. indicating whether something is enabled on a particular
// channel/OS) or one of the is* constants below (in cases when
// exposure is affected by channel or OS in a nontrivial way).
const version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
const isNightly = version.endsWith("a1");
const isEarlyBetaOrEarlier = SpecialPowers.EARLY_BETA_OR_EARLIER;
const isRelease = !version.includes("a");
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
const isMac = /Mac OS/.test(navigator.oscpu);
const isWindows = /Windows/.test(navigator.oscpu);
const isAndroid = navigator.userAgent.includes("Android");
const isLinux = /Linux/.test(navigator.oscpu) && !isAndroid;
const isInsecureContext = !window.isSecureContext;
// IMPORTANT: Do not change this list without review from // IMPORTANT: Do not change this list without review from
// a JavaScript Engine peer! // a JavaScript Engine peer!
@ -29,8 +45,8 @@ var ecmaGlobals =
{name: "ArrayBuffer", insecureContext: true}, {name: "ArrayBuffer", insecureContext: true},
{name: "Atomics", insecureContext: true, disabled: true}, {name: "Atomics", insecureContext: true, disabled: true},
{name: "Boolean", insecureContext: true}, {name: "Boolean", insecureContext: true},
{name: "ByteLengthQueuingStrategy", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()}, {name: "ByteLengthQueuingStrategy", insecureContext: true, disabled: true},
{name: "CountQueuingStrategy", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()}, {name: "CountQueuingStrategy", insecureContext: true, disabled: true},
{name: "DataView", insecureContext: true}, {name: "DataView", insecureContext: true},
{name: "Date", insecureContext: true}, {name: "Date", insecureContext: true},
{name: "Error", insecureContext: true}, {name: "Error", insecureContext: true},
@ -56,7 +72,7 @@ var ecmaGlobals =
{name: "Promise", insecureContext: true}, {name: "Promise", insecureContext: true},
{name: "Proxy", insecureContext: true}, {name: "Proxy", insecureContext: true},
{name: "RangeError", insecureContext: true}, {name: "RangeError", insecureContext: true},
{name: "ReadableStream", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()}, {name: "ReadableStream", insecureContext: true, disabled: true},
{name: "ReferenceError", insecureContext: true}, {name: "ReferenceError", insecureContext: true},
{name: "Reflect", insecureContext: true}, {name: "Reflect", insecureContext: true},
{name: "RegExp", insecureContext: true}, {name: "RegExp", insecureContext: true},
@ -75,7 +91,7 @@ var ecmaGlobals =
{name: "URIError", insecureContext: true}, {name: "URIError", insecureContext: true},
{name: "WeakMap", insecureContext: true}, {name: "WeakMap", insecureContext: true},
{name: "WeakSet", insecureContext: true}, {name: "WeakSet", insecureContext: true},
{name: "WebAssembly", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()} {name: "WebAssembly", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupportedByHardware()},
]; ];
// IMPORTANT: Do not change the list above without review from // IMPORTANT: Do not change the list above without review from
// a JavaScript Engine peer! // a JavaScript Engine peer!
@ -723,7 +739,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer! // IMPORTANT: Do not change this list without review from a DOM peer!
{name: "OfflineAudioContext", insecureContext: true}, {name: "OfflineAudioContext", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer! // IMPORTANT: Do not change this list without review from a DOM peer!
{name: "OfflineResourceList", insecureContext: SpecialPowers.getBoolPref("browser.cache.offline.insecure.enable")}, {name: "OfflineResourceList", insecureContext: !isEarlyBetaOrEarlier},
// IMPORTANT: Do not change this list without review from a DOM peer! // IMPORTANT: Do not change this list without review from a DOM peer!
{name: "Option", insecureContext: true}, {name: "Option", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer! // IMPORTANT: Do not change this list without review from a DOM peer!
@ -1267,16 +1283,6 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change the list above without review from a DOM peer! // IMPORTANT: Do not change the list above without review from a DOM peer!
function createInterfaceMap(isXBLScope) { function createInterfaceMap(isXBLScope) {
var version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
var isNightly = version.endsWith("a1");
var isRelease = !version.includes("a");
var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
var isMac = /Mac OS/.test(navigator.oscpu);
var isWindows = /Windows/.test(navigator.oscpu);
var isAndroid = navigator.userAgent.includes("Android");
var isLinux = /Linux/.test(navigator.oscpu) && !isAndroid;
var isInsecureContext = !window.isSecureContext;
var interfaceMap = {}; var interfaceMap = {};
function addInterfaces(interfaces) function addInterfaces(interfaces)

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

@ -18,6 +18,12 @@
// ]; // ];
// //
// See createInterfaceMap() below for a complete list of properties. // See createInterfaceMap() below for a complete list of properties.
//
// The values of the properties need to be literal true/false
// (e.g. indicating whether something is enabled on a particular
// channel/OS). If we ever end up in a situation where a propert
// value needs to depend on channel or OS, we will need to make sure
// we have that information before setting up the property lists.
// IMPORTANT: Do not change this list without review from // IMPORTANT: Do not change this list without review from
// a JavaScript Engine peer! // a JavaScript Engine peer!
@ -27,8 +33,8 @@ var ecmaGlobals =
{name: "ArrayBuffer", insecureContext: true}, {name: "ArrayBuffer", insecureContext: true},
{name: "Atomics", insecureContext: true, disabled: true}, {name: "Atomics", insecureContext: true, disabled: true},
{name: "Boolean", insecureContext: true}, {name: "Boolean", insecureContext: true},
{name: "ByteLengthQueuingStrategy", insecureContext: true, optional: true}, {name: "ByteLengthQueuingStrategy", insecureContext: true, disabled: true},
{name: "CountQueuingStrategy", insecureContext: true, optional: true}, {name: "CountQueuingStrategy", insecureContext: true, disabled: true},
{name: "DataView", insecureContext: true}, {name: "DataView", insecureContext: true},
{name: "Date", insecureContext: true}, {name: "Date", insecureContext: true},
{name: "Error", insecureContext: true}, {name: "Error", insecureContext: true},
@ -51,7 +57,7 @@ var ecmaGlobals =
{name: "Promise", insecureContext: true}, {name: "Promise", insecureContext: true},
{name: "Proxy", insecureContext: true}, {name: "Proxy", insecureContext: true},
{name: "RangeError", insecureContext: true}, {name: "RangeError", insecureContext: true},
{name: "ReadableStream", insecureContext: true, optional: true}, {name: "ReadableStream", insecureContext: true, disabled: true},
{name: "ReferenceError", insecureContext: true}, {name: "ReferenceError", insecureContext: true},
{name: "Reflect", insecureContext: true}, {name: "Reflect", insecureContext: true},
{name: "RegExp", insecureContext: true}, {name: "RegExp", insecureContext: true},
@ -70,7 +76,11 @@ var ecmaGlobals =
{name: "URIError", insecureContext: true}, {name: "URIError", insecureContext: true},
{name: "WeakMap", insecureContext: true}, {name: "WeakMap", insecureContext: true},
{name: "WeakSet", insecureContext: true}, {name: "WeakSet", insecureContext: true},
{name: "WebAssembly", insecureContext: true, optional: true} // WebAssembly is not supported on some hardware configurations,
// but we have no way to check that from here. Just give up for
// now and don't check for it at all. Do NOT add any other uses
// of "optional"!
{name: "WebAssembly", insecureContext: true, optional: true},
]; ];
// IMPORTANT: Do not change the list above without review from // IMPORTANT: Do not change the list above without review from
// a JavaScript Engine peer! // a JavaScript Engine peer!

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

@ -94,8 +94,8 @@ txExprLexer::nextIsOperatorToken(Token* aToken)
nsresult nsresult
txExprLexer::parse(const nsAString& aPattern) txExprLexer::parse(const nsAString& aPattern)
{ {
iterator start, end; iterator end;
start = aPattern.BeginReading(mPosition); aPattern.BeginReading(mPosition);
aPattern.EndReading(end); aPattern.EndReading(end);
//-- initialize previous token, this will automatically get //-- initialize previous token, this will automatically get
@ -125,7 +125,7 @@ txExprLexer::parse(const nsAString& aPattern)
// NCName, can get QName or OperatorName; // NCName, can get QName or OperatorName;
// FunctionName, NodeName, and AxisSpecifier may want whitespace, // FunctionName, NodeName, and AxisSpecifier may want whitespace,
// and are dealt with below // and are dealt with below
start = mPosition; iterator start = mPosition;
while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) { while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
/* just go */ /* just go */
} }
@ -170,7 +170,7 @@ txExprLexer::parse(const nsAString& aPattern)
newToken = new Token(start, mPosition, defType); newToken = new Token(start, mPosition, defType);
} }
else if (isXPathDigit(*mPosition)) { else if (isXPathDigit(*mPosition)) {
start = mPosition; iterator start = mPosition;
while (++mPosition < end && isXPathDigit(*mPosition)) { while (++mPosition < end && isXPathDigit(*mPosition)) {
/* just go */ /* just go */
} }
@ -193,7 +193,8 @@ txExprLexer::parse(const nsAString& aPattern)
break; break;
case S_QUOTE : case S_QUOTE :
case D_QUOTE : case D_QUOTE :
start = mPosition; {
iterator start = mPosition;
while (++mPosition < end && *mPosition != *start) { while (++mPosition < end && *mPosition != *start) {
// eat literal // eat literal
} }
@ -203,14 +204,15 @@ txExprLexer::parse(const nsAString& aPattern)
} }
newToken = new Token(start + 1, mPosition, Token::LITERAL); newToken = new Token(start + 1, mPosition, Token::LITERAL);
++mPosition; ++mPosition;
break; }
break;
case PERIOD: case PERIOD:
// period can be .., .(DIGITS)+ or ., check next // period can be .., .(DIGITS)+ or ., check next
if (++mPosition == end) { if (++mPosition == end) {
newToken = new Token(mPosition - 1, Token::SELF_NODE); newToken = new Token(mPosition - 1, Token::SELF_NODE);
} }
else if (isXPathDigit(*mPosition)) { else if (isXPathDigit(*mPosition)) {
start = mPosition - 1; iterator start = mPosition - 1;
while (++mPosition < end && isXPathDigit(*mPosition)) { while (++mPosition < end && isXPathDigit(*mPosition)) {
/* just go */ /* just go */
} }

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

@ -174,7 +174,13 @@ gfxFT2FontBase::GetCharWidth(char aChar, gfxFloat* aWidth)
{ {
FT_UInt gid = GetGlyph(aChar); FT_UInt gid = GetGlyph(aChar);
if (gid) { if (gid) {
*aWidth = FLOAT_FROM_16_16(GetFTGlyphAdvance(gid)); int32_t width;
if (!GetFTGlyphAdvance(gid, &width)) {
cairo_text_extents_t extents;
GetGlyphExtents(gid, &extents);
width = NS_lround(0x10000 * extents.x_advance);
}
*aWidth = FLOAT_FROM_16_16(width);
} }
return gid; return gid;
} }
@ -526,35 +532,42 @@ gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
return GetGlyph(unicode); return GetGlyph(unicode);
} }
FT_Fixed bool
gfxFT2FontBase::GetFTGlyphAdvance(uint16_t aGID) gfxFT2FontBase::GetFTGlyphAdvance(uint16_t aGID, int32_t* aAdvance)
{ {
gfxFT2LockedFace face(this); gfxFT2LockedFace face(this);
MOZ_ASSERT(face.get()); MOZ_ASSERT(face.get());
if (!face.get()) { if (!face.get()) {
// Failed to get the FT_Face? Give up already. // Failed to get the FT_Face? Give up already.
return 0; NS_WARNING("failed to get FT_Face!");
return false;
} }
// Due to bugs like 1435234 and 1440938, we currently prefer to fall back
// to reading the advance from cairo extents, unless we're dealing with
// a variation font (for which cairo metrics may be wrong, due to FreeType
// bug 52683).
if (!(face.get()->face_flags & FT_FACE_FLAG_SCALABLE) ||
!(face.get()->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
return false;
}
bool hinting = gfxPlatform::GetPlatform()->FontHintingEnabled(); bool hinting = gfxPlatform::GetPlatform()->FontHintingEnabled();
int32_t flags = int32_t flags =
hinting ? FT_LOAD_ADVANCE_ONLY hinting ? FT_LOAD_ADVANCE_ONLY
: FT_LOAD_ADVANCE_ONLY | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING; : FT_LOAD_ADVANCE_ONLY | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
FT_Error ftError = FT_Load_Glyph(face.get(), aGID, flags); FT_Error ftError = FT_Load_Glyph(face.get(), aGID, flags);
MOZ_ASSERT(!ftError);
if (ftError != FT_Err_Ok) { if (ftError != FT_Err_Ok) {
// FT_Face was somehow broken/invalid? Don't try to access glyph slot. // FT_Face was somehow broken/invalid? Don't try to access glyph slot.
return 0; // This probably shouldn't happen, but does: see bug 1440938.
NS_WARNING("failed to load glyph!");
return false;
} }
FT_Fixed advance = 0;
// Due to freetype bug 52683 we MUST use the linearHoriAdvance field when // Due to freetype bug 52683 we MUST use the linearHoriAdvance field when
// dealing with a variation font; also use it for scalable fonts when not // dealing with a variation font. (And other fonts would have returned
// applying hinting. Otherwise, prefer hinted width from glyph->advance.x. // earlier, so only variation fonts currently reach here.)
if ((face.get()->face_flags & FT_FACE_FLAG_SCALABLE) && FT_Fixed advance = face.get()->glyph->linearHoriAdvance;
(!hinting || (face.get()->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS))) {
advance = face.get()->glyph->linearHoriAdvance;
} else {
advance = face.get()->glyph->advance.x << 10; // convert 26.6 to 16.16
}
// If freetype emboldening is being used, and it's not a zero-width glyph, // If freetype emboldening is being used, and it's not a zero-width glyph,
// adjust the advance to account for the increased width. // adjust the advance to account for the increased width.
@ -569,9 +582,9 @@ gfxFT2FontBase::GetFTGlyphAdvance(uint16_t aGID)
// Round the 16.16 fixed-point value to whole pixels for better consistency // Round the 16.16 fixed-point value to whole pixels for better consistency
// with how cairo renders the glyphs. // with how cairo renders the glyphs.
advance = (advance + 0x8000) & 0xffff0000u; *aAdvance = (advance + 0x8000) & 0xffff0000u;
return advance; return true;
} }
int32_t int32_t
@ -587,7 +600,11 @@ gfxFT2FontBase::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
return width; return width;
} }
width = GetFTGlyphAdvance(aGID); if (!GetFTGlyphAdvance(aGID, &width)) {
cairo_text_extents_t extents;
GetGlyphExtents(aGID, &extents);
width = NS_lround(0x10000 * extents.x_advance);
}
mGlyphWidths->Put(aGID, width); mGlyphWidths->Put(aGID, width);
return width; return width;

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

@ -45,7 +45,12 @@ public:
private: private:
uint32_t GetCharExtents(char aChar, cairo_text_extents_t* aExtents); uint32_t GetCharExtents(char aChar, cairo_text_extents_t* aExtents);
uint32_t GetCharWidth(char aChar, gfxFloat* aWidth); uint32_t GetCharWidth(char aChar, gfxFloat* aWidth);
FT_Fixed GetFTGlyphAdvance(uint16_t aGID);
// Get advance of a single glyph from FreeType, and return true;
// or return false if we should fall back to getting the glyph
// extents from cairo instead.
bool GetFTGlyphAdvance(uint16_t aGID, int32_t* aWidth);
void InitMetrics(); void InitMetrics();
protected: protected:

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

@ -701,7 +701,30 @@ MessageChannel::Clear()
if (!Unsound_IsClosed()) { if (!Unsound_IsClosed()) {
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProtocolName"), CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProtocolName"),
nsDependentCString(mName)); nsDependentCString(mName));
MOZ_CRASH("MessageChannel destroyed without being closed"); switch (mChannelState) {
case ChannelOpening:
MOZ_CRASH("MessageChannel destroyed without being closed " \
"(mChannelState == ChannelOpening).");
break;
case ChannelConnected:
MOZ_CRASH("MessageChannel destroyed without being closed " \
"(mChannelState == ChannelConnected).");
break;
case ChannelTimeout:
MOZ_CRASH("MessageChannel destroyed without being closed " \
"(mChannelState == ChannelTimeout).");
break;
case ChannelClosing:
MOZ_CRASH("MessageChannel destroyed without being closed " \
"(mChannelState == ChannelClosing).");
break;
case ChannelError:
MOZ_CRASH("MessageChannel destroyed without being closed " \
"(mChannelState == ChannelError).");
break;
default:
MOZ_CRASH("MessageChannel destroyed without being closed.");
}
} }
#endif #endif

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

@ -40,8 +40,6 @@ extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr;
namespace JS { namespace JS {
class AutoIdVector;
/** /**
* The answer to a successful query as to whether an object is an Array per * The answer to a successful query as to whether an object is an Array per
* ES6's internal |IsArray| operation (as exposed by |Array.isArray|). * ES6's internal |IsArray| operation (as exposed by |Array.isArray|).

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

@ -99,14 +99,14 @@ class GCVector
return vector.infallibleAppend(aBegin, aLength); return vector.infallibleAppend(aBegin, aLength);
} }
template<typename U, size_t O, class BP> template<typename U>
MOZ_MUST_USE bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vector.appendAll(aU); } MOZ_MUST_USE bool appendAll(const U& aU) {
template<typename U, size_t O, class BP> return vector.append(aU.begin(), aU.end());
MOZ_MUST_USE bool appendAll(const GCVector<U, O, BP>& aU) {
return vector.append(aU.begin(), aU.length());
} }
MOZ_MUST_USE bool appendN(const T& val, size_t count) { return vector.appendN(val, count); } MOZ_MUST_USE bool appendN(const T& val, size_t count) {
return vector.appendN(val, count);
}
template<typename U> template<typename U>
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) { MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
@ -219,10 +219,8 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrappe
MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) {
return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...)); return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...));
} }
template<typename U, size_t O, class BP> template<typename U>
MOZ_MUST_USE bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vec().appendAll(aU); } MOZ_MUST_USE bool appendAll(const U& aU) { return vec().appendAll(aU); }
template<typename U, size_t O, class BP>
MOZ_MUST_USE bool appendAll(const JS::GCVector<U, O, BP>& aU) { return vec().appendAll(aU); }
MOZ_MUST_USE bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); } MOZ_MUST_USE bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); }
template<typename U> template<typename U>
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) { MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
@ -253,4 +251,17 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrappe
} // namespace js } // namespace js
namespace JS {
// An automatically rooted vector for stack use.
template <typename T>
class AutoVector : public Rooted<GCVector<T, 8>> {
using Vec = GCVector<T, 8>;
using Base = Rooted<Vec>;
public:
explicit AutoVector(JSContext* cx) : Base(cx, Vec(cx)) {}
};
} // namespace JS
#endif // js_GCVector_h #endif // js_GCVector_h

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

@ -895,19 +895,12 @@ class JS_PUBLIC_API(AutoGCRooter)
#if defined(JS_BUILD_BINAST) #if defined(JS_BUILD_BINAST)
BINPARSER = -4, /* js::frontend::BinSource */ BINPARSER = -4, /* js::frontend::BinSource */
#endif // defined(JS_BUILD_BINAST) #endif // defined(JS_BUILD_BINAST)
VALVECTOR = -10, /* js::AutoValueVector */
IDVECTOR = -11, /* js::AutoIdVector */
OBJVECTOR = -14, /* js::AutoObjectVector */
IONMASM = -19, /* js::jit::MacroAssembler */ IONMASM = -19, /* js::jit::MacroAssembler */
WRAPVECTOR = -20, /* js::AutoWrapperVector */ WRAPVECTOR = -20, /* js::AutoWrapperVector */
WRAPPER = -21, /* js::AutoWrapperRooter */ WRAPPER = -21, /* js::AutoWrapperRooter */
CUSTOM = -26 /* js::CustomAutoRooter */ CUSTOM = -26 /* js::CustomAutoRooter */
}; };
static ptrdiff_t GetTag(const Value& value) { return VALVECTOR; }
static ptrdiff_t GetTag(const jsid& id) { return IDVECTOR; }
static ptrdiff_t GetTag(JSObject* obj) { return OBJVECTOR; }
private: private:
AutoGCRooter ** const stackTop; AutoGCRooter ** const stackTop;

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

@ -475,6 +475,7 @@ const OPAQUE_TYPES: &'static [&'static str] = &[
"mozilla::BufferList", "mozilla::BufferList",
"mozilla::UniquePtr.*", "mozilla::UniquePtr.*",
"JS::Rooted<JS::Auto.*Vector.*>", "JS::Rooted<JS::Auto.*Vector.*>",
"JS::Auto.*Vector"
]; ];
/// Types for which we should NEVER generate bindings, even if it is used within /// Types for which we should NEVER generate bindings, even if it is used within

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

@ -30,9 +30,9 @@ class TwoByteCharsZ;
class UTF8Chars; class UTF8Chars;
class UTF8CharsZ; class UTF8CharsZ;
class AutoValueVector; using AutoValueVector = AutoVector<Value>;
class AutoIdVector; using AutoIdVector = AutoVector<jsid>;
class AutoObjectVector; using AutoObjectVector = AutoVector<JSObject*>;
using ValueVector = JS::GCVector<JS::Value>; using ValueVector = JS::GCVector<JS::Value>;
using IdVector = JS::GCVector<jsid>; using IdVector = JS::GCVector<jsid>;

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

@ -529,6 +529,14 @@ WasmIsSupported(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
static bool
WasmIsSupportedByHardware(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasCompilerSupport(cx));
return true;
}
static bool static bool
WasmDebuggingIsSupported(JSContext* cx, unsigned argc, Value* vp) WasmDebuggingIsSupported(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -5375,6 +5383,10 @@ gc::ZealModeHelpText),
"wasmIsSupported()", "wasmIsSupported()",
" Returns a boolean indicating whether WebAssembly is supported on the current device."), " Returns a boolean indicating whether WebAssembly is supported on the current device."),
JS_FN_HELP("wasmIsSupportedByHardware", WasmIsSupportedByHardware, 0, 0,
"wasmIsSupportedByHardware()",
" Returns a boolean indicating whether WebAssembly is supported on the current hardware (regardless of whether we've enabled support)."),
JS_FN_HELP("wasmDebuggingIsSupported", WasmDebuggingIsSupported, 0, 0, JS_FN_HELP("wasmDebuggingIsSupported", WasmDebuggingIsSupported, 0, 0,
"wasmDebuggingIsSupported()", "wasmDebuggingIsSupported()",
" Returns a boolean indicating whether WebAssembly debugging is supported on the current device;\n" " Returns a boolean indicating whether WebAssembly debugging is supported on the current device;\n"

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

@ -183,7 +183,11 @@ js::AllocateString(JSContext* cx, InitialHeap heap)
if (!rt->gc.checkAllocatorState<allowGC>(cx, kind)) if (!rt->gc.checkAllocatorState<allowGC>(cx, kind))
return nullptr; return nullptr;
if (cx->nursery().isEnabled() && heap != TenuredHeap && cx->nursery().canAllocateStrings()) { if (cx->nursery().isEnabled() &&
heap != TenuredHeap &&
cx->nursery().canAllocateStrings() &&
cx->zone()->allocNurseryStrings)
{
auto str = static_cast<StringAllocT*>(rt->gc.tryNewNurseryString<allowGC>(cx, size, kind)); auto str = static_cast<StringAllocT*>(rt->gc.tryNewNurseryString<allowGC>(cx, size, kind));
if (str) if (str)
return str; return str;

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

@ -2777,18 +2777,21 @@ js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const
return; return;
if (kind() == ElementKind) { if (kind() == ElementKind) {
int32_t initLen = obj->getDenseInitializedLength(); uint32_t initLen = obj->getDenseInitializedLength();
int32_t numShifted = obj->getElementsHeader()->numShiftedElements(); uint32_t numShifted = obj->getElementsHeader()->numShiftedElements();
int32_t clampedStart = Min(Max(0, start_ - numShifted), initLen); uint32_t clampedStart = start_;
int32_t clampedEnd = Min(Max(0, start_ + count_ - numShifted), initLen); clampedStart = numShifted < clampedStart ? clampedStart - numShifted : 0;
MOZ_ASSERT(clampedStart >= 0); clampedStart = Min(clampedStart, initLen);
uint32_t clampedEnd = start_ + count_;
clampedEnd = numShifted < clampedEnd ? clampedEnd - numShifted : 0;
clampedEnd = Min(clampedEnd, initLen);
MOZ_ASSERT(clampedStart <= clampedEnd); MOZ_ASSERT(clampedStart <= clampedEnd);
mover.traceSlots(static_cast<HeapSlot*>(obj->getDenseElements() + clampedStart) mover.traceSlots(static_cast<HeapSlot*>(obj->getDenseElements() + clampedStart)
->unsafeUnbarrieredForTracing(), clampedEnd - clampedStart); ->unsafeUnbarrieredForTracing(), clampedEnd - clampedStart);
} else { } else {
int32_t start = Min(uint32_t(start_), obj->slotSpan()); uint32_t start = Min(start_, obj->slotSpan());
int32_t end = Min(uint32_t(start_) + count_, obj->slotSpan()); uint32_t end = Min(start_ + count_, obj->slotSpan());
MOZ_ASSERT(end >= start); MOZ_ASSERT(start <= end);
mover.traceObjectSlots(obj, start, end - start); mover.traceObjectSlots(obj, start, end - start);
} }
} }
@ -3200,6 +3203,7 @@ js::TenuringTracer::moveToTenured(JSString* src)
AllocKind dstKind = src->getAllocKind(); AllocKind dstKind = src->getAllocKind();
Zone* zone = src->zone(); Zone* zone = src->zone();
zone->tenuredStrings++;
TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind)); TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind));
if (!t) { if (!t) {

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

@ -132,9 +132,9 @@ js::Nursery::Nursery(JSRuntime* rt)
, lastCanary_(nullptr) , lastCanary_(nullptr)
#endif #endif
{ {
const char* env = getenv("MOZ_ENABLE_NURSERY_STRINGS"); const char* env = getenv("MOZ_NURSERY_STRINGS");
if (env && *env) if (env && *env)
canAllocateStrings_ = true; canAllocateStrings_ = (*env == '1');
} }
bool bool
@ -738,21 +738,40 @@ js::Nursery::collect(JS::gcreason::Reason reason)
bool validPromotionRate; bool validPromotionRate;
const float promotionRate = calcPromotionRate(&validPromotionRate); const float promotionRate = calcPromotionRate(&validPromotionRate);
uint32_t pretenureCount = 0; uint32_t pretenureCount = 0;
if (validPromotionRate) { bool shouldPretenure = (validPromotionRate && promotionRate > 0.6) ||
if (promotionRate > 0.8 || IsFullStoreBufferReason(reason)) { IsFullStoreBufferReason(reason);
JSContext* cx = TlsContext.get();
for (auto& entry : tenureCounts.entries) { if (shouldPretenure) {
if (entry.count >= 3000) { JSContext* cx = TlsContext.get();
ObjectGroup* group = entry.group; for (auto& entry : tenureCounts.entries) {
if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) { if (entry.count >= 3000) {
AutoCompartment ac(cx, group); ObjectGroup* group = entry.group;
group->setShouldPreTenure(cx); if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) {
pretenureCount++; AutoCompartment ac(cx, group);
} group->setShouldPreTenure(cx);
pretenureCount++;
} }
} }
} }
} }
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) {
JSRuntime::AutoProhibitActiveContextChange apacc(rt);
CancelOffThreadIonCompile(zone);
bool preserving = zone->isPreservingCode();
zone->setPreservingCode(false);
zone->discardJitCode(rt->defaultFreeOp());
zone->setPreservingCode(preserving);
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
if (jit::JitCompartment* jitComp = c->jitCompartment()) {
jitComp->discardStubs();
jitComp->stringsCanBeInNursery = false;
}
}
zone->allocNurseryStrings = false;
}
zone->tenuredStrings = 0;
}
endProfile(ProfileKey::Pretenure); endProfile(ProfileKey::Pretenure);
// We ignore gcMaxBytes when allocating for minor collection. However, if we // We ignore gcMaxBytes when allocating for minor collection. However, if we
@ -1086,7 +1105,7 @@ js::Nursery::setStartPosition()
void void
js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason) js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason)
{ {
static const double GrowThreshold = 0.05; static const double GrowThreshold = 0.03;
static const double ShrinkThreshold = 0.01; static const double ShrinkThreshold = 0.01;
unsigned newMaxNurseryChunks; unsigned newMaxNurseryChunks;

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

@ -179,13 +179,13 @@ AutoGCRooter::trace(JSTracer* trc)
} }
case WRAPVECTOR: { case WRAPVECTOR: {
AutoWrapperVector::VectorImpl& vector = static_cast<AutoWrapperVector*>(this)->vector; auto vector = static_cast<AutoWrapperVector*>(this);
/* /*
* We need to use TraceManuallyBarrieredEdge here because we trace * We need to use TraceManuallyBarrieredEdge here because we trace
* wrapper roots in every slice. This is because of some rule-breaking * wrapper roots in every slice. This is because of some rule-breaking
* in RemapAllWrappersForObject; see comment there. * in RemapAllWrappersForObject; see comment there.
*/ */
for (WrapperValue* p = vector.begin(); p < vector.end(); p++) for (WrapperValue* p = vector->begin(); p < vector->end(); p++)
TraceManuallyBarrieredEdge(trc, &p->get(), "js::AutoWrapperVector.vector"); TraceManuallyBarrieredEdge(trc, &p->get(), "js::AutoWrapperVector.vector");
return; return;
} }

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

@ -276,17 +276,17 @@ class StoreBuffer
const static int ElementKind = 1; const static int ElementKind = 1;
uintptr_t objectAndKind_; // NativeObject* | Kind uintptr_t objectAndKind_; // NativeObject* | Kind
int32_t start_; uint32_t start_;
int32_t count_; uint32_t count_;
SlotsEdge() : objectAndKind_(0), start_(0), count_(0) {} SlotsEdge() : objectAndKind_(0), start_(0), count_(0) {}
SlotsEdge(NativeObject* object, int kind, int32_t start, int32_t count) SlotsEdge(NativeObject* object, int kind, uint32_t start, uint32_t count)
: objectAndKind_(uintptr_t(object) | kind), start_(start), count_(count) : objectAndKind_(uintptr_t(object) | kind), start_(start), count_(count)
{ {
MOZ_ASSERT((uintptr_t(object) & 1) == 0); MOZ_ASSERT((uintptr_t(object) & 1) == 0);
MOZ_ASSERT(kind <= 1); MOZ_ASSERT(kind <= 1);
MOZ_ASSERT(start >= 0);
MOZ_ASSERT(count > 0); MOZ_ASSERT(count > 0);
MOZ_ASSERT(start + count > start);
} }
NativeObject* object() const { return reinterpret_cast<NativeObject*>(objectAndKind_ & ~1); } NativeObject* object() const { return reinterpret_cast<NativeObject*>(objectAndKind_ & ~1); }
@ -313,10 +313,12 @@ class StoreBuffer
// is particularly useful for coalescing a series of increasing or // is particularly useful for coalescing a series of increasing or
// decreasing single index writes 0, 1, 2, ..., N into a SlotsEdge // decreasing single index writes 0, 1, 2, ..., N into a SlotsEdge
// range of elements [0, N]. // range of elements [0, N].
auto end = start_ + count_ + 1; uint32_t end = start_ + count_ + 1;
auto start = start_ - 1; uint32_t start = start_ > 0 ? start_ - 1 : 0;
MOZ_ASSERT(start < end);
auto otherEnd = other.start_ + other.count_; uint32_t otherEnd = other.start_ + other.count_;
MOZ_ASSERT(other.start_ <= otherEnd);
return (start <= other.start_ && other.start_ <= end) || return (start <= other.start_ && other.start_ <= end) ||
(start <= otherEnd && otherEnd <= end); (start <= otherEnd && otherEnd <= end);
} }
@ -326,7 +328,7 @@ class StoreBuffer
// overlap. // overlap.
void merge(const SlotsEdge& other) { void merge(const SlotsEdge& other) {
MOZ_ASSERT(overlaps(other)); MOZ_ASSERT(overlaps(other));
auto end = Max(start_ + count_, other.start_ + other.count_); uint32_t end = Max(start_ + count_, other.start_ + other.count_);
start_ = Min(start_, other.start_); start_ = Min(start_, other.start_);
count_ = end - start_; count_ = end - start_;
} }
@ -416,7 +418,7 @@ class StoreBuffer
void unputValue(JS::Value* vp) { unput(bufferVal, ValueEdge(vp)); } void unputValue(JS::Value* vp) { unput(bufferVal, ValueEdge(vp)); }
void putCell(Cell** cellp) { put(bufferCell, CellPtrEdge(cellp)); } void putCell(Cell** cellp) { put(bufferCell, CellPtrEdge(cellp)); }
void unputCell(Cell** cellp) { unput(bufferCell, CellPtrEdge(cellp)); } void unputCell(Cell** cellp) { unput(bufferCell, CellPtrEdge(cellp)); }
void putSlot(NativeObject* obj, int kind, int32_t start, int32_t count) { void putSlot(NativeObject* obj, int kind, uint32_t start, uint32_t count) {
SlotsEdge edge(obj, kind, start, count); SlotsEdge edge(obj, kind, start, count);
if (bufferSlot.last_.overlaps(edge)) if (bufferSlot.last_.overlaps(edge))
bufferSlot.last_.merge(edge); bufferSlot.last_.merge(edge);

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

@ -46,6 +46,8 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
usage(&rt->gc.usage), usage(&rt->gc.usage),
threshold(), threshold(),
gcDelayBytes(0), gcDelayBytes(0),
tenuredStrings(group, 0),
allocNurseryStrings(group, true),
propertyTree_(group, this), propertyTree_(group, this),
baseShapes_(group, this), baseShapes_(group, this),
initialShapes_(group, this), initialShapes_(group, this),

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

@ -482,6 +482,9 @@ struct Zone : public JS::shadow::Zone,
// the current GC. // the current GC.
js::UnprotectedData<size_t> gcDelayBytes; js::UnprotectedData<size_t> gcDelayBytes;
js::ZoneGroupData<uint32_t> tenuredStrings;
js::ZoneGroupData<bool> allocNurseryStrings;
private: private:
// Shared Shape property tree. // Shared Shape property tree.
js::ZoneGroupData<js::PropertyTree> propertyTree_; js::ZoneGroupData<js::PropertyTree> propertyTree_;

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

@ -283,9 +283,7 @@ BaselineCacheIRCompiler::emitGuardCompartment()
return false; return false;
Address addr(stubAddress(reader.stubOffset())); Address addr(stubAddress(reader.stubOffset()));
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch); masm.branchTestObjCompartment(Assembler::NotEqual, obj, addr, scratch, failure->label());
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
masm.branchPtr(Assembler::NotEqual, addr, scratch, failure->label());
return true; return true;
} }
@ -300,10 +298,7 @@ BaselineCacheIRCompiler::emitGuardAnyClass()
return false; return false;
Address testAddr(stubAddress(reader.stubOffset())); Address testAddr(stubAddress(reader.stubOffset()));
masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, testAddr, failure->label());
masm.loadObjGroup(obj, scratch);
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
masm.branchPtr(Assembler::NotEqual, testAddr, scratch, failure->label());
return true; return true;
} }
@ -528,9 +523,7 @@ BaselineCacheIRCompiler::emitMegamorphicLoadSlotResult()
return false; return false;
// The object must be Native. // The object must be Native.
masm.loadObjClass(obj, scratch3); masm.branchIfNonNativeObj(obj, scratch3, failure->label());
masm.branchTest32(Assembler::NonZero, Address(scratch3, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), failure->label());
masm.Push(UndefinedValue()); masm.Push(UndefinedValue());
masm.moveStackPtrTo(scratch3.get()); masm.moveStackPtrTo(scratch3.get());
@ -1176,27 +1169,22 @@ BaselineCacheIRCompiler::emitAddAndStoreSlotShared(CacheOp op)
// per the acquired properties analysis. Only change the group if the // per the acquired properties analysis. Only change the group if the
// old group still has a newScript. This only applies to PlainObjects. // old group still has a newScript. This only applies to PlainObjects.
Label noGroupChange; Label noGroupChange;
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch1); masm.branchIfObjGroupHasNoAddendum(obj, scratch1, &noGroupChange);
masm.branchPtr(Assembler::Equal,
Address(scratch1, ObjectGroup::offsetOfAddendum()),
ImmWord(0),
&noGroupChange);
// Reload the new group from the cache. // Update the object's group.
masm.loadPtr(newGroupAddr, scratch1); masm.loadPtr(newGroupAddr, scratch1);
masm.storeObjGroup(scratch1, obj, [](MacroAssembler& masm, const Address& addr) {
Address groupAddr(obj, JSObject::offsetOfGroup()); EmitPreBarrier(masm, addr, MIRType::ObjectGroup);
EmitPreBarrier(masm, groupAddr, MIRType::ObjectGroup); });
masm.storePtr(scratch1, groupAddr);
masm.bind(&noGroupChange); masm.bind(&noGroupChange);
} }
// Update the object's shape. // Update the object's shape.
Address shapeAddr(obj, ShapedObject::offsetOfShape());
masm.loadPtr(newShapeAddr, scratch1); masm.loadPtr(newShapeAddr, scratch1);
EmitPreBarrier(masm, shapeAddr, MIRType::Shape); masm.storeObjShape(scratch1, obj, [](MacroAssembler& masm, const Address& addr) {
masm.storePtr(scratch1, shapeAddr); EmitPreBarrier(masm, addr, MIRType::Shape);
});
// Perform the store. No pre-barrier required since this is a new // Perform the store. No pre-barrier required since this is a new
// initialization. // initialization.

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

@ -426,11 +426,10 @@ ICTypeUpdate_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
masm.branchTestObject(Assembler::NotEqual, R0, &failure); masm.branchTestObject(Assembler::NotEqual, R0, &failure);
// Guard on the object's ObjectGroup. // Guard on the object's ObjectGroup.
Register obj = masm.extractObject(R0, R1.scratchReg()); Register scratch = R1.scratchReg();
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), R1.scratchReg()); Register obj = masm.extractObject(R0, scratch);
Address expectedGroup(ICStubReg, ICTypeUpdate_ObjectGroup::offsetOfGroup()); Address expectedGroup(ICStubReg, ICTypeUpdate_ObjectGroup::offsetOfGroup());
masm.branchPtr(Assembler::NotEqual, expectedGroup, R1.scratchReg(), &failure); masm.branchTestObjGroup(Assembler::NotEqual, obj, expectedGroup, scratch, &failure);
// Group matches, load true into R1.scratchReg() and return. // Group matches, load true into R1.scratchReg() and return.
masm.mov(ImmWord(1), R1.scratchReg()); masm.mov(ImmWord(1), R1.scratchReg());
@ -775,9 +774,7 @@ LoadTypedThingLength(MacroAssembler& masm, TypedThingLayout layout, Register obj
break; break;
case Layout_OutlineTypedObject: case Layout_OutlineTypedObject:
case Layout_InlineTypedObject: case Layout_InlineTypedObject:
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), result); masm.loadTypedObjectLength(obj, result);
masm.loadPtr(Address(result, ObjectGroup::offsetOfAddendum()), result);
masm.unboxInt32(Address(result, ArrayTypeDescr::offsetOfLength()), result);
break; break;
default: default:
MOZ_CRASH(); MOZ_CRASH();
@ -3432,11 +3429,9 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
// Ensure the callee's class matches the one in this stub. // Ensure the callee's class matches the one in this stub.
Register callee = masm.extractObject(R1, ExtractTemp0); Register callee = masm.extractObject(R1, ExtractTemp0);
Register scratch = regs.takeAny(); Register scratch = regs.takeAny();
masm.loadObjClass(callee, scratch); masm.branchTestObjClass(Assembler::NotEqual, callee, scratch,
masm.branchPtr(Assembler::NotEqual, Address(ICStubReg, ICCall_ClassHook::offsetOfClass()),
Address(ICStubReg, ICCall_ClassHook::offsetOfClass()), &failure);
scratch, &failure);
regs.add(R1); regs.add(R1);
regs.takeUnchecked(callee); regs.takeUnchecked(callee);

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

@ -1472,9 +1472,7 @@ CacheIRCompiler::emitGuardIsNativeObject()
if (!addFailurePath(&failure)) if (!addFailurePath(&failure))
return false; return false;
masm.loadObjClass(obj, scratch); masm.branchIfNonNativeObj(obj, scratch, failure->label());
masm.branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), failure->label());
return true; return true;
} }
@ -2668,9 +2666,7 @@ CacheIRCompiler::emitMegamorphicLoadSlotByValueResult()
return false; return false;
// The object must be Native. // The object must be Native.
masm.loadObjClass(obj, scratch); masm.branchIfNonNativeObj(obj, scratch, failure->label());
masm.branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), failure->label());
// idVal will be in vp[0], result will be stored in vp[1]. // idVal will be in vp[0], result will be stored in vp[1].
masm.reserveStack(sizeof(Value)); masm.reserveStack(sizeof(Value));

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

@ -959,8 +959,7 @@ CodeGenerator::visitFunctionDispatch(LFunctionDispatch* lir)
MOZ_ASSERT(i < mir->numCases()); MOZ_ASSERT(i < mir->numCases());
LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir(); LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
if (ObjectGroup* funcGroup = mir->getCaseObjectGroup(i)) { if (ObjectGroup* funcGroup = mir->getCaseObjectGroup(i)) {
masm.branchPtr(Assembler::Equal, Address(input, JSObject::offsetOfGroup()), masm.branchTestObjGroup(Assembler::Equal, input, funcGroup, target->label());
ImmGCPtr(funcGroup), target->label());
} else { } else {
JSFunction* func = mir->getCase(i); JSFunction* func = mir->getCase(i);
masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label()); masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
@ -979,7 +978,7 @@ CodeGenerator::visitObjectGroupDispatch(LObjectGroupDispatch* lir)
Register temp = ToRegister(lir->temp()); Register temp = ToRegister(lir->temp());
// Load the incoming ObjectGroup in temp. // Load the incoming ObjectGroup in temp.
masm.loadPtr(Address(input, JSObject::offsetOfGroup()), temp); masm.loadObjGroupUnsafe(input, temp);
// Compare ObjectGroups. // Compare ObjectGroups.
MacroAssembler::BranchGCPtr lastBranch; MacroAssembler::BranchGCPtr lastBranch;
@ -2518,8 +2517,7 @@ CodeGenerator::visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape(); RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape();
masm.loadPtr(Address(temp, offset), temp); masm.loadPtr(Address(temp, offset), temp);
masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output); masm.branchTestObjShape(Assembler::NotEqual, object, temp, ool->entry());
masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
masm.move32(Imm32(0x1), output); masm.move32(Imm32(0x1), output);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
@ -2579,8 +2577,7 @@ CodeGenerator::visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
RegExpCompartment::offsetOfOptimizableRegExpInstanceShape(); RegExpCompartment::offsetOfOptimizableRegExpInstanceShape();
masm.loadPtr(Address(temp, offset), temp); masm.loadPtr(Address(temp, offset), temp);
masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output); masm.branchTestObjShape(Assembler::NotEqual, object, temp, ool->entry());
masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
masm.move32(Imm32(0x1), output); masm.move32(Imm32(0x1), output);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
@ -3716,11 +3713,8 @@ CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir)
OutOfLineCode* ool = oolCallVM(CopyElementsForWriteInfo, lir, OutOfLineCode* ool = oolCallVM(CopyElementsForWriteInfo, lir,
ArgList(object), StoreNothing()); ArgList(object), StoreNothing());
if (lir->mir()->checkNative()) { if (lir->mir()->checkNative())
masm.loadObjClass(object, temp); masm.branchIfNonNativeObj(object, temp, ool->rejoin());
masm.branchTest32(Assembler::NonZero, Address(temp, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), ool->rejoin());
}
masm.loadPtr(Address(object, NativeObject::offsetOfElements()), temp); masm.loadPtr(Address(object, NativeObject::offsetOfElements()), temp);
masm.branchTest32(Assembler::NonZero, masm.branchTest32(Assembler::NonZero,
@ -4302,17 +4296,8 @@ LoadDOMPrivate(MacroAssembler& masm, Register obj, Register priv, DOMObjectKind
masm.branchTestObjectIsProxy(true, obj, priv, &isProxy); masm.branchTestObjectIsProxy(true, obj, priv, &isProxy);
if (kind != DOMObjectKind::Proxy) { if (kind != DOMObjectKind::Proxy) {
#ifdef DEBUG
// If it's a native object, the value must be in a fixed slot. // If it's a native object, the value must be in a fixed slot.
Label hasFixedSlots; masm.debugAssertObjHasFixedSlots(obj, priv);
masm.loadPtr(Address(obj, ShapedObject::offsetOfShape()), priv);
masm.branchTest32(Assembler::NonZero,
Address(priv, Shape::offsetOfSlotInfo()),
Imm32(Shape::fixedSlotsMask()),
&hasFixedSlots);
masm.assumeUnreachable("Expected a fixed slot");
masm.bind(&hasFixedSlots);
#endif
masm.loadPrivate(Address(obj, NativeObject::getFixedSlotOffset(0)), priv); masm.loadPrivate(Address(obj, NativeObject::getFixedSlotOffset(0)), priv);
if (kind == DOMObjectKind::Unknown) if (kind == DOMObjectKind::Unknown)
masm.jump(&done); masm.jump(&done);
@ -4888,10 +4873,10 @@ CodeGenerator::emitApplyGeneric(T* apply)
// Unless already known, guard that calleereg is actually a function object. // Unless already known, guard that calleereg is actually a function object.
if (!apply->hasSingleTarget()) { if (!apply->hasSingleTarget()) {
masm.loadObjClass(calleereg, objreg); Label bail;
masm.branchTestObjClass(Assembler::NotEqual, calleereg, objreg, &JSFunction::class_,
ImmPtr ptr = ImmPtr(&JSFunction::class_); &bail);
bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot()); bailoutFrom(&bail, apply->snapshot());
} }
// Copy the arguments of the current function. // Copy the arguments of the current function.
@ -6378,38 +6363,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
Register temp = ToRegister(lir->temp()); Register temp = ToRegister(lir->temp());
Label bail; Label bail;
// obj->group() masm.branchIfNotSimdObject(object, temp, lir->mir()->simdType(), &bail);
masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp);
// Guard that the object has the same representation as the one produced for
// SIMD value-type.
Address clasp(temp, ObjectGroup::offsetOfClasp());
static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
&bail);
// obj->type()->typeDescr()
// The previous class pointer comparison implies that the addendumKind is
// Addendum_TypeDescr.
masm.loadPtr(Address(temp, ObjectGroup::offsetOfAddendum()), temp);
// Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
// Value which is equivalent to the object class check.
static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
masm.assertTestInt32(Assembler::Equal, typeDescrKind,
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
SimdType type = lir->mir()->simdType();
// Check if the SimdTypeDescr /Type/ match the specialization of this
// MSimdUnbox instruction.
static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
masm.assertTestInt32(Assembler::Equal, typeDescrType,
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(int32_t(type)), &bail);
// Load the value from the data of the InlineTypedObject. // Load the value from the data of the InlineTypedObject.
Address objectData(object, InlineTypedObject::offsetOfDataStart()); Address objectData(object, InlineTypedObject::offsetOfDataStart());
@ -7095,9 +7049,7 @@ CodeGenerator::visitTypedObjectDescr(LTypedObjectDescr* lir)
{ {
Register obj = ToRegister(lir->object()); Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output()); Register out = ToRegister(lir->output());
masm.loadTypedObjectDescr(obj, out);
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), out);
masm.loadPtr(Address(out, ObjectGroup::offsetOfAddendum()), out);
} }
void void
@ -7110,9 +7062,7 @@ CodeGenerator::visitTypedObjectElements(LTypedObjectElements* lir)
masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out); masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
} else { } else {
Label inlineObject, done; Label inlineObject, done;
masm.loadObjClass(obj, out); masm.branchIfInlineTypedObject(obj, out, &inlineObject);
masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out); masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
masm.jump(&done); masm.jump(&done);
@ -7135,9 +7085,7 @@ CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset* lir)
masm.loadPtr(Address(object, OutlineTypedObject::offsetOfOwner()), temp0); masm.loadPtr(Address(object, OutlineTypedObject::offsetOfOwner()), temp0);
Label inlineObject, done; Label inlineObject, done;
masm.loadObjClass(temp0, temp1); masm.branchIfInlineTypedObject(temp0, temp1, &inlineObject);
masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
masm.loadPrivate(Address(temp0, ArrayBufferObject::offsetOfDataSlot()), temp0); masm.loadPrivate(Address(temp0, ArrayBufferObject::offsetOfDataSlot()), temp0);
masm.jump(&done); masm.jump(&done);
@ -9323,8 +9271,7 @@ CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative*
OutOfLineCode* ool = oolCallVM(ConvertUnboxedPlainObjectToNativeInfo, OutOfLineCode* ool = oolCallVM(ConvertUnboxedPlainObjectToNativeInfo,
lir, ArgList(object), StoreNothing()); lir, ArgList(object), StoreNothing());
masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()), masm.branchTestObjGroup(Assembler::Equal, object, lir->mir()->group(), ool->entry());
ImmGCPtr(lir->mir()->group()), ool->entry());
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
} }
@ -9521,8 +9468,7 @@ CodeGenerator::visitArraySlice(LArraySlice* lir)
masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail); masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
// Fixup the group of the result in case it doesn't match the template object. // Fixup the group of the result in case it doesn't match the template object.
masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp2); masm.copyObjGroupNoPreBarrier(object, temp1, temp2);
masm.storePtr(temp2, Address(temp1, JSObject::offsetOfGroup()));
masm.jump(&call); masm.jump(&call);
{ {
@ -12140,7 +12086,7 @@ void
CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure) CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure)
{ {
Label notFunction, hasCOps, done; Label notFunction, hasCOps, done;
masm.loadObjClass(object, output); masm.loadObjClassUnsafe(object, output);
// Just skim proxies off. Their notion of isCallable()/isConstructor() is // Just skim proxies off. Their notion of isCallable()/isConstructor() is
// more complicated. // more complicated.
@ -12319,7 +12265,7 @@ static void
EmitObjectIsArray(MacroAssembler& masm, OutOfLineCode* ool, Register obj, Register output, EmitObjectIsArray(MacroAssembler& masm, OutOfLineCode* ool, Register obj, Register output,
Label* notArray = nullptr) Label* notArray = nullptr)
{ {
masm.loadObjClass(obj, output); masm.loadObjClassUnsafe(obj, output);
Label isArray; Label isArray;
masm.branchPtr(Assembler::Equal, output, ImmPtr(&ArrayObject::class_), &isArray); masm.branchPtr(Assembler::Equal, output, ImmPtr(&ArrayObject::class_), &isArray);
@ -12380,7 +12326,7 @@ CodeGenerator::visitIsTypedArray(LIsTypedArray* lir)
const Class* firstTypedArrayClass = TypedArrayObject::classForType(Scalar::Int8); const Class* firstTypedArrayClass = TypedArrayObject::classForType(Scalar::Int8);
const Class* lastTypedArrayClass = TypedArrayObject::classForType(Scalar::Uint8Clamped); const Class* lastTypedArrayClass = TypedArrayObject::classForType(Scalar::Uint8Clamped);
masm.loadObjClass(object, output); masm.loadObjClassUnsafe(object, output);
masm.branchPtr(Assembler::Below, output, ImmPtr(firstTypedArrayClass), &notTypedArray); masm.branchPtr(Assembler::Below, output, ImmPtr(firstTypedArrayClass), &notTypedArray);
masm.branchPtr(Assembler::Above, output, ImmPtr(lastTypedArrayClass), &notTypedArray); masm.branchPtr(Assembler::Above, output, ImmPtr(lastTypedArrayClass), &notTypedArray);
@ -12434,7 +12380,7 @@ CodeGenerator::visitHasClass(LHasClass* ins)
Register lhs = ToRegister(ins->lhs()); Register lhs = ToRegister(ins->lhs());
Register output = ToRegister(ins->output()); Register output = ToRegister(ins->output());
masm.loadObjClass(lhs, output); masm.loadObjClassUnsafe(lhs, output);
masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output); masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
} }

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

@ -205,7 +205,9 @@ CompileZone::addressOfStringNurseryCurrentEnd()
bool bool
CompileZone::canNurseryAllocateStrings() CompileZone::canNurseryAllocateStrings()
{ {
return nurseryExists() && zone()->group()->nursery().canAllocateStrings(); return nurseryExists() &&
zone()->group()->nursery().canAllocateStrings() &&
zone()->allocNurseryStrings;
} }
bool bool

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

@ -2229,6 +2229,12 @@ IsRegExpHoistable(MIRGenerator* mir, MDefinition* regexp, MDefinitionVector& wor
bool bool
jit::MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph) jit::MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph)
{ {
// If we are compiling try blocks, regular expressions may be observable
// from catch blocks (which Ion does not compile). For now just disable the
// pass in this case.
if (graph.hasTryBlock())
return true;
MDefinitionVector worklist(graph.alloc()); MDefinitionVector worklist(graph.alloc());
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) { for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {

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

@ -699,9 +699,8 @@ IonCacheIRCompiler::emitGuardCompartment()
if (!addFailurePath(&failure)) if (!addFailurePath(&failure))
return false; return false;
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch); masm.branchTestObjCompartment(Assembler::NotEqual, obj, compartment, scratch,
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch); failure->label());
masm.branchPtr(Assembler::NotEqual, scratch, ImmPtr(compartment), failure->label());
return true; return true;
} }
@ -935,9 +934,7 @@ IonCacheIRCompiler::emitMegamorphicLoadSlotResult()
return false; return false;
// The object must be Native. // The object must be Native.
masm.loadObjClass(obj, scratch3); masm.branchIfNonNativeObj(obj, scratch3, failure->label());
masm.branchTest32(Assembler::NonZero, Address(scratch3, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), failure->label());
masm.Push(UndefinedValue()); masm.Push(UndefinedValue());
masm.moveStackPtrTo(scratch3.get()); masm.moveStackPtrTo(scratch3.get());
@ -1652,23 +1649,20 @@ IonCacheIRCompiler::emitAddAndStoreSlotShared(CacheOp op)
// per the acquired properties analysis. Only change the group if the // per the acquired properties analysis. Only change the group if the
// old group still has a newScript. This only applies to PlainObjects. // old group still has a newScript. This only applies to PlainObjects.
Label noGroupChange; Label noGroupChange;
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch1); masm.branchIfObjGroupHasNoAddendum(obj, scratch1, &noGroupChange);
masm.branchPtr(Assembler::Equal,
Address(scratch1, ObjectGroup::offsetOfAddendum()),
ImmWord(0),
&noGroupChange);
Address groupAddr(obj, JSObject::offsetOfGroup()); // Update the object's group.
EmitPreBarrier(masm, groupAddr, MIRType::ObjectGroup); masm.storeObjGroup(newGroup, obj, [](MacroAssembler& masm, const Address& addr) {
masm.storePtr(ImmGCPtr(newGroup), groupAddr); EmitPreBarrier(masm, addr, MIRType::ObjectGroup);
});
masm.bind(&noGroupChange); masm.bind(&noGroupChange);
} }
// Update the object's shape. // Update the object's shape.
Address shapeAddr(obj, ShapedObject::offsetOfShape()); masm.storeObjShape(newShape, obj, [](MacroAssembler& masm, const Address& addr) {
EmitPreBarrier(masm, shapeAddr, MIRType::Shape); EmitPreBarrier(masm, addr, MIRType::Shape);
masm.storePtr(ImmGCPtr(newShape), shapeAddr); });
// Perform the store. No pre-barrier required since this is a new // Perform the store. No pre-barrier required since this is a new
// initialization. // initialization.

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

@ -621,6 +621,11 @@ class JitCompartment
void sweep(JSCompartment* compartment); void sweep(JSCompartment* compartment);
void discardStubs() {
for (ReadBarrieredJitCode& stubRef : stubs_)
stubRef = nullptr;
}
JitCode* stringConcatStubNoBarrier(uint32_t* requiredBarriersOut) const { JitCode* stringConcatStubNoBarrier(uint32_t* requiredBarriersOut) const {
return getStubNoBarrier(StringConcat, requiredBarriersOut); return getStubNoBarrier(StringConcat, requiredBarriersOut);
} }

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

@ -467,7 +467,7 @@ MacroAssembler::branchIfObjectEmulatesUndefined(Register objReg, Register scratc
{ {
// The branches to out-of-line code here implement a conservative version // The branches to out-of-line code here implement a conservative version
// of the JSObject::isWrapper test performed in EmulatesUndefined. // of the JSObject::isWrapper test performed in EmulatesUndefined.
loadObjClass(objReg, scratch); loadObjClassUnsafe(objReg, scratch);
branchTestClassIsProxy(true, scratch, slowCheck); branchTestClassIsProxy(true, scratch, slowCheck);
@ -492,13 +492,22 @@ MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind
} }
void void
MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class* clasp, MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch,
Label* label) const js::Class* clasp, Label* label)
{ {
loadObjGroup(obj, scratch); loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label); branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label);
} }
void
MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch,
const Address& clasp, Label* label)
{
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
branchPtr(cond, clasp, scratch, label);
}
void void
MacroAssembler::branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label) MacroAssembler::branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label)
{ {
@ -512,7 +521,8 @@ MacroAssembler::branchTestObjShape(Condition cond, Register obj, Register shape,
} }
void void
MacroAssembler::branchTestObjGroup(Condition cond, Register obj, ObjectGroup* group, Label* label) MacroAssembler::branchTestObjGroup(Condition cond, Register obj, const ObjectGroup* group,
Label* label)
{ {
branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), ImmGCPtr(group), label); branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), ImmGCPtr(group), label);
} }
@ -534,7 +544,7 @@ MacroAssembler::branchTestClassIsProxy(bool proxy, Register clasp, Label* label)
void void
MacroAssembler::branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label) MacroAssembler::branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label)
{ {
loadObjClass(object, scratch); loadObjClassUnsafe(object, scratch);
branchTestClassIsProxy(proxy, scratch, label); branchTestClassIsProxy(proxy, scratch, label);
} }
@ -733,6 +743,44 @@ MacroAssembler::reserveStack(uint32_t amount)
} }
#endif // !JS_CODEGEN_ARM64 #endif // !JS_CODEGEN_ARM64
template <typename EmitPreBarrier>
void
MacroAssembler::storeObjGroup(Register group, Register obj, EmitPreBarrier emitPreBarrier)
{
MOZ_ASSERT(group != obj);
Address groupAddr(obj, JSObject::offsetOfGroup());
emitPreBarrier(*this, groupAddr);
storePtr(group, groupAddr);
}
template <typename EmitPreBarrier>
void
MacroAssembler::storeObjGroup(ObjectGroup* group, Register obj, EmitPreBarrier emitPreBarrier)
{
Address groupAddr(obj, JSObject::offsetOfGroup());
emitPreBarrier(*this, groupAddr);
storePtr(ImmGCPtr(group), groupAddr);
}
template <typename EmitPreBarrier>
void
MacroAssembler::storeObjShape(Register shape, Register obj, EmitPreBarrier emitPreBarrier)
{
MOZ_ASSERT(shape != obj);
Address shapeAddr(obj, ShapedObject::offsetOfShape());
emitPreBarrier(*this, shapeAddr);
storePtr(shape, shapeAddr);
}
template <typename EmitPreBarrier>
void
MacroAssembler::storeObjShape(Shape* shape, Register obj, EmitPreBarrier emitPreBarrier)
{
Address shapeAddr(obj, ShapedObject::offsetOfShape());
emitPreBarrier(*this, shapeAddr);
storePtr(ImmGCPtr(shape), shapeAddr);
}
template <typename T> template <typename T>
void void
MacroAssembler::storeObjectOrNull(Register src, const T& dest) MacroAssembler::storeObjectOrNull(Register src, const T& dest)

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

@ -1751,7 +1751,7 @@ void
MacroAssembler::typeOfObject(Register obj, Register scratch, Label* slow, MacroAssembler::typeOfObject(Register obj, Register scratch, Label* slow,
Label* isObject, Label* isCallable, Label* isUndefined) Label* isObject, Label* isCallable, Label* isUndefined)
{ {
loadObjClass(obj, scratch); loadObjClassUnsafe(obj, scratch);
// Proxies can emulate undefined and have complex isCallable behavior. // Proxies can emulate undefined and have complex isCallable behavior.
branchTestClassIsProxy(true, scratch, slow); branchTestClassIsProxy(true, scratch, slow);
@ -3200,6 +3200,128 @@ MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch
branchTest32(Assembler::Zero, scratch, Imm32(bits), label); branchTest32(Assembler::Zero, scratch, Imm32(bits), label);
} }
void
MacroAssembler::branchTestObjGroup(Condition cond, Register obj, const Address& group,
Register scratch, Label* label)
{
// Note: obj and scratch registers may alias.
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
branchPtr(cond, group, scratch, label);
}
void
MacroAssembler::branchTestObjCompartment(Condition cond, Register obj, const Address& compartment,
Register scratch, Label* label)
{
MOZ_ASSERT(obj != scratch);
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
branchPtr(cond, compartment, scratch, label);
}
void
MacroAssembler::branchTestObjCompartment(Condition cond, Register obj,
const JSCompartment* compartment, Register scratch,
Label* label)
{
MOZ_ASSERT(obj != scratch);
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
branchPtr(cond, scratch, ImmPtr(compartment), label);
}
void
MacroAssembler::branchIfObjGroupHasNoAddendum(Register obj, Register scratch, Label* label)
{
MOZ_ASSERT(obj != scratch);
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
branchPtr(Assembler::Equal,
Address(scratch, ObjectGroup::offsetOfAddendum()),
ImmWord(0),
label);
}
void
MacroAssembler::branchIfPretenuredGroup(const ObjectGroup* group, Register scratch, Label* label)
{
movePtr(ImmGCPtr(group), scratch);
branchTest32(Assembler::NonZero, Address(scratch, ObjectGroup::offsetOfFlags()),
Imm32(OBJECT_FLAG_PRE_TENURE), label);
}
void
MacroAssembler::branchIfNonNativeObj(Register obj, Register scratch, Label* label)
{
loadObjClassUnsafe(obj, scratch);
branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), label);
}
void
MacroAssembler::branchIfInlineTypedObject(Register obj, Register scratch, Label* label)
{
loadObjClassUnsafe(obj, scratch);
branchPtr(Assembler::Equal, scratch, ImmPtr(&InlineOpaqueTypedObject::class_), label);
branchPtr(Assembler::Equal, scratch, ImmPtr(&InlineTransparentTypedObject::class_), label);
}
void
MacroAssembler::branchIfNotSimdObject(Register obj, Register scratch, SimdType simdType,
Label* label)
{
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
// Guard that the object has the same representation as the one produced for
// SIMD value-type.
Address clasp(scratch, ObjectGroup::offsetOfClasp());
static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
label);
// obj->type()->typeDescr()
// The previous class pointer comparison implies that the addendumKind is
// Addendum_TypeDescr.
loadPtr(Address(scratch, ObjectGroup::offsetOfAddendum()), scratch);
// Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
// Value which is equivalent to the object class check.
static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
Address typeDescrKind(scratch, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
assertTestInt32(Assembler::Equal, typeDescrKind,
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
branch32(Assembler::NotEqual, ToPayload(typeDescrKind), Imm32(js::type::Simd), label);
// Check if the SimdTypeDescr /Type/ matches the specialization of this
// MSimdUnbox instruction.
static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
Address typeDescrType(scratch, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
assertTestInt32(Assembler::Equal, typeDescrType,
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
branch32(Assembler::NotEqual, ToPayload(typeDescrType), Imm32(int32_t(simdType)), label);
}
void
MacroAssembler::copyObjGroupNoPreBarrier(Register sourceObj, Register destObj, Register scratch)
{
loadPtr(Address(sourceObj, JSObject::offsetOfGroup()), scratch);
storePtr(scratch, Address(destObj, JSObject::offsetOfGroup()));
}
void
MacroAssembler::loadTypedObjectDescr(Register obj, Register dest)
{
loadPtr(Address(obj, JSObject::offsetOfGroup()), dest);
loadPtr(Address(dest, ObjectGroup::offsetOfAddendum()), dest);
}
void
MacroAssembler::loadTypedObjectLength(Register obj, Register dest)
{
loadTypedObjectDescr(obj, dest);
unboxInt32(Address(dest, ArrayTypeDescr::offsetOfLength()), dest);
}
void void
MacroAssembler::maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label) MacroAssembler::maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label)
{ {
@ -3570,6 +3692,21 @@ MacroAssembler::debugAssertIsObject(const ValueOperand& val)
#endif #endif
} }
void
MacroAssembler::debugAssertObjHasFixedSlots(Register obj, Register scratch)
{
#ifdef DEBUG
Label hasFixedSlots;
loadPtr(Address(obj, ShapedObject::offsetOfShape()), scratch);
branchTest32(Assembler::NonZero,
Address(scratch, Shape::offsetOfSlotInfo()),
Imm32(Shape::fixedSlotsMask()),
&hasFixedSlots);
assumeUnreachable("Expected a fixed slot");
bind(&hasFixedSlots);
#endif
}
void void
MacroAssembler::spectreMaskIndex(Register index, Register length, Register output) MacroAssembler::spectreMaskIndex(Register index, Register length, Register output)
{ {

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

@ -1177,13 +1177,32 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchIfObjectEmulatesUndefined(Register objReg, Register scratch, Label* slowCheck, inline void branchIfObjectEmulatesUndefined(Register objReg, Register scratch, Label* slowCheck,
Label* label); Label* label);
inline void branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class* clasp, inline void branchTestObjClass(Condition cond, Register obj, Register scratch,
Label* label); const js::Class* clasp, Label* label);
inline void branchTestObjClass(Condition cond, Register obj, Register scratch,
const Address& clasp, Label* label);
inline void branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label); inline void branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label);
inline void branchTestObjShape(Condition cond, Register obj, Register shape, Label* label); inline void branchTestObjShape(Condition cond, Register obj, Register shape, Label* label);
inline void branchTestObjGroup(Condition cond, Register obj, ObjectGroup* group, Label* label); inline void branchTestObjGroup(Condition cond, Register obj, const ObjectGroup* group,
Label* label);
inline void branchTestObjGroup(Condition cond, Register obj, Register group, Label* label); inline void branchTestObjGroup(Condition cond, Register obj, Register group, Label* label);
void branchTestObjGroup(Condition cond, Register obj, const Address& group, Register scratch,
Label* label);
void branchTestObjCompartment(Condition cond, Register obj, const Address& compartment,
Register scratch, Label* label);
void branchTestObjCompartment(Condition cond, Register obj, const JSCompartment* compartment,
Register scratch, Label* label);
void branchIfObjGroupHasNoAddendum(Register obj, Register scratch, Label* label);
void branchIfPretenuredGroup(const ObjectGroup* group, Register scratch, Label* label);
void branchIfNonNativeObj(Register obj, Register scratch, Label* label);
void branchIfInlineTypedObject(Register obj, Register scratch, Label* label);
void branchIfNotSimdObject(Register obj, Register scratch, SimdType simdType, Label* label);
inline void branchTestClassIsProxy(bool proxy, Register clasp, Label* label); inline void branchTestClassIsProxy(bool proxy, Register clasp, Label* label);
inline void branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label); inline void branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label);
@ -1191,6 +1210,11 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestProxyHandlerFamily(Condition cond, Register proxy, Register scratch, inline void branchTestProxyHandlerFamily(Condition cond, Register proxy, Register scratch,
const void* handlerp, Label* label); const void* handlerp, Label* label);
void copyObjGroupNoPreBarrier(Register sourceObj, Register destObj, Register scratch);
void loadTypedObjectDescr(Register obj, Register dest);
void loadTypedObjectLength(Register obj, Register dest);
// Emit type case branch on tag matching if the type tag in the definition // Emit type case branch on tag matching if the type tag in the definition
// might actually be that type. // might actually be that type.
void maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label); void maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label);
@ -1951,21 +1975,25 @@ class MacroAssembler : public MacroAssemblerSpecific
Label* label); Label* label);
#endif #endif
void loadObjShape(Register objReg, Register dest) { // Unsafe here means the caller is responsible for Spectre mitigations if
loadPtr(Address(objReg, ShapedObject::offsetOfShape()), dest); // needed. Prefer branchTestObjGroup or one of the other masm helpers!
void loadObjGroupUnsafe(Register obj, Register dest) {
loadPtr(Address(obj, JSObject::offsetOfGroup()), dest);
} }
void loadObjGroup(Register objReg, Register dest) { void loadObjClassUnsafe(Register obj, Register dest) {
loadPtr(Address(objReg, JSObject::offsetOfGroup()), dest); loadPtr(Address(obj, JSObject::offsetOfGroup()), dest);
}
void loadBaseShape(Register objReg, Register dest) {
loadObjShape(objReg, dest);
loadPtr(Address(dest, Shape::offsetOfBase()), dest);
}
void loadObjClass(Register objReg, Register dest) {
loadObjGroup(objReg, dest);
loadPtr(Address(dest, ObjectGroup::offsetOfClasp()), dest); loadPtr(Address(dest, ObjectGroup::offsetOfClasp()), dest);
} }
template <typename EmitPreBarrier>
inline void storeObjGroup(Register group, Register obj, EmitPreBarrier emitPreBarrier);
template <typename EmitPreBarrier>
inline void storeObjGroup(ObjectGroup* group, Register obj, EmitPreBarrier emitPreBarrier);
template <typename EmitPreBarrier>
inline void storeObjShape(Register shape, Register obj, EmitPreBarrier emitPreBarrier);
template <typename EmitPreBarrier>
inline void storeObjShape(Shape* shape, Register obj, EmitPreBarrier emitPreBarrier);
void loadObjPrivate(Register obj, uint32_t nfixed, Register dest) { void loadObjPrivate(Register obj, uint32_t nfixed, Register dest) {
loadPtr(Address(obj, NativeObject::getPrivateDataOffset(nfixed)), dest); loadPtr(Address(obj, NativeObject::getPrivateDataOffset(nfixed)), dest);
} }
@ -2192,6 +2220,7 @@ class MacroAssembler : public MacroAssemblerSpecific
const ConstantOrRegister& value, Label* failure); const ConstantOrRegister& value, Label* failure);
void debugAssertIsObject(const ValueOperand& val); void debugAssertIsObject(const ValueOperand& val);
void debugAssertObjHasFixedSlots(Register obj, Register scratch);
using MacroAssemblerSpecific::extractTag; using MacroAssemblerSpecific::extractTag;
Register extractTag(const TypedOrValueRegister& reg, Register scratch) { Register extractTag(const TypedOrValueRegister& reg, Register scratch) {

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

@ -2540,10 +2540,9 @@ ICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
// Guard on the object's ObjectGroup. // Guard on the object's ObjectGroup.
Register obj = masm.extractObject(R0, ExtractTemp0); Register obj = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), R1.scratchReg());
Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup()); Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup());
masm.branchPtr(Assembler::NotEqual, expectedGroup, R1.scratchReg(), &failure); masm.branchTestObjGroup(Assembler::NotEqual, obj, expectedGroup, R1.scratchReg(),
&failure);
MaybeWorkAroundAmdBug(masm); MaybeWorkAroundAmdBug(masm);
EmitReturnFromIC(masm); EmitReturnFromIC(masm);
@ -2765,9 +2764,7 @@ GenerateNewObjectWithTemplateCode(JSContext* cx, JSObject* templateObject)
Label failure; Label failure;
Register objReg = R0.scratchReg(); Register objReg = R0.scratchReg();
Register tempReg = R1.scratchReg(); Register tempReg = R1.scratchReg();
masm.movePtr(ImmGCPtr(templateObject->group()), tempReg); masm.branchIfPretenuredGroup(templateObject->group(), tempReg, &failure);
masm.branchTest32(Assembler::NonZero, Address(tempReg, ObjectGroup::offsetOfFlags()),
Imm32(OBJECT_FLAG_PRE_TENURE), &failure);
masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(cx->compartment()->addressOfMetadataBuilder()), masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(cx->compartment()->addressOfMetadataBuilder()),
ImmWord(0), &failure); ImmWord(0), &failure);
masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, &failure); masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, &failure);

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

@ -721,7 +721,10 @@ PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
if (InBounds == IndexInBounds::Yes) { if (InBounds == IndexInBounds::Yes) {
MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength()); MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength());
} else { } else {
if (MOZ_UNLIKELY(!obj->is<NativeObject>() || index < 0)) { if (MOZ_UNLIKELY(!obj->is<NativeObject>() ||
index < 0 ||
uint32_t(index) >= NativeObject::MAX_DENSE_ELEMENTS_COUNT))
{
rt->gc.storeBuffer().putWholeCell(obj); rt->gc.storeBuffer().putWholeCell(obj);
return; return;
} }

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

@ -1746,29 +1746,20 @@ void
CodeGeneratorARM::visitGuardShape(LGuardShape* guard) CodeGeneratorARM::visitGuardShape(LGuardShape* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt()); Label bail;
masm.branchTestObjShape(Assembler::NotEqual, obj, guard->mir()->shape(), &bail);
ScratchRegisterScope scratch(masm); bailoutFrom(&bail, guard->snapshot());
masm.ma_ldr(DTRAddr(obj, DtrOffImm(ShapedObject::offsetOfShape())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->shape()), scratch);
bailoutIf(Assembler::NotEqual, guard->snapshot());
} }
void void
CodeGeneratorARM::visitGuardObjectGroup(LGuardObjectGroup* guard) CodeGeneratorARM::visitGuardObjectGroup(LGuardObjectGroup* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt());
MOZ_ASSERT(obj != tmp);
ScratchRegisterScope scratch(masm);
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfGroup())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->group()), scratch);
Assembler::Condition cond = Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual; guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
bailoutIf(cond, guard->snapshot()); Label bail;
masm.branchTestObjGroup(cond, obj, guard->mir()->group(), &bail);
bailoutFrom(&bail, guard->snapshot());
} }
void void
@ -1776,12 +1767,9 @@ CodeGeneratorARM::visitGuardClass(LGuardClass* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt()); Register tmp = ToRegister(guard->tempInt());
Label bail;
ScratchRegisterScope scratch(masm); masm.branchTestObjClass(Assembler::NotEqual, obj, tmp, guard->mir()->getClass(), &bail);
bailoutFrom(&bail, guard->snapshot());
masm.loadObjClass(obj, tmp);
masm.ma_cmp(tmp, Imm32((uint32_t)guard->mir()->getClass()), scratch);
bailoutIf(Assembler::NotEqual, guard->snapshot());
} }
void void

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

@ -383,14 +383,13 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 2>
} }
}; };
class LGuardShape : public LInstructionHelper<0, 1, 1> class LGuardShape : public LInstructionHelper<0, 1, 0>
{ {
public: public:
LIR_HEADER(GuardShape); LIR_HEADER(GuardShape);
LGuardShape(const LAllocation& in, const LDefinition& temp) { explicit LGuardShape(const LAllocation& in) {
setOperand(0, in); setOperand(0, in);
setTemp(0, temp);
} }
const MGuardShape* mir() const { const MGuardShape* mir() const {
return mir_->toGuardShape(); return mir_->toGuardShape();
@ -400,14 +399,13 @@ class LGuardShape : public LInstructionHelper<0, 1, 1>
} }
}; };
class LGuardObjectGroup : public LInstructionHelper<0, 1, 1> class LGuardObjectGroup : public LInstructionHelper<0, 1, 0>
{ {
public: public:
LIR_HEADER(GuardObjectGroup); LIR_HEADER(GuardObjectGroup);
LGuardObjectGroup(const LAllocation& in, const LDefinition& temp) { explicit LGuardObjectGroup(const LAllocation& in) {
setOperand(0, in); setOperand(0, in);
setTemp(0, temp);
} }
const MGuardObjectGroup* mir() const { const MGuardObjectGroup* mir() const {
return mir_->toGuardObjectGroup(); return mir_->toGuardObjectGroup();

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

@ -485,8 +485,7 @@ LIRGeneratorARM::visitGuardShape(MGuardShape* ins)
{ {
MOZ_ASSERT(ins->object()->type() == MIRType::Object); MOZ_ASSERT(ins->object()->type() == MIRType::Object);
LDefinition tempObj = temp(LDefinition::OBJECT); LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()));
LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()), tempObj);
assignSnapshot(guard, ins->bailoutKind()); assignSnapshot(guard, ins->bailoutKind());
add(guard, ins); add(guard, ins);
redefine(ins, ins->object()); redefine(ins, ins->object());
@ -497,8 +496,7 @@ LIRGeneratorARM::visitGuardObjectGroup(MGuardObjectGroup* ins)
{ {
MOZ_ASSERT(ins->object()->type() == MIRType::Object); MOZ_ASSERT(ins->object()->type() == MIRType::Object);
LDefinition tempObj = temp(LDefinition::OBJECT); LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()));
LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()), tempObj);
assignSnapshot(guard, ins->bailoutKind()); assignSnapshot(guard, ins->bailoutKind());
add(guard, ins); add(guard, ins);
redefine(ins, ins->object()); redefine(ins, ins->object());

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

@ -1772,25 +1772,20 @@ void
CodeGeneratorMIPSShared::visitGuardShape(LGuardShape* guard) CodeGeneratorMIPSShared::visitGuardShape(LGuardShape* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt()); Label bail;
masm.branchTestObjShape(Assembler::NotEqual, obj, guard->mir()->shape(), &bail);
masm.loadPtr(Address(obj, ShapedObject::offsetOfShape()), tmp); bailoutFrom(&bail, guard->snapshot());
bailoutCmpPtr(Assembler::NotEqual, tmp, ImmGCPtr(guard->mir()->shape()),
guard->snapshot());
} }
void void
CodeGeneratorMIPSShared::visitGuardObjectGroup(LGuardObjectGroup* guard) CodeGeneratorMIPSShared::visitGuardObjectGroup(LGuardObjectGroup* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt()); Assembler::Condition cond =
MOZ_ASSERT(obj != tmp); guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
Label bail;
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp); masm.branchTestObjGroup(cond, obj, guard->mir()->group(), &bail);
Assembler::Condition cond = guard->mir()->bailOnEquality() bailoutFrom(&bail, guard->snapshot());
? Assembler::Equal
: Assembler::NotEqual;
bailoutCmpPtr(cond, tmp, ImmGCPtr(guard->mir()->group()), guard->snapshot());
} }
void void
@ -1798,10 +1793,9 @@ CodeGeneratorMIPSShared::visitGuardClass(LGuardClass* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt()); Register tmp = ToRegister(guard->tempInt());
Label bail;
masm.loadObjClass(obj, tmp); masm.branchTestObjClass(Assembler::NotEqual, obj, tmp, guard->mir()->getClass(), &bail);
bailoutCmpPtr(Assembler::NotEqual, tmp, ImmPtr(guard->mir()->getClass()), bailoutFrom(&bail, guard->snapshot());
guard->snapshot());
} }
void void

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

@ -210,14 +210,13 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
} }
}; };
class LGuardShape : public LInstructionHelper<0, 1, 1> class LGuardShape : public LInstructionHelper<0, 1, 0>
{ {
public: public:
LIR_HEADER(GuardShape); LIR_HEADER(GuardShape);
LGuardShape(const LAllocation& in, const LDefinition& temp) { explicit LGuardShape(const LAllocation& in) {
setOperand(0, in); setOperand(0, in);
setTemp(0, temp);
} }
const MGuardShape* mir() const { const MGuardShape* mir() const {
return mir_->toGuardShape(); return mir_->toGuardShape();
@ -227,14 +226,13 @@ class LGuardShape : public LInstructionHelper<0, 1, 1>
} }
}; };
class LGuardObjectGroup : public LInstructionHelper<0, 1, 1> class LGuardObjectGroup : public LInstructionHelper<0, 1, 0>
{ {
public: public:
LIR_HEADER(GuardObjectGroup); LIR_HEADER(GuardObjectGroup);
LGuardObjectGroup(const LAllocation& in, const LDefinition& temp) { explicit LGuardObjectGroup(const LAllocation& in) {
setOperand(0, in); setOperand(0, in);
setTemp(0, temp);
} }
const MGuardObjectGroup* mir() const { const MGuardObjectGroup* mir() const {
return mir_->toGuardObjectGroup(); return mir_->toGuardObjectGroup();

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

@ -292,8 +292,7 @@ LIRGeneratorMIPSShared::visitGuardShape(MGuardShape* ins)
{ {
MOZ_ASSERT(ins->object()->type() == MIRType::Object); MOZ_ASSERT(ins->object()->type() == MIRType::Object);
LDefinition tempObj = temp(LDefinition::OBJECT); LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()));
LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()), tempObj);
assignSnapshot(guard, ins->bailoutKind()); assignSnapshot(guard, ins->bailoutKind());
add(guard, ins); add(guard, ins);
redefine(ins, ins->object()); redefine(ins, ins->object());
@ -304,8 +303,7 @@ LIRGeneratorMIPSShared::visitGuardObjectGroup(MGuardObjectGroup* ins)
{ {
MOZ_ASSERT(ins->object()->type() == MIRType::Object); MOZ_ASSERT(ins->object()->type() == MIRType::Object);
LDefinition tempObj = temp(LDefinition::OBJECT); LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()));
LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()), tempObj);
assignSnapshot(guard, ins->bailoutKind()); assignSnapshot(guard, ins->bailoutKind());
add(guard, ins); add(guard, ins);
redefine(ins, ins->object()); redefine(ins, ins->object());

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

@ -2376,21 +2376,20 @@ void
CodeGeneratorX86Shared::visitGuardShape(LGuardShape* guard) CodeGeneratorX86Shared::visitGuardShape(LGuardShape* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
masm.cmpPtr(Operand(obj, ShapedObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape())); Label bail;
masm.branchTestObjShape(Assembler::NotEqual, obj, guard->mir()->shape(), &bail);
bailoutIf(Assembler::NotEqual, guard->snapshot()); bailoutFrom(&bail, guard->snapshot());
} }
void void
CodeGeneratorX86Shared::visitGuardObjectGroup(LGuardObjectGroup* guard) CodeGeneratorX86Shared::visitGuardObjectGroup(LGuardObjectGroup* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
masm.cmpPtr(Operand(obj, JSObject::offsetOfGroup()), ImmGCPtr(guard->mir()->group()));
Assembler::Condition cond = Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual; guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
bailoutIf(cond, guard->snapshot()); Label bail;
masm.branchTestObjGroup(cond, obj, guard->mir()->group(), &bail);
bailoutFrom(&bail, guard->snapshot());
} }
void void
@ -2398,10 +2397,9 @@ CodeGeneratorX86Shared::visitGuardClass(LGuardClass* guard)
{ {
Register obj = ToRegister(guard->input()); Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt()); Register tmp = ToRegister(guard->tempInt());
Label bail;
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp); masm.branchTestObjClass(Assembler::NotEqual, obj, tmp, guard->mir()->getClass(), &bail);
masm.cmpPtr(Operand(tmp, ObjectGroup::offsetOfClasp()), ImmPtr(guard->mir()->getClass())); bailoutFrom(&bail, guard->snapshot());
bailoutIf(Assembler::NotEqual, guard->snapshot());
} }
void void

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

@ -3993,6 +3993,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp
introductionOffset = rhs.introductionOffset; introductionOffset = rhs.introductionOffset;
hasIntroductionInfo = rhs.hasIntroductionInfo; hasIntroductionInfo = rhs.hasIntroductionInfo;
isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode; isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode;
hideScriptFromDebugger = rhs.hideScriptFromDebugger;
}; };
void void
@ -4678,6 +4679,17 @@ JS::InitScriptSourceElement(JSContext* cx, HandleScript script,
return ScriptSourceObject::initElementProperties(cx, sso, element, elementAttrName); return ScriptSourceObject::initElementProperties(cx, sso, element, elementAttrName);
} }
JS_PUBLIC_API(void)
JS::ExposeScriptToDebugger(JSContext* cx, HandleScript script)
{
MOZ_ASSERT(cx);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
MOZ_ASSERT(script->hideScriptFromDebugger());
script->clearHideScriptFromDebugger();
Debugger::onNewScript(cx, script);
}
JS_PUBLIC_API(JSString*) JS_PUBLIC_API(JSString*)
JS_DecompileScript(JSContext* cx, HandleScript script) JS_DecompileScript(JSContext* cx, HandleScript script)
{ {

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

@ -102,133 +102,6 @@ class MOZ_RAII AutoValueArray : public AutoGCRooter
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
}; };
template<class T>
class MOZ_RAII AutoVectorRooterBase : protected AutoGCRooter
{
typedef js::Vector<T, 8> VectorImpl;
VectorImpl vector;
public:
explicit AutoVectorRooterBase(JSContext* cx, ptrdiff_t tag
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, tag), vector(cx)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
typedef T ElementType;
typedef typename VectorImpl::Range Range;
size_t length() const { return vector.length(); }
bool empty() const { return vector.empty(); }
MOZ_MUST_USE bool append(const T& v) { return vector.append(v); }
MOZ_MUST_USE bool appendN(const T& v, size_t len) { return vector.appendN(v, len); }
MOZ_MUST_USE bool append(const T* ptr, size_t len) { return vector.append(ptr, len); }
MOZ_MUST_USE bool appendAll(const AutoVectorRooterBase<T>& other) {
return vector.appendAll(other.vector);
}
MOZ_MUST_USE bool insert(T* p, const T& val) { return vector.insert(p, val); }
/* For use when space has already been reserved. */
void infallibleAppend(const T& v) { vector.infallibleAppend(v); }
void popBack() { vector.popBack(); }
T popCopy() { return vector.popCopy(); }
MOZ_MUST_USE bool growBy(size_t inc) {
size_t oldLength = vector.length();
if (!vector.growByUninitialized(inc))
return false;
makeRangeGCSafe(oldLength);
return true;
}
MOZ_MUST_USE bool resize(size_t newLength) {
size_t oldLength = vector.length();
if (newLength <= oldLength) {
vector.shrinkBy(oldLength - newLength);
return true;
}
if (!vector.growByUninitialized(newLength - oldLength))
return false;
makeRangeGCSafe(oldLength);
return true;
}
void clear() { vector.clear(); }
MOZ_MUST_USE bool reserve(size_t newLength) {
return vector.reserve(newLength);
}
JS::MutableHandle<T> operator[](size_t i) {
return JS::MutableHandle<T>::fromMarkedLocation(&vector[i]);
}
JS::Handle<T> operator[](size_t i) const {
return JS::Handle<T>::fromMarkedLocation(&vector[i]);
}
const T* begin() const { return vector.begin(); }
T* begin() { return vector.begin(); }
const T* end() const { return vector.end(); }
T* end() { return vector.end(); }
Range all() { return vector.all(); }
const T& back() const { return vector.back(); }
friend void AutoGCRooter::trace(JSTracer* trc);
private:
void makeRangeGCSafe(size_t oldLength) {
T* t = vector.begin() + oldLength;
for (size_t i = oldLength; i < vector.length(); ++i, ++t)
memset(t, 0, sizeof(T));
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
template <typename T>
class MOZ_RAII AutoVectorRooter : public AutoVectorRooterBase<T>
{
public:
explicit AutoVectorRooter(JSContext* cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoVectorRooterBase<T>(cx, this->GetTag(T()))
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoValueVector : public Rooted<GCVector<Value, 8>> {
using Vec = GCVector<Value, 8>;
using Base = Rooted<Vec>;
public:
explicit AutoValueVector(JSContext* cx) : Base(cx, Vec(cx)) {}
};
class AutoIdVector : public Rooted<GCVector<jsid, 8>> {
using Vec = GCVector<jsid, 8>;
using Base = Rooted<Vec>;
public:
explicit AutoIdVector(JSContext* cx) : Base(cx, Vec(cx)) {}
bool appendAll(const AutoIdVector& other) { return this->Base::appendAll(other.get()); }
};
class AutoObjectVector : public Rooted<GCVector<JSObject*, 8>> {
using Vec = GCVector<JSObject*, 8>;
using Base = Rooted<Vec>;
public:
explicit AutoObjectVector(JSContext* cx) : Base(cx, Vec(cx)) {}
};
using ValueVector = JS::GCVector<JS::Value>; using ValueVector = JS::GCVector<JS::Value>;
using IdVector = JS::GCVector<jsid>; using IdVector = JS::GCVector<jsid>;
using ScriptVector = JS::GCVector<JSScript*>; using ScriptVector = JS::GCVector<JSScript*>;
@ -3692,6 +3565,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
sourceIsLazy(false), sourceIsLazy(false),
allowHTMLComments(true), allowHTMLComments(true),
isProbablySystemOrAddonCode(false), isProbablySystemOrAddonCode(false),
hideScriptFromDebugger(false),
introductionType(nullptr), introductionType(nullptr),
introductionLineno(0), introductionLineno(0),
introductionOffset(0), introductionOffset(0),
@ -3727,6 +3601,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
bool sourceIsLazy; bool sourceIsLazy;
bool allowHTMLComments; bool allowHTMLComments;
bool isProbablySystemOrAddonCode; bool isProbablySystemOrAddonCode;
bool hideScriptFromDebugger;
// |introductionType| is a statically allocated C string: // |introductionType| is a statically allocated C string:
// one of "eval", "Function", or "GeneratorFunction". // one of "eval", "Function", or "GeneratorFunction".
@ -4134,6 +4009,13 @@ extern JS_PUBLIC_API(bool)
InitScriptSourceElement(JSContext* cx, HandleScript script, InitScriptSourceElement(JSContext* cx, HandleScript script,
HandleObject element, HandleString elementAttrName = nullptr); HandleObject element, HandleString elementAttrName = nullptr);
/*
* For a script compiled with the hideScriptFromDebugger option, expose the
* script to the debugger by calling the debugger's onNewScript hook.
*/
extern JS_PUBLIC_API(void)
ExposeScriptToDebugger(JSContext* cx, HandleScript script);
} /* namespace JS */ } /* namespace JS */
extern JS_PUBLIC_API(JSString*) extern JS_PUBLIC_API(JSString*)

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

@ -29,7 +29,11 @@
namespace JS { namespace JS {
class AutoIdVector; template <typename T> class AutoVector;
using AutoIdVector = AutoVector<jsid>;
using AutoValueVector = AutoVector<Value>;
using AutoObjectVector = AutoVector<JSObject*>;
class CallArgs; class CallArgs;
class JS_FRIEND_API(CompileOptions); class JS_FRIEND_API(CompileOptions);

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

@ -9085,7 +9085,8 @@ main(int argc, char** argv, char** envp)
|| !op.addBoolOption('\0', "no-ggc", "Disable Generational GC") || !op.addBoolOption('\0', "no-ggc", "Disable Generational GC")
|| !op.addBoolOption('\0', "no-cgc", "Disable Compacting GC") || !op.addBoolOption('\0', "no-cgc", "Disable Compacting GC")
|| !op.addBoolOption('\0', "no-incremental-gc", "Disable Incremental GC") || !op.addBoolOption('\0', "no-incremental-gc", "Disable Incremental GC")
|| !op.addBoolOption('\0', "nursery-strings", "Allocate strings in the nursery") || !op.addStringOption('\0', "nursery-strings", "on/off",
"Allocate strings in the nursery")
|| !op.addIntOption('\0', "available-memory", "SIZE", || !op.addIntOption('\0', "available-memory", "SIZE",
"Select GC settings based on available memory (MB)", 0) "Select GC settings based on available memory (MB)", 0)
|| !op.addStringOption('\0', "arm-hwcap", "[features]", || !op.addStringOption('\0', "arm-hwcap", "[features]",
@ -9233,8 +9234,14 @@ main(int argc, char** argv, char** envp)
js::UseInternalJobQueues(cx); js::UseInternalJobQueues(cx);
if (op.getBoolOption("nursery-strings")) if (const char* opt = op.getStringOption("nursery-strings")) {
cx->runtime()->gc.nursery().enableStrings(); if (strcmp(opt, "on") == 0)
cx->runtime()->gc.nursery().enableStrings();
else if (strcmp(opt, "off") == 0)
cx->runtime()->gc.nursery().disableStrings();
else
MOZ_CRASH("invalid option value for --nursery-strings, must be on/off");
}
if (!JS::InitSelfHostedCode(cx)) if (!JS::InitSelfHostedCode(cx))
return 1; return 1;

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

@ -1800,6 +1800,11 @@ Debugger::onNewScript(JSContext* cx, HandleScript script)
MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() && MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() &&
!script->selfHosted(), !script->selfHosted(),
script->compartment()->firedOnNewGlobalObject); script->compartment()->firedOnNewGlobalObject);
// The script may not be ready to be interrogated by the debugger.
if (script->hideScriptFromDebugger())
return;
if (script->compartment()->isDebuggee()) if (script->compartment()->isDebuggee())
slowPathOnNewScript(cx, script); slowPathOnNewScript(cx, script);
} }

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

@ -218,6 +218,7 @@ GetSelectorRuntime(const CompilationSelector& selector)
{ {
JSRuntime* match(JSScript* script) { return script->runtimeFromActiveCooperatingThread(); } JSRuntime* match(JSScript* script) { return script->runtimeFromActiveCooperatingThread(); }
JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromActiveCooperatingThread(); } JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromActiveCooperatingThread(); }
JSRuntime* match(Zone* zone) { return zone->runtimeFromActiveCooperatingThread(); }
JSRuntime* match(ZonesInState zbs) { return zbs.runtime; } JSRuntime* match(ZonesInState zbs) { return zbs.runtime; }
JSRuntime* match(JSRuntime* runtime) { return runtime; } JSRuntime* match(JSRuntime* runtime) { return runtime; }
JSRuntime* match(AllCompilations all) { return nullptr; } JSRuntime* match(AllCompilations all) { return nullptr; }
@ -234,6 +235,7 @@ JitDataStructuresExist(const CompilationSelector& selector)
{ {
bool match(JSScript* script) { return !!script->compartment()->jitCompartment(); } bool match(JSScript* script) { return !!script->compartment()->jitCompartment(); }
bool match(JSCompartment* comp) { return !!comp->jitCompartment(); } bool match(JSCompartment* comp) { return !!comp->jitCompartment(); }
bool match(Zone* zone) { return !!zone->jitZone(); }
bool match(ZonesInState zbs) { return zbs.runtime->hasJitRuntime(); } bool match(ZonesInState zbs) { return zbs.runtime->hasJitRuntime(); }
bool match(JSRuntime* runtime) { return runtime->hasJitRuntime(); } bool match(JSRuntime* runtime) { return runtime->hasJitRuntime(); }
bool match(AllCompilations all) { return true; } bool match(AllCompilations all) { return true; }
@ -252,6 +254,7 @@ IonBuilderMatches(const CompilationSelector& selector, jit::IonBuilder* builder)
bool match(JSScript* script) { return script == builder_->script(); } bool match(JSScript* script) { return script == builder_->script(); }
bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); } bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); }
bool match(Zone* zone) { return zone == builder_->script()->zone(); }
bool match(JSRuntime* runtime) { return runtime == builder_->script()->runtimeFromAnyThread(); } bool match(JSRuntime* runtime) { return runtime == builder_->script()->runtimeFromAnyThread(); }
bool match(AllCompilations all) { return true; } bool match(AllCompilations all) { return true; }
bool match(ZonesInState zbs) { bool match(ZonesInState zbs) {

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

@ -516,6 +516,7 @@ struct CompilationsUsingNursery { JSRuntime* runtime; };
using CompilationSelector = mozilla::Variant<JSScript*, using CompilationSelector = mozilla::Variant<JSScript*,
JSCompartment*, JSCompartment*,
Zone*,
ZonesInState, ZonesInState,
JSRuntime*, JSRuntime*,
CompilationsUsingNursery, CompilationsUsingNursery,
@ -539,6 +540,12 @@ CancelOffThreadIonCompile(JSCompartment* comp)
CancelOffThreadIonCompile(CompilationSelector(comp), true); CancelOffThreadIonCompile(CompilationSelector(comp), true);
} }
inline void
CancelOffThreadIonCompile(Zone* zone)
{
CancelOffThreadIonCompile(CompilationSelector(zone), true);
}
inline void inline void
CancelOffThreadIonCompile(JSRuntime* runtime, JS::Zone::GCState state) CancelOffThreadIonCompile(JSRuntime* runtime, JS::Zone::GCState state)
{ {

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

@ -1384,16 +1384,20 @@ struct WrapperValue
Value value; Value value;
}; };
class MOZ_RAII AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue> class MOZ_RAII AutoWrapperVector : public JS::GCVector<WrapperValue, 8>,
private JS::AutoGCRooter
{ {
public: public:
explicit AutoWrapperVector(JSContext* cx explicit AutoWrapperVector(JSContext* cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoVectorRooterBase<WrapperValue>(cx, WRAPVECTOR) : JS::GCVector<WrapperValue, 8>(cx),
JS::AutoGCRooter(cx, WRAPVECTOR)
{ {
MOZ_GUARD_OBJECT_NOTIFIER_INIT; MOZ_GUARD_OBJECT_NOTIFIER_INIT;
} }
friend void AutoGCRooter::trace(JSTracer* trc);
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
}; };

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

@ -541,7 +541,15 @@ class JSObject : public js::gc::Cell
void dump() const; void dump() const;
#endif #endif
/* JIT Accessors */ // Maximum size in bytes of a JSObject.
static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
protected:
// JIT Accessors.
//
// To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
// to call the method below.
friend class js::jit::MacroAssembler;
static constexpr size_t offsetOfGroup() { static constexpr size_t offsetOfGroup() {
return offsetof(JSObject, group_); return offsetof(JSObject, group_);
@ -550,9 +558,6 @@ class JSObject : public js::gc::Cell
return offsetof(JSObject, shapeOrExpando_); return offsetof(JSObject, shapeOrExpando_);
} }
// Maximum size in bytes of a JSObject.
static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
private: private:
JSObject() = delete; JSObject() = delete;
JSObject(const JSObject& other) = delete; JSObject(const JSObject& other) = delete;

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

@ -2732,6 +2732,8 @@ JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
script->toStringStart_ = toStringStart; script->toStringStart_ = toStringStart;
script->toStringEnd_ = toStringEnd; script->toStringEnd_ = toStringEnd;
script->hideScriptFromDebugger_ = options.hideScriptFromDebugger;
#ifdef MOZ_VTUNE #ifdef MOZ_VTUNE
script->vtuneMethodId_ = vtune::GenerateUniqueMethodID(); script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
#endif #endif
@ -3625,6 +3627,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->isAsync_ = src->isAsync_; dst->isAsync_ = src->isAsync_;
dst->hasRest_ = src->hasRest_; dst->hasRest_ = src->hasRest_;
dst->isExprBody_ = src->isExprBody_; dst->isExprBody_ = src->isExprBody_;
dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_;
if (nconsts != 0) { if (nconsts != 0) {
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector); GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);

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

@ -1142,6 +1142,9 @@ class JSScript : public js::gc::TenuredCell
bool hasRest_:1; bool hasRest_:1;
bool isExprBody_:1; bool isExprBody_:1;
// True if the debugger's onNewScript hook has not yet been called.
bool hideScriptFromDebugger_:1;
// Add padding so JSScript is gc::Cell aligned. Make padding protected // Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings. // instead of private to suppress -Wunused-private-field compiler warnings.
protected: protected:
@ -1463,6 +1466,13 @@ class JSScript : public js::gc::TenuredCell
isExprBody_ = true; isExprBody_ = true;
} }
bool hideScriptFromDebugger() const {
return hideScriptFromDebugger_;
}
void clearHideScriptFromDebugger() {
hideScriptFromDebugger_ = false;
}
void setNeedsHomeObject() { void setNeedsHomeObject() {
needsHomeObject_ = true; needsHomeObject_ = true;
} }

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

@ -459,6 +459,10 @@ class ObjectGroup : public gc::TenuredCell
static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup; static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup;
private:
// See JSObject::offsetOfGroup() comment.
friend class js::jit::MacroAssembler;
static inline uint32_t offsetOfClasp() { static inline uint32_t offsetOfClasp() {
return offsetof(ObjectGroup, clasp_); return offsetof(ObjectGroup, clasp_);
} }
@ -479,6 +483,7 @@ class ObjectGroup : public gc::TenuredCell
return offsetof(ObjectGroup, flags_); return offsetof(ObjectGroup, flags_);
} }
public:
const ObjectGroupFlags* addressOfFlags() const { const ObjectGroupFlags* addressOfFlags() const {
return &flags_; return &flags_;
} }

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

@ -1800,12 +1800,12 @@ Shape::fixupDictionaryShapeAfterMovingGC()
if (listpPointsIntoShape) { if (listpPointsIntoShape) {
// listp points to the parent field of the next shape. // listp points to the parent field of the next shape.
Shape* next = reinterpret_cast<Shape*>(uintptr_t(listp) - offsetof(Shape, parent)); Shape* next = Shape::fromParentFieldPointer(uintptr_t(listp));
if (gc::IsForwarded(next)) if (gc::IsForwarded(next))
listp = &gc::Forwarded(next)->parent; listp = &gc::Forwarded(next)->parent;
} else { } else {
// listp points to the shape_ field of an object. // listp points to the shape_ field of an object.
JSObject* last = reinterpret_cast<JSObject*>(uintptr_t(listp) - ShapedObject::offsetOfShape()); JSObject* last = ShapedObject::fromShapeFieldPointer(uintptr_t(listp));
if (gc::IsForwarded(last)) if (gc::IsForwarded(last))
listp = gc::Forwarded(last)->as<NativeObject>().shapePtr(); listp = gc::Forwarded(last)->as<NativeObject>().shapePtr();
} }

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

@ -1169,15 +1169,20 @@ class Shape : public gc::TenuredCell
void fixupGetterSetterForBarrier(JSTracer* trc); void fixupGetterSetterForBarrier(JSTracer* trc);
void updateBaseShapeAfterMovingGC(); void updateBaseShapeAfterMovingGC();
/* For JIT usage */ #ifdef DEBUG
static inline size_t offsetOfBase() { return offsetof(Shape, base_); } // For JIT usage.
static inline size_t offsetOfSlotInfo() { return offsetof(Shape, slotInfo); } static inline size_t offsetOfSlotInfo() { return offsetof(Shape, slotInfo); }
static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; } static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
#endif
private: private:
void fixupDictionaryShapeAfterMovingGC(); void fixupDictionaryShapeAfterMovingGC();
void fixupShapeTreeAfterMovingGC(); void fixupShapeTreeAfterMovingGC();
static Shape* fromParentFieldPointer(uintptr_t p) {
return reinterpret_cast<Shape*>(p - offsetof(Shape, parent));
}
static void staticAsserts() { static void staticAsserts() {
JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base)); JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo)); JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));

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

@ -50,6 +50,14 @@ class ShapedObject : public JSObject
TraceEdge(trc, shapePtr(), "shape"); TraceEdge(trc, shapePtr(), "shape");
} }
static JSObject* fromShapeFieldPointer(uintptr_t p) {
return reinterpret_cast<JSObject*>(p - ShapedObject::offsetOfShape());
}
private:
// See JSObject::offsetOfGroup() comment.
friend class js::jit::MacroAssembler;
static constexpr size_t offsetOfShape() { static constexpr size_t offsetOfShape() {
static_assert(offsetOfShapeOrExpando() == offsetof(shadow::Object, shape), static_assert(offsetOfShapeOrExpando() == offsetof(shadow::Object, shape),
"shadow shape must match actual shape"); "shadow shape must match actual shape");

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

@ -525,7 +525,8 @@ JSRope::flattenInternal(JSContext* maybecx)
Nursery& nursery = zone()->group()->nursery(); Nursery& nursery = zone()->group()->nursery();
if (!nursery.registerMallocedBuffer(wholeChars)) { if (!nursery.registerMallocedBuffer(wholeChars)) {
js_free(wholeChars); js_free(wholeChars);
ReportOutOfMemory(maybecx); if (maybecx)
ReportOutOfMemory(maybecx);
return nullptr; return nullptr;
} }
} }

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

@ -87,15 +87,25 @@ wasm::HasCompilerSupport(JSContext* cx)
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64) #if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
return false; return false;
#else #else
return BaselineCanCompile() || IonCanCompile();
#endif
}
// Return whether wasm compilation is allowed by prefs. This check
// only makes sense if HasCompilerSupport() is true.
static bool
HasAvailableCompilerTier(JSContext* cx)
{
return (cx->options().wasmBaseline() && BaselineCanCompile()) || return (cx->options().wasmBaseline() && BaselineCanCompile()) ||
(cx->options().wasmIon() && IonCanCompile()); (cx->options().wasmIon() && IonCanCompile());
#endif
} }
bool bool
wasm::HasSupport(JSContext* cx) wasm::HasSupport(JSContext* cx)
{ {
return cx->options().wasm() && HasCompilerSupport(cx); return cx->options().wasm() &&
HasCompilerSupport(cx) &&
HasAvailableCompilerTier(cx);
} }
bool bool

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

@ -12,10 +12,6 @@
#include "js/CallNonGenericMethod.h" #include "js/CallNonGenericMethod.h"
#include "js/Wrapper.h" #include "js/Wrapper.h"
namespace JS {
class AutoIdVector;
} // namespace JS
namespace xpc { namespace xpc {
template <typename Base, typename Policy> template <typename Base, typename Policy>

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

@ -200,12 +200,6 @@ IsReversedDirectionFrame(nsIFrame* aFrame)
} }
#include "nsILineIterator.h" #include "nsILineIterator.h"
//non Hack prototypes
#if 0
static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
#endif
#include "prenv.h" #include "prenv.h"
NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics) NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics)

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

@ -921,7 +921,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-003.xht css-writ
== css-writing-modes/sizing-orthog-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-006.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-006.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-007.xht css-writing-modes/sizing-orthog-htb-in-vlr-007-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-007.xht css-writing-modes/sizing-orthog-htb-in-vlr-007-ref.xht
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vlr-008.xht css-writing-modes/sizing-orthog-htb-in-vlr-008-ref.xht fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vlr-008.xht css-writing-modes/sizing-orthog-htb-in-vlr-008-ref.xht
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-009.xht css-writing-modes/sizing-orthog-htb-in-vlr-003-ref.xht fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-009.xht css-writing-modes/sizing-orthog-htb-in-vlr-003-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-010.xht css-writing-modes/sizing-orthog-htb-in-vlr-010-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-010.xht css-writing-modes/sizing-orthog-htb-in-vlr-010-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-011.xht css-writing-modes/sizing-orthog-htb-in-vlr-011-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-011.xht css-writing-modes/sizing-orthog-htb-in-vlr-011-ref.xht
@ -931,7 +931,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-015.xht css-writ
== css-writing-modes/sizing-orthog-htb-in-vlr-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-018.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-018.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-019.xht css-writing-modes/sizing-orthog-htb-in-vlr-019-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-019.xht css-writing-modes/sizing-orthog-htb-in-vlr-019-ref.xht
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vlr-020.xht css-writing-modes/sizing-orthog-htb-in-vlr-020-ref.xht fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vlr-020.xht css-writing-modes/sizing-orthog-htb-in-vlr-020-ref.xht
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-021.xht css-writing-modes/sizing-orthog-htb-in-vlr-015-ref.xht fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-021.xht css-writing-modes/sizing-orthog-htb-in-vlr-015-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-022.xht css-writing-modes/sizing-orthog-htb-in-vlr-022-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-022.xht css-writing-modes/sizing-orthog-htb-in-vlr-022-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vlr-023.xht css-writing-modes/sizing-orthog-htb-in-vlr-023-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-023.xht css-writing-modes/sizing-orthog-htb-in-vlr-023-ref.xht
@ -941,7 +941,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-003.xht css-writ
fails == css-writing-modes/sizing-orthog-htb-in-vrl-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht fails == css-writing-modes/sizing-orthog-htb-in-vrl-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-006.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-006.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-007.xht css-writing-modes/sizing-orthog-htb-in-vrl-007-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-007.xht css-writing-modes/sizing-orthog-htb-in-vrl-007-ref.xht
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vrl-008.xht css-writing-modes/sizing-orthog-htb-in-vrl-008-ref.xht fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vrl-008.xht css-writing-modes/sizing-orthog-htb-in-vrl-008-ref.xht
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-009.xht css-writing-modes/sizing-orthog-htb-in-vrl-003-ref.xht fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-009.xht css-writing-modes/sizing-orthog-htb-in-vrl-003-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-010.xht css-writing-modes/sizing-orthog-htb-in-vrl-010-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-010.xht css-writing-modes/sizing-orthog-htb-in-vrl-010-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-011.xht css-writing-modes/sizing-orthog-htb-in-vrl-011-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-011.xht css-writing-modes/sizing-orthog-htb-in-vrl-011-ref.xht
@ -951,7 +951,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-015.xht css-writ
== css-writing-modes/sizing-orthog-htb-in-vrl-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-018.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-018.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-019.xht css-writing-modes/sizing-orthog-htb-in-vrl-019-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-019.xht css-writing-modes/sizing-orthog-htb-in-vrl-019-ref.xht
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vrl-020.xht css-writing-modes/sizing-orthog-htb-in-vrl-020-ref.xht fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vrl-020.xht css-writing-modes/sizing-orthog-htb-in-vrl-020-ref.xht
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-021.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-021.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-022.xht css-writing-modes/sizing-orthog-htb-in-vrl-022-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-022.xht css-writing-modes/sizing-orthog-htb-in-vrl-022-ref.xht
== css-writing-modes/sizing-orthog-htb-in-vrl-023.xht css-writing-modes/sizing-orthog-htb-in-vrl-023-ref.xht == css-writing-modes/sizing-orthog-htb-in-vrl-023.xht css-writing-modes/sizing-orthog-htb-in-vrl-023-ref.xht

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

@ -139,6 +139,11 @@ public:
aIdealSegmentSize - sizeof(Segment) < sizeof(T)); aIdealSegmentSize - sizeof(Segment) < sizeof(T));
} }
SegmentedVector(SegmentedVector&& aOther)
: mSegments(mozilla::Move(aOther.mSegments))
{
}
~SegmentedVector() { Clear(); } ~SegmentedVector() { Clear(); }
bool IsEmpty() const { return !mSegments.getFirst(); } bool IsEmpty() const { return !mSegments.getFirst(); }

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

@ -3596,7 +3596,7 @@ public class BrowserApp extends GeckoApp
super.closeOptionsMenu(); super.closeOptionsMenu();
} }
@Override // GeckoView.ContentListener @Override // GeckoView.ContentDelegate
public void onFullScreen(final GeckoSession session, final boolean fullscreen) { public void onFullScreen(final GeckoSession session, final boolean fullscreen) {
super.onFullScreen(session, fullscreen); super.onFullScreen(session, fullscreen);

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

@ -111,7 +111,7 @@ public abstract class GeckoApp extends GeckoActivity
BundleEventListener, BundleEventListener,
GeckoMenu.Callback, GeckoMenu.Callback,
GeckoMenu.MenuPresenter, GeckoMenu.MenuPresenter,
GeckoSession.ContentListener, GeckoSession.ContentDelegate,
ScreenOrientationDelegate, ScreenOrientationDelegate,
Tabs.OnTabsChangedListener, Tabs.OnTabsChangedListener,
ViewTreeObserver.OnGlobalLayoutListener { ViewTreeObserver.OnGlobalLayoutListener {
@ -873,19 +873,19 @@ public abstract class GeckoApp extends GeckoActivity
return inSampleSize; return inSampleSize;
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onTitleChange(final GeckoSession session, final String title) { public void onTitleChange(final GeckoSession session, final String title) {
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onFocusRequest(final GeckoSession session) { public void onFocusRequest(final GeckoSession session) {
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onCloseRequest(final GeckoSession session) { public void onCloseRequest(final GeckoSession session) {
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onFullScreen(final GeckoSession session, final boolean fullScreen) { public void onFullScreen(final GeckoSession session, final boolean fullScreen) {
if (fullScreen) { if (fullScreen) {
SnackbarBuilder.builder(this) SnackbarBuilder.builder(this)
@ -1087,7 +1087,7 @@ public abstract class GeckoApp extends GeckoActivity
session.getSettings().setString(GeckoSessionSettings.CHROME_URI, session.getSettings().setString(GeckoSessionSettings.CHROME_URI,
"chrome://browser/content/browser.xul"); "chrome://browser/content/browser.xul");
session.setContentListener(this); session.setContentDelegate(this);
GeckoAccessibility.setDelegate(mLayerView); GeckoAccessibility.setDelegate(mLayerView);

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

@ -34,7 +34,7 @@ import org.mozilla.gecko.SiteIdentity;
import org.mozilla.gecko.Tab; import org.mozilla.gecko.Tab;
import org.mozilla.gecko.toolbar.SecurityModeUtil; import org.mozilla.gecko.toolbar.SecurityModeUtil;
import org.mozilla.gecko.util.ColorUtil; import org.mozilla.gecko.util.ColorUtil;
import org.mozilla.geckoview.GeckoSession.ProgressListener.SecurityInformation; import org.mozilla.geckoview.GeckoSession.ProgressDelegate.SecurityInformation;
import org.mozilla.geckoview.GeckoView; import org.mozilla.geckoview.GeckoView;
/** /**

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

@ -73,9 +73,9 @@ import java.util.List;
public class CustomTabsActivity extends AppCompatActivity public class CustomTabsActivity extends AppCompatActivity
implements ActionModePresenter, implements ActionModePresenter,
GeckoMenu.Callback, GeckoMenu.Callback,
GeckoSession.ContentListener, GeckoSession.ContentDelegate,
GeckoSession.NavigationListener, GeckoSession.NavigationDelegate,
GeckoSession.ProgressListener { GeckoSession.ProgressDelegate {
private static final String LOGTAG = "CustomTabsActivity"; private static final String LOGTAG = "CustomTabsActivity";
@ -134,9 +134,9 @@ public class CustomTabsActivity extends AppCompatActivity
mGeckoSession = new GeckoSession(); mGeckoSession = new GeckoSession();
mGeckoView.setSession(mGeckoSession); mGeckoView.setSession(mGeckoSession);
mGeckoSession.setNavigationListener(this); mGeckoSession.setNavigationDelegate(this);
mGeckoSession.setProgressListener(this); mGeckoSession.setProgressDelegate(this);
mGeckoSession.setContentListener(this); mGeckoSession.setContentDelegate(this);
mPromptService = new PromptService(this, mGeckoView.getEventDispatcher()); mPromptService = new PromptService(this, mGeckoView.getEventDispatcher());
mDoorHangerPopup = new DoorHangerPopup(this, mGeckoView.getEventDispatcher()); mDoorHangerPopup = new DoorHangerPopup(this, mGeckoView.getEventDispatcher());
@ -591,7 +591,7 @@ public class CustomTabsActivity extends AppCompatActivity
return null; return null;
} }
/* GeckoSession.NavigationListener */ /* GeckoSession.NavigationDelegate */
@Override @Override
public void onLocationChange(GeckoSession session, String url) { public void onLocationChange(GeckoSession session, String url) {
mCurrentUrl = url; mCurrentUrl = url;
@ -656,7 +656,7 @@ public class CustomTabsActivity extends AppCompatActivity
throw new IllegalStateException("Unexpected new session"); throw new IllegalStateException("Unexpected new session");
} }
/* GeckoSession.ProgressListener */ /* GeckoSession.ProgressDelegate */
@Override @Override
public void onPageStart(GeckoSession session, String url) { public void onPageStart(GeckoSession session, String url) {
mCurrentUrl = url; mCurrentUrl = url;
@ -679,7 +679,7 @@ public class CustomTabsActivity extends AppCompatActivity
updateActionBar(); updateActionBar();
} }
/* GeckoSession.ContentListener */ /* GeckoSession.ContentDelegate */
@Override @Override
public void onTitleChange(GeckoSession session, String title) { public void onTitleChange(GeckoSession session, String title) {
mCurrentTitle = title; mCurrentTitle = title;

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

@ -33,7 +33,7 @@ import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.AnchoredPopup; import org.mozilla.gecko.widget.AnchoredPopup;
import org.mozilla.gecko.widget.DoorHanger; import org.mozilla.gecko.widget.DoorHanger;
import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener; import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener;
import org.mozilla.geckoview.GeckoSession.ProgressListener.SecurityInformation; import org.mozilla.geckoview.GeckoSession.ProgressDelegate.SecurityInformation;
import org.mozilla.geckoview.GeckoView; import org.mozilla.geckoview.GeckoView;
import android.app.Activity; import android.app.Activity;

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

@ -53,8 +53,8 @@ import org.mozilla.geckoview.GeckoView;
public class WebAppActivity extends AppCompatActivity public class WebAppActivity extends AppCompatActivity
implements ActionModePresenter, implements ActionModePresenter,
GeckoSession.ContentListener, GeckoSession.ContentDelegate,
GeckoSession.NavigationListener { GeckoSession.NavigationDelegate {
private static final String LOGTAG = "WebAppActivity"; private static final String LOGTAG = "WebAppActivity";
public static final String MANIFEST_PATH = "MANIFEST_PATH"; public static final String MANIFEST_PATH = "MANIFEST_PATH";
@ -103,9 +103,9 @@ public class WebAppActivity extends AppCompatActivity
mGeckoSession = new GeckoSession(); mGeckoSession = new GeckoSession();
mGeckoView.setSession(mGeckoSession); mGeckoView.setSession(mGeckoSession);
mGeckoSession.setNavigationListener(this); mGeckoSession.setNavigationDelegate(this);
mGeckoSession.setContentListener(this); mGeckoSession.setContentDelegate(this);
mGeckoSession.setProgressListener(new GeckoSession.ProgressListener() { mGeckoSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
@Override @Override
public void onPageStart(GeckoSession session, String url) { public void onPageStart(GeckoSession session, String url) {
@ -332,36 +332,36 @@ public class WebAppActivity extends AppCompatActivity
mGeckoView.getSettings().setInt(GeckoSessionSettings.DISPLAY_MODE, mode); mGeckoView.getSettings().setInt(GeckoSessionSettings.DISPLAY_MODE, mode);
} }
@Override // GeckoSession.NavigationListener @Override // GeckoSession.NavigationDelegate
public void onLocationChange(GeckoSession session, String url) { public void onLocationChange(GeckoSession session, String url) {
} }
@Override // GeckoSession.NavigationListener @Override // GeckoSession.NavigationDelegate
public void onCanGoBack(GeckoSession session, boolean canGoBack) { public void onCanGoBack(GeckoSession session, boolean canGoBack) {
mCanGoBack = canGoBack; mCanGoBack = canGoBack;
} }
@Override // GeckoSession.NavigationListener @Override // GeckoSession.NavigationDelegate
public void onCanGoForward(GeckoSession session, boolean canGoForward) { public void onCanGoForward(GeckoSession session, boolean canGoForward) {
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onTitleChange(GeckoSession session, String title) { public void onTitleChange(GeckoSession session, String title) {
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onFocusRequest(GeckoSession session) { public void onFocusRequest(GeckoSession session) {
Intent intent = new Intent(getIntent()); Intent intent = new Intent(getIntent());
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent); startActivity(intent);
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onCloseRequest(GeckoSession session) { public void onCloseRequest(GeckoSession session) {
// Ignore // Ignore
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onContextMenu(GeckoSession session, int screenX, int screenY, public void onContextMenu(GeckoSession session, int screenX, int screenY,
String uri, String elementSrc) { String uri, String elementSrc) {
final String content = uri != null ? uri : elementSrc != null ? elementSrc : ""; final String content = uri != null ? uri : elementSrc != null ? elementSrc : "";
@ -373,7 +373,7 @@ public class WebAppActivity extends AppCompatActivity
WebApps.openInFennec(validUri, WebAppActivity.this); WebApps.openInFennec(validUri, WebAppActivity.this);
} }
@Override // GeckoSession.ContentListener @Override // GeckoSession.ContentDelegate
public void onFullScreen(GeckoSession session, boolean fullScreen) { public void onFullScreen(GeckoSession session, boolean fullScreen) {
updateFullScreenContent(fullScreen); updateFullScreenContent(fullScreen);
} }

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

@ -63,7 +63,7 @@ public class BaseGeckoViewTest {
protected void loadTestPage(final String url, final Runnable finished) { protected void loadTestPage(final String url, final Runnable finished) {
final String path = Uri.parse(url).getPath(); final String path = Uri.parse(url).getPath();
mSession.setProgressListener(new GeckoSession.ProgressListener() { mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
@Override @Override
public void onPageStart(GeckoSession session, String loadingUrl) { public void onPageStart(GeckoSession session, String loadingUrl) {
assertTrue("Loaded url should end with " + path, loadingUrl.endsWith(path)); assertTrue("Loaded url should end with " + path, loadingUrl.endsWith(path));
@ -72,7 +72,7 @@ public class BaseGeckoViewTest {
@Override @Override
public void onPageStop(GeckoSession session, boolean success) { public void onPageStop(GeckoSession session, boolean success) {
assertTrue("Load should succeed", success); assertTrue("Load should succeed", success);
mSession.setProgressListener(null); mSession.setProgressDelegate(null);
finished.run(); finished.run();
} }

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

@ -27,7 +27,7 @@ inline fun GeckoSession.loadTestPath(path: String) =
/** /**
* Test for the GeckoSessionTestRule class, to ensure it properly sets up a session for * Test for the GeckoSessionTestRule class, to ensure it properly sets up a session for
* each test, and to ensure it can properly wait for and assert listener/delegate * each test, and to ensure it can properly wait for and assert delegate
* callbacks. * callbacks.
*/ */
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -75,9 +75,7 @@ class GeckoSessionTestRuleTest {
@Test fun includesAllCallbacks() { @Test fun includesAllCallbacks() {
for (ifce in GeckoSession::class.java.classes) { for (ifce in GeckoSession::class.java.classes) {
if (!ifce.isInterface || ( if (!ifce.isInterface || !ifce.simpleName.endsWith("Delegate")) {
!ifce.simpleName.endsWith("Listener") &&
!ifce.simpleName.endsWith("Delegate"))) {
continue continue
} }
assertThat("Callbacks.All should include interface " + ifce.simpleName, assertThat("Callbacks.All should include interface " + ifce.simpleName,
@ -91,7 +89,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
counter++ counter++
} }
@ -102,7 +100,7 @@ class GeckoSessionTestRuleTest {
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
fun waitForPageStop_throwOnChangedCallback() { fun waitForPageStop_throwOnChangedCallback() {
sessionRule.session.progressListener = Callbacks.Default sessionRule.session.progressDelegate = Callbacks.Default
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
} }
@ -114,7 +112,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
counter++ counter++
} }
@ -125,11 +123,11 @@ class GeckoSessionTestRuleTest {
@Test fun waitUntilCalled_anyInterfaceMethod() { @Test fun waitUntilCalled_anyInterfaceMethod() {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitUntilCalled(GeckoSession.ProgressListener::class) sessionRule.waitUntilCalled(GeckoSession.ProgressDelegate::class)
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
} }
@ -139,7 +137,7 @@ class GeckoSessionTestRuleTest {
} }
override fun onSecurityChange(session: GeckoSession, override fun onSecurityChange(session: GeckoSession,
securityInfo: GeckoSession.ProgressListener.SecurityInformation) { securityInfo: GeckoSession.ProgressDelegate.SecurityInformation) {
counter++ counter++
} }
}) })
@ -149,12 +147,12 @@ class GeckoSessionTestRuleTest {
@Test fun waitUntilCalled_specificInterfaceMethod() { @Test fun waitUntilCalled_specificInterfaceMethod() {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitUntilCalled(GeckoSession.ProgressListener::class, sessionRule.waitUntilCalled(GeckoSession.ProgressDelegate::class,
"onPageStart", "onPageStop") "onPageStart", "onPageStop")
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
} }
@ -178,7 +176,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener { sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
} }
@ -188,7 +186,7 @@ class GeckoSessionTestRuleTest {
} }
override fun onSecurityChange(session: GeckoSession, override fun onSecurityChange(session: GeckoSession,
securityInfo: GeckoSession.ProgressListener.SecurityInformation) { securityInfo: GeckoSession.ProgressDelegate.SecurityInformation) {
counter++ counter++
} }
}) })
@ -201,7 +199,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener { sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
@AssertCalled @AssertCalled
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -222,7 +220,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener { sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 2) @AssertCalled(count = 2)
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -243,7 +241,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener { sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 2, order = intArrayOf(1, 2)) @AssertCalled(count = 2, order = intArrayOf(1, 2))
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
val info = sessionRule.currentCall val info = sessionRule.currentCall
@ -265,7 +263,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
counter++ counter++
} }
@ -279,7 +277,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(GeckoSession.ScrollListener { _, _, _ -> }) sessionRule.forCallbacksDuringWait(GeckoSession.ScrollDelegate { _, _, _ -> })
} }
@Test fun forCallbacksDuringWait_specificMethod() { @Test fun forCallbacksDuringWait_specificMethod() {
@ -288,7 +286,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled @AssertCalled
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -310,7 +308,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled @AssertCalled
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -331,7 +329,7 @@ class GeckoSessionTestRuleTest {
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait( sessionRule.forCallbacksDuringWait(
GeckoSession.ScrollListener @AssertCalled { _, _, _ -> }) GeckoSession.ScrollDelegate @AssertCalled { _, _, _ -> })
} }
@Test fun forCallbacksDuringWait_specificCount() { @Test fun forCallbacksDuringWait_specificCount() {
@ -341,7 +339,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 2) @AssertCalled(count = 2)
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -362,7 +360,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.reload() sessionRule.session.reload()
sessionRule.waitForPageStops(2) sessionRule.waitForPageStops(2)
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
} }
@ -377,7 +375,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(order = intArrayOf(1)) @AssertCalled(order = intArrayOf(1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
} }
@ -393,7 +391,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(order = intArrayOf(2)) @AssertCalled(order = intArrayOf(2))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
} }
@ -409,7 +407,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.reload() sessionRule.session.reload()
sessionRule.waitForPageStops(2) sessionRule.waitForPageStops(2)
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(order = intArrayOf(1, 3, 1)) @AssertCalled(order = intArrayOf(1, 3, 1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
} }
@ -426,7 +424,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.reload() sessionRule.session.reload()
sessionRule.waitForPageStops(2) sessionRule.waitForPageStops(2)
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(order = intArrayOf(1, 2, 1)) @AssertCalled(order = intArrayOf(1, 2, 1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
} }
@ -442,7 +440,7 @@ class GeckoSessionTestRuleTest {
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait( sessionRule.forCallbacksDuringWait(
GeckoSession.ScrollListener @AssertCalled(false) { _, _, _ -> }) GeckoSession.ScrollDelegate @AssertCalled(false) { _, _, _ -> })
} }
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
@ -450,7 +448,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(false) @AssertCalled(false)
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
} }
@ -472,7 +470,7 @@ class GeckoSessionTestRuleTest {
var counter = 0 var counter = 0
// assert should only apply to callbacks within range (loadUri, first reload]. // assert should only apply to callbacks within range (loadUri, first reload].
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -491,7 +489,7 @@ class GeckoSessionTestRuleTest {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
val info = sessionRule.currentCall val info = sessionRule.currentCall
@ -512,7 +510,7 @@ class GeckoSessionTestRuleTest {
@Test fun delegateUntilTestEnd() { @Test fun delegateUntilTestEnd() {
var counter = 0 var counter = 0
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener { sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -532,19 +530,19 @@ class GeckoSessionTestRuleTest {
@Test fun delegateUntilTestEnd_notCalled() { @Test fun delegateUntilTestEnd_notCalled() {
sessionRule.delegateUntilTestEnd( sessionRule.delegateUntilTestEnd(
GeckoSession.ScrollListener @AssertCalled(false) { _, _, _ -> }) GeckoSession.ScrollDelegate @AssertCalled(false) { _, _, _ -> })
} }
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
fun delegateUntilTestEnd_throwOnNotCalled() { fun delegateUntilTestEnd_throwOnNotCalled() {
sessionRule.delegateUntilTestEnd( sessionRule.delegateUntilTestEnd(
GeckoSession.ScrollListener @AssertCalled(count = 1) { _, _, _ -> }) GeckoSession.ScrollDelegate @AssertCalled(count = 1) { _, _, _ -> })
sessionRule.performTestEndCheck() sessionRule.performTestEndCheck()
} }
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
fun delegateUntilTestEnd_throwOnCallingNoCall() { fun delegateUntilTestEnd_throwOnCallingNoCall() {
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener { sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
@AssertCalled(false) @AssertCalled(false)
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
} }
@ -556,7 +554,7 @@ class GeckoSessionTestRuleTest {
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
fun delegateUntilTestEnd_throwOnWrongOrder() { fun delegateUntilTestEnd_throwOnWrongOrder() {
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener { sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1, order = intArrayOf(2)) @AssertCalled(count = 1, order = intArrayOf(2))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
} }
@ -571,7 +569,7 @@ class GeckoSessionTestRuleTest {
} }
@Test fun delegateUntilTestEnd_currentCall() { @Test fun delegateUntilTestEnd_currentCall() {
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener { sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onPageStop(session: GeckoSession, success: Boolean) { override fun onPageStop(session: GeckoSession, success: Boolean) {
val info = sessionRule.currentCall val info = sessionRule.currentCall
@ -590,7 +588,7 @@ class GeckoSessionTestRuleTest {
@Test fun delegateDuringNextWait() { @Test fun delegateDuringNextWait() {
var counter = 0 var counter = 0
sessionRule.delegateDuringNextWait(object : Callbacks.ProgressListener { sessionRule.delegateDuringNextWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
counter++ counter++
@ -616,7 +614,7 @@ class GeckoSessionTestRuleTest {
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
fun delegateDuringNextWait_throwOnNotCalled() { fun delegateDuringNextWait_throwOnNotCalled() {
sessionRule.delegateDuringNextWait( sessionRule.delegateDuringNextWait(
GeckoSession.ScrollListener @AssertCalled(count = 1) { _, _, _ -> }) GeckoSession.ScrollDelegate @AssertCalled(count = 1) { _, _, _ -> })
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
} }
@ -624,7 +622,7 @@ class GeckoSessionTestRuleTest {
@Test(expected = AssertionError::class) @Test(expected = AssertionError::class)
fun delegateDuringNextWait_throwOnNotCalledAtTestEnd() { fun delegateDuringNextWait_throwOnNotCalledAtTestEnd() {
sessionRule.delegateDuringNextWait( sessionRule.delegateDuringNextWait(
GeckoSession.ScrollListener @AssertCalled(count = 1) { _, _, _ -> }) GeckoSession.ScrollDelegate @AssertCalled(count = 1) { _, _, _ -> })
sessionRule.performTestEndCheck() sessionRule.performTestEndCheck()
} }
@ -632,8 +630,8 @@ class GeckoSessionTestRuleTest {
var testCounter = 0 var testCounter = 0
var waitCounter = 0 var waitCounter = 0
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener, sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate,
Callbacks.NavigationListener { Callbacks.NavigationDelegate {
@AssertCalled(count = 1, order = intArrayOf(2)) @AssertCalled(count = 1, order = intArrayOf(2))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
testCounter++ testCounter++
@ -655,7 +653,7 @@ class GeckoSessionTestRuleTest {
} }
}) })
sessionRule.delegateDuringNextWait(object : Callbacks.ProgressListener { sessionRule.delegateDuringNextWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
waitCounter++ waitCounter++

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

@ -20,7 +20,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@MediumTest @MediumTest
class NavigationListenerTest { class NavigationDelegateTest {
companion object { companion object {
const val HELLO_HTML_PATH = "/assets/www/hello.html"; const val HELLO_HTML_PATH = "/assets/www/hello.html";
const val HELLO2_HTML_PATH = "/assets/www/hello2.html"; const val HELLO2_HTML_PATH = "/assets/www/hello2.html";
@ -39,16 +39,16 @@ class NavigationListenerTest {
sessionRule.session.loadTestPath(HELLO_HTML_PATH) sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener { sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadUri(session: GeckoSession, uri: String, override fun onLoadUri(session: GeckoSession, uri: String,
where: GeckoSession.NavigationListener.TargetWindow): Boolean { where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
assertThat("Session should not be null", session, notNullValue()) assertThat("Session should not be null", session, notNullValue())
assertThat("URI should not be null", uri, notNullValue()) assertThat("URI should not be null", uri, notNullValue())
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH)) assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
assertThat("Where should not be null", where, notNullValue()) assertThat("Where should not be null", where, notNullValue())
assertThat("Where should match", where, assertThat("Where should match", where,
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT)) equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
return false return false
} }
@ -85,13 +85,13 @@ class NavigationListenerTest {
sessionRule.session.reload() sessionRule.session.reload()
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener { sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadUri(session: GeckoSession, uri: String, override fun onLoadUri(session: GeckoSession, uri: String,
where: GeckoSession.NavigationListener.TargetWindow): Boolean { where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH)) assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
assertThat("Where should match", where, assertThat("Where should match", where,
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT)) equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
return false return false
} }
@ -124,7 +124,7 @@ class NavigationListenerTest {
sessionRule.session.loadTestPath(HELLO2_HTML_PATH) sessionRule.session.loadTestPath(HELLO2_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener { sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onLocationChange(session: GeckoSession, url: String) { override fun onLocationChange(session: GeckoSession, url: String) {
assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH)) assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH))
@ -134,13 +134,13 @@ class NavigationListenerTest {
sessionRule.session.goBack() sessionRule.session.goBack()
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener { sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadUri(session: GeckoSession, uri: String, override fun onLoadUri(session: GeckoSession, uri: String,
where: GeckoSession.NavigationListener.TargetWindow): Boolean { where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH)) assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
assertThat("Where should match", where, assertThat("Where should match", where,
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT)) equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
return false return false
} }
@ -168,13 +168,13 @@ class NavigationListenerTest {
sessionRule.session.goForward() sessionRule.session.goForward()
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener { sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadUri(session: GeckoSession, uri: String, override fun onLoadUri(session: GeckoSession, uri: String,
where: GeckoSession.NavigationListener.TargetWindow): Boolean { where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
assertThat("URI should match", uri, endsWith(HELLO2_HTML_PATH)) assertThat("URI should match", uri, endsWith(HELLO2_HTML_PATH))
assertThat("Where should match", where, assertThat("Where should match", where,
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT)) equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
return false return false
} }
@ -201,10 +201,10 @@ class NavigationListenerTest {
} }
@Test fun onLoadUri_returnTrueCancelsLoad() { @Test fun onLoadUri_returnTrueCancelsLoad() {
sessionRule.delegateDuringNextWait(object : Callbacks.NavigationListener { sessionRule.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 2) @AssertCalled(count = 2)
override fun onLoadUri(session: GeckoSession, uri: String, override fun onLoadUri(session: GeckoSession, uri: String,
where: GeckoSession.NavigationListener.TargetWindow): Boolean { where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
return uri.endsWith(HELLO_HTML_PATH) return uri.endsWith(HELLO_HTML_PATH)
} }
}) })
@ -213,7 +213,7 @@ class NavigationListenerTest {
sessionRule.session.loadTestPath(HELLO2_HTML_PATH) sessionRule.session.loadTestPath(HELLO2_HTML_PATH)
sessionRule.waitForPageStop() sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener { sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
@AssertCalled(count = 1, order = intArrayOf(1)) @AssertCalled(count = 1, order = intArrayOf(1))
override fun onPageStart(session: GeckoSession, url: String) { override fun onPageStart(session: GeckoSession, url: String) {
assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH)) assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH))

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

@ -37,7 +37,7 @@ public class NavigationTests extends BaseGeckoViewTest {
@Override public void run() { @Override public void run() {
loadTestPath("hello2.html", new Runnable() { loadTestPath("hello2.html", new Runnable() {
@Override public void run() { @Override public void run() {
mSession.setNavigationListener(new GeckoSession.NavigationListener() { mSession.setNavigationDelegate(new GeckoSession.NavigationDelegate() {
@Override @Override
public void onLocationChange(GeckoSession session, String url) { public void onLocationChange(GeckoSession session, String url) {
assertTrue("URL should end with " + startPath + ", got " + url, url.endsWith(startPath)); assertTrue("URL should end with " + startPath + ", got " + url, url.endsWith(startPath));
@ -78,7 +78,7 @@ public class NavigationTests extends BaseGeckoViewTest {
public void testReload() { public void testReload() {
loadTestPath("hello.html", new Runnable() { loadTestPath("hello.html", new Runnable() {
@Override public void run() { @Override public void run() {
mSession.setProgressListener(new GeckoSession.ProgressListener() { mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
@Override @Override
public void onPageStart(GeckoSession session, String url) { public void onPageStart(GeckoSession session, String url) {
} }
@ -104,7 +104,7 @@ public class NavigationTests extends BaseGeckoViewTest {
@Test @Test
public void testExpiredCert() { public void testExpiredCert() {
mSession.setProgressListener(new GeckoSession.ProgressListener() { mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
private boolean mNotBlank; private boolean mNotBlank;
@Override @Override
@ -133,7 +133,7 @@ public class NavigationTests extends BaseGeckoViewTest {
@Test @Test
public void testValidTLS() { public void testValidTLS() {
mSession.setProgressListener(new GeckoSession.ProgressListener() { mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
private boolean mNotBlank; private boolean mNotBlank;
@Override @Override
@ -162,7 +162,7 @@ public class NavigationTests extends BaseGeckoViewTest {
@Test @Test
public void testOnNewSession() { public void testOnNewSession() {
mSession.setNavigationListener(new GeckoSession.NavigationListener() { mSession.setNavigationDelegate(new GeckoSession.NavigationDelegate() {
@Override @Override
public void onLocationChange(GeckoSession session, String url) { public void onLocationChange(GeckoSession session, String url) {
} }
@ -185,7 +185,7 @@ public class NavigationTests extends BaseGeckoViewTest {
@Override @Override
public void onNewSession(GeckoSession session, String uri, GeckoSession.Response<GeckoSession> response) { public void onNewSession(GeckoSession session, String uri, GeckoSession.Response<GeckoSession> response) {
final GeckoSession newSession = new GeckoSession(session.getSettings()); final GeckoSession newSession = new GeckoSession(session.getSettings());
newSession.setContentListener(new GeckoSession.ContentListener() { newSession.setContentDelegate(new GeckoSession.ContentDelegate() {
@Override @Override
public void onTitleChange(GeckoSession session, String title) { public void onTitleChange(GeckoSession session, String title) {
@ -218,7 +218,7 @@ public class NavigationTests extends BaseGeckoViewTest {
} }
}); });
mSession.setProgressListener(new GeckoSession.ProgressListener() { mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
@Override @Override
public void onPageStart(GeckoSession session, String url) { public void onPageStart(GeckoSession session, String url) {
@ -245,10 +245,10 @@ public class NavigationTests extends BaseGeckoViewTest {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testOnNewSessionNoExisting() { public void testOnNewSessionNoExisting() {
// This makes sure that we get an exception if you try to return // This makes sure that we get an exception if you try to return
// an existing GeckoSession instance from the NavigationListener.onNewSession() // an existing GeckoSession instance from the NavigationDelegate.onNewSession()
// implementation. // implementation.
mSession.setNavigationListener(new GeckoSession.NavigationListener() { mSession.setNavigationDelegate(new GeckoSession.NavigationDelegate() {
@Override @Override
public void onLocationChange(GeckoSession session, String url) { public void onLocationChange(GeckoSession session, String url) {
} }
@ -275,7 +275,7 @@ public class NavigationTests extends BaseGeckoViewTest {
} }
}); });
mSession.setProgressListener(new GeckoSession.ProgressListener() { mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
@Override @Override
public void onPageStart(GeckoSession session, String url) { public void onPageStart(GeckoSession session, String url) {

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